json_compilation_db.c [plain text]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <err.h>
#include <sysexits.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/param.h>
void usage(void);
char *escape_string(const char *);
int main(int argc, char * argv[])
{
struct stat sb;
int ret;
int dstfd;
FILE *dst = NULL;
const char *json_output = NULL;
const char *cwd = NULL;
const char *input_file = NULL;
char start[2];
size_t read_bytes;
int i;
size_t input_file_len;
if (argc < 5) {
usage();
}
json_output = argv[1];
cwd = argv[2];
input_file = argv[3];
argv += 4;
argc -= 4;
input_file_len = strlen(input_file);
if (!(input_file_len > 2 && 0 == strcmp(".c", input_file + input_file_len - 2)) &&
!(input_file_len > 3 && 0 == strcmp(".cp", input_file + input_file_len - 3)) &&
!(input_file_len > 4 && 0 == strcmp(".cpp", input_file + input_file_len - 4))) {
return 0;
}
dstfd = open(json_output, O_RDWR | O_CREAT | O_EXLOCK, DEFFILEMODE);
if (dstfd < 0)
err(EX_NOINPUT, "open(%s)", json_output);
ret = fstat(dstfd, &sb);
if (ret < 0)
err(EX_NOINPUT, "fstat(%s)", json_output);
if (!S_ISREG(sb.st_mode))
err(EX_USAGE, "%s is not a regular file", json_output);
dst = fdopen(dstfd, "w+");
if (dst == NULL)
err(EX_UNAVAILABLE, "fdopen");
read_bytes = fread(start, sizeof(start[0]), sizeof(start)/sizeof(start[0]), dst);
if ((read_bytes != sizeof(start)) || (0 != memcmp(start, "[\n", sizeof(start)/sizeof(start[0])))) {
ret = fseeko(dst, 0, SEEK_SET);
if (ret < 0)
err(EX_UNAVAILABLE, "fseeko");
ret = fputs("[", dst);
if (ret < 0)
err(EX_UNAVAILABLE, "fputs");
} else {
ret = fseeko(dst, -3, SEEK_END);
if (ret < 0)
err(EX_UNAVAILABLE, "fseeko");
ret = fputs(",", dst);
if (ret < 0)
err(EX_UNAVAILABLE, "fputs");
}
fprintf(dst, "\n");
fprintf(dst, "{\n");
fprintf(dst, " \"directory\": \"%s\",\n", cwd);
fprintf(dst, " \"file\": \"%s\",\n", input_file);
fprintf(dst, " \"command\": \"");
for (i=0; i < argc; i++) {
bool needs_escape = strchr(argv[i], '\\') || strchr(argv[i], '"') || strchr(argv[i], ' ');
if (needs_escape) {
char *escaped_string = escape_string(argv[i]);
fprintf(dst, "%s\\\"%s\\\"", i == 0 ? "" : " ", escaped_string);
free(escaped_string);
} else {
fprintf(dst, "%s%s", i == 0 ? "" : " ", argv[i]);
}
}
fprintf(dst, "\"\n");
fprintf(dst, "}\n");
fprintf(dst, "]\n");
ret = fclose(dst);
if (ret < 0)
err(EX_UNAVAILABLE, "fclose");
return 0;
}
void usage(void)
{
fprintf(stderr, "Usage: %s <json_output> <cwd> <input_file> <compiler> [<invocation> ...]\n", getprogname());
exit(EX_USAGE);
}
char *
escape_string(const char *input)
{
size_t len = strlen(input);
size_t i, j;
char *output = malloc(len * 4 + 1);
for (i=0, j=0; i < len; i++) {
char ch = input[i];
if (ch == '\\' || ch == '"') {
output[j++] = '\\';
output[j++] = '\\';
output[j++] = '\\';
}
output[j++] = ch;
}
output[j] = '\0';
return output;
}