#include #include #include #include #include "cJSON.h" #ifdef _WIN32 char *strndup(const char *s, size_t n) { size_t len = strnlen(s, n); char *p = (char *)malloc(len + 1); if (!p) return NULL; memcpy(p, s, len); p[len] = '\0'; return p; } #endif typedef struct { char *level; char *message; char *title; char *file; int line; int end_line; int col; int end_col; } LogMessage; char *read_stdin_line() { size_t size = 4096; char *line = malloc(size); if (!fgets(line, size, stdin)) { free(line); return NULL; } return line; } char *extract_field(const char *src, const char *key) { const char *start = strstr(src, key); if (!start) return NULL; start += strlen(key); const char *end = strchr(start, ','); if (!end) end = strstr(start, "::"); if (!end) return strdup(start); return strndup(start, end - start); } char *extract_message(const char *src) { const char *start = strstr(src, "::"); if (!start) return NULL; start = strstr(start + 2, "::"); if (!start) return NULL; return strdup(start + 2); } LogMessage parse_log_line(const char *line) { LogMessage msg = {0}; if (strstr(line, "::warning")) msg.level = strdup("Warning"); else if (strstr(line, "::error")) msg.level = strdup("Error"); else if (strstr(line, "::notice")) msg.level = strdup("Notice"); else msg.level = strdup("Debug"); msg.file = extract_field(line, "file="); char *line_str = extract_field(line, "line="); char *col_str = extract_field(line, "col="); msg.line = line_str ? atoi(line_str) : 0; msg.col = col_str ? atoi(col_str) : 0; msg.message = extract_message(line); free(line_str); free(col_str); return msg; } cJSON *log_message_to_json(const LogMessage *msg) { cJSON *obj = cJSON_CreateObject(); cJSON_AddStringToObject(obj, "level", msg->level); cJSON_AddStringToObject(obj, "message", msg->message ? msg->message : ""); cJSON_AddStringToObject(obj, "title", msg->title ? msg->title : NULL); cJSON_AddStringToObject(obj, "file", msg->file ? msg->file : NULL); if (msg->line) cJSON_AddNumberToObject(obj, "line", msg->line); if (msg->end_line) cJSON_AddNumberToObject(obj, "end_line", msg->end_line); if (msg->col) cJSON_AddNumberToObject(obj, "col", msg->col); if (msg->end_col) cJSON_AddNumberToObject(obj, "end_col", msg->end_col); return obj; } void append_log_to_file(const char *filename, const LogMessage *msg) { FILE *fp = fopen(filename, "r"); long length = 0; char *data = NULL; cJSON *array = NULL; if (fp) { fseek(fp, 0, SEEK_END); length = ftell(fp); fseek(fp, 0, SEEK_SET); data = malloc(length + 1); fread(data, 1, length, fp); data[length] = 0; fclose(fp); array = cJSON_Parse(data); free(data); } if (!array || !cJSON_IsArray(array)) { if (array) cJSON_Delete(array); array = cJSON_CreateArray(); } cJSON_AddItemToArray(array, log_message_to_json(msg)); char *json_out = cJSON_Print(array); fp = fopen(filename, "w"); if (fp) { fputs(json_out, fp); fclose(fp); } free(json_out); cJSON_Delete(array); } int main(int argc, char **argv) { const char *filename = NULL; for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "-file") == 0 && i + 1 < argc) { filename = argv[++i]; } } if (!filename) { fprintf(stderr, "Usage: dump_json_append -file \n"); return 1; } char *line = read_stdin_line(); if (!line) { fprintf(stderr, "No input read.\n"); return 0; } // Trim leading and trailing whitespace char *start = line; while (isspace((unsigned char)*start)) start++; char *end = start + strlen(start) - 1; while (end > start && isspace((unsigned char)*end)) end--; *(end + 1) = '\0'; if (strlen(start) == 0) { fprintf(stderr, "Input is empty.\n"); free(line); return 0; } LogMessage msg = parse_log_line(line); append_log_to_file(filename, &msg); free(line); free(msg.level); free(msg.message); free(msg.title); free(msg.file); return 0; }