Files
my-os-project2/user/tb/interp.c
2025-09-28 22:37:03 +02:00

176 lines
4.2 KiB
C

#include <stddef.h>
#include <stdbool.h>
#include <ulib.h>
#include "interp.h"
#include "runtime.h"
#include "macros.h"
extern uint64_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] != '\'') {
str[j++] = tz->str[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])) {
tkstr[j++] = tz->str[i++];
}
Token *tk = umalloc(sizeof(*tk));
tk->str = tkstr;
tk->next = NULL;
LL_APPEND(tz->tokens, tk);
}
}
}
void tz_classify(Tokenizer *tz) {
Token *tk, *tktmp;
LL_FOREACH_SAFE(tz->tokens, tk, tktmp) {
if (tk->str[0] == '"') {
tk->type = TOK_STRING;
} else if (tk->str[0] == '%') {
RtCmd *cmd, *cmdtmp;
LL_FOREACH_SAFE(RTCMDS, cmd, cmdtmp) {
if (string_strcmp(tk->str, cmd->cmdname) == 0) {
tk->type = TOK_CMD;
tk->cmd = cmd;
break;
}
}
} 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) {
RtAlias *alias, *aliastmp;
LL_FOREACH_SAFE(RTALIASES, alias, aliastmp) {
if (string_strcmp(alias->namebuf, tk->str) == 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);
}
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->fn(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;
}