186 lines
4.5 KiB
C
186 lines
4.5 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#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);
|
|
|
|
if (!msg.message || strlen(msg.message) == 0) {
|
|
free(msg.level);
|
|
free(msg.file);
|
|
free(line_str);
|
|
free(col_str);
|
|
return NULL;
|
|
}
|
|
|
|
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 <filename>\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);
|
|
|
|
if (!msg) {
|
|
free(line);
|
|
return 0;
|
|
}
|
|
|
|
append_log_to_file(filename, &msg);
|
|
free(line);
|
|
free(msg.level);
|
|
free(msg.message);
|
|
free(msg.title);
|
|
free(msg.file);
|
|
return 0;
|
|
}
|