From: Emil Date: Mon, 16 Oct 2023 00:56:16 +0000 (+0000) Subject: Baked -> Bake, Add Shake as bootstrapper, @COMPILECMD comes first X-Git-Tag: v20240302~40 X-Git-Url: https://git.xolatile.top/?a=commitdiff_plain;h=4b1ff1f7c26612fa014861ae030bfaf2b22374cf;p=emil-bake.git Baked -> Bake, Add Shake as bootstrapper, @COMPILECMD comes first --- diff --git a/README b/README index f1d1699..510d4af 100644 --- a/README +++ b/README @@ -1,35 +1,49 @@ -Baked, embed scripts into files. +Bake scripts into files. Executes @EXEC to the end of the line or STOP@ within in any given file. +If there is no STOP@, it'll simply execute until the end of line, supports +backslashes to include additional lines. -you may see a real example in the primary and only source file: `baked.c'. +you may see a real example in the primary and only source file: `bake.c'. this is not targeted toward any language and should be fairly flexible, especially when multi-line comments are available. +The execution takes place at the root of the target file, so if you have: +/my/test/file.c, and then execution takes place at /my/test. + Buildng +Bootstrapping may be done with Shake, simply run `./shake ./bake.c' + Initial building may be done by examining and running `install.sh', if you don't want to install it right away, run `SUDO= TARGET=. ./install.sh' -Name/Arg extension +Name/Arg Extension $@: the name of the executed file $*: the text of the filename before the last dot -$+: the remaining arguments to Baked +$+: the remaining arguments to Bake -Options extension +Options Extension only one option may be in use at a time, and must come as the first argument. -h, --help: displays help message, similiarly to empty input. -n, --dry-run: DRYRUN, does NOT run anything! -Notes +Shake -Baked was inspired by the Bash-based Shake utility (formerly eMake, +Bake was inspired by the Bash-based Shake utility (formerly eMake, he liked my suggestion for a name), written by an anon, which you may view at: -Baked is licensed under the GPLv3, See LICENSE. +Bake includes Shake, both in installation, and as a bootstrapper. It +is included under creator's permission. It is not a replacement for +Bake, but it is platform independent in regards to it's use of Bash. + +Shake is a bash based build utility which only seaches for, and executes +the first line including @COMPILECMD. It supports $@, and $*. + +Bake is licensed under the GPLv3, See LICENSE. -Baked began on September 13th, 2023. +Bake began on September 13th, 2023. diff --git a/bake.c b/bake.c new file mode 100644 index 0000000..01e3b70 --- /dev/null +++ b/bake.c @@ -0,0 +1,354 @@ +/* bake.c - Ever burned a cake? + * Copyright 2023 Emil Williams + * + * Licensed under the GNU Public License version 3 only, see LICENSE. + * + * Using COMPILECMD and including the # STOP for bake/shake support + * @COMPILECMD cc $@ -o $* -std=gnu89 -O2 -Wall -Wextra -Wpedantic -pipe $CFLAGS # STOP@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Require space after COMPILECMD/EXEC and before STOP (no space required around newline) */ +#define REQUIRE_SPACE +/* May be be left undefined, comes second */ +#define OTHER_START "@EXEC" + +#define START "@COMPILECMD" +#define STOP "STOP@" +#define HELP \ + "target-file [arguments ...]\n" \ + "Use the format `@EXEC cmd ...' within the target-file, this will execute the\n" \ + "rest of line, or if found within the file, until the STOP@ marker. You may use\n" \ + "@COMPILECMD instead of @EXEC. Whitespace is required after and before both\n" \ + "operators always.\n" + + +#define DESC \ + "Options [Must always be first]\n" \ + "\t-h --help, -n --dry-run\n" \ + "Expansions\n" \ + "\t$@ returns target-file (abc.x.txt)\n" \ + "\t$* returns target-file without suffix (^-> abc.x)\n" \ + "\t$+ returns arguments\n" + +#define local_assert(expr, ret) do { assert(expr); if (!expr) { return ret; }} while (0) + +static char * g_filename, * g_short, * g_all; + +static char * +map(char * fn, size_t * len) +{ + struct stat s; + int fd; + char * addr = NULL; + fd = open(fn, O_RDONLY); + if (fd != -1) + { + if (!fstat(fd,&s) + && s.st_mode & S_IFREG + && s.st_size) + { + *len = s.st_size; + addr = mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0); + } + close(fd); + } + return addr; +} + +static char * +find(char * x, char * buf, size_t max, size_t min) +{ + char * start = buf; + for (; *buf; ++buf) + { + if (max - (buf - start) > min && !strncmp(buf, x, min)) + { return buf; } + } + return NULL; +} + +static char * +find_region(char * fn) +{ + size_t len = 0; + char * buf = NULL, * addr; + char * start, * stop; + addr = map(fn, &len); + if ((ptrdiff_t) addr > 0) + { + start = find(START, addr, len, strlen(START)); +#ifdef OTHER_START + if (!start) + { + start = find(OTHER_START, addr, len, strlen(OTHER_START)); + start = (char *) /* DON'T QUESTION IT */ + ((ptrdiff_t) (start - strlen(START) + strlen(OTHER_START)) * (start != 0)); + } +#endif /* OTHER_START */ + if (start) + { + start += strlen(START); +#ifdef REQUIRE_SPACE + if (!isspace(*start)) + { + fprintf(stderr, "ERROR: Found start without suffix spacing.\n"); + goto stop; + } +#endif + stop = find(STOP, start, len - (start - addr), strlen(STOP)); + if (!stop) + { + stop = start; + while (*stop && *stop != '\n') + { + if (stop[0] == '\\' && stop[1] == '\n') + { stop += 2; } + ++stop; + } + } +#ifdef REQUIRE_SPACE + else + { + if (!isspace(*(stop - 1))) + { + fprintf(stderr, "ERROR: Found stop without prefixing spacing.\n"); + goto stop; + } + } +#endif + if (stop) + { buf = strndup(start, (stop - addr) - (start - addr)); } + } + stop: + munmap(addr, len); + } + return buf; +} + +static void +swap(char * a, char * b) +{ + *a ^= *b; + *b ^= *a; + *a ^= *b; +} + +static int +root(char * root) +{ + int ret; + char x[1] = "\0"; + size_t len = strlen(root); + while (len && root[len] != '/') + { --len; } + if (!len) + { return 0; } + swap(root + len, x); + ret = chdir(root); + swap(root + len, x); + return ret; +} + +static char * +insert(char * new, char * str, size_t offset, size_t shift) +{ + size_t len, max; + local_assert(new, str); + local_assert(str, NULL); + len = strlen(new); + max = (strlen(str) + 1 - offset - shift); + memmove(str + offset + len, str + offset + shift, max); + memcpy(str + offset, new, len); + return str; +} + +static char * +shorten(char * fn) +{ + size_t i, last = 0, len; + char * sh; + local_assert(fn, NULL); + len = strlen(fn); + sh = malloc(len + 1); + local_assert(sh, NULL); + for (i = 0; i < len; ++i) + { + if (fn[i] == '.') + { last = i; } + } + last = last ? last : i; + 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 = argc; + for (i = 2; i < argc; ++i) + { len += strlen(argv[i]); } + all = malloc(len + 1); + local_assert(all, NULL); + all[len] = '\0'; + len = 0; + for (i = 2; i < argc; ++i) + { + strcpy(all + len, argv[i]); + len += strlen(argv[i]) + 1; + if (i + 1 < argc) + { all[len - 1] = ' '; } + } + } + return all; +} + +static size_t +expand_size(char * buf, int argc, char ** argv) +{ + size_t i, len, max; + len = max = strlen(buf) + 1; + for (i = 0; i < len; ++i) + { + if (buf[i] == '\\') + { i += 2; continue; } + else if (buf[i] == '$') + { + switch (buf[++i]) + { + case '@': + max += strlen(g_filename); + break; + case '*': + if (!g_short) + { g_short = shorten(g_filename); } + max += g_short ? strlen(g_short) : 0; + break; + case '+': + if (!g_all) + { g_all = all_args((size_t) argc, argv); } + max += g_all ? strlen(g_all) : 0; + break; + } + } + } + return max; +} + +static char * +expand(char * buf) +{ + size_t i; + char * ptr = NULL; + for (i = 0; buf[i]; ++i) + { + if (buf[i] == '\\') + { i += 2; continue; } + else if (buf[i] == '$') + { + switch (buf[++i]) + { + case '@': + ptr = g_filename; + break; + case '*': + ptr = g_short; + break; + case '+': + ptr = g_all ? g_all : ""; + break; + default: continue; + } + buf = insert(ptr, buf, i - 1, 2); + } + } + free(g_short); free(g_all); + return buf; +} + +static size_t +strip(char * buf) +{ + size_t i = strlen(buf); + if (!i) + { return 0; } + while (isspace(buf[i - 1])) + { --i; } + buf[i] = '\0'; + for (i = 0; isspace(buf[i]); ++i); + return i - (buf[i - 1] == '\n'); +} + +static int +run(char * buf) +{ + fputs("Output:\n", stderr); + root(g_filename); + return system(buf); +} + +int +main(int argc, char ** argv) +{ + int ret = 0; + char * buf; + + assert(setlocale(LC_ALL, "C")); + + if (argc < 2 + || !strcmp(argv[1], "-h") + || !strcmp(argv[1], "--help")) + { goto help; } + + g_filename = argv[1]; + + if (!strcmp(argv[1], "-n") + || !strcmp(argv[1], "--dry-run")) + { + if (argc > 2) + { ret = 1; g_filename = argv[2]; } + else + { goto help; } + } + + buf = find_region(g_filename); + + if (!buf) + { + if (errno) + { perror(argv[0]); } + else + { fprintf(stderr, "%s: File unrecognized.\n", argv[0]); } + return 1; + } + + buf = realloc(buf, expand_size(buf, argc, argv)); + local_assert(buf, 1); + buf = expand(buf); + fprintf(stderr, "Exec: %s\n", buf + strip(buf)); + if ((ret = ret ? 0 : run(buf))) + { fprintf(stderr, "Result: %d\n", ret); } + + free(buf); + return ret; +help: + fprintf(stderr, "%s: %s", argv[0], HELP DESC); + return 1; +} diff --git a/baked-nobloat.c b/baked-nobloat.c deleted file mode 100644 index 69b8d84..0000000 --- a/baked-nobloat.c +++ /dev/null @@ -1,227 +0,0 @@ -/* baked-nobloat.c - cake makes you fat. This version just removes features I don't find entirely necessary ($+, require space, shake support, ctype, and options). - * Copyright 2023 Emil Williams - * Licensed under the GNU Public License version 3 only, see LICENSE. - * @EXEC cc $@ -o $* -std=gnu89 -O2 -Wall -Wextra -Wpedantic -pipe $CFLAGS STOP@ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define START "@EXEC" -#define STOP "STOP@" -#define HELP \ - "target-file [arguments ...]\n" \ - "Use the format `@EXEC cmd ...' within the target-file, this will execute the\n" \ - "rest of line, or if found within the file, until the STOP@ marker.\n" - -#define DESC \ - "Expansions\n" \ - "\t$@ returns target-file (abc.x.txt)\n" \ - "\t$* returns target-file without suffix (^-> abc.x)\n" - -char * g_filename, * g_short; - -static char * -map(char * fn, size_t * len) -{ - struct stat s; - int fd; - char * addr = NULL; - fd = open(fn, O_RDONLY); - if (fd != -1) - { - if (!fstat(fd,&s) - && s.st_mode & S_IFREG - && s.st_size) - { - *len = s.st_size; - addr = mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0); - } - close(fd); - } - return addr; -} - -static char * -find(char * x, char * buf, size_t max, size_t min) -{ - char * start = buf; - for (; *buf; ++buf) - { - if (max - (buf - start) > min && !strncmp(buf, x, min)) - { return buf; } - } - return NULL; -} - -static char * -find_region(char * fn, char * start, char * stop) -{ - size_t len = 0; - char * buf = NULL, * addr; - char * pb, * pe; - addr = map(fn, &len); - if (addr != MAP_FAILED) - { - if ((pb = find(start, addr, len, strlen(start)))) - { - pb += strlen(start); - pe = find(stop, pb, len - (pb - addr), strlen(stop)); - if (pe) - { buf = strndup(pb, (pe - addr) - (pb - addr)); } - } - munmap(addr, len); - } - return buf; -} - - -static char * -insert(char * new, char * str, size_t offset, size_t shift) -{ - size_t len, max; - if (!new || !str) { return NULL; } - len = strlen(new); - max = (strlen(str) + 1 - offset - shift); - memmove(str + offset + len, str + offset + shift, max); - memcpy(str + offset, new, len); - return str; -} - -static char * -shorten(char * fn) -{ - size_t i, last = 0, len; - char * sh; - len = strlen(fn); - sh = malloc(len + 1); - if (!sh) { return NULL; } - for (i = 0; i < len; ++i) - { - if (fn[i] == '.') - { last = i; } - } - last = last ? last : i; - strncpy(sh, fn, last); - sh[last] = '\0'; - return sh; -} - -static size_t -expand_size(char * buf) -{ - size_t i, len, max; - len = max = strlen(buf) + 1; - for (i = 0; i < len; ++i) - { - if (buf[i] == '\\') - { i += 2; continue; } - else if (buf[i] == '$') - { - switch (buf[++i]) - { - case '@': - max += strlen(g_filename); - break; - case '*': - if (!g_short) - { g_short = shorten(g_filename); } - max += g_short ? strlen(g_short) : 0; - break; - } - } - } - return max; -} - -static char * -expand(char * buf) -{ - size_t i; - char * ptr = NULL; - buf = realloc(buf, expand_size(buf)); - if (!buf) { return NULL; } - for (i = 0; buf[i]; ++i) - { - if (buf[i] == '\\') - { i += 2; continue; } - else if (buf[i] == '$') - { - switch (buf[++i]) - { - case '@': - ptr = g_filename; - break; - case '*': - ptr = g_short; - break; - default: continue; - } - buf = insert(ptr, buf, i - 1, 2); - } - } - free(g_short); - return buf; -} - -static void -swap(char * a, char * b) -{ - *a ^= *b; - *b ^= *a; - *a ^= *b; -} - -static int -root(char * root) -{ - int ret; - char x[1] = "\0"; - size_t len = strlen(root); - while (len && root[len] != '/') - { --len; } - if (!len) - { return 0; } - swap(root + len, x); - ret = chdir(root); - swap(root + len, x); - return ret; -} - -int -main(int argc, char ** argv) -{ - char * buf; - setlocale(LC_ALL, "C"); - if (argc < 2) { goto help; } - g_filename = argv[1]; - buf = find_region(g_filename, START, STOP); - if (!buf) - { - if (errno) - { perror(argv[0]); } - else - { fprintf(stderr, "%s: File unrecognized.\n", argv[0]); } - return 1; - } - buf = expand(buf); - root(argv[0]); - fprintf(stderr, "Exec: %s\n", buf); - if (!buf) { return 1; } - fputs("Output:\n", stderr); - fflush(stderr); - system(buf); - free(buf); - return 0; -help: - fprintf(stderr, "%s: %s", argv[0], HELP DESC); - return 1; -} diff --git a/baked.c b/baked.c deleted file mode 100644 index 9c1c379..0000000 --- a/baked.c +++ /dev/null @@ -1,353 +0,0 @@ -/* baked.c - Ever burned a cake? - * Copyright 2023 Emil Williams - * - * Licensed under the GNU Public License version 3 only, see LICENSE. - * - * @EXEC cc $@ -o $* -std=gnu89 -O2 -Wall -Wextra -Wpedantic -pipe $CFLAGS STOP@ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Require space after @ABC and before STOP@ (no space required around newline) */ -#define REQUIRE_SPACE -/* May be undefined */ -#define OTHER_START "@COMPILECMD" - -#define START "@EXEC" -#define STOP "STOP@" -#define HELP \ - "target-file [arguments ...]\n" \ - "Use the format `@EXEC cmd ...' within the target-file, this will execute the\n" \ - "rest of line, or if found within the file, until the STOP@ marker. You may use\n" \ - "@COMPILECMD instead of @EXEC. Whitespace is required after and before both\n" \ - "operators always.\n" - - -#define DESC \ - "Options [Must always be first]\n" \ - "\t-h --help, -n --dry-run\n" \ - "Expansions\n" \ - "\t$@ returns target-file (abc.x.txt)\n" \ - "\t$* returns target-file without suffix (^-> abc.x)\n" \ - "\t$+ returns arguments\n" - -#define local_assert(expr, ret) do { assert(expr); if (!expr) { return ret; }} while (0) - -static char * g_filename, * g_short, * g_all; - -static char * -map(char * fn, size_t * len) -{ - struct stat s; - int fd; - char * addr = NULL; - fd = open(fn, O_RDONLY); - if (fd != -1) - { - if (!fstat(fd,&s) - && s.st_mode & S_IFREG - && s.st_size) - { - *len = s.st_size; - addr = mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0); - } - close(fd); - } - return addr; -} - -static char * -find(char * x, char * buf, size_t max, size_t min) -{ - char * start = buf; - for (; *buf; ++buf) - { - if (max - (buf - start) > min && !strncmp(buf, x, min)) - { return buf; } - } - return NULL; -} - -static char * -find_region(char * fn) -{ - size_t len = 0; - char * buf = NULL, * addr; - char * start, * stop; - addr = map(fn, &len); - if ((ptrdiff_t) addr > 0) - { - start = find(START, addr, len, strlen(START)); -#ifdef OTHER_START - if (!start) - { - start = find(OTHER_START, addr, len, strlen(OTHER_START)); - start = (char *) /* DON'T QUESTION IT */ - ((ptrdiff_t) (start - strlen(START) + strlen(OTHER_START)) * (start != 0)); - } -#endif /* OTHER_START */ - if (start) - { - start += strlen(START); -#ifdef REQUIRE_SPACE - if (!isspace(*start)) - { - fprintf(stderr, "ERROR: Found start without suffix spacing.\n"); - goto stop; - } -#endif - stop = find(STOP, start, len - (start - addr), strlen(STOP)); - if (!stop) - { - stop = start; - while (*stop && *stop != '\n') - { - if (stop[0] == '\\' && stop[1] == '\n') - { stop += 2; } - ++stop; - } - } -#ifdef REQUIRE_SPACE - else - { - if (!isspace(*(stop - 1))) - { - fprintf(stderr, "ERROR: Found stop without prefixing spacing.\n"); - goto stop; - } - } -#endif - if (stop) - { buf = strndup(start, (stop - addr) - (start - addr)); } - } - stop: - munmap(addr, len); - } - return buf; -} - -static void -swap(char * a, char * b) -{ - *a ^= *b; - *b ^= *a; - *a ^= *b; -} - -static int -root(char * root) -{ - int ret; - char x[1] = "\0"; - size_t len = strlen(root); - while (len && root[len] != '/') - { --len; } - if (!len) - { return 0; } - swap(root + len, x); - ret = chdir(root); - swap(root + len, x); - return ret; -} - -static char * -insert(char * new, char * str, size_t offset, size_t shift) -{ - size_t len, max; - local_assert(new, str); - local_assert(str, NULL); - len = strlen(new); - max = (strlen(str) + 1 - offset - shift); - memmove(str + offset + len, str + offset + shift, max); - memcpy(str + offset, new, len); - return str; -} - -static char * -shorten(char * fn) -{ - size_t i, last = 0, len; - char * sh; - local_assert(fn, NULL); - len = strlen(fn); - sh = malloc(len + 1); - local_assert(sh, NULL); - for (i = 0; i < len; ++i) - { - if (fn[i] == '.') - { last = i; } - } - last = last ? last : i; - 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 = argc; - for (i = 2; i < argc; ++i) - { len += strlen(argv[i]); } - all = malloc(len + 1); - local_assert(all, NULL); - all[len] = '\0'; - len = 0; - for (i = 2; i < argc; ++i) - { - strcpy(all + len, argv[i]); - len += strlen(argv[i]) + 1; - if (i + 1 < argc) - { all[len - 1] = ' '; } - } - } - return all; -} - -static size_t -expand_size(char * buf, int argc, char ** argv) -{ - size_t i, len, max; - len = max = strlen(buf) + 1; - for (i = 0; i < len; ++i) - { - if (buf[i] == '\\') - { i += 2; continue; } - else if (buf[i] == '$') - { - switch (buf[++i]) - { - case '@': - max += strlen(g_filename); - break; - case '*': - if (!g_short) - { g_short = shorten(g_filename); } - max += g_short ? strlen(g_short) : 0; - break; - case '+': - if (!g_all) - { g_all = all_args((size_t) argc, argv); } - max += g_all ? strlen(g_all) : 0; - break; - } - } - } - return max; -} - -static char * -expand(char * buf) -{ - size_t i; - char * ptr = NULL; - for (i = 0; buf[i]; ++i) - { - if (buf[i] == '\\') - { i += 2; continue; } - else if (buf[i] == '$') - { - switch (buf[++i]) - { - case '@': - ptr = g_filename; - break; - case '*': - ptr = g_short; - break; - case '+': - ptr = g_all ? g_all : ""; - break; - default: continue; - } - buf = insert(ptr, buf, i - 1, 2); - } - } - free(g_short); free(g_all); - return buf; -} - -static size_t -strip(char * buf) -{ - size_t i = strlen(buf); - if (!i) - { return 0; } - while (isspace(buf[i - 1])) - { --i; } - buf[i] = '\0'; - for (i = 0; isspace(buf[i]); ++i); - return i - (buf[i - 1] == '\n'); -} - -static int -run(char * buf) -{ - fputs("Output:\n", stderr); - root(g_filename); - return system(buf); -} - -int -main(int argc, char ** argv) -{ - int ret = 0; - char * buf; - - assert(setlocale(LC_ALL, "C")); - - if (argc < 2 - || !strcmp(argv[1], "-h") - || !strcmp(argv[1], "--help")) - { goto help; } - - g_filename = argv[1]; - - if (!strcmp(argv[1], "-n") - || !strcmp(argv[1], "--dry-run")) - { - if (argc > 2) - { ret = 1; g_filename = argv[2]; } - else - { goto help; } - } - - buf = find_region(g_filename); - - if (!buf) - { - if (errno) - { perror(argv[0]); } - else - { fprintf(stderr, "%s: File unrecognized.\n", argv[0]); } - return 1; - } - - buf = realloc(buf, expand_size(buf, argc, argv)); - local_assert(buf, 1); - buf = expand(buf); - fprintf(stderr, "Exec: %s\n", buf + strip(buf)); - if ((ret = ret ? 0 : run(buf))) - { fprintf(stderr, "Result: %d\n", ret); } - - free(buf); - return ret; -help: - fprintf(stderr, "%s: %s", argv[0], HELP DESC); - return 1; -} diff --git a/install.sh b/install.sh index 5435c1f..1c7eb3c 100755 --- a/install.sh +++ b/install.sh @@ -1,5 +1,6 @@ #!/bin/sh cd $(dirname "$(readlink -f "$0")") SUDO=${SUDO:-sudo} -cc baked.c -o baked -std=gnu89 -O2 -Wall -Wextra -Wpedantic -pipe $CFLAGS -$SUDO install -m 755 baked ${TARGET:-/usr/local/bin} +chmod +x shake +./shake bake.c +$SUDO install -m 755 shake bake ${TARGET:-/usr/local/bin} diff --git a/shake b/shake new file mode 100755 index 0000000..5044f51 --- /dev/null +++ b/shake @@ -0,0 +1,56 @@ +#!/bin/bash + +BLUE='\033[34m' +GREEN='\033[32m' +BOLD='\033[1m' +NORMAL='\033[0m' + +MARK="@COMPILECMD " +MARKSTR="${BLUE}@COMPILECMD${NORMAL}" + +enable -n echo + +usage() { + IFSTR="${GREEN}${NORMAL}" + echo -e "${BOLD}Usage: $0 ${NORMAL}" >&2 + echo -e "\t$0 runs the value of ${MARKSTR}." >&2 + echo -e "\tThe point of this script is ease to compialation of singe source file (toy) programs." >&2 + echo -e "\tThe value of ${MARKSTR} is read from ${IFSTR} in is whatever comes after '${MARK}' until the end of the line." >&2 + echo -e "\tInside the value of ${MARKSTR} all mentions of special placeholders are replaced:" >&2 + echo -e "\t\t${BLUE}\$@${NORMAL} - ${IFSTR}" + echo -e "\t\t${BLUE}\$*${NORMAL} - ${IFSTR} with the last extension cut off" +} + + + +if [[ $# -ne 1 ]]; then + usage + exit 1 +fi + +if [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then + usage + exit 0 +fi + + + +input_file=$1 + +if [[ ! -f $input_file ]]; then + echo -e "Input file '$input_file' does not exist." >&2 + exit 1 +fi + +line=$(grep "$MARK" "$input_file" | head -1) +line=${line//\$@/$input_file} +line=${line//\$\*/${input_file%.*}} + +if [[ -n $line ]]; then + command="${line#*@COMPILECMD }" + + echo "$command" + eval "$command" +else + echo -e "${MARKSTR} is not defined." >&2 +fi