aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/rc/exec.c
diff options
context:
space:
mode:
authorNicholas <nbnoll@eml.cc>2021-11-15 15:08:03 -0800
committerNicholas <nbnoll@eml.cc>2021-11-15 15:08:14 -0800
commite9ff1c6fbbbac9ece2604876ab589ac282360446 (patch)
tree1e1378a1cb37ca4e751d8140eeed99db7ccc4ce7 /src/cmd/rc/exec.c
parent27d656be97f1544d7535d8c144ff28b9214aed97 (diff)
Feat: added if/else branching and switch statement
Unsure about my modification to the language. I found the parsing of the case body within switches to be odd - specifically that it parses liberally and then checks that it has case -> cmd structuring while it walks the code. This means the language is more permissive than the semantics. I modified it to be more explicit, but at the cost of having to end each case statement with a semicolon. I wanted a colon, but this is a valid word character and thus will be lexed as part of the word.
Diffstat (limited to 'src/cmd/rc/exec.c')
-rw-r--r--src/cmd/rc/exec.c63
1 files changed, 59 insertions, 4 deletions
diff --git a/src/cmd/rc/exec.c b/src/cmd/rc/exec.c
index 5baaf1a..a551d52 100644
--- a/src/cmd/rc/exec.c
+++ b/src/cmd/rc/exec.c
@@ -360,6 +360,18 @@ count(Word *w)
// -----------------------------------------------------------------------
// builtins
+static void
+setstatus(char *msg)
+{
+ if(!msg || msg[0] == 0)
+ runner->status = 0;
+ else
+ runner->status = 1;
+}
+
+// -----------------------------------------------------------------------
+// builtins
+
void
xecho(void)
{
@@ -402,10 +414,13 @@ xexit(void)
Word *arg;
popword(); // exit
+
arg = runner->args->word;
switch(count(arg)){
default:
print(shell.err, "invalid number of arguments to exit, exiting anyways\n");
+ case 1:
+ setstatus(runner->args->word->str);
case 0:
Xexit();
}
@@ -420,19 +435,24 @@ xcd(void)
char dir[512];
popword(); // cd
+ setstatus(nil);
arg = runner->args->word;
switch(count(arg)){
default:
print(shell.err, "usage: cd [directory]\n");
+ setstatus("failed cd");
break;
case 0:
arg = var("home")->val;
if(count(arg) >= 1){
- if(chdir(arg->str) < 0)
+ if(chdir(arg->str) < 0){
print(shell.err, "failed cd: %s\n", strerror(errno));
+ setstatus("failed cd");
+ }
}else{
print(shell.err, "ambiguous cd: $home empty\n");
+ setstatus("failed cd");
}
break;
@@ -443,9 +463,12 @@ xcd(void)
strcpy(dir, cdpath->str);
if(dir[0])
strcat(dir,"/");
+
strcat(dir, arg->str);
+
if(chdir(dir) < 0){
print(shell.err, "failed cd %s: %s\n", dir, strerror(errno));
+ setstatus("failed cd");
}
break;
}
@@ -510,6 +533,8 @@ xdot(void)
if(fd<0){
print(shell.err, "failed open: %s: ", base);
+ setstatus("failed open");
+ Xerror(".: failed open");
return;
}
/* set up for a new command loop */
@@ -633,12 +658,20 @@ Xword(void)
}
void
+Xsettrue(void)
+{
+ setstatus(nil);
+}
+
+void
Xtrue(void)
{
if(!runner->status){
- assert(runner->wait.status == Pdone);
runner->code.i++;
- deljob(runner);
+ if(runner->wait.status){
+ assert(runner->wait.status == Pdone);
+ deljob(runner);
+ }
runner->pgid = -1;
}else
runner->code.i = runner->code.exe[runner->code.i].i;
@@ -663,6 +696,27 @@ Xgoto(void)
}
void
+Xcase(void)
+{
+ Word *p; // pattern
+ Word *c; // case value
+
+ for(p=runner->args->word; p; p=p->link){
+ for(c=runner->args->link->word; c; c=c->link){
+ if(match(c->str, p->str, 0))
+ goto hit;
+ }
+ }
+nohit:
+ runner->code.i = runner->code.exe[runner->code.i].i;
+ goto clean;
+hit:
+ runner->code.i++;
+clean:
+ poplist(); // pop case words
+}
+
+void
Xfor(void)
{
if(!runner->args->word){
@@ -678,7 +732,6 @@ Xfor(void)
runner->local->val->link = nil;
runner->code.i++;
}
-
}
static
@@ -1261,6 +1314,8 @@ Xerror(char *msg)
{
print(shell.err, "rc: %s", msg);
flush(shell.err);
+
+ setstatus("error");
while(!runner->flag.user)
Xreturn();
}