Files
cppcheck-action/dump_json_append.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;
}