expunge and whatever

This commit is contained in:
Chad C. Starz 2024-08-31 23:05:09 +00:00
parent d1d459283c
commit 4c96d993fa
No known key found for this signature in database
GPG Key ID: CEEBC9208C287297
3 changed files with 138 additions and 36 deletions

44
README
View File

@ -64,3 +64,47 @@ needs to be tested a bit more to confirm full compatibility.
changes - Rewrite of the code; Removal of -x --expunge; Addition of
@LINE & @NAME, list, & select.
24/08/22 - Expunge
I decided to add expunge back in, after I went back to a project using
it, because I didn't feel like writing a regexp that would prune it.
It works the same. However it's less tested. Backslashes are reliable.
It doesn't eat characters around itself and returns a reliable string.
It does, however, cover the same space as the origin string.
Such brutal expressions as '@{\} @{\}@SHORT\}}' -> '} @{}@SHORT}'
successfully, with expunge_me correctly containing only that.
It's the same, as before. Sadly I didn't generalize the search and
replace code, that's what sed is for, and I didn't want to implement
finite automata for this simple update, so its implementation is primitive.
The implementation as a whole was meant for simplicity,
extensibility. I, before getting it working, got a gorilla version
that removed contextless @{ } successfully, and a version that
contextually removed each @{ and it's respective } via expand.
Interesting note: Old Bake's executable is larger than new Bakes.
So, not only do we have constant memory, but I've saved space.
Note that the only real limitation is that, that we can't make a @BAKE
command the size of THIS file, or a a @BAKE command inlining all of
Bake. If you need such a feature, use the old version of Bake, or
simply extend this version. I may do such things, because the code
here is better.
This project really was never meant to be optimized, simply memory
confined. if it goes over, it'll SEGV and imply to the diligent user
to shorten his commands. If you just need enough in a simple fashion,
boosting:
#define BUFFER_SIZE (1 << 12) /* 4096 bytes; 4 KiB */
TO (1 << 20) /* 1048576 bytes; 1 MiB */
4 KiB is enough in 99% cases and covers 100% of usage that I am aware
of apart from the case of testing this exact faculty. If it does limit
you, you can use an external script or <Using Make!/Old Bake>
I'm not planning to update Shake with @STOP, @LINE, (-x, --expunge),
or any new bells and wistles.

14
bake.1
View File

@ -4,7 +4,7 @@
\- file embeddable scripts
.SH SYNOPSIS
.B bake
[\-chln] [\-s <n>] <FILENAME> [ARGS...]
[\-chlnx] [\-s <N>] <FILENAME> [ARGS...]
.SH DESCRIPTION
bake is a simple tool meant to execute embedded shell commands within
@ -16,10 +16,15 @@ instance of \fB@BAKE\fP appears.
It roots the shell execution in the directory of the given file.
Options must always be put first, and short options may be merged together.
Options must always be put first, and short options may be merged together, numerical options must be trailing.
.HP
\fB\-c \-\-color\fP, \-h \-\-help, \fB\-n \-\-dry\-run\fP, \fB\-l \-\-list\fP, \fB\-s \-\-select\fP <\fBn\fP>
\fB\-c \-\-color\fP, Disables color
\-h \-\-help, Help message
\fB\-n \-\-dry\-run\fP, don't execute anything
\fB\-l \-\-list\fP, lists available shell commands
\fB\-s \-\-select\fP <\FBn\fP>, selects Nth shell command
\fB\-x \-\-expunge\fP, Removes what's specified in the expunge block
.PP
Macros
@ -47,7 +52,8 @@ Additional Features And Notes
Shell execution may be disabled with the \fB-n\fP or \fB--dry-run\fP option.
Colors may be disabled with the \fB-c\fP or \fB--color\fP option.
Expunge removes exactly one file specified in the @{...} format. You may use
backslashes to remove
.SH EXAMPLE
.\" SRC BEGIN (example.c)

114
bake.c
View File

@ -1,4 +1,7 @@
// @BAKE cc -std=c99 -O2 -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough -o @SHORT @FILENAME @ARGS @STOP
/* @BAKE cc -std=c99 -O2 -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough -o @SHORT @FILENAME @ARGS @STOP */
/* @BAKE cc -std=c99 -O2 -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough -o '@{\} @{\}@SHORT\}}' @FILENAME @ARGS @STOP */
/* @BAKE cc -std=c99 -O2 -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough -o '@{\}}' @FILENAME @ARGS @STOP */
/* @BAKE cc -std=c99 -O2 -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough -o '@{a}' @FILENAME @ARGS @STOP */
#define _GNU_SOURCE
#include <ctype.h>
@ -16,8 +19,8 @@
#define BUFFER_SIZE (1 << 12)
#define START ("@" "BAKE" " ")
#define STOP ("@" "STOP")
#define START "@" "BAKE" " "
#define STOP "@" "STOP"
#define AUTONOMOUS_COMPILE 0
@ -45,10 +48,8 @@
#define ARRLEN(x) (sizeof (x) / sizeof (x [0]))
#if AUTONOMOUS_COMPILE
__attribute__((__section__(".text"))) static char autonomous_compile [] =
"@BAKE" " cc -w @FILENAME.c -o @FILENAME @ARGS\n";
#endif
__attribute__((__section__(".text"))) static volatile char autonomous_compile [] =
"@BAKE cc -std=c99 -O2 -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough -o @SHORT @FILENAME.c @ARGS @STOP";
static void
swap (char * a, char * b) {
@ -113,8 +114,7 @@ lines (char * buffer, size_t off) {
}
static char *
expand (char * buffer, size_t length, char ** pairs, size_t count) {
static char expanded [BUFFER_SIZE] = {0};
expand_buffer(char * expanded, char * buffer, size_t length, char ** pairs, size_t count) {
size_t old, new, i, f, off = 0;
/* I need to test the bounds checking here, it'll crash normally if this provision doesn't do anything, though. */
length &= (1 << 12) - 1;
@ -138,6 +138,36 @@ expand (char * buffer, size_t length, char ** pairs, size_t count) {
}
static char *
expand (char * buffer, size_t length, char ** pairs, size_t count) {
static char expanded [BUFFER_SIZE] = {0};
return expand_buffer (expanded, buffer, length, pairs, count);
}
static char *
expunge (char * to, char * from, size_t length, char ** pair, size_t count) {
size_t i, f;
(void)count; /* count isn't actually used... */
static char expunge_me [FILENAME_MAX] = {0};
for (i = 0; i < length; ++i) {
if (memcmp(from + i, pair[0], strlen(pair[0])) == 0) {
if (from[i - 1] == '\\') { --i; memmove(from + i, from + i + 1, length - i); i+=1+strlen(pair[0]); --length; continue; }
for (f = i + strlen(pair[0]); f < length; ++f) {
if (memcmp(from + f, pair[1], strlen(pair[1])) == 0) {
if (from[f - 1] == '\\') { --f; memmove(from + f, from + f + 1, length - f); --length; continue; }
memmove(to + i, from + i + strlen(pair[0]), length - i - strlen(pair[0]));
memmove(to + f - strlen(pair[1]), from + f - 1, length - f);
/* memcpy(to + f - 2, " ", strlen(pair[1])); */
memcpy(expunge_me, to + i, f - i - 1 - strlen(pair[1]));
goto end;
}
}
}
}
end:
return expunge_me;
}
static char *
getmap (char * filename, size_t * length) {
char * buffer = NULL;
int fd = open (filename, O_RDONLY);
@ -192,21 +222,24 @@ color_fprintf (FILE * fp, char * format, ...) {
free (buf);
va_end (ap);
}
/* -- */
int main (int argc, char ** argv) {
void help (void);
int off, run = 1, list = 0, select_input, select = 1;
int off, run = 1, list = 0, ex = 0, select_input, select = 1;
size_t length, begin = 0, end = 0;
pid_t pid;
char line [10], expanded [BUFFER_SIZE], * buffer, * expandedp, * args, * shortened, * filename = NULL;
char line [10], expanded [BUFFER_SIZE], * buffer, * expandedp, * args, * shortened, * filename = NULL,
* paren [] = { "@{", "}" }, * expunge_me = NULL, * bake_begin = START, * bake_end = STOP;
/* opts */
for (off = 1; off < argc; ++off) {
if (argv [off][0] != '-') { filename = argv [off]; ++off; break; }
if (argv [off][1] != '-') {
while (*(++argv [off]))
switch (argv [off][0]) {
case_select: case 's':
select: case 's':
select = atoi (argv [off] + 1);
if (!select) {
++off;
@ -214,19 +247,23 @@ int main (int argc, char ** argv) {
select = atoi (argv [off]);
}
if (select) { goto next; }
case_help: default: case 'h': help ();
case_list: case 'l': list = 1;
case_dryrun: case 'n': run = 0; break;
case_color: case 'c': color = 0; break;
default: case 'h': help ();
case 'l': list = 1;
case 'n': run = 0; break;
case 'c': color = 0; break;
case 'x': ex = 1; break;
case 'q': fclose(stderr); fclose(stdout); break;
}
continue;
}
argv[off] += 2;
if (strcmp(argv[off], "select") == 0) { goto case_select; }
else if (strcmp(argv[off], "list") == 0) { goto case_list; }
else if (strcmp(argv[off], "dry-run") == 0) { goto case_dryrun; }
else if (strcmp(argv[off], "color") == 0) { goto case_color; }
else if (strcmp(argv[off], "help") == 0) { goto case_help; }
if (strcmp(argv[off], "select") == 0) { goto select; }
else if (strcmp(argv[off], "list") == 0) { list = 1; run = 0; }
else if (strcmp(argv[off], "dry-run") == 0) { run = 0; }
else if (strcmp(argv[off], "color") == 0) { color = 0; }
else if (strcmp(argv[off], "expunge") == 0) { ex = 1; }
else if (strcmp(argv[off], "quiet") == 0) { fclose(stderr); fclose(stdout); }
else if (strcmp(argv[off], "help") == 0) { help(); }
next:;
}
if (argc == 1 || !filename) { help (); }
@ -239,14 +276,14 @@ int main (int argc, char ** argv) {
color_fprintf (stderr, RED "%s" RESET ": Could not access '" BOLD "%s" RESET "'\n", argv [0], filename);
return 1;
}
for (begin = 0; (list || select) && begin < length - strlen (START); ++begin) {
if (memcmp (buffer + begin, START, strlen (START)) == 0) {
for (begin = 0; (list || select) && begin < length - strlen (bake_begin); ++begin) {
if (memcmp (buffer + begin, bake_begin, strlen (bake_begin)) == 0) {
size_t stop = begin;
end = begin;
again: while (end < length && buffer[end] != '\n') { ++end; }
if (buffer[end - 1] == '\\') { ++end; goto again; }
while (stop < length - strlen(STOP)) {
if (memcmp(buffer + stop, STOP, strlen(STOP)) == 0) {
while (stop < length - strlen(bake_end)) {
if (memcmp(buffer + stop, bake_end, strlen(bake_end)) == 0) {
if (stop && buffer[stop - 1] == '\\') { ++stop; continue; }
end = stop;
break;
@ -259,7 +296,7 @@ int main (int argc, char ** argv) {
color_puts (RESET);
} else { --select; }
}}
begin += strlen (START) - 1;
begin += strlen (bake_begin) - 1;
if (list) { return 0; }
if (end < begin) {
@ -281,18 +318,32 @@ int main (int argc, char ** argv) {
"$+", args,
"@LINE", line
};
size_t count = ARRLEN (pair);
snprintf (line, 16, "%lu", lines (buffer, begin));
expandedp = expand (buffer + begin, end - begin, pair, count);
expandedp = expand (buffer + begin, end - begin, pair, ARRLEN (pair));
memcpy(expanded, expandedp, BUFFER_SIZE);
expunge_me = expunge (expanded, expanded, strlen(expanded), paren, ARRLEN (paren));
munmap (buffer, length);
/* print and execute */
color_printf (GREEN "%s" RESET ": " BOLD "%s" RESET, argv [0], expanded);
color_fprintf (stderr, GREEN "%s" RESET ": " BOLD "%s" RESET, argv [0], expanded);
if (expanded[strlen(expanded)] != '\n') { puts(""); }
if (ex) {
color_fprintf (stderr, GREEN "%s" RESET ": removing '%s'\n", argv [0], expunge_me);
char * jin = ".c";
if (expunge_me
&& run
&& /* just in case */
memcmp(expunge_me + strlen(expunge_me) - strlen(jin), jin, strlen(jin)) != 0)
{ remove(expunge_me); }
return 0;
}
if (!run) { return 0; }
fflush(stdout);
color_fprintf (stderr, GREEN "output" RESET ":\n");
fflush(stdout);
if ((pid = fork ()) == 0) {
execl ("/bin/sh", "sh", "-c", expanded, NULL);
return 0; /* execl overwrites the process anyways */
@ -334,7 +385,8 @@ void help (void) {
"of the shell command (-n, --dry-run); disable color (-c, --color); list\n"
"(-l, --list) and select (-s<n>, --select <n>) which respectively lists\n"
"all " BOLD "@BAKE" RESET " commands and select & run the Nth command.\n\n"
"It roots the shell execution in the directory of the given file.\n\n"
"It roots the shell execution in the directory of the given file.\n"
"Expunge with @{filename...}, using (-x, --expunge), \\@{} or @{\\}}.\n\n"
"Licensed under the public domain.\n";
color_printf ("%s", help);
exit (1);