]> git.xolatile.top Git - emil-bake.git/commitdiff
flex bake
authorEmil Williams <emilemilemil@cock.li>
Sun, 22 Sep 2024 21:21:10 +0000 (21:21 +0000)
committerEmil Williams <emilemilemil@cock.li>
Sun, 22 Sep 2024 21:21:10 +0000 (21:21 +0000)
.gitignore [new file with mode: 0644]
cbake.l [new file with mode: 0644]
install.sh [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0fcb3f7
--- /dev/null
@@ -0,0 +1,2 @@
+cbake
+lex.yy.c
diff --git a/cbake.l b/cbake.l
new file mode 100644 (file)
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 <ctype.h>
+
+#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
+%%
+<FOUND>{
+ \\.                { /* 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|<FOUND>\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, "<SHORTEN> 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: <gpipe> %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 (file)
index 0000000..806173b
--- /dev/null
@@ -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/