commit b0a2fc6331f2a05485713d98e2162ed7b7709b74 Author: Emil Williams Date: Sun Sep 22 21:21:10 2024 +0000 flex bake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fcb3f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +cbake +lex.yy.c diff --git a/cbake.l b/cbake.l new file mode 100644 index 0000000..56f551b --- /dev/null +++ b/cbake.l @@ -0,0 +1,135 @@ +/* cbake.l @BAKE flex @FILE && cc -std=c99 -D_GNU_SOURCE -o @SHORT lex.yy.c @ARGS -lfl @STOP */ +%{ + +#include + +#define backspace(fs) fputs("\x08", fs) +#undef ECHO +#define ECHO do { fprintf(stdout, yytext); if (gpipe) { fprintf(gpipe, yytext); } } while (0) +#define CHAR(c) do { fputc(c, stdout); if (gpipe) { fputc(c, gpipe); } } while (0) +#define STRING(s) do { fputs(s, stdout); if (gpipe) { fputs(s, gpipe); } } while (0) +#define FORMAT(...) do { fprintf(stdout, __VA_ARGS__); if (gpipe) { fprintf(gpipe, __VA_ARGS__); } } while (0) +#define FWRITE(str, len) do { fwrite(str, 1, len, stdout); if (gpipe) { fwrite(str, 1, len, gpipe); } } while (0) + +FILE * gpipe; + +char * filename; +int gac; +char ** gav; +/* Options */ +int gselect = 1; +/* Line accum */ +int line = 1; + +extern void root(char * filename); +extern void args(int n); +extern void shorten(char * filename, int n); +%} + +SPACE [[:space:]] +NUM [[:digit:]] + +%x FOUND + +%option nodefault +%% +{ + \\. { /* skip next char */ ; } + @FILENAME|@FILE|$@ { STRING(filename); } + @SHORT:{NUM}+ { shorten(filename, atoi(strrchr(yytext, ':')+1)); } + @SHORT|$\* { shorten(filename, 1); } + @ARGS:{NUM}+ { args(atoi(strrchr(yytext, ':')+1)); } + @ARGS|$\+ { args(-1); } + @STOP { CHAR('\n'); if (gpipe) { fprintf(stderr, "output: "); } if (!gselect) { return 0; } BEGIN INITIAL; } + {SPACE}+ { CHAR(' '); } + . { ECHO; } +} + +@BAKE{SPACE} { if (gselect < 0) { static int nth = 0; printf("%s:%d:s%d: ", filename, line, ++nth); BEGIN FOUND; } if (!--gselect) { BEGIN FOUND; } } +\n|\n { ++line; } +. { ; } +%% + +void root(char * filename) { + char * path, * terminator; + if (!(path = realpath(filename, NULL))) { return; } + if (terminator = strrchr(path, '/')) { + *terminator = '\0'; + chroot(path); + } + free(path); +} + +void args(int n) { + if (n < 0) { for (int i = 0; i < gac; ++i) { STRING(gav[i]); if (i + 1 < gac) { CHAR(' '); } } } + else if (n < gac) { STRING(gav[n]); } +} + +void shorten(char * filename, int n) { + char * end = filename + strlen(filename); + while (n && (end = memrchr(filename, '.', end - filename))) { --n; } + if (!end) { fprintf(stderr, " context error: Argument out of range.\n"); STRING("idiot"); return; } + FWRITE(filename, end - filename); +} + +#define HELP \ + "bake(1) - \"Buy high. Sell low.\"\n" +void help(void) { puts(HELP); } + +int main (int ac, char ** av) { + int run = 1; + char * av0 = av[0]; + FILE * fp, * op; + + while (++av, --ac) { + int i; + if (av[0][0] != '-') { goto start; } + if (av[0][1] == '-') { + if (av[0][2] == '\0') { ++av, --ac; goto start; } + if (!strcmp(av[0]+2, "dry-run")) { i = strlen(av[0]); goto opt_dry_run; } + if (!strcmp(av[0]+2, "select" )) { if (!ac-1 || isdigit(av[1][0])) { goto opt_arg; } ++av, --ac; + i = strlen(av[0]); goto opt_select; } + if (!strcmp(av[0]+2, "list" )) { i = strlen(av[0]); goto opt_list; } + if (!strcmp(av[0]+2, "help" )) { goto opt_help; } + goto opt_default; + } + for (i = 1; i < strlen(av[0]); ++i) { + switch (av[0][i]) { + opt_dry_run: case 'n': run = 0; break; + opt_select: case 's': gselect = atoi(av[0]+2+(av[0][2] == '=')); break; + opt_list: case 'l': run = 0; gselect = -1; break; + opt_help: case 'h': help(); return 0; + opt_default: default: fprintf(stderr, "%s: Unknown option '%s'\n", av0, av[0]); return 1; + opt_arg: fprintf(stderr, "%s: Argument missing for '%s'\n", av0, av[0]); return 1; + } + } + } + + start: + if (!ac) { fprintf(stderr, "%s: Missing filename\n", av0); return 1; } + + /* filename and self placement */ + filename = av[0]; + root(filename); + { + char * tmp = strrchr(filename, '/'); + if (tmp) { filename = tmp+1; } + } + + /* open and prepare ac, av */ + if (!(yyin = fp = fopen(filename, "rb"))) + { fprintf(stderr, "%s: '%s' %s\n", av0, filename, strerror(errno)); return 1; } + gac = --ac, gav = ++av; + + if (run) { + gpipe = popen("/bin/sh -e", "w"); + if (!gpipe) { fprintf(stderr, "%s: %s\n", av0, strerror(errno)); return 1; } + } + if (gselect > 0) { fprintf(stderr, "%s: ", av0); fflush(stderr); } + yylex(); + if (gselect > 0) { fprintf(stderr, "%s: Out of range\n", av0); } + fclose(fp); + + if (run) { run = pclose(gpipe); if (run) { printf("%s: Exit code %d\n", av0, run); } return run; } + return 0; +} diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..806173b --- /dev/null +++ b/install.sh @@ -0,0 +1,5 @@ +cd "$(dirname "$(readlink -f $0)")" +PREFIX=${PREFIX:-/usr/local} +echo "PREFIX=$PREFIX" +bake cbake.l +install -m755 -sv ./cbake $PREFIX/bin/