244 lines
6.1 KiB
C
244 lines
6.1 KiB
C
#include <stddef.h>
|
|
#include <stdbool.h>
|
|
#include <ulib.h>
|
|
#include "interp.h"
|
|
#include "runtime.h"
|
|
#include "macros.h"
|
|
|
|
extern PID_t PID;
|
|
|
|
static InterpResult RES;
|
|
|
|
void tz_init(Tokenizer *tz, char *str) {
|
|
tz->str = str;
|
|
tz->tokens = NULL;
|
|
}
|
|
|
|
void tz_free(Tokenizer *tz) {
|
|
Token *tk, *tktmp;
|
|
LL_FOREACH_SAFE(tz->tokens, tk, tktmp) {
|
|
ufree(tk->str);
|
|
ufree(tk);
|
|
}
|
|
tz->tokens = NULL;
|
|
}
|
|
|
|
#define TZ_MAX_TK 1024
|
|
|
|
void tz_tokenize(Tokenizer *tz) {
|
|
size_t len = string_len(tz->str);
|
|
for (size_t i = 0; i < len; i++) {
|
|
if (tz->str[i] == '\'') {
|
|
char *str = umalloc(TZ_MAX_TK);
|
|
string_memset(str, 0, TZ_MAX_TK);
|
|
i++;
|
|
size_t j = 0;
|
|
while (i < len && tz->str[i] != '\'') {
|
|
if (tz->str[i] == '\\') {
|
|
if (i + 1 < len) {
|
|
i++;
|
|
char c;
|
|
switch (tz->str[i]) {
|
|
case 'n': c = '\n'; break;
|
|
case 't': c = '\t'; break;
|
|
case 'r': c = '\r'; break;
|
|
case '\\': c = '\\'; break;
|
|
case '\'': c = '\''; break;
|
|
case '"': c = '"'; break;
|
|
case 'x': {
|
|
if (i + 2 < len) {
|
|
char buf[3];
|
|
buf[0] = tz->str[i + 1];
|
|
buf[1] = tz->str[i + 2];
|
|
buf[2] = '\0';
|
|
|
|
char *endp;
|
|
uint8_t b = (uint8_t)string_conv_strtoul(buf, &endp, 16);
|
|
c = *(char *)&b;
|
|
|
|
i += 2;
|
|
}
|
|
} break;
|
|
default: c = tz->str[i]; break;
|
|
}
|
|
if (j + 1 < TZ_MAX_TK) {
|
|
str[j++] = c;
|
|
}
|
|
} else {
|
|
if (j + 1 < TZ_MAX_TK) {
|
|
str[j++] = '\\';
|
|
}
|
|
}
|
|
} else {
|
|
if (j + 1 < TZ_MAX_TK) {
|
|
str[j++] = tz->str[i];
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
Token *tk = umalloc(sizeof(*tk));
|
|
tk->str = str;
|
|
tk->next = NULL;
|
|
LL_APPEND(tz->tokens, tk);
|
|
} else {
|
|
char *tkstr = umalloc(TZ_MAX_TK);
|
|
string_memset(tkstr, 0, TZ_MAX_TK);
|
|
size_t j = 0;
|
|
while (i < len && !string_chr_isspace(tz->str[i]) && tz->str[i] != '\'') {
|
|
if (j + 1 < TZ_MAX_TK) {
|
|
tkstr[j++] = tz->str[i];
|
|
}
|
|
i++;
|
|
}
|
|
Token *tk = umalloc(sizeof(*tk));
|
|
tk->str = tkstr;
|
|
tk->next = NULL;
|
|
LL_APPEND(tz->tokens, tk);
|
|
}
|
|
}
|
|
}
|
|
|
|
void tz_classify(Tokenizer *tz) {
|
|
#define IF_RTCMD(name) if (string_strcmp(tk->str, #name) == 0) { \
|
|
tk->type = TOK_CMD; \
|
|
tk->cmd = &rt_ ## name; \
|
|
}
|
|
|
|
Token *tk, *tktmp;
|
|
LL_FOREACH_SAFE(tz->tokens, tk, tktmp) {
|
|
if (tk->str[0] == '\'') {
|
|
tk->type = TOK_STRING;
|
|
}
|
|
else IF_RTCMD(print)
|
|
else IF_RTCMD(mkalias)
|
|
else IF_RTCMD(PID)
|
|
else IF_RTCMD(do)
|
|
else IF_RTCMD(stackpush)
|
|
else IF_RTCMD(stackpop)
|
|
else {
|
|
tk->type = TOK_MISC;
|
|
}
|
|
}
|
|
}
|
|
|
|
void tz_expandspecial(Tokenizer *tz) {
|
|
Token *tk, *tktmp;
|
|
LL_FOREACH_SAFE(tz->tokens, tk, tktmp) {
|
|
if (tk->str[0] == '$' && string_len(tk->str) > 1) {
|
|
if (string_strcmp(tk->str, "$stack") == 0) {
|
|
char *s = rtstringv_stackpeek();
|
|
ufree(tk->str);
|
|
if (s == NULL) {
|
|
tk->str = umalloc(1);
|
|
tk->str[0] = '\0';
|
|
} else {
|
|
size_t len = string_len(s);
|
|
char *copy = umalloc(len+1);
|
|
string_memcpy(copy, s, len);
|
|
copy[len] = '\0';
|
|
tk->str = copy;
|
|
}
|
|
} else {
|
|
RtAlias *alias, *aliastmp;
|
|
LL_FOREACH_SAFE(RTALIASES, alias, aliastmp) {
|
|
if (string_strcmp(alias->namebuf, tk->str+1) == 0) {
|
|
ufree(tk->str);
|
|
size_t len = string_len(alias->valbuf)+1;
|
|
tk->str = umalloc(len);
|
|
string_memset(tk->str, 0, len);
|
|
string_memcpy(tk->str, alias->valbuf, string_len(alias->valbuf));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#define LINE_MAX 1024
|
|
|
|
bool interp_runstring(char *string, InterpResult **res, bool logcmds, bool interactive) {
|
|
*res = &RES;
|
|
string_memset(RES.errmsg, 0, sizeof(RES.errmsg));
|
|
|
|
rt_init();
|
|
bool ok = true;
|
|
|
|
char *line = string_tokenizealloc(string, "\n");
|
|
while (line != NULL) {
|
|
if (logcmds) {
|
|
uprintf("+%s\n", line);
|
|
}
|
|
|
|
bool skip;
|
|
STRING_CHECK_ALL(line, string_chr_isspace, skip);
|
|
if (skip) {
|
|
line = string_tokenizealloc(NULL, "\n");
|
|
continue;
|
|
}
|
|
|
|
Tokenizer tz; ZERO(&tz);
|
|
tz_init(&tz, line);
|
|
|
|
tz_tokenize(&tz);
|
|
|
|
tz_classify(&tz);
|
|
tz_expandspecial(&tz);
|
|
|
|
Token *cmdtk = tz.tokens;
|
|
if (cmdtk->type == TOK_CMD) {
|
|
ok = cmdtk->cmd(cmdtk->next);
|
|
if (!ok) {
|
|
usprintf(RES.errmsg, "cmd %s failed", cmdtk->str);
|
|
goto next;
|
|
}
|
|
} else if (cmdtk->type == TOK_MISC) {
|
|
size_t argslen1;
|
|
Token *argtk, *argtktmp;
|
|
LL_FOREACH_SAFE_IDX(cmdtk->next, argtk, argtktmp, argslen1);
|
|
|
|
size_t i;
|
|
char **args1 = (char **)umalloc(sizeof(char *) * argslen1);
|
|
LL_FOREACH_SAFE_IDX(cmdtk->next, argtk, argtktmp, i) {
|
|
args1[i] = (char *)umalloc(PROC_ARG_MAX);
|
|
string_memset(args1[i], 0, PROC_ARG_MAX);
|
|
string_memcpy(args1[i], argtk->str, MIN(string_len(argtk->str), PROC_ARG_MAX));
|
|
}
|
|
|
|
int32_t app = processctl(-1, PCTL_SPAWN, (uint64_t)cmdtk->str, (uint64_t)args1, argslen1);
|
|
if (app < 0) {
|
|
usprintf(RES.errmsg, "Could not run %s: %s\n", cmdtk->str, ERRSTRING(app));
|
|
ok = false;
|
|
goto cleanup;
|
|
}
|
|
|
|
processctl(app, PCTL_RUN, 0, 0, 0);
|
|
|
|
uint8_t b;
|
|
while(processctl(app, PCTL_POLLSTATE, 0, 0, 0) != 4) {
|
|
if (interactive) {
|
|
int32_t nrd = ipcpipe(PID, IPCPIPE_IN, IPCPIPE_READ, &b, 1);
|
|
if (nrd > 0 && b == C('S')) {
|
|
processctl(app, PCTL_KILL, 0, 0, 0);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
schedrelease();
|
|
}
|
|
|
|
cleanup: {
|
|
for (size_t j = 0; j < argslen1; j++) ufree(args1[j]);
|
|
ufree(args1);
|
|
}
|
|
}
|
|
|
|
next:
|
|
tz_free(&tz);
|
|
ufree(line);
|
|
line = string_tokenizealloc(NULL, "\n");
|
|
}
|
|
|
|
done:
|
|
return ok;
|
|
}
|