the  exceptions  of   multi-line  commands.   It  is   not  a  general
 replacement for Bake.
 
+Shake doesn't support multi-line commands.
+
 Changelog
 
 Bake was created on 2023/09/13, and complete as of 2024/03/02.
 
 Lex. As adviced  by the original creator, I learned  and implemented a
 Bake with lex. It's fully featured, and has new stuff.
+
+2024-10-24 - Awake
+
+Egor (some dead guy) made a AWK implementation of Bake, it's POSIX.
+It doesn't support multi-line, expunge, parses options after filename,
+or changing directory to file's directory - it's compatible with Bake
+otherwise.
+
+ cd /dir/of/file; awake file
+
+See ./awake --help
 
 #!/bin/sh
 # vim:set ft=awk:
+# Written by Egor, modified for compatibility by Emil.
 # SPDX-License-Identifier: Unlicense
-"exec" "${AWK:-awk}" "-f" "$0" "--" "$@" && 0
+"exec" "${AWK:-awk}" "-f" "$(basename $0)" "--" "$@" && 0
 function usage() {
        print "awake: usage: awake [-nl] [-s num] filename [args...]"
        exit
        if (list) {
                print bakenum": "$0
        } else if (select == bakenum) {
-               gsub(/@FILENAME/, filename)
-               gsub(/@NAME/, filename)
-               gsub(/@SHORT/, shortname)
-               gsub(/@ARGS/, extraargs)
-               print
+               gsub(/\$@|@(FILE|FILENAME|NAME)/, filename)
+               gsub(/\$\*|@SHORT/, shortname)
+               gsub(/\$\+|@ARGS/, extraargs)
+               gsub(/@RECURS/, ARGV[0])
+               print "Awake: " $0
+        printf "Output: "
                if (!dryrun) {
                        system($0)
+            print ""
                }
        }
 }
 
-/* cbake.l @BAKE flex @FILE && cc -Wall -Wextra -std=c99 -D_GNU_SOURCE -o   @SHORT  lex.yy.c @ARGS @STOP */
-/* expunge @BAKE flex @FILE && cc -Wall -Wextra -std=c99 -D_GNU_SOURCE -o @{@SHORT} lex.yy.c @ARGS @STOP */
+/* @BAKE flex @FILE && cc -Wall -Wextra -Wwrite-strings -std=c99 -D_GNU_SOURCE -o @SHORT lex.yy.c @ARGS @STOP */
 /* Licensed under the public domain. */
 
 %{
 extern void root(char * filename);
 extern void args(int n, int rest);
 extern void shorten(char * filename, int n);
-extern void pipeopen(char * filename, char * mode);
 %}
 
 SPACE [ \t\r\v\f]
 %%
 
 #include <limits.h>
+#include <stdarg.h>
 
 # define    RED "\033[91m"
 # define  GREEN "\033[92m"
   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");
-    /* Ensures consistency. @SHORT will always return *something* that isn't filename */
-    STRING("idiot");
-    return;
+    fprintf(stderr, "%s: Cannot shorten '%s' any further, aborting due to paranoia\n", av0, filename);
+    abort();
   }
   FWRITE(filename, end - filename);
 }
 
 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: <g_pipe> %s\n", av0, strerror(errno)); exit(1); }
+FILE * pipeopen(char * filename, char * mode) {
+  FILE * pipe = popen(filename, mode);
+  if (!pipe) { fprintf(stderr, "%s: <pipeopen> %s\n", av0, strerror(errno)); exit(1); }
+  return pipe;
+}
+
+void print(FILE * fp, char * color_prefix, char * format, ...) {
+  va_list ap;
+  size_t len = strlen(format);
+  g_color ? fprintf(fp, "%s%s: ", color_prefix, av0)
+          : fprintf(fp,   "%s: ", av0);
+  va_start(ap, format);
+  for (size_t i = 0, f = 0; i < len; ++i) {
+    if (!(format[i] ^ '\033')) {
+      while (format[i] && format[i] != 'm') ++i;
+    } else format[f++] = format[i];
+  }
+  vfprintf(fp, format, ap);
+  va_end(ap);
 }
 
 int main (int ac, char ** av) {
   /* setup pipe and output */
 
   if (run) {
-    pipeopen("/bin/sh -e /dev/stdin", "w");
+#define pipeopen(a,b) pipeopen((char*)(a), (char*)(b))
+    g_pipe = pipeopen("/bin/sh -e /dev/stdin", "w");
   }
   if (g_rm) {
     g_restore = stdout;
   yylex(); fflush(stdout);
 
   if (g_rm) {
-    fputs("\n", g_restore);
+    fputc('\n', g_restore);
     stdout = g_restore;
     g_pipe = g_expunge;
   }
 
   run = pclose(g_pipe); /* repurposed run */
   if (!g_rm) { putchar('\n'); }
-  if (run) { fprintf(stderr, "%s: Exit code %d\n", av0, run); }
+  if (run < 0) { fprintf(stderr, "%s: Exit failure\n", av0); }
+  if (run > 0) { 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;
 }
 
 #!/bin/sh
 # source install
 
-TARGET=${TARGET:-/usr/local}
-INSTALL=${INSTALL:-bake}
+TARGET="${TARGET:-/usr/local}"
+INSTALL="bake"
 
-cd "$(dirname "$(readlink -f $0)")"
+usage() {
+    echo "compiles and installs Bake into /usr/local (or TARGET) in bin/"
+    echo ""
+    echo "--alternatives          Includes awake and shake into the build"
+    echo "--target=DIRECTORY      Target directory like /usr or /usr/local"
+    echo ""
+    exit 1
+}
+
+while [ ! -z $1 ]; do
+    case $(echo "$1" | cut -d= -f1) in
+        "--target")
+            TARGET=$(echo "$1" | cut -d= -f2)
+            ;;
+        "--alternatives")
+            INSTALL="bake shake awake"
+            ;;
+        "--help")
+            usage
+            ;;
+        *)
+            echo "Unknown option: " $1
+            usage
+            ;;
+    esac
+    shift
+done
 
-./shake bake.l -s $@ && \
-mkdir $TARGET/bin $TARGET/man/man1 -p && \
-install -m 755 $INSTALL $TARGET/bin
+cd "$(dirname "$(readlink -f $0)")"
 
-gzip -c bake.1 > $TARGET/man/man1/bake.1.gz
+./awake bake.l
+mkdir -p "$TARGET/bin" "$TARGET/man/man1"
+install -m 755 $INSTALL "$TARGET/bin"
+gzip -c bake.1 > "$TARGET/man/man1/bake.1.gz"