merge cbake/balex
This commit is contained in:
commit
8179969546
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
bake
|
bake
|
||||||
|
lex.yy.c
|
||||||
|
6
bake.1
6
bake.1
@ -24,7 +24,7 @@ Options must always be put first, and short options may be merged together, nume
|
|||||||
\fB\-n \-\-dry\-run\fP, don't execute anything
|
\fB\-n \-\-dry\-run\fP, don't execute anything
|
||||||
\fB\-l \-\-list\fP, lists available shell commands
|
\fB\-l \-\-list\fP, lists available shell commands
|
||||||
\fB\-s \-\-select\fP <\FBn\fP>, selects Nth shell command
|
\fB\-s \-\-select\fP <\FBn\fP>, selects Nth shell command
|
||||||
\fB\-x \-\-expunge\fP, Removes what's specified in the expunge block
|
\fB\-x \-\-expunge\fP, Removes what's specified in the expunge block <disabled for this build>
|
||||||
.PP
|
.PP
|
||||||
Macros
|
Macros
|
||||||
|
|
||||||
@ -34,15 +34,17 @@ done by a leading backslash, which are NOT subtracted.
|
|||||||
|
|
||||||
These macros will expand to their counterpart before execution.
|
These macros will expand to their counterpart before execution.
|
||||||
.TP
|
.TP
|
||||||
.B @FILENAME, @NAME, $@
|
.B @FILE, @FILENAME, @NAME, $@
|
||||||
returns target\-file (abc.x.txt)
|
returns target\-file (abc.x.txt)
|
||||||
.TP
|
.TP
|
||||||
.B @SHORT, $*
|
.B @SHORT, $*
|
||||||
returns target\-file without suffix (abc.x.txt \-> abc.x)
|
returns target\-file without suffix (abc.x.txt \-> abc.x)
|
||||||
|
supports choice syntax, @SHORT:1
|
||||||
.TP
|
.TP
|
||||||
.B @ARGS, $+
|
.B @ARGS, $+
|
||||||
returns
|
returns
|
||||||
.B arguments
|
.B arguments
|
||||||
|
, supports choice syntax, @ARGS:0 returns the first argument, @ARGS:N so on.
|
||||||
.TP
|
.TP
|
||||||
.B @LINE
|
.B @LINE
|
||||||
returns the line number
|
returns the line number
|
||||||
|
176
bake.l
Normal file
176
bake.l
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/* cbake.l @BAKE flex @FILE && cc -Wall -Wextra -std=c99 -D_GNU_SOURCE -o @SHORT lex.yy.c @ARGS -lfl @STOP */
|
||||||
|
/* TODO: implement expunge, color */
|
||||||
|
%{
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#undef ECHO
|
||||||
|
#define ECHO do { fprintf(stdout, yytext); if (g_pipe) { fprintf(g_pipe, yytext); } } while (0)
|
||||||
|
#define CHAR(c) do { fputc(c, stdout); if (g_pipe) { fputc(c, g_pipe); } } while (0)
|
||||||
|
#define STRING(s) do { fputs(s, stdout); if (g_pipe) { fputs(s, g_pipe); } } while (0)
|
||||||
|
#define FORMAT(...) do { fprintf(stdout, __VA_ARGS__); if (g_pipe) { fprintf(g_pipe, __VA_ARGS__); } } while (0)
|
||||||
|
#define FWRITE(str, len) do { fwrite(str, 1, len, stdout); if (g_pipe) { fwrite(str, 1, len, g_pipe); } } while (0)
|
||||||
|
|
||||||
|
/* input from main to lexer */
|
||||||
|
FILE * g_pipe;
|
||||||
|
char * g_filename;
|
||||||
|
int g_ac;
|
||||||
|
char ** g_av;
|
||||||
|
int g_select = 1;
|
||||||
|
/* for the lexers eyes only */
|
||||||
|
int line = 1, nth = 0, expunge_depth = 0, first_nl, tmpline;
|
||||||
|
|
||||||
|
extern void root(char * filename);
|
||||||
|
extern void args(int n);
|
||||||
|
extern void shorten(char * filename, int n);
|
||||||
|
%}
|
||||||
|
|
||||||
|
SPACE [ \t\r\v\f]
|
||||||
|
MACROS (@BAKE|@FILENAME|@FILE|@NAME|@SHORT|@ARGS|@LINE|@STOP|$@|$*|$+)
|
||||||
|
|
||||||
|
%x FOUND PADDING STOP
|
||||||
|
%option nodefault noinput nounput noyywrap
|
||||||
|
%%
|
||||||
|
|
||||||
|
@BAKE[[:space:]] { bake:
|
||||||
|
first_nl = 1;
|
||||||
|
|
||||||
|
if (yytext[yyleng-1] == '\n') { ++line; }
|
||||||
|
if (!g_select) { ; }
|
||||||
|
else if (g_select < 0) { BEGIN FOUND; printf("\n%s:%d:s%d: ", g_filename, line, ++nth); }
|
||||||
|
else if (!--g_select) { BEGIN FOUND; }
|
||||||
|
}
|
||||||
|
|
||||||
|
\n { ++line; }
|
||||||
|
. {;}
|
||||||
|
|
||||||
|
<FOUND>{
|
||||||
|
@BAKE[[:space:]]|@STOP { BEGIN INITIAL; yyless(0); if (first_nl) { CHAR('\n'); } if (!g_select) { return 0; } }
|
||||||
|
@FILENAME|@FILE|@NAME|$@ { STRING(g_filename); }
|
||||||
|
@SHORT:[[:digit:]]+ { shorten(g_filename, atoi(strrchr(yytext, ':')+1)); }
|
||||||
|
@SHORT|$\* { shorten(g_filename, 1); }
|
||||||
|
@ARGS:[[:digit:]]+ { args(atoi(strrchr(yytext, ':')+1)); }
|
||||||
|
@ARGS|$\+ { args(-1); }
|
||||||
|
@LINE { FORMAT("%d", line); }
|
||||||
|
@\{ { ++expunge_depth; }
|
||||||
|
\} { if (!expunge_depth--) { ECHO; } }
|
||||||
|
\\\n { BEGIN PADDING; ++line; CHAR(' '); }
|
||||||
|
\\{MACROS} { STRING(yytext + 1); }
|
||||||
|
\n { CHAR('\n'); ++line; if (first_nl) { BEGIN STOP; first_nl = 0; tmpline = 0; } }
|
||||||
|
{SPACE} { BEGIN PADDING; CHAR(' '); }
|
||||||
|
. { ECHO; }
|
||||||
|
}
|
||||||
|
|
||||||
|
<PADDING>{
|
||||||
|
{SPACE} { ; }
|
||||||
|
.|\n { yyless(0); BEGIN FOUND; }
|
||||||
|
}
|
||||||
|
|
||||||
|
<STOP>{
|
||||||
|
@BAKE[[:space:]] { line += tmpline; goto bake; }
|
||||||
|
@STOP { BEGIN FOUND; yyless(0); }
|
||||||
|
\n { ++tmpline; yymore(); }
|
||||||
|
.|\\@ { yymore(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
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 < g_ac; ++i) { STRING(g_av[i]); if (i + 1 < g_ac) { CHAR(' '); } } }
|
||||||
|
else if (n < g_ac) { STRING(g_av[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");
|
||||||
|
/* Ensures consistency. @SHORT will always return *something* that isn't filename */
|
||||||
|
STRING("idiot");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FWRITE(filename, end - filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void help(void) { fputs("see bake(1) - \"Buy high. Sell low.\"\n", stderr); }
|
||||||
|
|
||||||
|
int main (int ac, char ** av) {
|
||||||
|
int run = 1;
|
||||||
|
char * av0 = av[0];
|
||||||
|
FILE * fp;
|
||||||
|
|
||||||
|
/* supports long/short, -allinone, (-X ... -X=... -X<NUM>) */
|
||||||
|
while (++av, --ac) {
|
||||||
|
size_t 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;
|
||||||
|
case 's':
|
||||||
|
/* Covers cases -<LAST>s<NUM> -<LAST>s <NUM> */
|
||||||
|
if (isdigit(av[0][i+1])) { g_select = atoi(av[0]+i+1); }
|
||||||
|
else if (ac > 1 && isdigit(av[1][0])) { ++av, --ac; opt_select: g_select = atoi(av[0]); }
|
||||||
|
else { g_select = 0; }
|
||||||
|
if (!g_select) { fprintf(stderr, "%s: Invalid argument for -s\n", av0); return 1; }
|
||||||
|
i = strlen(av[0]);
|
||||||
|
break;
|
||||||
|
opt_list: case 'l': run = 0; g_select = -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; }
|
||||||
|
if (!g_select) { goto out_of_range; }
|
||||||
|
|
||||||
|
g_filename = av[0];
|
||||||
|
root(g_filename);
|
||||||
|
{ /* ensures the filename doesn't have a relative path that would misdirect the command within the new root */
|
||||||
|
char * tmp = strrchr(g_filename, '/');
|
||||||
|
if (tmp) { g_filename = tmp+1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open and prepare ac, av */
|
||||||
|
if (!(yyin = fp = fopen(g_filename, "rb")))
|
||||||
|
{ fprintf(stderr, "%s: '%s' %s\n", av0, g_filename, strerror(errno)); return 1; }
|
||||||
|
g_ac = --ac, g_av = ++av;
|
||||||
|
|
||||||
|
/* Prepares our UNIX pipe for input */
|
||||||
|
if (run) {
|
||||||
|
g_pipe = popen("/bin/sh -e", "w");
|
||||||
|
if (!g_pipe) { fprintf(stderr, "%s: <g_pipe> %s\n", av0, strerror(errno)); return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_select > 0) { fprintf(stderr, "%s: ", av0); fflush(stderr); }
|
||||||
|
yylex(); fflush(stdout);
|
||||||
|
fclose(fp);
|
||||||
|
if (g_select > 0) { pclose(g_pipe); goto out_of_range; }
|
||||||
|
|
||||||
|
if (!run) { return 0; }
|
||||||
|
fprintf(stderr, "output: "); fflush(stderr);
|
||||||
|
run = pclose(g_pipe); /* repurposed run */
|
||||||
|
if (run) { printf("%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;
|
||||||
|
}
|
10
install.sh
10
install.sh
@ -2,14 +2,12 @@
|
|||||||
# source install
|
# source install
|
||||||
|
|
||||||
TARGET=${TARGET:-/usr/local}
|
TARGET=${TARGET:-/usr/local}
|
||||||
INSTALL=${INSTALL:-bake shake}
|
INSTALL=${INSTALL:-bake}
|
||||||
|
|
||||||
cd $(dirname "$(readlink -f "$0")")/src
|
cd "$(dirname "$(readlink -f $0)")"
|
||||||
chmod +x shake
|
|
||||||
|
|
||||||
./shake bake.c -s $@ && \
|
./shake bake.l -s $@ && \
|
||||||
mkdir $TARGET/bin $TARGET/man/man1 -p && \
|
mkdir $TARGET/bin $TARGET/man/man1 -p && \
|
||||||
install -m 755 $INSTALL $TARGET/bin
|
install -m 755 $INSTALL $TARGET/bin
|
||||||
|
|
||||||
gzip -c bake.1 > $TARGET/man/man1/bake.1.gz && \
|
gzip -c bake.1 > $TARGET/man/man1/bake.1.gz
|
||||||
ln -f -s $TARGET/man/man1/bake.1.gz $TARGET/man/man1/shake.1.gz
|
|
||||||
|
@ -79,6 +79,8 @@ if [[ -n $line ]]; then
|
|||||||
line=${line//@FILENAME/$input_file}
|
line=${line//@FILENAME/$input_file}
|
||||||
line=${line//@SHORT/${input_file%.*}}
|
line=${line//@SHORT/${input_file%.*}}
|
||||||
line=${line//@ARGS/$@}
|
line=${line//@ARGS/$@}
|
||||||
|
line=${line//@NAME/$input_file}
|
||||||
|
line=${line//@FILE/$input_file}
|
||||||
line=$(echo "$line" | sed 's/@STOP.*//')
|
line=$(echo "$line" | sed 's/@STOP.*//')
|
||||||
|
|
||||||
echo -e "${BOLD}${GREEN}$0${NORMAL}: ${line#*${MARK}}"
|
echo -e "${BOLD}${GREEN}$0${NORMAL}: ${line#*${MARK}}"
|
392
source/bake.c
392
source/bake.c
@ -1,392 +0,0 @@
|
|||||||
/* @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 $+ @STOP */
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#define BUFFER_SIZE (1 << 12)
|
|
||||||
|
|
||||||
#define START "@" "BAKE" " "
|
|
||||||
#define STOP "@" "STOP"
|
|
||||||
|
|
||||||
#define AUTONOMOUS_COMPILE 0
|
|
||||||
|
|
||||||
#define ENABLE_COLOR 1
|
|
||||||
|
|
||||||
#if ENABLE_COLOR == 1
|
|
||||||
# define RED "\033[91m"
|
|
||||||
# define GREEN "\033[92m"
|
|
||||||
# define YELLOW "\033[93m"
|
|
||||||
# define BOLD "\033[1m"
|
|
||||||
# define RESET "\033[0m"
|
|
||||||
#elif ENABLE_COLOR
|
|
||||||
# define RED "\033[91;5m"
|
|
||||||
# define GREEN "\033[96;7m"
|
|
||||||
# define YELLOW "\033[94m"
|
|
||||||
# define BOLD "\033[1;4m"
|
|
||||||
# define RESET "\033[0m"
|
|
||||||
#else
|
|
||||||
# define RED
|
|
||||||
# define GREEN
|
|
||||||
# define YELLOW
|
|
||||||
# define BOLD
|
|
||||||
# define RESET
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ARRLEN(x) (sizeof (x) / sizeof (x [0]))
|
|
||||||
|
|
||||||
__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) {
|
|
||||||
*a ^= *b;
|
|
||||||
*b ^= *a;
|
|
||||||
*a ^= *b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
root (char ** rootp) {
|
|
||||||
char x [1] = {'\0'};
|
|
||||||
char * root = *rootp;
|
|
||||||
size_t len = strlen (root);
|
|
||||||
int ret;
|
|
||||||
while (len && root [len] != '/') { --len; }
|
|
||||||
if (!len) { return 0; }
|
|
||||||
swap (root + len, x);
|
|
||||||
ret = chdir (root);
|
|
||||||
swap (root + len, x);
|
|
||||||
*rootp += len + 1;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
shorten (char * filename) {
|
|
||||||
size_t i, last, len;
|
|
||||||
static char sh [FILENAME_MAX];
|
|
||||||
len = strlen (filename);
|
|
||||||
for (last = i = 0; i < len; ++i) {
|
|
||||||
if (filename [i] == '.') { last = i; }
|
|
||||||
}
|
|
||||||
last = last ? last : i;
|
|
||||||
strncpy (sh, filename, last);
|
|
||||||
sh [last] = '\0';
|
|
||||||
return sh;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
all_args (size_t argc, char ** argv) {
|
|
||||||
static char buffer [BUFFER_SIZE] = {0};
|
|
||||||
if (argc > 0) {
|
|
||||||
size_t i, len = argc;
|
|
||||||
for (i = 0; i < argc; ++i) { len += strlen (argv [i]); }
|
|
||||||
buffer [len] = '\0';
|
|
||||||
for (len = 0, i = 0; i < argc; ++i) {
|
|
||||||
strcpy (buffer + len, argv [i]);
|
|
||||||
len += strlen (argv [i]) + 1;
|
|
||||||
if (i + 1 < argc) { buffer [len - 1] = ' '; }
|
|
||||||
}}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
lines (char * buffer, size_t off) {
|
|
||||||
size_t line = 1;
|
|
||||||
char * end = buffer + off;
|
|
||||||
while (buffer < end) {
|
|
||||||
if (*buffer == '\n') { ++line; }
|
|
||||||
++buffer;
|
|
||||||
}
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
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;
|
|
||||||
for (f = 0; f < length; ++f) {
|
|
||||||
for (i = 0; i < count; i += 2) {
|
|
||||||
old = strlen (pairs [i]);
|
|
||||||
new = strlen (pairs [i + 1]);
|
|
||||||
if (memcmp (buffer + f - off, pairs [i], old) == 0) {
|
|
||||||
if (f && buffer [f - off - 1] == '\\')
|
|
||||||
{ --f; --off; break; }
|
|
||||||
memcpy (expanded + f, pairs [i + 1], new);
|
|
||||||
f += new;
|
|
||||||
length += new - old;
|
|
||||||
off += new - old;
|
|
||||||
break;
|
|
||||||
}}
|
|
||||||
expanded [f] = buffer [f - off];
|
|
||||||
}
|
|
||||||
expanded [f] = '\0';
|
|
||||||
return expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
if (fd != -1) {
|
|
||||||
struct stat s;
|
|
||||||
if (!fstat (fd, &s)
|
|
||||||
&& s.st_mode & S_IFREG
|
|
||||||
&& s.st_size) {
|
|
||||||
*length = (size_t) s.st_size;
|
|
||||||
buffer = (char *) mmap (NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
|
||||||
}
|
|
||||||
close (fd);
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
# define color_printf(...) color_fprintf (stdout, __VA_ARGS__)
|
|
||||||
/* not perfect, too simple, doesn't work with a var, only a literal. */
|
|
||||||
# define color_fputs(fp, msg) color_fprintf (fp, msg "\n")
|
|
||||||
# define color_puts(msg) color_fputs (stdout, msg)
|
|
||||||
|
|
||||||
static int color = ENABLE_COLOR;
|
|
||||||
|
|
||||||
static void
|
|
||||||
color_fprintf (FILE * fp, char * format, ...) {
|
|
||||||
va_list ap;
|
|
||||||
char * buf;
|
|
||||||
|
|
||||||
va_start (ap, format);
|
|
||||||
|
|
||||||
if (color) {
|
|
||||||
vfprintf (fp, format, ap);
|
|
||||||
va_end (ap);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vasprintf (&buf, format, ap);
|
|
||||||
|
|
||||||
if (buf) {
|
|
||||||
char * expanded, * colors [] = {
|
|
||||||
YELLOW, "",
|
|
||||||
GREEN, "",
|
|
||||||
RED, "",
|
|
||||||
BOLD, "",
|
|
||||||
RESET, ""
|
|
||||||
};
|
|
||||||
size_t count = ARRLEN (colors);
|
|
||||||
expanded = expand (buf, strlen (buf), colors, count - 2);
|
|
||||||
expanded = expand (expanded, strlen (buf), colors + count - 2, 2);
|
|
||||||
fwrite (expanded, strlen (expanded), 1, fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
free (buf);
|
|
||||||
va_end (ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -- */
|
|
||||||
|
|
||||||
int main (int argc, char ** argv) {
|
|
||||||
void help (void);
|
|
||||||
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,
|
|
||||||
* 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]) {
|
|
||||||
select: case 's':
|
|
||||||
select = atoi (argv [off] + 1);
|
|
||||||
if (!select) {
|
|
||||||
++off;
|
|
||||||
if (off >= argc) { help (); }
|
|
||||||
select = atoi (argv [off]);
|
|
||||||
}
|
|
||||||
if (select) { goto next; }
|
|
||||||
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 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 (); }
|
|
||||||
select_input = select;
|
|
||||||
/* roots to directory of filename and mutates filename with the change */
|
|
||||||
root (&filename);
|
|
||||||
|
|
||||||
buffer = getmap (filename, &length);
|
|
||||||
if (!buffer) {
|
|
||||||
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 (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(bake_end)) {
|
|
||||||
if (memcmp(buffer + stop, bake_end, strlen(bake_end)) == 0) {
|
|
||||||
if (stop && buffer[stop - 1] == '\\') { ++stop; continue; }
|
|
||||||
end = stop;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++stop;
|
|
||||||
}
|
|
||||||
if (list) {
|
|
||||||
color_printf (GREEN "%d,%d" RESET ": " BOLD, select++, lines (buffer, begin));
|
|
||||||
fwrite (buffer + begin, 1, end - begin, stdout);
|
|
||||||
color_puts (RESET);
|
|
||||||
} else { --select; }
|
|
||||||
}}
|
|
||||||
begin += strlen (bake_begin) - 1;
|
|
||||||
|
|
||||||
if (list) { return 0; }
|
|
||||||
if (end < begin) {
|
|
||||||
color_fprintf (stderr, RED "%s" RESET ": " BOLD "%d" RESET " is out of range\n", argv [0], select_input);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* expansion */
|
|
||||||
|
|
||||||
args = all_args (argc - off, argv + off);
|
|
||||||
shortened = shorten (filename);
|
|
||||||
char * pair [] = {
|
|
||||||
"@FILENAME", filename,
|
|
||||||
"@FILE", filename,
|
|
||||||
"$@", filename,
|
|
||||||
"@SHORT", shortened,
|
|
||||||
"$*", shortened,
|
|
||||||
"@ARGS", args,
|
|
||||||
"$+", args,
|
|
||||||
"@LINE", line
|
|
||||||
};
|
|
||||||
snprintf (line, 16, "%lu", lines (buffer, begin));
|
|
||||||
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_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; }
|
|
||||||
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid == -1) {
|
|
||||||
color_fprintf (stderr, GREEN "%s" RESET ": %s, %s\n",
|
|
||||||
argv [0], "Fork Error", strerror (errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reuse of run as status return */
|
|
||||||
if (waitpid (pid, &run, 0) < 0) {
|
|
||||||
color_fprintf (stderr, GREEN "%s" RESET ": " RED "%s" RESET ", %s\n",
|
|
||||||
argv [0], "Wait PID Error", strerror (errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!WIFEXITED (run)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return WEXITSTATUS (run);
|
|
||||||
}
|
|
||||||
|
|
||||||
void help (void) {
|
|
||||||
char * help =
|
|
||||||
BOLD "bake [-chln] [-s <n>] <FILENAME> [ARGS...]; version 20240804\n\n" RESET
|
|
||||||
GREEN "Bake" RESET " is a simple tool meant to execute embedded shell commands within\n"
|
|
||||||
"any file. It executes with /bin/sh the command after a \"" BOLD "@BAKE" RESET " \" to\n"
|
|
||||||
"the end of the line (a UNIX newline: '\\n').\n\n"
|
|
||||||
"It expands some macros,\n"
|
|
||||||
YELLOW "\t@NAME " RESET "- filename\n"
|
|
||||||
YELLOW "\t@SHORT " RESET "- shortened filename\n"
|
|
||||||
YELLOW "\t@ARGS " RESET "- other arguments to the program\n"
|
|
||||||
YELLOW "\t@LINE " RESET "- line number at the selected " BOLD "@BAKE" RESET "\n\n"
|
|
||||||
"All macros can be exempted by prefixing them with a backslash,\n"
|
|
||||||
"which'll be subtracted in the expansion. multi-line commands may be\n"
|
|
||||||
"done by a leading backslash, which are NOT subtracted.\n\n"
|
|
||||||
"It has five options, this message (-h, --help); prevents the execution\n"
|
|
||||||
"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"
|
|
||||||
"Expunge with @{filename...}, using (-x, --expunge), \\@{} or @{\\}}.\n\n"
|
|
||||||
"Licensed under the public domain.\n";
|
|
||||||
color_printf ("%s", help);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
192
source/bake2.c
192
source/bake2.c
@ -1,192 +0,0 @@
|
|||||||
/* @BAKE cc -I. -std=c99 -O2 -Wall -Wextra -Wpedantic -Wno-parentheses -Wno-implicit-fallthrough -o @SHORT sds.c @FILENAME @ARGS @STOP */
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <sds.h>
|
|
||||||
|
|
||||||
#define ARRLEN(x) (sizeof (x) / sizeof (x [0]))
|
|
||||||
|
|
||||||
#define START "@" "BAKE" " "
|
|
||||||
#define STOP "@" "STOP"
|
|
||||||
|
|
||||||
#define ENABLE_COLOR 1
|
|
||||||
|
|
||||||
#include "color.h"
|
|
||||||
|
|
||||||
static int map(char * filename, char ** buffer, size_t * buffer_length) {
|
|
||||||
int err = 0, fd = open(filename, O_RDONLY);
|
|
||||||
if (fd != -1) {
|
|
||||||
struct stat s;
|
|
||||||
if (!fstat(fd, &s) && s.st_mode & S_IFREG && s.st_size) {
|
|
||||||
*buffer_length = (size_t) s.st_size;
|
|
||||||
*buffer = (char *) mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
|
||||||
} else {
|
|
||||||
err = 1;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void root(const char * filename) {
|
|
||||||
char * string = strdupa(filename), * terminator = strrchr(string, '/');
|
|
||||||
if (terminator) {
|
|
||||||
terminator = '\0';
|
|
||||||
chdir(string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void err(char * msg) { fprintf(stderr, "%s\n", msg); abort(); }
|
|
||||||
|
|
||||||
void help(void) { abort(); }
|
|
||||||
|
|
||||||
|
|
||||||
void selection_list(char * buffer, size_t buffer_length, sds ** rlist, size_t * rlist_length) {
|
|
||||||
sds * list = malloc(0);
|
|
||||||
size_t list_length = 0;
|
|
||||||
|
|
||||||
char * search = buffer;
|
|
||||||
char * start;
|
|
||||||
while (start = memmem(search, buffer_length, START, strlen(START))) {
|
|
||||||
buffer_length -= start - buffer + strlen(START);
|
|
||||||
search = start + strlen(START);
|
|
||||||
char * end = memmem(search, buffer_length, STOP, strlen(STOP));
|
|
||||||
if (!end) { end = memchr(search, '\n', buffer_length);}
|
|
||||||
if (start && end) {
|
|
||||||
list = realloc(list, ++list_length * sizeof(sds));
|
|
||||||
list[list_length-1] = sdsnewlen(start,end-start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*rlist = list;
|
|
||||||
*rlist_length = list_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char ** argv) {
|
|
||||||
char * filename = NULL;
|
|
||||||
int run = 1, select = 0, olist = 0;
|
|
||||||
|
|
||||||
for (int 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]) {
|
|
||||||
select: case 's':
|
|
||||||
select = atoi(argv [off] + 1);
|
|
||||||
if (!select) {
|
|
||||||
++off;
|
|
||||||
if (off >= argc) { help(); }
|
|
||||||
select = atoi(argv [off]);
|
|
||||||
}
|
|
||||||
if (select) { goto next; }
|
|
||||||
default: case 'h': help();
|
|
||||||
case 'l': olist = 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 select; }
|
|
||||||
else if (strcmp(argv[off], "list") == 0) { olist = 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(); }
|
|
||||||
|
|
||||||
root(filename);
|
|
||||||
|
|
||||||
char * buffer = NULL;
|
|
||||||
size_t buffer_length = 0;
|
|
||||||
|
|
||||||
if (map(filename, &buffer, &buffer_length) || !buffer) { err("Could not access file"); }
|
|
||||||
|
|
||||||
/* select */
|
|
||||||
sds * list;
|
|
||||||
size_t list_length;
|
|
||||||
selection_list(buffer, buffer_length, &list, &list_length);
|
|
||||||
|
|
||||||
if (olist) {
|
|
||||||
for (size_t i = 0; i < list_length; ++i) {
|
|
||||||
printf("%s\n", list[i]);
|
|
||||||
}}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < list_length; ++i) {
|
|
||||||
if (olist || (size_t) select != i) { sdsfree(list[i]); }
|
|
||||||
}
|
|
||||||
|
|
||||||
sds command = list[select];
|
|
||||||
free(list);
|
|
||||||
|
|
||||||
if (olist) { return 0; }
|
|
||||||
|
|
||||||
/* expand */
|
|
||||||
|
|
||||||
char * macro [] = {
|
|
||||||
"$*",
|
|
||||||
"$+",
|
|
||||||
"$@",
|
|
||||||
"@ARGS",
|
|
||||||
"@FILE",
|
|
||||||
"@FILENAME",
|
|
||||||
"@LINE"
|
|
||||||
"@SHORT",
|
|
||||||
};
|
|
||||||
|
|
||||||
char * search;
|
|
||||||
size_t search_length = sdslen(command);
|
|
||||||
for (size_t i = 0; i < ARRLEN(macro); ++i) {
|
|
||||||
search = command;
|
|
||||||
while (search = memmem(search, search_length, macro[i], strlen(macro[i]))) {
|
|
||||||
search += strlen(macro[i]);
|
|
||||||
printf("Found %s\n", macro[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* execute */
|
|
||||||
printf("command: '%s'\n", command);
|
|
||||||
sdsfree(command);
|
|
||||||
|
|
||||||
if (!run) { return 0; }
|
|
||||||
|
|
||||||
fprintf (stderr, GREEN "output" RESET ":\n");
|
|
||||||
|
|
||||||
pid_t pid;
|
|
||||||
if ((pid = fork ()) == 0) {
|
|
||||||
execl ("/bin/sh", "sh", "-c", command, NULL);
|
|
||||||
return 0; /* execl overwrites the process anyways */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid == -1) {
|
|
||||||
fprintf (stderr, GREEN "%s" RESET ": %s, %s\n", argv [0], "Fork Error", strerror (errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reuse of run as status return */
|
|
||||||
if (waitpid (pid, &run, 0) < 0) {
|
|
||||||
fprintf (stderr, GREEN "%s" RESET ": " RED "%s" RESET ", %s\n", argv [0], "Wait PID Error", strerror (errno));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!WIFEXITED (run)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return WEXITSTATUS (run);
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
/* static int color = ENABLE_COLOR; */
|
|
||||||
|
|
||||||
#if ENABLE_COLOR
|
|
||||||
# define RED "\033[91m"
|
|
||||||
# define GREEN "\033[92m"
|
|
||||||
# define YELLOW "\033[93m"
|
|
||||||
# define BOLD "\033[1m"
|
|
||||||
# define RESET "\033[0m"
|
|
||||||
#else
|
|
||||||
# define RED
|
|
||||||
# define GREEN
|
|
||||||
# define YELLOW
|
|
||||||
# define BOLD
|
|
||||||
# define RESET
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
# define color_printf(...) color_fprintf (stdout, __VA_ARGS__)
|
|
||||||
/* not perfect, too simple, doesn't work with a var, only a literal. */
|
|
||||||
# define color_fputs(fp, msg) color_fprintf (fp, msg "\n")
|
|
||||||
# define color_puts(msg) color_fputs (stdout, msg)
|
|
||||||
|
|
||||||
static void
|
|
||||||
color_fprintf (FILE * fp, char * format, ...) {
|
|
||||||
va_list ap;
|
|
||||||
char * buf;
|
|
||||||
|
|
||||||
va_start (ap, format);
|
|
||||||
|
|
||||||
if (color) {
|
|
||||||
vfprintf (fp, format, ap);
|
|
||||||
va_end (ap);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vasprintf (&buf, format, ap);
|
|
||||||
|
|
||||||
if (buf) {
|
|
||||||
/* char * expanded, * colors [] = { */
|
|
||||||
/* YELLOW, "", */
|
|
||||||
/* GREEN, "", */
|
|
||||||
/* RED, "", */
|
|
||||||
/* BOLD, "", */
|
|
||||||
/* RESET, "" */
|
|
||||||
/* }; */
|
|
||||||
/* size_t count = ARRLEN (colors); */
|
|
||||||
/* expanded = expand (buf, strlen (buf), colors, count - 2); */
|
|
||||||
/* expanded = expand (expanded, strlen (buf), colors + count - 2, 2); */
|
|
||||||
/* fwrite (expanded, strlen (expanded), 1, fp); */
|
|
||||||
}
|
|
||||||
|
|
||||||
free (buf);
|
|
||||||
va_end (ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
1328
source/sds.c
1328
source/sds.c
File diff suppressed because it is too large
Load Diff
274
source/sds.h
274
source/sds.h
@ -1,274 +0,0 @@
|
|||||||
/* SDSLib 2.0 -- A C dynamic strings library
|
|
||||||
*
|
|
||||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
||||||
* Copyright (c) 2015, Oran Agra
|
|
||||||
* Copyright (c) 2015, Redis Labs, Inc
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of Redis nor the names of its contributors may be used
|
|
||||||
* to endorse or promote products derived from this software without
|
|
||||||
* specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SDS_H
|
|
||||||
#define __SDS_H
|
|
||||||
|
|
||||||
#define SDS_MAX_PREALLOC (1024*1024)
|
|
||||||
extern const char *SDS_NOINIT;
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef char *sds;
|
|
||||||
|
|
||||||
/* Note: sdshdr5 is never used, we just access the flags byte directly.
|
|
||||||
* However is here to document the layout of type 5 SDS strings. */
|
|
||||||
struct __attribute__ ((__packed__)) sdshdr5 {
|
|
||||||
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
|
|
||||||
char buf[];
|
|
||||||
};
|
|
||||||
struct __attribute__ ((__packed__)) sdshdr8 {
|
|
||||||
uint8_t len; /* used */
|
|
||||||
uint8_t alloc; /* excluding the header and null terminator */
|
|
||||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
|
||||||
char buf[];
|
|
||||||
};
|
|
||||||
struct __attribute__ ((__packed__)) sdshdr16 {
|
|
||||||
uint16_t len; /* used */
|
|
||||||
uint16_t alloc; /* excluding the header and null terminator */
|
|
||||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
|
||||||
char buf[];
|
|
||||||
};
|
|
||||||
struct __attribute__ ((__packed__)) sdshdr32 {
|
|
||||||
uint32_t len; /* used */
|
|
||||||
uint32_t alloc; /* excluding the header and null terminator */
|
|
||||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
|
||||||
char buf[];
|
|
||||||
};
|
|
||||||
struct __attribute__ ((__packed__)) sdshdr64 {
|
|
||||||
uint64_t len; /* used */
|
|
||||||
uint64_t alloc; /* excluding the header and null terminator */
|
|
||||||
unsigned char flags; /* 3 lsb of type, 5 unused bits */
|
|
||||||
char buf[];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SDS_TYPE_5 0
|
|
||||||
#define SDS_TYPE_8 1
|
|
||||||
#define SDS_TYPE_16 2
|
|
||||||
#define SDS_TYPE_32 3
|
|
||||||
#define SDS_TYPE_64 4
|
|
||||||
#define SDS_TYPE_MASK 7
|
|
||||||
#define SDS_TYPE_BITS 3
|
|
||||||
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
|
|
||||||
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
|
|
||||||
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
|
|
||||||
|
|
||||||
static inline size_t sdslen(const sds s) {
|
|
||||||
unsigned char flags = s[-1];
|
|
||||||
switch(flags&SDS_TYPE_MASK) {
|
|
||||||
case SDS_TYPE_5:
|
|
||||||
return SDS_TYPE_5_LEN(flags);
|
|
||||||
case SDS_TYPE_8:
|
|
||||||
return SDS_HDR(8,s)->len;
|
|
||||||
case SDS_TYPE_16:
|
|
||||||
return SDS_HDR(16,s)->len;
|
|
||||||
case SDS_TYPE_32:
|
|
||||||
return SDS_HDR(32,s)->len;
|
|
||||||
case SDS_TYPE_64:
|
|
||||||
return SDS_HDR(64,s)->len;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t sdsavail(const sds s) {
|
|
||||||
unsigned char flags = s[-1];
|
|
||||||
switch(flags&SDS_TYPE_MASK) {
|
|
||||||
case SDS_TYPE_5: {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case SDS_TYPE_8: {
|
|
||||||
SDS_HDR_VAR(8,s);
|
|
||||||
return sh->alloc - sh->len;
|
|
||||||
}
|
|
||||||
case SDS_TYPE_16: {
|
|
||||||
SDS_HDR_VAR(16,s);
|
|
||||||
return sh->alloc - sh->len;
|
|
||||||
}
|
|
||||||
case SDS_TYPE_32: {
|
|
||||||
SDS_HDR_VAR(32,s);
|
|
||||||
return sh->alloc - sh->len;
|
|
||||||
}
|
|
||||||
case SDS_TYPE_64: {
|
|
||||||
SDS_HDR_VAR(64,s);
|
|
||||||
return sh->alloc - sh->len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sdssetlen(sds s, size_t newlen) {
|
|
||||||
unsigned char flags = s[-1];
|
|
||||||
switch(flags&SDS_TYPE_MASK) {
|
|
||||||
case SDS_TYPE_5:
|
|
||||||
{
|
|
||||||
unsigned char *fp = ((unsigned char*)s)-1;
|
|
||||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_8:
|
|
||||||
SDS_HDR(8,s)->len = newlen;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_16:
|
|
||||||
SDS_HDR(16,s)->len = newlen;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_32:
|
|
||||||
SDS_HDR(32,s)->len = newlen;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_64:
|
|
||||||
SDS_HDR(64,s)->len = newlen;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sdsinclen(sds s, size_t inc) {
|
|
||||||
unsigned char flags = s[-1];
|
|
||||||
switch(flags&SDS_TYPE_MASK) {
|
|
||||||
case SDS_TYPE_5:
|
|
||||||
{
|
|
||||||
unsigned char *fp = ((unsigned char*)s)-1;
|
|
||||||
unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc;
|
|
||||||
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_8:
|
|
||||||
SDS_HDR(8,s)->len += inc;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_16:
|
|
||||||
SDS_HDR(16,s)->len += inc;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_32:
|
|
||||||
SDS_HDR(32,s)->len += inc;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_64:
|
|
||||||
SDS_HDR(64,s)->len += inc;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sdsalloc() = sdsavail() + sdslen() */
|
|
||||||
static inline size_t sdsalloc(const sds s) {
|
|
||||||
unsigned char flags = s[-1];
|
|
||||||
switch(flags&SDS_TYPE_MASK) {
|
|
||||||
case SDS_TYPE_5:
|
|
||||||
return SDS_TYPE_5_LEN(flags);
|
|
||||||
case SDS_TYPE_8:
|
|
||||||
return SDS_HDR(8,s)->alloc;
|
|
||||||
case SDS_TYPE_16:
|
|
||||||
return SDS_HDR(16,s)->alloc;
|
|
||||||
case SDS_TYPE_32:
|
|
||||||
return SDS_HDR(32,s)->alloc;
|
|
||||||
case SDS_TYPE_64:
|
|
||||||
return SDS_HDR(64,s)->alloc;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sdssetalloc(sds s, size_t newlen) {
|
|
||||||
unsigned char flags = s[-1];
|
|
||||||
switch(flags&SDS_TYPE_MASK) {
|
|
||||||
case SDS_TYPE_5:
|
|
||||||
/* Nothing to do, this type has no total allocation info. */
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_8:
|
|
||||||
SDS_HDR(8,s)->alloc = newlen;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_16:
|
|
||||||
SDS_HDR(16,s)->alloc = newlen;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_32:
|
|
||||||
SDS_HDR(32,s)->alloc = newlen;
|
|
||||||
break;
|
|
||||||
case SDS_TYPE_64:
|
|
||||||
SDS_HDR(64,s)->alloc = newlen;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sds sdsnewlen(const void *init, size_t initlen);
|
|
||||||
sds sdsnew(const char *init);
|
|
||||||
sds sdsempty(void);
|
|
||||||
sds sdsdup(const sds s);
|
|
||||||
void sdsfree(sds s);
|
|
||||||
sds sdsgrowzero(sds s, size_t len);
|
|
||||||
sds sdscatlen(sds s, const void *t, size_t len);
|
|
||||||
sds sdscat(sds s, const char *t);
|
|
||||||
sds sdscatsds(sds s, const sds t);
|
|
||||||
sds sdscpylen(sds s, const char *t, size_t len);
|
|
||||||
sds sdscpy(sds s, const char *t);
|
|
||||||
|
|
||||||
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
|
|
||||||
#ifdef __GNUC__
|
|
||||||
sds sdscatprintf(sds s, const char *fmt, ...)
|
|
||||||
__attribute__((format(printf, 2, 3)));
|
|
||||||
#else
|
|
||||||
sds sdscatprintf(sds s, const char *fmt, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sds sdscatfmt(sds s, char const *fmt, ...);
|
|
||||||
sds sdstrim(sds s, const char *cset);
|
|
||||||
void sdsrange(sds s, ssize_t start, ssize_t end);
|
|
||||||
void sdsupdatelen(sds s);
|
|
||||||
void sdsclear(sds s);
|
|
||||||
int sdscmp(const sds s1, const sds s2);
|
|
||||||
sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count);
|
|
||||||
void sdsfreesplitres(sds *tokens, int count);
|
|
||||||
void sdstolower(sds s);
|
|
||||||
void sdstoupper(sds s);
|
|
||||||
sds sdsfromlonglong(long long value);
|
|
||||||
sds sdscatrepr(sds s, const char *p, size_t len);
|
|
||||||
sds *sdssplitargs(const char *line, int *argc);
|
|
||||||
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
|
||||||
sds sdsjoin(char **argv, int argc, char *sep);
|
|
||||||
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
|
||||||
|
|
||||||
/* Low level functions exposed to the user API */
|
|
||||||
sds sdsMakeRoomFor(sds s, size_t addlen);
|
|
||||||
void sdsIncrLen(sds s, ssize_t incr);
|
|
||||||
sds sdsRemoveFreeSpace(sds s);
|
|
||||||
size_t sdsAllocSize(sds s);
|
|
||||||
void *sdsAllocPtr(sds s);
|
|
||||||
|
|
||||||
/* Export the allocator used by SDS to the program using SDS.
|
|
||||||
* Sometimes the program SDS is linked to, may use a different set of
|
|
||||||
* allocators, but may want to allocate or free things that SDS will
|
|
||||||
* respectively free or allocate. */
|
|
||||||
void *sds_malloc(size_t size);
|
|
||||||
void *sds_realloc(void *ptr, size_t size);
|
|
||||||
void sds_free(void *ptr);
|
|
||||||
|
|
||||||
#ifdef REDIS_TEST
|
|
||||||
int sdsTest(int argc, char *argv[]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,42 +0,0 @@
|
|||||||
/* SDSLib 2.0 -- A C dynamic strings library
|
|
||||||
*
|
|
||||||
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
|
||||||
* Copyright (c) 2015, Oran Agra
|
|
||||||
* Copyright (c) 2015, Redis Labs, Inc
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of Redis nor the names of its contributors may be used
|
|
||||||
* to endorse or promote products derived from this software without
|
|
||||||
* specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* SDS allocator selection.
|
|
||||||
*
|
|
||||||
* This file is used in order to change the SDS allocator at compile time.
|
|
||||||
* Just define the following defines to what you want to use. Also add
|
|
||||||
* the include of your alternate allocator if needed (not needed in order
|
|
||||||
* to use the default libc allocator). */
|
|
||||||
|
|
||||||
#define s_malloc malloc
|
|
||||||
#define s_realloc realloc
|
|
||||||
#define s_free free
|
|
BIN
test.a.txt
Normal file
BIN
test.a.txt
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user