From 3d1e3f9421730b73b5e0259674793c3f6ee25826 Mon Sep 17 00:00:00 2001 From: Emil Williams Date: Sat, 28 Sep 2024 21:35:50 +0000 Subject: [PATCH] expunge, color --- bake.l | 154 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 53 deletions(-) diff --git a/bake.l b/bake.l index 069336f..fa0b1f5 100644 --- a/bake.l +++ b/bake.l @@ -1,63 +1,84 @@ /* cbake.l @BAKE flex @FILE && cc -Wall -Wextra -std=c99 -D_GNU_SOURCE -o @SHORT lex.yy.c @ARGS -lfl @STOP */ -/* TODO: implement expunge, color */ +/* expunge @BAKE flex @FILE && cc -Wall -Wextra -std=c99 -D_GNU_SOURCE -o @{@SHORT} lex.yy.c @ARGS -lfl @STOP */ +/* expunge @BAKE @STOP */ + %{ #include +#define CHAR(c) do { if (stdout) { fputc(c, stdout); } if (g_pipe) { fputc(c, g_pipe); } } while (0) +#define STRING(s) do { if (stdout) { fputs(s, stdout); } if (g_pipe) { fputs(s, g_pipe); } } while (0) +#define FORMAT(...) do { if (stdout) { fprintf(stdout, __VA_ARGS__); } if (g_pipe) { fprintf(g_pipe, __VA_ARGS__); } } while (0) +#define FWRITE(str, len) do { if (stdout) { fwrite(str, 1, len, stdout); } if (g_pipe) { fwrite(str, 1, len, g_pipe); } } while (0) + #undef ECHO -#define ECHO do { fprintf(stdout, yytext); if (g_pipe) { fprintf(g_pipe, yytext); } } while (0) -#define CHAR(c) do { fputc(c, stdout); if (g_pipe) { fputc(c, g_pipe); } } while (0) -#define STRING(s) do { fputs(s, stdout); if (g_pipe) { fputs(s, g_pipe); } } while (0) -#define FORMAT(...) do { fprintf(stdout, __VA_ARGS__); if (g_pipe) { fprintf(g_pipe, __VA_ARGS__); } } while (0) -#define FWRITE(str, len) do { fwrite(str, 1, len, stdout); if (g_pipe) { fwrite(str, 1, len, g_pipe); } } while (0) +#define ECHO STRING(yytext) /* input from main to lexer */ -FILE * g_pipe; -char * g_filename; -int g_ac; -char ** g_av; -int g_select = 1; +FILE * g_pipe = NULL, * g_restore, * g_expunge; +int g_ac, g_select = 1, g_color = 1, g_rm = 0; +char ** g_av, * g_filename, * av0; /* for the lexers eyes only */ -int line = 1, nth = 0, expunge_depth = 0, first_nl, tmpline; +int line = 1, expunge_depth, first_nl, tmpline; extern void root(char * filename); extern void args(int n); extern void shorten(char * filename, int n); +extern void pipeopen(char * filename, char * mode); %} SPACE [ \t\r\v\f] MACROS (@BAKE|@FILENAME|@FILE|@NAME|@SHORT|@ARGS|@LINE|@STOP|$@|$*|$+) -%x FOUND PADDING STOP +%x FOUND PADDING STOP EXPAND %option nodefault noinput nounput noyywrap %% +\n { ++line; } +. { ; } + @BAKE[[:space:]] { bake: + static int nth = 0; first_nl = 1; - - if (yytext[yyleng-1] == '\n') { ++line; } - if (!g_select) { ; } - else if (g_select < 0) { BEGIN FOUND; printf("\n%s:%d:s%d: ", g_filename, line, ++nth); } - else if (!--g_select) { BEGIN FOUND; } + if (yytext[yyleng-1] == '\n') { ++line; } + if (!g_select) { ; } + else if (g_select < 0) { BEGIN FOUND; printf("\n%s:%d:s%d: ", g_filename, line, ++nth); } + else if (!--g_select) { BEGIN FOUND; } } -\n { ++line; } -. {;} - { - @BAKE[[:space:]]|@STOP { BEGIN INITIAL; yyless(0); if (first_nl) { CHAR('\n'); } if (!g_select) { return 0; } } - @FILENAME|@FILE|@NAME|$@ { STRING(g_filename); } - @SHORT:[[:digit:]]+ { shorten(g_filename, atoi(strrchr(yytext, ':')+1)); } - @SHORT|$\* { shorten(g_filename, 1); } - @ARGS:[[:digit:]]+ { args(atoi(strrchr(yytext, ':')+1)); } - @ARGS|$\+ { args(-1); } - @LINE { FORMAT("%d", line); } - @\{ { ++expunge_depth; } - \} { if (!expunge_depth--) { ECHO; } } - \\\n { BEGIN PADDING; ++line; CHAR(' '); } - \\{MACROS} { STRING(yytext + 1); } - \n { CHAR('\n'); ++line; if (first_nl) { BEGIN STOP; first_nl = 0; tmpline = 0; } } - {SPACE} { BEGIN PADDING; CHAR(' '); } - . { ECHO; } + @\{ { + expunge_depth = 1; + if (g_select < 0) { ECHO; } + else if (g_rm && !g_pipe) { + stdout = g_restore; + g_pipe = g_expunge; STRING("rm '"); + } + } + + \} { + if (g_select < 0 || !expunge_depth) { ECHO; break; } + if (g_rm) { STRING("'"); return 0; } + expunge_depth = 0; + } + + ' { if (g_rm) { STRING("\\'"); } else { ECHO; } } + @BAKE[[:space:]]|@STOP { BEGIN INITIAL; yyless(0); if (first_nl) { CHAR('\n'); } if (!g_select) { return 0; } } + \\\n { BEGIN PADDING; ++line; CHAR(' '); } + {MACROS} { BEGIN EXPAND; yyless(0); } + \\{MACROS} { STRING(yytext + 1); } + {SPACE} { BEGIN PADDING; CHAR(' '); } + \n { CHAR('\n'); ++line; if (first_nl) { BEGIN STOP; first_nl = 0; tmpline = 0; } } + .|\\' { ECHO; } +} + +{ + @FILENAME|@FILE|@NAME|$@ { BEGIN FOUND; STRING(g_filename); } + @SHORT:[[:digit:]]+ { BEGIN FOUND; shorten(g_filename, atoi(strrchr(yytext, ':')+1)); } + @SHORT|$\* { BEGIN FOUND; shorten(g_filename, 1); } + @ARGS:[[:digit:]]+ { BEGIN FOUND; args(atoi(strrchr(yytext, ':')+1)); } + @ARGS|$\+ { BEGIN FOUND; args(-1); } + @LINE { BEGIN FOUND; FORMAT("%d", line); } + .|\n { BEGIN FOUND; yyless(0); } } { @@ -74,6 +95,13 @@ MACROS (@BAKE|@FILENAME|@FILE|@NAME|@SHORT|@ARGS|@LINE|@STOP|$@|$*|$+) %% +# define RED "\033[91m" +# define GREEN "\033[92m" +# define YELLOW "\033[93m" +# define DIM "\033[2m" +# define BOLD "\033[1m" +# define RESET "\033[0m" + void root(char * filename) { char * path, * terminator; if (!(path = realpath(filename, NULL))) { return; } @@ -101,13 +129,17 @@ void shorten(char * filename, int n) { FWRITE(filename, end - filename); } -void help(void) { fputs("see bake(1) - \"Buy high. Sell low.\"\n", stderr); } +void help(void) { fprintf(stderr, g_color ? BOLD "%s" RESET : "%s", "see bake(1) - \"Buy high. Sell low.\"\n"); } + +void pipeopen(char * filename, char * mode) { + g_pipe = popen(filename, mode); + if (!g_pipe) { fprintf(stderr, "%s: %s\n", av0, strerror(errno)); exit(1); } +} int main (int ac, char ** av) { int run = 1; - char * av0 = av[0]; + av0 = av[0]; FILE * fp; - /* supports long/short, -allinone, (-X ... -X=... -X) */ while (++av, --ac) { size_t i; @@ -116,7 +148,7 @@ int main (int ac, char ** av) { 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, "color")) { i = strlen(av[0]); goto opt_color; } - if (!strcmp(av[0]+2, "expunge")) { i = strlen(av[0]); goto opt_expunge; } + if (!strcmp(av[0]+2, "expunge")) { i = strlen(av[0]); goto opt_expunge; } 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; } @@ -128,16 +160,18 @@ int main (int ac, char ** av) { opt_dry_run: case 'n': run = 0; break; case 's': /* Covers cases -s -s */ - if (isdigit(av[0][i+1])) { g_select = atoi(av[0]+i+1); } - else if (ac > 1 && isdigit(av[1][0])) { ++av, --ac; opt_select: g_select = atoi(av[0]); } - else { g_select = 0; } - if (!g_select) { fprintf(stderr, "%s: Invalid argument for -s\n", av0); return 1; } + if (g_select != -1) { + if (isdigit(av[0][i+1])) { g_select = atoi(av[0]+i+1); } + else if (ac > 1 && isdigit(av[1][0])) { ++av, --ac; opt_select: g_select = atoi(av[0]); } + else { g_select = 0; } + if (!g_select) { fprintf(stderr, "%s: Invalid argument for -s\n", av0); return 1; } + } i = strlen(av[0]); break; opt_list: case 'l': run = 0; g_select = -1; break; opt_help: case 'h': help(); return 0; - opt_color: case 'c': break; - opt_expunge: case 'x': break; + opt_color: case 'c': g_color = 0; break; + opt_expunge: case 'x': if (g_select > 0) { g_rm = 1; } break; 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; } @@ -157,25 +191,39 @@ int main (int ac, char ** av) { /* open and prepare ac, av */ if (!(yyin = fp = fopen(g_filename, "rb"))) - { fprintf(stderr, "%s: '%s' %s\n", av0, g_filename, strerror(errno)); return 1; } + { fprintf(stderr, g_color ? RED "%s" RESET ": '" BOLD "%s" RESET "' %s\n" : "%s: '%s' %s\n", av0, g_filename, strerror(errno)); return 1; } g_ac = --ac, g_av = ++av; - /* Prepares our UNIX pipe for input */ + /* setup pipe and output */ if (run) { - g_pipe = popen("/bin/sh -e", "w"); - if (!g_pipe) { fprintf(stderr, "%s: %s\n", av0, strerror(errno)); return 1; } + pipeopen("/bin/sh -e /dev/stdin", "w"); } + if (g_rm) { + g_restore = stdout; + g_expunge = g_pipe; + stdout = NULL; + g_pipe = NULL; + } + if (g_select > 0) { fprintf(stderr, g_color ? GREEN "%s" RESET ": " : "%s: ", av0); fflush(stderr); } - if (g_select > 0) { fprintf(stderr, "%s: ", av0); fflush(stderr); } yylex(); fflush(stdout); + + if (g_rm) { + fputs("\n", g_restore); + stdout = g_restore; + g_pipe = g_expunge; + } fclose(fp); + if (g_select > 0) { pclose(g_pipe); goto out_of_range; } if (!run) { return 0; } - fprintf(stderr, "output: "); fflush(stderr); + + if (!g_rm) { fprintf(stderr, g_color ? GREEN "output" RESET ": " : "output: "); fflush(stderr); } + run = pclose(g_pipe); /* repurposed run */ - putchar('\n'); - if (run) { printf("%s: Exit code %d\n", av0, run); } + if (!g_rm) { putchar('\n'); } + if (run) { fprintf(stderr, "%s: Exit code %d\n", av0, run); } return run; out_of_range: fprintf(stderr, "%s: <%d> Out of range\n", av0, g_select); return 1; } -- 2.39.5