Last active
April 11, 2023 09:21
-
-
Save abrasumente233/5f60c9467750130558d3aa2b09483a42 to your computer and use it in GitHub Desktop.
com
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* $ clang++ -o # @ -O2 -Wall | |
* | |
* compile anything | |
* original version by Tom Duff: http://www.iq0.com/duffgram/com.html | |
* here's my own version, with the purpose to learn exec() syscall. | |
* | |
* - 44 | |
* 2021.11.24 | |
*/ | |
// @TODO: don't force C-style comments at start | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <ctype.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
void no_compile_command() { | |
printf("no compile command found.\n"); | |
printf("add your compile command to the first line of your program like:\n"); | |
printf(" // $ clang @ -o #\n"); | |
printf("where:\n"); | |
printf(" $ is the start of the command\n"); | |
printf(" @ is the source filename\n"); | |
printf(" # is the source filename without extension\n"); | |
exit(1); | |
} | |
void help(const char *prog) { | |
printf("usage: %s [-qg] <source> [more arguments]...\n", prog); | |
printf(" -q: don't echo the compile command\n"); | |
printf(" -g: generate compile_commands.json\n"); | |
} | |
int main(int argc, char *argv[]) { | |
if (argc < 2) { | |
help(argv[0]); | |
exit(1); | |
} | |
int arg_index = 1; | |
bool quiet_mode = false; | |
bool generate_compile_commands_json = false; | |
while (argv[arg_index][0] == '-') { | |
if (argv[arg_index][0] == '-') { | |
if (argv[arg_index][1] == 'q') { | |
quiet_mode = true; | |
} else if (argv[arg_index][1] == 'g') { | |
generate_compile_commands_json = true; | |
} else { | |
help(argv[0]); | |
exit(1); | |
} | |
} | |
arg_index++; | |
} | |
const char *filename = argv[arg_index]; | |
int source_fd = open(filename, O_RDONLY); | |
if (source_fd == -1) { | |
printf("unable to open file: %s\n", argv[arg_index]); | |
exit(1); | |
} | |
// get the first line | |
char buffer[8096]; | |
char *sp = buffer; | |
int rc; | |
while ((rc = read(source_fd, sp, 1) != 0)) { | |
if (rc == -1) { | |
printf("read error\n"); | |
exit(1); | |
} | |
if (*sp == '\0') { | |
no_compile_command(); | |
} else if (*sp == '\n') { | |
*sp = '\0'; | |
break; | |
} else if (*sp == '@') { | |
strcpy(sp, argv[arg_index]); | |
sp += strlen(sp); | |
} else if (*sp == '#') { | |
strcpy(sp, argv[arg_index]); | |
for (int i = strlen(sp); i >= 0; i--) { | |
if (sp[i] == '.') { | |
sp[i] = '\0'; | |
sp += i; | |
break; | |
} | |
if (i == 0) { | |
printf("file has no extension.\n"); | |
exit(1); | |
} | |
} | |
} else { | |
sp++; | |
} | |
} | |
close(source_fd); | |
arg_index++; | |
// concat additional arguments to buffer | |
for (int i = arg_index; i < argc; i++) { | |
sp += sprintf(sp, " %s", argv[i]); | |
} | |
// find the command in the first line | |
// by skipping // or /*, plus a $, | |
// which is the start of the command. | |
sp = buffer; | |
while (isspace(*sp)) | |
sp++; | |
if (sp[0] != '/' || (sp[1] != '*' && sp[1] != '/')) { | |
no_compile_command(); | |
} | |
sp += 2; // skip comment mark | |
while (isspace(*sp)) | |
sp++; | |
if (sp[0] != '$') { | |
no_compile_command(); | |
} | |
sp += 1; // skip $ | |
while (isspace(*sp)) | |
sp++; | |
char *command = sp; | |
if (!quiet_mode) { | |
printf("%s\n", command); | |
} | |
if (generate_compile_commands_json) { | |
int cc = open("compile_commands.json", O_WRONLY | O_CREAT | O_TRUNC, 0655); | |
if (cc == -1) { | |
printf("unable to open file: compile_commands.json\n"); | |
exit(1); | |
} | |
char *abs_path = realpath(filename, NULL); | |
if (!abs_path) { | |
printf("realpath: error\n"); | |
exit(1); | |
} | |
char buf[8096]; | |
sprintf(buf, | |
"[\n" | |
" {\n" | |
" \"command\": \"%s\",\n" | |
" \"directory\": \".\",\n" | |
" \"file\": \"%s\"\n" | |
" }\n" | |
"]\n", | |
command, abs_path); | |
if (write(cc, buf, strlen(buf)) == -1) { | |
printf("unable to write file: compile_commands.json\n"); | |
exit(1); | |
} | |
close(cc); | |
free(abs_path); | |
} | |
if (execl("/bin/sh", "sh", "-c", command, NULL) == -1) { | |
printf("exec error\n"); | |
exit(1); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment