Error handler that logs into the file defined by the CPL_LOG configuration * option, or stderr otherwise. */
| 1140 | * option, or stderr otherwise. |
| 1141 | */ |
| 1142 | void CPL_STDCALL CPLLoggingErrorHandler(CPLErr eErrClass, CPLErrorNum nError, |
| 1143 | const char *pszErrorMsg) |
| 1144 | |
| 1145 | { |
| 1146 | if (!bLogInit) |
| 1147 | { |
| 1148 | bLogInit = true; |
| 1149 | |
| 1150 | CPLSetConfigOption("CPL_TIMESTAMP", "ON"); |
| 1151 | |
| 1152 | const char *cpl_log = CPLGetConfigOption("CPL_LOG", nullptr); |
| 1153 | |
| 1154 | fpLog = stderr; |
| 1155 | if (cpl_log != nullptr && EQUAL(cpl_log, "OFF")) |
| 1156 | { |
| 1157 | fpLog = nullptr; |
| 1158 | } |
| 1159 | else if (cpl_log != nullptr) |
| 1160 | { |
| 1161 | size_t nPathLen = strlen(cpl_log) + 20; |
| 1162 | char *pszPath = static_cast<char *>(CPLMalloc(nPathLen)); |
| 1163 | strcpy(pszPath, cpl_log); |
| 1164 | |
| 1165 | int i = 0; |
| 1166 | while ((fpLog = CPLfopenUTF8(pszPath, "rt")) != nullptr) |
| 1167 | { |
| 1168 | fclose(fpLog); |
| 1169 | |
| 1170 | // Generate sequenced log file names, inserting # before ext. |
| 1171 | if (strrchr(cpl_log, '.') == nullptr) |
| 1172 | { |
| 1173 | snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log, i++, |
| 1174 | ".log"); |
| 1175 | } |
| 1176 | else |
| 1177 | { |
| 1178 | size_t pos = 0; |
| 1179 | char *cpl_log_base = CPLStrdup(cpl_log); |
| 1180 | pos = strcspn(cpl_log_base, "."); |
| 1181 | if (pos > 0) |
| 1182 | { |
| 1183 | cpl_log_base[pos] = '\0'; |
| 1184 | } |
| 1185 | snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log_base, i++, |
| 1186 | ".log"); |
| 1187 | CPLFree(cpl_log_base); |
| 1188 | } |
| 1189 | } |
| 1190 | |
| 1191 | fpLog = CPLfopenUTF8(pszPath, "wt"); |
| 1192 | CPLFree(pszPath); |
| 1193 | } |
| 1194 | } |
| 1195 | |
| 1196 | if (fpLog == nullptr) |
| 1197 | return; |
| 1198 | |
| 1199 | if (eErrClass == CE_Debug) |