1
0
mirror of https://git.lain.church/bake/bake.git synced 2025-05-15 08:06:43 +00:00
bake/source/bake2.c

193 lines
4.9 KiB
C

/* @BAKE cc -I. -std=c99 -O2 -Wall -Wextra -Wpedantic -Wno-parentheses -Wno-implicit-fallthrough -o @SHORT sds.c @FILENAME @ARGS @STOP */
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sds.h>
#define ARRLEN(x) (sizeof (x) / sizeof (x [0]))
#define START "@" "BAKE" " "
#define STOP "@" "STOP"
#define ENABLE_COLOR 1
#include "color.h"
static int map(char * filename, char ** buffer, size_t * buffer_length) {
int err = 0, fd = open(filename, O_RDONLY);
if (fd != -1) {
struct stat s;
if (!fstat(fd, &s) && s.st_mode & S_IFREG && s.st_size) {
*buffer_length = (size_t) s.st_size;
*buffer = (char *) mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
} else {
err = 1;
}
close(fd);
}
return err;
}
void root(const char * filename) {
char * string = strdupa(filename), * terminator = strrchr(string, '/');
if (terminator) {
terminator = '\0';
chdir(string);
}
}
void err(char * msg) { fprintf(stderr, "%s\n", msg); abort(); }
void help(void) { abort(); }
void selection_list(char * buffer, size_t buffer_length, sds ** rlist, size_t * rlist_length) {
sds * list = malloc(0);
size_t list_length = 0;
char * search = buffer;
char * start;
while (start = memmem(search, buffer_length, START, strlen(START))) {
buffer_length -= start - buffer + strlen(START);
search = start + strlen(START);
char * end = memmem(search, buffer_length, STOP, strlen(STOP));
if (!end) { end = memchr(search, '\n', buffer_length);}
if (start && end) {
list = realloc(list, ++list_length * sizeof(sds));
list[list_length-1] = sdsnewlen(start,end-start);
}
}
*rlist = list;
*rlist_length = list_length;
}
int main(int argc, char ** argv) {
char * filename = NULL;
int run = 1, select = 0, olist = 0;
for (int off = 1; off < argc; ++off) {
if (argv [off][0] != '-') { filename = argv [off]; ++off; break; }
if (argv [off][1] != '-') {
while (*(++argv [off]))
switch (argv [off][0]) {
select: case 's':
select = atoi(argv [off] + 1);
if (!select) {
++off;
if (off >= argc) { help(); }
select = atoi(argv [off]);
}
if (select) { goto next; }
default: case 'h': help();
case 'l': olist = 1;
case 'n': run = 0; break;
/* case 'c': color = 0; break; */
/* case 'x': ex = 1; break; */
case 'q': fclose(stderr); fclose(stdout); break;
}
continue;
}
argv[off] += 2;
if (strcmp(argv[off], "select") == 0) { goto select; }
else if (strcmp(argv[off], "list") == 0) { olist = 1; run = 0; }
else if (strcmp(argv[off], "dry-run") == 0) { run = 0; }
/* else if (strcmp(argv[off], "color") == 0) { color = 0; } */
/* else if (strcmp(argv[off], "expunge") == 0) { ex = 1; } */
else if (strcmp(argv[off], "quiet") == 0) { fclose(stderr); fclose(stdout); }
else if (strcmp(argv[off], "help") == 0) { help(); }
next:;
}
if (argc == 1 || !filename) { help(); }
root(filename);
char * buffer = NULL;
size_t buffer_length = 0;
if (map(filename, &buffer, &buffer_length) || !buffer) { err("Could not access file"); }
/* select */
sds * list;
size_t list_length;
selection_list(buffer, buffer_length, &list, &list_length);
if (olist) {
for (size_t i = 0; i < list_length; ++i) {
printf("%s\n", list[i]);
}}
for (size_t i = 0; i < list_length; ++i) {
if (olist || (size_t) select != i) { sdsfree(list[i]); }
}
sds command = list[select];
free(list);
if (olist) { return 0; }
/* expand */
char * macro [] = {
"$*",
"$+",
"$@",
"@ARGS",
"@FILE",
"@FILENAME",
"@LINE"
"@SHORT",
};
char * search;
size_t search_length = sdslen(command);
for (size_t i = 0; i < ARRLEN(macro); ++i) {
search = command;
while (search = memmem(search, search_length, macro[i], strlen(macro[i]))) {
search += strlen(macro[i]);
printf("Found %s\n", macro[i]);
}
}
/* execute */
printf("command: '%s'\n", command);
sdsfree(command);
if (!run) { return 0; }
fprintf (stderr, GREEN "output" RESET ":\n");
pid_t pid;
if ((pid = fork ()) == 0) {
execl ("/bin/sh", "sh", "-c", command, NULL);
return 0; /* execl overwrites the process anyways */
}
if (pid == -1) {
fprintf (stderr, GREEN "%s" RESET ": %s, %s\n", argv [0], "Fork Error", strerror (errno));
return 1;
}
/* reuse of run as status return */
if (waitpid (pid, &run, 0) < 0) {
fprintf (stderr, GREEN "%s" RESET ": " RED "%s" RESET ", %s\n", argv [0], "Wait PID Error", strerror (errno));
return 1;
}
if (!WIFEXITED (run)) {
return 1;
}
return WEXITSTATUS (run);
}