diff --git a/baked.c b/baked.c index b7c26da..13e26f3 100644 --- a/baked.c +++ b/baked.c @@ -1,43 +1,4 @@ -/* baked.c - Ever burned a cake? - * - * Copyright 2023 Emil Williams - * - * baked is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 - * as published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License - * version 3 along with this program. If not, see . - * - * This program is independent of language, it simply expects the notation as listed below, - * - * EXEC:cc $@ -o $* -std=gnu99 -O2 -Wall -Wextra -Wpedantic -pipe $CFLAGS:STOP - * - * Which will run, and in this case, result in this program compiling itself. - * - * Another (functional) example: - EXEC: - CFLAGS='-std=gnu99 -O2 -Wall -Wextra -Wpedantic -pipe' - cc $@ -o $* $CFLAGS # baked - :STOP - * - * See install.sh for another example coded into a different language. - * It is possible to override environmental variables, as in install.sh, - * you can then have some dynamism. - * - * Realistically, any traditional shell script could be composed in this - * fashion, and be embedded in any file. However, some programming languages - * may not have multiline comments, so you may be restricted to a single line. - * - * with the flag CFLAGS='-DSHAKE_COMPAT' Shake compatibility will be enabled, - * @COMPILECMD cc $@ -o $* -std=gnu99 -O2 -Wall -Wextra -Wpedantic -pipe $CFLAGS # SHAKE_COMPAT enabled - * - * TODO - * - * 1. somehow convince the compiler to do NULL checks before g_... - * so that allocs can be minimized even further (maybe it should be volatile) - * 2. support #!/bin/someshell - */ +/* EXEC:cc $@ -o $* -std=gnu89 -O2 -Wall -Wextra -Wpedantic -pipe $CFLAGS:STOP */ #include #include @@ -49,74 +10,73 @@ #include #ifndef SHAKE_COMPAT -# define HELP \ - "target-file\n" \ +# define HELP \ + "target-file [arguments ...]\n" \ "Use the format `EXEC:command ...:STOP' within the target-file\n" # define START "EXEC:" # define STOP ":STOP" #else -# define HELP \ - "target-file\n" \ +# define HELP \ + "target-file [arguments ...]\n" \ "Use the format `@COMPILECMD command ...\n' within the target-file\n" # define START "@COMPILECMD " # define STOP "\n" #endif #define DESC \ - "\t$@ returns target-file value\n" \ - "\t$* returns target-file without extension\n" \ + "\t$@ returns target-file\n" \ + "\t$* returns target-file without suffix\n" \ "\t$+ returns arguments\n" -#define die(fmt, ...) do { _die(fmt, ##__VA_ARGS__); goto stop; } while (0) - -static const char * argv0; -static char * g_filename = NULL, * g_sh = NULL, * g_all = NULL; - -#define local_assert(expr, ret) do { assert(expr); return ret; } while(0) - -static void -_die(const char * fmt, ...) +static char * +find(char * buf, const char * token) { - va_list ap; - assert(fmt); - fprintf(stderr, "%s: ", argv0); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - if (fmt[0] && - fmt[strlen(fmt)-1] == ':') - { - fputc(' ', stderr); - perror(NULL); - } - else - { fputc('\n', stderr); } + size_t len = strlen(token); + const char * stop = buf + strlen(buf); + do if (!strncmp(buf,token,len)) + { return buf + len; } + while (buf < stop && ++buf); + return NULL; } static char * load(const char * fn) { - struct stat s; + char * buf = NULL; FILE * fp = fopen(fn, "rb"); - if (!(stat(fn,&s)) && - s.st_mode & S_IFREG && - fp) + if (fp) { + struct stat s; size_t len; - char * buf; - len = s.st_size; - if (!(buf = malloc(len + 1))) - { return NULL; } - if (fread(buf, 1, len, fp) > strlen(STOP) + strlen(START)) - { - buf[len] = '\0'; - fclose(fp); - return buf; - } + if (! stat(fn,&s) + && s.st_mode & S_IFREG + && (len = s.st_size) + && (buf = malloc(len + 1)) + && fread(buf, 1, len, fp) > strlen(STOP) + strlen(START)) + { buf[len] = '\0'; } fclose(fp); - free(buf); } - return NULL; + return buf; +} + +static char * +find_region(const char * fn) +{ + size_t len; + char * buf, * start, * stop; + + if (!(buf = load(fn))) + { fprintf(stderr, errno ? "cannot access '%s':" : "'%s': file too short", fn); return NULL; } + + if (!(start = find(buf, START)) + || !(stop = find(start, STOP))) + { fprintf(stderr, "No usable format located in '%s'", fn); return NULL; } + + len = stop - start - strlen(STOP); + memmove(buf, start, len); + buf = realloc(buf, len + 1); + buf[len] = '\0'; + return buf; } static void @@ -140,148 +100,112 @@ root(char * root) swap(root + len, x); ret = chdir(root); swap(root + len, x); - printf("root:%d\n", ret); return ret; } static char * -find(char * buf, const char * token) -{ - size_t len = strlen(token); - const char * stop = buf + strlen(buf); - do if (!strncmp(buf,token,len)) - { return buf + len; } - while (buf < stop && ++buf); - return NULL; -} - -static char * insert(const char * new, char * str, size_t offset, size_t shift) { size_t len = strlen(new); size_t max = strlen(str) + 1; - /* fprintf(stderr, "params '%s' '%s' %ld %ld\n", new, str, offset, shift); */ - str = realloc(str, max + len); - local_assert(str, NULL); + /* str = realloc(str, max + len); */ memmove(str + offset + len, str + offset + shift, max - offset - shift); memcpy(str + offset, new, len); return str; } static char * -expand(char * buf, size_t len) +expand(char * buf, char ** str) { - size_t i = 0; - char * str = ""; - local_assert(buf, NULL); + size_t i, len = strlen(buf); + int x; + buf = realloc(buf, 500); for (i = 0; i < len; ++i) { if (buf[i] == '\\') - { i+=2; continue; } - if (buf[i] == '$') + { i += 2; continue; } + else if (buf[i] == '$') { switch (buf[++i]) { - case '@': /* replace $@ with g_filename */ - str = g_filename; - break; - case '*': /* replace $* with short nm */ - str = g_sh; - break; - case '+': /* replace $+ with all args */ - str = g_all ? g_all : ""; - break; + case '@': x = 0; break; + case '*': x = 1; break; + case '+': x = 2; break; default: continue; } - buf = insert(str, buf, i - 1, 2); + buf = insert(str[x], buf, i - 1, 2); len = strlen(buf); } } return buf; } -static void -init(char ** argv, int argc) +static char * +shorten(char * fn) { - size_t i, len; - - /* g_filename */ - g_filename = malloc(strlen(argv[1]) + 1); - strcpy(g_filename, argv[1]); - - /* sh */ - { size_t last = 0; - len = strlen(argv[1]); /* co-opting len */ - g_sh = malloc(len + 1); + size_t i, last = 0, len = strlen(fn); + char * sh = malloc(len + 1); for (i = 0; i < len; ++i) { - if (argv[1][i] == '.') + if (fn[i] == '.') { last = i; } } last = last ? last : i; - strncpy(g_sh, argv[1], last); - g_sh[last] = '\0'; - } /* EOL last */ - /* all */ + strncpy(sh, fn, last); + sh[last] = '\0'; + return sh; +} + +static char * +all_args(size_t argc, char ** argv) +{ + char * all = NULL; if (argc > 2) { + size_t i, len = 0; + for (i = 2; i < argc; ++i) + { len += strlen(argv[i]); } + all = malloc(len + 1); + all[len] = '\0'; len = 0; - i = 2; - while (i < (size_t) argc) + for (i = 2; i < argc; ++i) { + strcpy(all + len, argv[i]); len += strlen(argv[i]); - ++i; - } - g_all = malloc(len + 1); - g_all[len] = '\0'; - len = 0; - i = 2; - while (i < (size_t) argc) - { - strcpy(g_all + len, argv[i]); - len += strlen(argv[i]); - ++i; } } + return all; } int main(int argc, char ** argv) { - int ret = 0; - char * buf = NULL; - { size_t len; - { char * start, * stop; - - argv0 = argv[0]; - + int ret; + char * str[3]; + char * buf; if (argc < 2) - { die(HELP); } + { + fprintf(stderr, "%s: %s", argv[0], HELP DESC); + return 1; + } - if (!(buf = load(argv[1])) - || root(argv[1])) - { die(errno ? "cannot access '%s':" : "'%s': file too short", argv[1]); } + /* filename */ + str[0] = argv[1]; - if (!(start = find(buf, START)) - || !(stop = find(start, STOP))) - { die("No usable format located in '%s'", argv[1]); } + /* sh */ + str[1] = shorten(argv[1]); - init(argv, argc); + /* all */ - len = stop - start - strlen(STOP); - memmove(buf, start, len); - } /* EOL start stop*/ - buf = realloc(buf, len + 1); - buf[len] = '\0'; + str[2] = all_args((size_t) argc, argv); + + buf = find_region(argv[1]); + root(argv[1]); + buf = expand(buf, str); fprintf(stderr, "Exec: %s\nOutput:\n", buf); - buf = expand(buf, len); - } /* EOL len */ fprintf(stderr, "Result: %d\n", (ret = system(buf))); - -stop: - free(g_filename); - free(g_sh); - free(g_all); + free(str[2]); + free(str[1]); free(buf); return ret; }