aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2000-07-27 00:15:20 +0000
committerEric Andersen <andersen@codepoet.org>2000-07-27 00:15:20 +0000
commit6a99aaf0208151b7f5e5058efaa409496e2b7c4b (patch)
treec2f6f79643b050fb13345f1176795397aa98ae66
parent7ce41ad69296d391e4ef2fa92112e57264687063 (diff)
downloadbusybox-w32-6a99aaf0208151b7f5e5058efaa409496e2b7c4b.tar.gz
busybox-w32-6a99aaf0208151b7f5e5058efaa409496e2b7c4b.tar.bz2
busybox-w32-6a99aaf0208151b7f5e5058efaa409496e2b7c4b.zip
More shell features.... if-then-else-fi is now basically usable (disable
by default pending further debugging). Added in some basic shell environment support (i.e. $?, $0-$9, $$, $!, $#). -Erik
-rw-r--r--lash.c352
-rw-r--r--sh.c352
-rw-r--r--shell/lash.c352
3 files changed, 717 insertions, 339 deletions
diff --git a/lash.c b/lash.c
index f746757d8..e57567608 100644
--- a/lash.c
+++ b/lash.c
@@ -26,9 +26,9 @@
26 */ 26 */
27 27
28 28
29#define BB_FEATURE_SH_BACKTICKS 29//#define BB_FEATURE_SH_BACKTICKS
30//#define BB_FEATURE_SH_IF_EXPRESSIONS 30//#define BB_FEATURE_SH_IF_EXPRESSIONS
31 31//#define BB_FEATURE_SH_ENVIRONMENT
32 32
33 33
34#include "internal.h" 34#include "internal.h"
@@ -57,13 +57,11 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
57}; 57};
58 58
59static const unsigned int REGULAR_JOB_CONTEXT=0x1; 59static const unsigned int REGULAR_JOB_CONTEXT=0x1;
60static const unsigned int IF_EXP_CONTEXT=0x2; 60static const unsigned int IF_TRUE_CONTEXT=0x2;
61static const unsigned int THEN_EXP_CONTEXT=0x4; 61static const unsigned int IF_FALSE_CONTEXT=0x4;
62static const unsigned int ELSE_EXP_CONTEXT=0x8; 62static const unsigned int THEN_EXP_CONTEXT=0x8;
63 63static const unsigned int ELSE_EXP_CONTEXT=0x10;
64 64
65enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
66};
67 65
68struct jobSet { 66struct jobSet {
69 struct job *head; /* head of list of running jobs */ 67 struct job *head; /* head of list of running jobs */
@@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk);
128/* function prototypes for shell stuff */ 126/* function prototypes for shell stuff */
129static void checkJobs(struct jobSet *jobList); 127static void checkJobs(struct jobSet *jobList);
130static int getCommand(FILE * source, char *command); 128static int getCommand(FILE * source, char *command);
131static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg); 129static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg);
132static int setupRedirections(struct childProgram *prog);
133static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); 130static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
134static int busy_loop(FILE * input); 131static int busy_loop(FILE * input);
135 132
@@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = {
146 {"export", "Set environment variable", builtin_export}, 143 {"export", "Set environment variable", builtin_export},
147 {"unset", "Unset environment variable", builtin_unset}, 144 {"unset", "Unset environment variable", builtin_unset},
148 {"read", "Input environment variable", builtin_read}, 145 {"read", "Input environment variable", builtin_read},
146#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
147 {"if", NULL, builtin_if},
148 {"then", NULL, builtin_then},
149 {"else", NULL, builtin_else},
150 {"fi", NULL, builtin_fi},
151#endif
149 {NULL, NULL, NULL} 152 {NULL, NULL, NULL}
150}; 153};
151 154
@@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = {
154static struct builtInCommand bltins_forking[] = { 157static struct builtInCommand bltins_forking[] = {
155 {"env", "Print all environment variables", builtin_env}, 158 {"env", "Print all environment variables", builtin_env},
156 {"pwd", "Print current directory", builtin_pwd}, 159 {"pwd", "Print current directory", builtin_pwd},
157#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
158 {"if", NULL, builtin_if},
159 {"then", NULL, builtin_then},
160 {"else", NULL, builtin_else},
161 {"fi", NULL, builtin_fi},
162#endif
163 {".", "Source-in and run commands in a file", builtin_source}, 160 {".", "Source-in and run commands in a file", builtin_source},
164 {"help", "List shell built-in commands", builtin_help}, 161 {"help", "List shell built-in commands", builtin_help},
165 {NULL, NULL, NULL} 162 {NULL, NULL, NULL}
@@ -170,6 +167,13 @@ static char *cwd;
170static char *local_pending_command = NULL; 167static char *local_pending_command = NULL;
171static char *promptStr = NULL; 168static char *promptStr = NULL;
172static struct jobSet jobList = { NULL, NULL }; 169static struct jobSet jobList = { NULL, NULL };
170static int argc;
171static char **argv;
172#ifdef BB_FEATURE_SH_ENVIRONMENT
173static int lastBgPid=-1;
174static int lastReturnCode=-1;
175#endif
176
173 177
174#ifdef BB_FEATURE_SH_COMMAND_EDITING 178#ifdef BB_FEATURE_SH_COMMAND_EDITING
175void win_changed(int junk) 179void win_changed(int junk)
@@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
369 373
370#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 374#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
371/* Built-in handler for 'if' commands */ 375/* Built-in handler for 'if' commands */
372static int builtin_if(struct job *cmd, struct jobSet *junk) 376static int builtin_if(struct job *cmd, struct jobSet *jobList)
373{ 377{
374 cmd->jobContext |= IF_EXP_CONTEXT; 378 int status;
375 printf("Hit an if -- jobContext=%d\n", cmd->jobContext); 379 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
376 return TRUE; 380
381 /* Now run the 'if' command */
382 status=strlen(charptr1);
383 local_pending_command = xmalloc(status+1);
384 strncpy(local_pending_command, charptr1, status);
385 printf("'if' now running '%s'\n", charptr1);
386 status = busy_loop(NULL); /* Frees local_pending_command */
387 printf("if test returned ");
388 if (status == 0) {
389 printf("TRUE\n");
390 cmd->jobContext |= IF_TRUE_CONTEXT;
391 } else {
392 printf("FALSE\n");
393 cmd->jobContext |= IF_FALSE_CONTEXT;
394 }
395
396 return status;
377} 397}
378 398
379/* Built-in handler for 'then' (part of the 'if' command) */ 399/* Built-in handler for 'then' (part of the 'if' command) */
380static int builtin_then(struct job *cmd, struct jobSet *junk) 400static int builtin_then(struct job *cmd, struct jobSet *junk)
381{ 401{
382 if (cmd->jobContext & IF_EXP_CONTEXT) { 402 int status;
383 fprintf(stderr, "unexpected token `then'\n"); 403 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
384 fflush(stderr); 404
405 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
406 errorMsg("unexpected token `then'\n");
385 return FALSE; 407 return FALSE;
386 } 408 }
409 /* If the if result was FALSE, skip the 'then' stuff */
410 if (cmd->jobContext & IF_TRUE_CONTEXT) {
411 return TRUE;
412 }
413
387 cmd->jobContext |= THEN_EXP_CONTEXT; 414 cmd->jobContext |= THEN_EXP_CONTEXT;
388 printf("Hit an then -- jobContext=%d\n", cmd->jobContext); 415 //printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
389 return TRUE; 416
417 /* Now run the 'then' command */
418 status=strlen(charptr1);
419 local_pending_command = xmalloc(status+1);
420 strncpy(local_pending_command, charptr1, status);
421 printf("'then' now running '%s'\n", charptr1);
422 return( busy_loop(NULL));
390} 423}
391 424
392/* Built-in handler for 'else' (part of the 'if' command) */ 425/* Built-in handler for 'else' (part of the 'if' command) */
393static int builtin_else(struct job *cmd, struct jobSet *junk) 426static int builtin_else(struct job *cmd, struct jobSet *junk)
394{ 427{
395 printf("Hit an else\n"); 428 int status;
429 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
430
431 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
432 errorMsg("unexpected token `else'\n");
433 return FALSE;
434 }
435 /* If the if result was TRUE, skip the 'else' stuff */
436 if (cmd->jobContext & IF_FALSE_CONTEXT) {
437 return TRUE;
438 }
439
396 cmd->jobContext |= ELSE_EXP_CONTEXT; 440 cmd->jobContext |= ELSE_EXP_CONTEXT;
397 return TRUE; 441 //printf("Hit an else -- jobContext=%d\n", cmd->jobContext);
442
443 /* Now run the 'else' command */
444 status=strlen(charptr1);
445 local_pending_command = xmalloc(status+1);
446 strncpy(local_pending_command, charptr1, status);
447 printf("'else' now running '%s'\n", charptr1);
448 return( busy_loop(NULL));
398} 449}
399 450
400/* Built-in handler for 'fi' (part of the 'if' command) */ 451/* Built-in handler for 'fi' (part of the 'if' command) */
401static int builtin_fi(struct job *cmd, struct jobSet *junk) 452static int builtin_fi(struct job *cmd, struct jobSet *junk)
402{ 453{
403 printf("Hit an fi\n"); 454 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
455 errorMsg("unexpected token `fi'\n");
456 return FALSE;
457 }
458 /* Clear out the if and then context bits */
459 cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
460 printf("Hit an fi -- jobContext=%d\n", cmd->jobContext);
404 return TRUE; 461 return TRUE;
405} 462}
406#endif 463#endif
@@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList)
521 perror("waitpid"); 578 perror("waitpid");
522} 579}
523 580
581static int setupRedirections(struct childProgram *prog)
582{
583 int i;
584 int openfd;
585 int mode = O_RDONLY;
586 struct redirectionSpecifier *redir = prog->redirections;
587
588 for (i = 0; i < prog->numRedirections; i++, redir++) {
589 switch (redir->type) {
590 case REDIRECT_INPUT:
591 mode = O_RDONLY;
592 break;
593 case REDIRECT_OVERWRITE:
594 mode = O_RDWR | O_CREAT | O_TRUNC;
595 break;
596 case REDIRECT_APPEND:
597 mode = O_RDWR | O_CREAT | O_APPEND;
598 break;
599 }
600
601 openfd = open(redir->filename, mode, 0666);
602 if (openfd < 0) {
603 /* this could get lost if stderr has been redirected, but
604 bash and ash both lose it as well (though zsh doesn't!) */
605 errorMsg("error opening %s: %s\n", redir->filename,
606 strerror(errno));
607 return 1;
608 }
609
610 if (openfd != redir->fd) {
611 dup2(openfd, redir->fd);
612 close(openfd);
613 }
614 }
615
616 return 0;
617}
618
619
524static int getCommand(FILE * source, char *command) 620static int getCommand(FILE * source, char *command)
525{ 621{
526 if (source == NULL) { 622 if (source == NULL) {
@@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command)
562 return 0; 658 return 0;
563} 659}
564 660
661#ifdef BB_FEATURE_SH_ENVIRONMENT
662#define __MAX_INT_CHARS 7
663static char* itoa(register int i)
664{
665 static char a[__MAX_INT_CHARS];
666 register char *b = a + sizeof(a) - 1;
667 int sign = (i < 0);
668
669 if (sign)
670 i = -i;
671 *b = 0;
672 do
673 {
674 *--b = '0' + (i % 10);
675 i /= 10;
676 }
677 while (i);
678 if (sign)
679 *--b = '-';
680 return b;
681}
682#endif
683
565static void globLastArgument(struct childProgram *prog, int *argcPtr, 684static void globLastArgument(struct childProgram *prog, int *argcPtr,
566 int *argcAllocedPtr) 685 int *argcAllocedPtr)
567{ 686{
568 int argc = *argcPtr; 687 int argc_l = *argcPtr;
569 int argcAlloced = *argcAllocedPtr; 688 int argcAlloced = *argcAllocedPtr;
570 int rc; 689 int rc;
571 int flags; 690 int flags;
572 int i; 691 int i;
573 char *src, *dst, *var; 692 char *src, *dst, *var;
574 693
575 if (argc > 1) { /* cmd->globResult is already initialized */ 694 if (argc_l > 1) { /* cmd->globResult is already initialized */
576 flags = GLOB_APPEND; 695 flags = GLOB_APPEND;
577 i = prog->globResult.gl_pathc; 696 i = prog->globResult.gl_pathc;
578 } else { 697 } else {
@@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
581 i = 0; 700 i = 0;
582 } 701 }
583 /* do shell variable substitution */ 702 /* do shell variable substitution */
584 if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1))) 703 if(*prog->argv[argc_l - 1] == '$') {
585 prog->argv[argc - 1] = var; 704 if ((var = getenv(prog->argv[argc_l - 1] + 1))) {
705 prog->argv[argc_l - 1] = var;
706 }
707#ifdef BB_FEATURE_SH_ENVIRONMENT
708 else {
709 switch(*(prog->argv[argc_l - 1] + 1)) {
710 case '?':
711 prog->argv[argc_l - 1] = itoa(lastReturnCode);
712 break;
713 case '$':
714 prog->argv[argc_l - 1] = itoa(getpid());
715 break;
716 case '#':
717 prog->argv[argc_l - 1] = itoa(argc-1);
718 break;
719 case '!':
720 if (lastBgPid==-1)
721 *(prog->argv[argc_l - 1])='\0';
722 else
723 prog->argv[argc_l - 1] = itoa(lastBgPid);
724 break;
725 case '0':case '1':case '2':case '3':case '4':
726 case '5':case '6':case '7':case '8':case '9':
727 {
728 int index=*(prog->argv[argc_l - 1] + 1)-48;
729 if (index >= argc) {
730 *(prog->argv[argc_l - 1])='\0';
731 } else {
732 prog->argv[argc_l - 1] = argv[index];
733 }
734 }
735 break;
736 }
737 }
738#endif
739 }
586 740
587 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); 741 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult);
588 if (rc == GLOB_NOSPACE) { 742 if (rc == GLOB_NOSPACE) {
589 errorMsg("out of space during glob operation\n"); 743 errorMsg("out of space during glob operation\n");
590 return; 744 return;
591 } else if (rc == GLOB_NOMATCH || 745 } else if (rc == GLOB_NOMATCH ||
592 (!rc && (prog->globResult.gl_pathc - i) == 1 && 746 (!rc && (prog->globResult.gl_pathc - i) == 1 &&
593 strcmp(prog->argv[argc - 1], 747 strcmp(prog->argv[argc_l - 1],
594 prog->globResult.gl_pathv[i]) == 0)) { 748 prog->globResult.gl_pathv[i]) == 0)) {
595 /* we need to remove whatever \ quoting is still present */ 749 /* we need to remove whatever \ quoting is still present */
596 src = dst = prog->argv[argc - 1]; 750 src = dst = prog->argv[argc_l - 1];
597 while (*src) { 751 while (*src) {
598 if (*src != '\\') 752 if (*src != '\\')
599 *dst++ = *src; 753 *dst++ = *src;
@@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
604 argcAlloced += (prog->globResult.gl_pathc - i); 758 argcAlloced += (prog->globResult.gl_pathc - i);
605 prog->argv = 759 prog->argv =
606 realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 760 realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
607 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, 761 memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i,
608 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 762 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
609 argc += (prog->globResult.gl_pathc - i - 1); 763 argc_l += (prog->globResult.gl_pathc - i - 1);
610 } 764 }
611 765
612 *argcAllocedPtr = argcAlloced; 766 *argcAllocedPtr = argcAlloced;
613 *argcPtr = argc; 767 *argcPtr = argc_l;
614} 768}
615 769
616/* Return cmd->numProgs as 0 if no command is present (e.g. an empty 770/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
@@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
618 the beginning of the next command (if the original command had more 772 the beginning of the next command (if the original command had more
619 then one job associated with it) or NULL if no more commands are 773 then one job associated with it) or NULL if no more commands are
620 present. */ 774 present. */
621static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg) 775static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg)
622{ 776{
623 char *command; 777 char *command;
624 char *returnCommand = NULL; 778 char *returnCommand = NULL;
625 char *src, *buf, *chptr; 779 char *src, *buf, *chptr;
626 int argc = 0; 780 int argc_l = 0;
627 int done = 0; 781 int done = 0;
628 int argvAlloced; 782 int argvAlloced;
629 int i; 783 int i;
@@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
641 return 0; 795 return 0;
642 } 796 }
643 797
644 *isBg = 0; 798 *inBg = 0;
645 job->numProgs = 1; 799 job->numProgs = 1;
646 job->progs = xmalloc(sizeof(*job->progs)); 800 job->progs = xmalloc(sizeof(*job->progs));
647 801
@@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
654 cleaner (though it is, admittedly, a tad less efficient) */ 808 cleaner (though it is, admittedly, a tad less efficient) */
655 job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); 809 job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
656 job->text = NULL; 810 job->text = NULL;
657 job->jobContext = REGULAR_JOB_CONTEXT;
658 811
659 prog = job->progs; 812 prog = job->progs;
660 prog->numRedirections = 0; 813 prog->numRedirections = 0;
@@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
687 *src == ']') *buf++ = '\\'; 840 *src == ']') *buf++ = '\\';
688 *buf++ = *src; 841 *buf++ = *src;
689 } else if (isspace(*src)) { 842 } else if (isspace(*src)) {
690 if (*prog->argv[argc]) { 843 if (*prog->argv[argc_l]) {
691 buf++, argc++; 844 buf++, argc_l++;
692 /* +1 here leaves room for the NULL which ends argv */ 845 /* +1 here leaves room for the NULL which ends argv */
693 if ((argc + 1) == argvAlloced) { 846 if ((argc_l + 1) == argvAlloced) {
694 argvAlloced += 5; 847 argvAlloced += 5;
695 prog->argv = realloc(prog->argv, 848 prog->argv = realloc(prog->argv,
696 sizeof(*prog->argv) * 849 sizeof(*prog->argv) *
697 argvAlloced); 850 argvAlloced);
698 } 851 }
699 globLastArgument(prog, &argc, &argvAlloced); 852 globLastArgument(prog, &argc_l, &argvAlloced);
700 prog->argv[argc] = buf; 853 prog->argv[argc_l] = buf;
701 } 854 }
702 } else 855 } else
703 switch (*src) { 856 switch (*src) {
@@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
707 break; 860 break;
708 861
709 case '#': /* comment */ 862 case '#': /* comment */
710 done = 1; 863 if (*(src-1)== '$')
864 *buf++ = *src;
865 else
866 done = 1;
711 break; 867 break;
712 868
713 case '>': /* redirections */ 869 case '>': /* redirections */
@@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
718 (i + 1)); 874 (i + 1));
719 875
720 prog->redirections[i].fd = -1; 876 prog->redirections[i].fd = -1;
721 if (buf != prog->argv[argc]) { 877 if (buf != prog->argv[argc_l]) {
722 /* the stuff before this character may be the file number 878 /* the stuff before this character may be the file number
723 being redirected */ 879 being redirected */
724 prog->redirections[i].fd = 880 prog->redirections[i].fd =
725 strtol(prog->argv[argc], &chptr, 10); 881 strtol(prog->argv[argc_l], &chptr, 10);
726 882
727 if (*chptr && *prog->argv[argc]) { 883 if (*chptr && *prog->argv[argc_l]) {
728 buf++, argc++; 884 buf++, argc_l++;
729 globLastArgument(prog, &argc, &argvAlloced); 885 globLastArgument(prog, &argc_l, &argvAlloced);
730 prog->argv[argc] = buf; 886 prog->argv[argc_l] = buf;
731 } 887 }
732 } 888 }
733 889
@@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
765 *buf++ = *chptr++; 921 *buf++ = *chptr++;
766 922
767 src = chptr - 1; /* we src++ later */ 923 src = chptr - 1; /* we src++ later */
768 prog->argv[argc] = ++buf; 924 prog->argv[argc_l] = ++buf;
769 break; 925 break;
770 926
771 case '|': /* pipe */ 927 case '|': /* pipe */
772 /* finish this command */ 928 /* finish this command */
773 if (*prog->argv[argc]) 929 if (*prog->argv[argc_l])
774 argc++; 930 argc_l++;
775 if (!argc) { 931 if (!argc_l) {
776 errorMsg("empty command in pipe\n"); 932 errorMsg("empty command in pipe\n");
777 freeJob(job); 933 freeJob(job);
778 job->numProgs=0; 934 job->numProgs=0;
779 return 1; 935 return 1;
780 } 936 }
781 prog->argv[argc] = NULL; 937 prog->argv[argc_l] = NULL;
782 938
783 /* and start the next */ 939 /* and start the next */
784 job->numProgs++; 940 job->numProgs++;
@@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
788 prog->numRedirections = 0; 944 prog->numRedirections = 0;
789 prog->redirections = NULL; 945 prog->redirections = NULL;
790 prog->freeGlob = 0; 946 prog->freeGlob = 0;
791 argc = 0; 947 argc_l = 0;
792 948
793 argvAlloced = 5; 949 argvAlloced = 5;
794 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 950 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
@@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
809 break; 965 break;
810 966
811 case '&': /* background */ 967 case '&': /* background */
812 *isBg = 1; 968 *inBg = 1;
813 case ';': /* multiple commands */ 969 case ';': /* multiple commands */
814 done = 1; 970 done = 1;
815 returnCommand = *commandPtr + (src - *commandPtr) + 1; 971 returnCommand = *commandPtr + (src - *commandPtr) + 1;
@@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
848 snprintf(charptr1, 1+ptr-src, src); 1004 snprintf(charptr1, 1+ptr-src, src);
849 newJob = xmalloc(sizeof(struct job)); 1005 newJob = xmalloc(sizeof(struct job));
850 /* Now parse and run the backticked command */ 1006 /* Now parse and run the backticked command */
851 if (!parseCommand(&charptr1, newJob, &njobList, isBg) 1007 if (!parseCommand(&charptr1, newJob, &njobList, inBg)
852 && newJob->numProgs) { 1008 && newJob->numProgs) {
853 pipe(pipefd); 1009 pipe(pipefd);
854 runCommand(newJob, &njobList, 0, pipefd); 1010 runCommand(newJob, &njobList, 0, pipefd);
@@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
890 * and improved version of the command line with the backtick 1046 * and improved version of the command line with the backtick
891 * results expanded in place... */ 1047 * results expanded in place... */
892 freeJob(job); 1048 freeJob(job);
893 return(parseCommand(commandPtr, job, jobList, isBg)); 1049 return(parseCommand(commandPtr, job, jobList, inBg));
894 } 1050 }
895 break; 1051 break;
896#endif // BB_FEATURE_SH_BACKTICKS 1052#endif // BB_FEATURE_SH_BACKTICKS
@@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
901 src++; 1057 src++;
902 } 1058 }
903 1059
904 if (*prog->argv[argc]) { 1060 if (*prog->argv[argc_l]) {
905 argc++; 1061 argc_l++;
906 globLastArgument(prog, &argc, &argvAlloced); 1062 globLastArgument(prog, &argc_l, &argvAlloced);
907 } 1063 }
908 if (!argc) { 1064 if (!argc_l) {
909 freeJob(job); 1065 freeJob(job);
910 return 0; 1066 return 0;
911 } 1067 }
912 prog->argv[argc] = NULL; 1068 prog->argv[argc_l] = NULL;
913 1069
914 if (!returnCommand) { 1070 if (!returnCommand) {
915 job->text = xmalloc(strlen(*commandPtr) + 1); 1071 job->text = xmalloc(strlen(*commandPtr) + 1);
@@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
991 * works, but '/bin/cat' doesn't ) */ 1147 * works, but '/bin/cat' doesn't ) */
992 while (a->name != 0) { 1148 while (a->name != 0) {
993 if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { 1149 if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
994 int argc; 1150 int argc_l;
995 char** argv=newJob->progs[i].argv; 1151 char** argv=newJob->progs[i].argv;
996 for(argc=0;*argv!=NULL; argv++, argc++); 1152 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
997 exit((*(a->main)) (argc, newJob->progs[i].argv)); 1153 exit((*(a->main)) (argc_l, newJob->progs[i].argv));
998 } 1154 }
999 a++; 1155 a++;
1000 } 1156 }
1001#endif 1157#endif
1002 1158
1003 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); 1159 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
1004 fatalError("sh: %s: %s\n", newJob->progs[i].argv[0], 1160 fatalError("%s: %s\n", newJob->progs[i].argv[0],
1005 strerror(errno)); 1161 strerror(errno));
1006 } 1162 }
1007 if (outPipe[1]!=-1) { 1163 if (outPipe[1]!=-1) {
@@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1048 to the list of backgrounded theJobs and leave it alone */ 1204 to the list of backgrounded theJobs and leave it alone */
1049 printf("[%d] %d\n", theJob->jobId, 1205 printf("[%d] %d\n", theJob->jobId,
1050 newJob->progs[newJob->numProgs - 1].pid); 1206 newJob->progs[newJob->numProgs - 1].pid);
1207#ifdef BB_FEATURE_SH_ENVIRONMENT
1208 lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
1209#endif
1051 } else { 1210 } else {
1052 jobList->fg = theJob; 1211 jobList->fg = theJob;
1053 1212
@@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1060 return 0; 1219 return 0;
1061} 1220}
1062 1221
1063static int setupRedirections(struct childProgram *prog)
1064{
1065 int i;
1066 int openfd;
1067 int mode = O_RDONLY;
1068 struct redirectionSpecifier *redir = prog->redirections;
1069
1070 for (i = 0; i < prog->numRedirections; i++, redir++) {
1071 switch (redir->type) {
1072 case REDIRECT_INPUT:
1073 mode = O_RDONLY;
1074 break;
1075 case REDIRECT_OVERWRITE:
1076 mode = O_RDWR | O_CREAT | O_TRUNC;
1077 break;
1078 case REDIRECT_APPEND:
1079 mode = O_RDWR | O_CREAT | O_APPEND;
1080 break;
1081 }
1082
1083 openfd = open(redir->filename, mode, 0666);
1084 if (openfd < 0) {
1085 /* this could get lost if stderr has been redirected, but
1086 bash and ash both lose it as well (though zsh doesn't!) */
1087 errorMsg("error opening %s: %s\n", redir->filename,
1088 strerror(errno));
1089 return 1;
1090 }
1091
1092 if (openfd != redir->fd) {
1093 dup2(openfd, redir->fd);
1094 close(openfd);
1095 }
1096 }
1097
1098 return 0;
1099}
1100
1101
1102static int busy_loop(FILE * input) 1222static int busy_loop(FILE * input)
1103{ 1223{
1104 char *command; 1224 char *command;
@@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input)
1106 struct job newJob; 1226 struct job newJob;
1107 pid_t parent_pgrp; 1227 pid_t parent_pgrp;
1108 int i; 1228 int i;
1109 int status;
1110 int inBg; 1229 int inBg;
1230 int status;
1231 newJob.jobContext = REGULAR_JOB_CONTEXT;
1111 1232
1112 /* save current owner of TTY so we can restore it on exit */ 1233 /* save current owner of TTY so we can restore it on exit */
1113 parent_pgrp = tcgetpgrp(0); 1234 parent_pgrp = tcgetpgrp(0);
@@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input)
1160 removeJob(&jobList, jobList.fg); 1281 removeJob(&jobList, jobList.fg);
1161 jobList.fg = NULL; 1282 jobList.fg = NULL;
1162 } 1283 }
1284#ifdef BB_FEATURE_SH_ENVIRONMENT
1285 lastReturnCode=WEXITSTATUS(status);
1286#endif
1163 } else { 1287 } else {
1164 /* the child was stopped */ 1288 /* the child was stopped */
1165 jobList.fg->stoppedProgs++; 1289 jobList.fg->stoppedProgs++;
@@ -1211,9 +1335,11 @@ void free_memory(void)
1211#endif 1335#endif
1212 1336
1213 1337
1214int shell_main(int argc, char **argv) 1338int shell_main(int argc_l, char **argv_l)
1215{ 1339{
1216 FILE *input = stdin; 1340 FILE *input = stdin;
1341 argc = argc_l;
1342 argv = argv_l;
1217 1343
1218 /* initialize the cwd -- this is never freed...*/ 1344 /* initialize the cwd -- this is never freed...*/
1219 cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); 1345 cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
diff --git a/sh.c b/sh.c
index f746757d8..e57567608 100644
--- a/sh.c
+++ b/sh.c
@@ -26,9 +26,9 @@
26 */ 26 */
27 27
28 28
29#define BB_FEATURE_SH_BACKTICKS 29//#define BB_FEATURE_SH_BACKTICKS
30//#define BB_FEATURE_SH_IF_EXPRESSIONS 30//#define BB_FEATURE_SH_IF_EXPRESSIONS
31 31//#define BB_FEATURE_SH_ENVIRONMENT
32 32
33 33
34#include "internal.h" 34#include "internal.h"
@@ -57,13 +57,11 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
57}; 57};
58 58
59static const unsigned int REGULAR_JOB_CONTEXT=0x1; 59static const unsigned int REGULAR_JOB_CONTEXT=0x1;
60static const unsigned int IF_EXP_CONTEXT=0x2; 60static const unsigned int IF_TRUE_CONTEXT=0x2;
61static const unsigned int THEN_EXP_CONTEXT=0x4; 61static const unsigned int IF_FALSE_CONTEXT=0x4;
62static const unsigned int ELSE_EXP_CONTEXT=0x8; 62static const unsigned int THEN_EXP_CONTEXT=0x8;
63 63static const unsigned int ELSE_EXP_CONTEXT=0x10;
64 64
65enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
66};
67 65
68struct jobSet { 66struct jobSet {
69 struct job *head; /* head of list of running jobs */ 67 struct job *head; /* head of list of running jobs */
@@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk);
128/* function prototypes for shell stuff */ 126/* function prototypes for shell stuff */
129static void checkJobs(struct jobSet *jobList); 127static void checkJobs(struct jobSet *jobList);
130static int getCommand(FILE * source, char *command); 128static int getCommand(FILE * source, char *command);
131static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg); 129static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg);
132static int setupRedirections(struct childProgram *prog);
133static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); 130static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
134static int busy_loop(FILE * input); 131static int busy_loop(FILE * input);
135 132
@@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = {
146 {"export", "Set environment variable", builtin_export}, 143 {"export", "Set environment variable", builtin_export},
147 {"unset", "Unset environment variable", builtin_unset}, 144 {"unset", "Unset environment variable", builtin_unset},
148 {"read", "Input environment variable", builtin_read}, 145 {"read", "Input environment variable", builtin_read},
146#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
147 {"if", NULL, builtin_if},
148 {"then", NULL, builtin_then},
149 {"else", NULL, builtin_else},
150 {"fi", NULL, builtin_fi},
151#endif
149 {NULL, NULL, NULL} 152 {NULL, NULL, NULL}
150}; 153};
151 154
@@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = {
154static struct builtInCommand bltins_forking[] = { 157static struct builtInCommand bltins_forking[] = {
155 {"env", "Print all environment variables", builtin_env}, 158 {"env", "Print all environment variables", builtin_env},
156 {"pwd", "Print current directory", builtin_pwd}, 159 {"pwd", "Print current directory", builtin_pwd},
157#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
158 {"if", NULL, builtin_if},
159 {"then", NULL, builtin_then},
160 {"else", NULL, builtin_else},
161 {"fi", NULL, builtin_fi},
162#endif
163 {".", "Source-in and run commands in a file", builtin_source}, 160 {".", "Source-in and run commands in a file", builtin_source},
164 {"help", "List shell built-in commands", builtin_help}, 161 {"help", "List shell built-in commands", builtin_help},
165 {NULL, NULL, NULL} 162 {NULL, NULL, NULL}
@@ -170,6 +167,13 @@ static char *cwd;
170static char *local_pending_command = NULL; 167static char *local_pending_command = NULL;
171static char *promptStr = NULL; 168static char *promptStr = NULL;
172static struct jobSet jobList = { NULL, NULL }; 169static struct jobSet jobList = { NULL, NULL };
170static int argc;
171static char **argv;
172#ifdef BB_FEATURE_SH_ENVIRONMENT
173static int lastBgPid=-1;
174static int lastReturnCode=-1;
175#endif
176
173 177
174#ifdef BB_FEATURE_SH_COMMAND_EDITING 178#ifdef BB_FEATURE_SH_COMMAND_EDITING
175void win_changed(int junk) 179void win_changed(int junk)
@@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
369 373
370#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 374#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
371/* Built-in handler for 'if' commands */ 375/* Built-in handler for 'if' commands */
372static int builtin_if(struct job *cmd, struct jobSet *junk) 376static int builtin_if(struct job *cmd, struct jobSet *jobList)
373{ 377{
374 cmd->jobContext |= IF_EXP_CONTEXT; 378 int status;
375 printf("Hit an if -- jobContext=%d\n", cmd->jobContext); 379 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
376 return TRUE; 380
381 /* Now run the 'if' command */
382 status=strlen(charptr1);
383 local_pending_command = xmalloc(status+1);
384 strncpy(local_pending_command, charptr1, status);
385 printf("'if' now running '%s'\n", charptr1);
386 status = busy_loop(NULL); /* Frees local_pending_command */
387 printf("if test returned ");
388 if (status == 0) {
389 printf("TRUE\n");
390 cmd->jobContext |= IF_TRUE_CONTEXT;
391 } else {
392 printf("FALSE\n");
393 cmd->jobContext |= IF_FALSE_CONTEXT;
394 }
395
396 return status;
377} 397}
378 398
379/* Built-in handler for 'then' (part of the 'if' command) */ 399/* Built-in handler for 'then' (part of the 'if' command) */
380static int builtin_then(struct job *cmd, struct jobSet *junk) 400static int builtin_then(struct job *cmd, struct jobSet *junk)
381{ 401{
382 if (cmd->jobContext & IF_EXP_CONTEXT) { 402 int status;
383 fprintf(stderr, "unexpected token `then'\n"); 403 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
384 fflush(stderr); 404
405 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
406 errorMsg("unexpected token `then'\n");
385 return FALSE; 407 return FALSE;
386 } 408 }
409 /* If the if result was FALSE, skip the 'then' stuff */
410 if (cmd->jobContext & IF_TRUE_CONTEXT) {
411 return TRUE;
412 }
413
387 cmd->jobContext |= THEN_EXP_CONTEXT; 414 cmd->jobContext |= THEN_EXP_CONTEXT;
388 printf("Hit an then -- jobContext=%d\n", cmd->jobContext); 415 //printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
389 return TRUE; 416
417 /* Now run the 'then' command */
418 status=strlen(charptr1);
419 local_pending_command = xmalloc(status+1);
420 strncpy(local_pending_command, charptr1, status);
421 printf("'then' now running '%s'\n", charptr1);
422 return( busy_loop(NULL));
390} 423}
391 424
392/* Built-in handler for 'else' (part of the 'if' command) */ 425/* Built-in handler for 'else' (part of the 'if' command) */
393static int builtin_else(struct job *cmd, struct jobSet *junk) 426static int builtin_else(struct job *cmd, struct jobSet *junk)
394{ 427{
395 printf("Hit an else\n"); 428 int status;
429 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
430
431 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
432 errorMsg("unexpected token `else'\n");
433 return FALSE;
434 }
435 /* If the if result was TRUE, skip the 'else' stuff */
436 if (cmd->jobContext & IF_FALSE_CONTEXT) {
437 return TRUE;
438 }
439
396 cmd->jobContext |= ELSE_EXP_CONTEXT; 440 cmd->jobContext |= ELSE_EXP_CONTEXT;
397 return TRUE; 441 //printf("Hit an else -- jobContext=%d\n", cmd->jobContext);
442
443 /* Now run the 'else' command */
444 status=strlen(charptr1);
445 local_pending_command = xmalloc(status+1);
446 strncpy(local_pending_command, charptr1, status);
447 printf("'else' now running '%s'\n", charptr1);
448 return( busy_loop(NULL));
398} 449}
399 450
400/* Built-in handler for 'fi' (part of the 'if' command) */ 451/* Built-in handler for 'fi' (part of the 'if' command) */
401static int builtin_fi(struct job *cmd, struct jobSet *junk) 452static int builtin_fi(struct job *cmd, struct jobSet *junk)
402{ 453{
403 printf("Hit an fi\n"); 454 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
455 errorMsg("unexpected token `fi'\n");
456 return FALSE;
457 }
458 /* Clear out the if and then context bits */
459 cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
460 printf("Hit an fi -- jobContext=%d\n", cmd->jobContext);
404 return TRUE; 461 return TRUE;
405} 462}
406#endif 463#endif
@@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList)
521 perror("waitpid"); 578 perror("waitpid");
522} 579}
523 580
581static int setupRedirections(struct childProgram *prog)
582{
583 int i;
584 int openfd;
585 int mode = O_RDONLY;
586 struct redirectionSpecifier *redir = prog->redirections;
587
588 for (i = 0; i < prog->numRedirections; i++, redir++) {
589 switch (redir->type) {
590 case REDIRECT_INPUT:
591 mode = O_RDONLY;
592 break;
593 case REDIRECT_OVERWRITE:
594 mode = O_RDWR | O_CREAT | O_TRUNC;
595 break;
596 case REDIRECT_APPEND:
597 mode = O_RDWR | O_CREAT | O_APPEND;
598 break;
599 }
600
601 openfd = open(redir->filename, mode, 0666);
602 if (openfd < 0) {
603 /* this could get lost if stderr has been redirected, but
604 bash and ash both lose it as well (though zsh doesn't!) */
605 errorMsg("error opening %s: %s\n", redir->filename,
606 strerror(errno));
607 return 1;
608 }
609
610 if (openfd != redir->fd) {
611 dup2(openfd, redir->fd);
612 close(openfd);
613 }
614 }
615
616 return 0;
617}
618
619
524static int getCommand(FILE * source, char *command) 620static int getCommand(FILE * source, char *command)
525{ 621{
526 if (source == NULL) { 622 if (source == NULL) {
@@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command)
562 return 0; 658 return 0;
563} 659}
564 660
661#ifdef BB_FEATURE_SH_ENVIRONMENT
662#define __MAX_INT_CHARS 7
663static char* itoa(register int i)
664{
665 static char a[__MAX_INT_CHARS];
666 register char *b = a + sizeof(a) - 1;
667 int sign = (i < 0);
668
669 if (sign)
670 i = -i;
671 *b = 0;
672 do
673 {
674 *--b = '0' + (i % 10);
675 i /= 10;
676 }
677 while (i);
678 if (sign)
679 *--b = '-';
680 return b;
681}
682#endif
683
565static void globLastArgument(struct childProgram *prog, int *argcPtr, 684static void globLastArgument(struct childProgram *prog, int *argcPtr,
566 int *argcAllocedPtr) 685 int *argcAllocedPtr)
567{ 686{
568 int argc = *argcPtr; 687 int argc_l = *argcPtr;
569 int argcAlloced = *argcAllocedPtr; 688 int argcAlloced = *argcAllocedPtr;
570 int rc; 689 int rc;
571 int flags; 690 int flags;
572 int i; 691 int i;
573 char *src, *dst, *var; 692 char *src, *dst, *var;
574 693
575 if (argc > 1) { /* cmd->globResult is already initialized */ 694 if (argc_l > 1) { /* cmd->globResult is already initialized */
576 flags = GLOB_APPEND; 695 flags = GLOB_APPEND;
577 i = prog->globResult.gl_pathc; 696 i = prog->globResult.gl_pathc;
578 } else { 697 } else {
@@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
581 i = 0; 700 i = 0;
582 } 701 }
583 /* do shell variable substitution */ 702 /* do shell variable substitution */
584 if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1))) 703 if(*prog->argv[argc_l - 1] == '$') {
585 prog->argv[argc - 1] = var; 704 if ((var = getenv(prog->argv[argc_l - 1] + 1))) {
705 prog->argv[argc_l - 1] = var;
706 }
707#ifdef BB_FEATURE_SH_ENVIRONMENT
708 else {
709 switch(*(prog->argv[argc_l - 1] + 1)) {
710 case '?':
711 prog->argv[argc_l - 1] = itoa(lastReturnCode);
712 break;
713 case '$':
714 prog->argv[argc_l - 1] = itoa(getpid());
715 break;
716 case '#':
717 prog->argv[argc_l - 1] = itoa(argc-1);
718 break;
719 case '!':
720 if (lastBgPid==-1)
721 *(prog->argv[argc_l - 1])='\0';
722 else
723 prog->argv[argc_l - 1] = itoa(lastBgPid);
724 break;
725 case '0':case '1':case '2':case '3':case '4':
726 case '5':case '6':case '7':case '8':case '9':
727 {
728 int index=*(prog->argv[argc_l - 1] + 1)-48;
729 if (index >= argc) {
730 *(prog->argv[argc_l - 1])='\0';
731 } else {
732 prog->argv[argc_l - 1] = argv[index];
733 }
734 }
735 break;
736 }
737 }
738#endif
739 }
586 740
587 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); 741 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult);
588 if (rc == GLOB_NOSPACE) { 742 if (rc == GLOB_NOSPACE) {
589 errorMsg("out of space during glob operation\n"); 743 errorMsg("out of space during glob operation\n");
590 return; 744 return;
591 } else if (rc == GLOB_NOMATCH || 745 } else if (rc == GLOB_NOMATCH ||
592 (!rc && (prog->globResult.gl_pathc - i) == 1 && 746 (!rc && (prog->globResult.gl_pathc - i) == 1 &&
593 strcmp(prog->argv[argc - 1], 747 strcmp(prog->argv[argc_l - 1],
594 prog->globResult.gl_pathv[i]) == 0)) { 748 prog->globResult.gl_pathv[i]) == 0)) {
595 /* we need to remove whatever \ quoting is still present */ 749 /* we need to remove whatever \ quoting is still present */
596 src = dst = prog->argv[argc - 1]; 750 src = dst = prog->argv[argc_l - 1];
597 while (*src) { 751 while (*src) {
598 if (*src != '\\') 752 if (*src != '\\')
599 *dst++ = *src; 753 *dst++ = *src;
@@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
604 argcAlloced += (prog->globResult.gl_pathc - i); 758 argcAlloced += (prog->globResult.gl_pathc - i);
605 prog->argv = 759 prog->argv =
606 realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 760 realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
607 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, 761 memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i,
608 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 762 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
609 argc += (prog->globResult.gl_pathc - i - 1); 763 argc_l += (prog->globResult.gl_pathc - i - 1);
610 } 764 }
611 765
612 *argcAllocedPtr = argcAlloced; 766 *argcAllocedPtr = argcAlloced;
613 *argcPtr = argc; 767 *argcPtr = argc_l;
614} 768}
615 769
616/* Return cmd->numProgs as 0 if no command is present (e.g. an empty 770/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
@@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
618 the beginning of the next command (if the original command had more 772 the beginning of the next command (if the original command had more
619 then one job associated with it) or NULL if no more commands are 773 then one job associated with it) or NULL if no more commands are
620 present. */ 774 present. */
621static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg) 775static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg)
622{ 776{
623 char *command; 777 char *command;
624 char *returnCommand = NULL; 778 char *returnCommand = NULL;
625 char *src, *buf, *chptr; 779 char *src, *buf, *chptr;
626 int argc = 0; 780 int argc_l = 0;
627 int done = 0; 781 int done = 0;
628 int argvAlloced; 782 int argvAlloced;
629 int i; 783 int i;
@@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
641 return 0; 795 return 0;
642 } 796 }
643 797
644 *isBg = 0; 798 *inBg = 0;
645 job->numProgs = 1; 799 job->numProgs = 1;
646 job->progs = xmalloc(sizeof(*job->progs)); 800 job->progs = xmalloc(sizeof(*job->progs));
647 801
@@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
654 cleaner (though it is, admittedly, a tad less efficient) */ 808 cleaner (though it is, admittedly, a tad less efficient) */
655 job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); 809 job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
656 job->text = NULL; 810 job->text = NULL;
657 job->jobContext = REGULAR_JOB_CONTEXT;
658 811
659 prog = job->progs; 812 prog = job->progs;
660 prog->numRedirections = 0; 813 prog->numRedirections = 0;
@@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
687 *src == ']') *buf++ = '\\'; 840 *src == ']') *buf++ = '\\';
688 *buf++ = *src; 841 *buf++ = *src;
689 } else if (isspace(*src)) { 842 } else if (isspace(*src)) {
690 if (*prog->argv[argc]) { 843 if (*prog->argv[argc_l]) {
691 buf++, argc++; 844 buf++, argc_l++;
692 /* +1 here leaves room for the NULL which ends argv */ 845 /* +1 here leaves room for the NULL which ends argv */
693 if ((argc + 1) == argvAlloced) { 846 if ((argc_l + 1) == argvAlloced) {
694 argvAlloced += 5; 847 argvAlloced += 5;
695 prog->argv = realloc(prog->argv, 848 prog->argv = realloc(prog->argv,
696 sizeof(*prog->argv) * 849 sizeof(*prog->argv) *
697 argvAlloced); 850 argvAlloced);
698 } 851 }
699 globLastArgument(prog, &argc, &argvAlloced); 852 globLastArgument(prog, &argc_l, &argvAlloced);
700 prog->argv[argc] = buf; 853 prog->argv[argc_l] = buf;
701 } 854 }
702 } else 855 } else
703 switch (*src) { 856 switch (*src) {
@@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
707 break; 860 break;
708 861
709 case '#': /* comment */ 862 case '#': /* comment */
710 done = 1; 863 if (*(src-1)== '$')
864 *buf++ = *src;
865 else
866 done = 1;
711 break; 867 break;
712 868
713 case '>': /* redirections */ 869 case '>': /* redirections */
@@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
718 (i + 1)); 874 (i + 1));
719 875
720 prog->redirections[i].fd = -1; 876 prog->redirections[i].fd = -1;
721 if (buf != prog->argv[argc]) { 877 if (buf != prog->argv[argc_l]) {
722 /* the stuff before this character may be the file number 878 /* the stuff before this character may be the file number
723 being redirected */ 879 being redirected */
724 prog->redirections[i].fd = 880 prog->redirections[i].fd =
725 strtol(prog->argv[argc], &chptr, 10); 881 strtol(prog->argv[argc_l], &chptr, 10);
726 882
727 if (*chptr && *prog->argv[argc]) { 883 if (*chptr && *prog->argv[argc_l]) {
728 buf++, argc++; 884 buf++, argc_l++;
729 globLastArgument(prog, &argc, &argvAlloced); 885 globLastArgument(prog, &argc_l, &argvAlloced);
730 prog->argv[argc] = buf; 886 prog->argv[argc_l] = buf;
731 } 887 }
732 } 888 }
733 889
@@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
765 *buf++ = *chptr++; 921 *buf++ = *chptr++;
766 922
767 src = chptr - 1; /* we src++ later */ 923 src = chptr - 1; /* we src++ later */
768 prog->argv[argc] = ++buf; 924 prog->argv[argc_l] = ++buf;
769 break; 925 break;
770 926
771 case '|': /* pipe */ 927 case '|': /* pipe */
772 /* finish this command */ 928 /* finish this command */
773 if (*prog->argv[argc]) 929 if (*prog->argv[argc_l])
774 argc++; 930 argc_l++;
775 if (!argc) { 931 if (!argc_l) {
776 errorMsg("empty command in pipe\n"); 932 errorMsg("empty command in pipe\n");
777 freeJob(job); 933 freeJob(job);
778 job->numProgs=0; 934 job->numProgs=0;
779 return 1; 935 return 1;
780 } 936 }
781 prog->argv[argc] = NULL; 937 prog->argv[argc_l] = NULL;
782 938
783 /* and start the next */ 939 /* and start the next */
784 job->numProgs++; 940 job->numProgs++;
@@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
788 prog->numRedirections = 0; 944 prog->numRedirections = 0;
789 prog->redirections = NULL; 945 prog->redirections = NULL;
790 prog->freeGlob = 0; 946 prog->freeGlob = 0;
791 argc = 0; 947 argc_l = 0;
792 948
793 argvAlloced = 5; 949 argvAlloced = 5;
794 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 950 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
@@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
809 break; 965 break;
810 966
811 case '&': /* background */ 967 case '&': /* background */
812 *isBg = 1; 968 *inBg = 1;
813 case ';': /* multiple commands */ 969 case ';': /* multiple commands */
814 done = 1; 970 done = 1;
815 returnCommand = *commandPtr + (src - *commandPtr) + 1; 971 returnCommand = *commandPtr + (src - *commandPtr) + 1;
@@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
848 snprintf(charptr1, 1+ptr-src, src); 1004 snprintf(charptr1, 1+ptr-src, src);
849 newJob = xmalloc(sizeof(struct job)); 1005 newJob = xmalloc(sizeof(struct job));
850 /* Now parse and run the backticked command */ 1006 /* Now parse and run the backticked command */
851 if (!parseCommand(&charptr1, newJob, &njobList, isBg) 1007 if (!parseCommand(&charptr1, newJob, &njobList, inBg)
852 && newJob->numProgs) { 1008 && newJob->numProgs) {
853 pipe(pipefd); 1009 pipe(pipefd);
854 runCommand(newJob, &njobList, 0, pipefd); 1010 runCommand(newJob, &njobList, 0, pipefd);
@@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
890 * and improved version of the command line with the backtick 1046 * and improved version of the command line with the backtick
891 * results expanded in place... */ 1047 * results expanded in place... */
892 freeJob(job); 1048 freeJob(job);
893 return(parseCommand(commandPtr, job, jobList, isBg)); 1049 return(parseCommand(commandPtr, job, jobList, inBg));
894 } 1050 }
895 break; 1051 break;
896#endif // BB_FEATURE_SH_BACKTICKS 1052#endif // BB_FEATURE_SH_BACKTICKS
@@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
901 src++; 1057 src++;
902 } 1058 }
903 1059
904 if (*prog->argv[argc]) { 1060 if (*prog->argv[argc_l]) {
905 argc++; 1061 argc_l++;
906 globLastArgument(prog, &argc, &argvAlloced); 1062 globLastArgument(prog, &argc_l, &argvAlloced);
907 } 1063 }
908 if (!argc) { 1064 if (!argc_l) {
909 freeJob(job); 1065 freeJob(job);
910 return 0; 1066 return 0;
911 } 1067 }
912 prog->argv[argc] = NULL; 1068 prog->argv[argc_l] = NULL;
913 1069
914 if (!returnCommand) { 1070 if (!returnCommand) {
915 job->text = xmalloc(strlen(*commandPtr) + 1); 1071 job->text = xmalloc(strlen(*commandPtr) + 1);
@@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
991 * works, but '/bin/cat' doesn't ) */ 1147 * works, but '/bin/cat' doesn't ) */
992 while (a->name != 0) { 1148 while (a->name != 0) {
993 if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { 1149 if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
994 int argc; 1150 int argc_l;
995 char** argv=newJob->progs[i].argv; 1151 char** argv=newJob->progs[i].argv;
996 for(argc=0;*argv!=NULL; argv++, argc++); 1152 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
997 exit((*(a->main)) (argc, newJob->progs[i].argv)); 1153 exit((*(a->main)) (argc_l, newJob->progs[i].argv));
998 } 1154 }
999 a++; 1155 a++;
1000 } 1156 }
1001#endif 1157#endif
1002 1158
1003 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); 1159 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
1004 fatalError("sh: %s: %s\n", newJob->progs[i].argv[0], 1160 fatalError("%s: %s\n", newJob->progs[i].argv[0],
1005 strerror(errno)); 1161 strerror(errno));
1006 } 1162 }
1007 if (outPipe[1]!=-1) { 1163 if (outPipe[1]!=-1) {
@@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1048 to the list of backgrounded theJobs and leave it alone */ 1204 to the list of backgrounded theJobs and leave it alone */
1049 printf("[%d] %d\n", theJob->jobId, 1205 printf("[%d] %d\n", theJob->jobId,
1050 newJob->progs[newJob->numProgs - 1].pid); 1206 newJob->progs[newJob->numProgs - 1].pid);
1207#ifdef BB_FEATURE_SH_ENVIRONMENT
1208 lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
1209#endif
1051 } else { 1210 } else {
1052 jobList->fg = theJob; 1211 jobList->fg = theJob;
1053 1212
@@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1060 return 0; 1219 return 0;
1061} 1220}
1062 1221
1063static int setupRedirections(struct childProgram *prog)
1064{
1065 int i;
1066 int openfd;
1067 int mode = O_RDONLY;
1068 struct redirectionSpecifier *redir = prog->redirections;
1069
1070 for (i = 0; i < prog->numRedirections; i++, redir++) {
1071 switch (redir->type) {
1072 case REDIRECT_INPUT:
1073 mode = O_RDONLY;
1074 break;
1075 case REDIRECT_OVERWRITE:
1076 mode = O_RDWR | O_CREAT | O_TRUNC;
1077 break;
1078 case REDIRECT_APPEND:
1079 mode = O_RDWR | O_CREAT | O_APPEND;
1080 break;
1081 }
1082
1083 openfd = open(redir->filename, mode, 0666);
1084 if (openfd < 0) {
1085 /* this could get lost if stderr has been redirected, but
1086 bash and ash both lose it as well (though zsh doesn't!) */
1087 errorMsg("error opening %s: %s\n", redir->filename,
1088 strerror(errno));
1089 return 1;
1090 }
1091
1092 if (openfd != redir->fd) {
1093 dup2(openfd, redir->fd);
1094 close(openfd);
1095 }
1096 }
1097
1098 return 0;
1099}
1100
1101
1102static int busy_loop(FILE * input) 1222static int busy_loop(FILE * input)
1103{ 1223{
1104 char *command; 1224 char *command;
@@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input)
1106 struct job newJob; 1226 struct job newJob;
1107 pid_t parent_pgrp; 1227 pid_t parent_pgrp;
1108 int i; 1228 int i;
1109 int status;
1110 int inBg; 1229 int inBg;
1230 int status;
1231 newJob.jobContext = REGULAR_JOB_CONTEXT;
1111 1232
1112 /* save current owner of TTY so we can restore it on exit */ 1233 /* save current owner of TTY so we can restore it on exit */
1113 parent_pgrp = tcgetpgrp(0); 1234 parent_pgrp = tcgetpgrp(0);
@@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input)
1160 removeJob(&jobList, jobList.fg); 1281 removeJob(&jobList, jobList.fg);
1161 jobList.fg = NULL; 1282 jobList.fg = NULL;
1162 } 1283 }
1284#ifdef BB_FEATURE_SH_ENVIRONMENT
1285 lastReturnCode=WEXITSTATUS(status);
1286#endif
1163 } else { 1287 } else {
1164 /* the child was stopped */ 1288 /* the child was stopped */
1165 jobList.fg->stoppedProgs++; 1289 jobList.fg->stoppedProgs++;
@@ -1211,9 +1335,11 @@ void free_memory(void)
1211#endif 1335#endif
1212 1336
1213 1337
1214int shell_main(int argc, char **argv) 1338int shell_main(int argc_l, char **argv_l)
1215{ 1339{
1216 FILE *input = stdin; 1340 FILE *input = stdin;
1341 argc = argc_l;
1342 argv = argv_l;
1217 1343
1218 /* initialize the cwd -- this is never freed...*/ 1344 /* initialize the cwd -- this is never freed...*/
1219 cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); 1345 cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
diff --git a/shell/lash.c b/shell/lash.c
index f746757d8..e57567608 100644
--- a/shell/lash.c
+++ b/shell/lash.c
@@ -26,9 +26,9 @@
26 */ 26 */
27 27
28 28
29#define BB_FEATURE_SH_BACKTICKS 29//#define BB_FEATURE_SH_BACKTICKS
30//#define BB_FEATURE_SH_IF_EXPRESSIONS 30//#define BB_FEATURE_SH_IF_EXPRESSIONS
31 31//#define BB_FEATURE_SH_ENVIRONMENT
32 32
33 33
34#include "internal.h" 34#include "internal.h"
@@ -57,13 +57,11 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
57}; 57};
58 58
59static const unsigned int REGULAR_JOB_CONTEXT=0x1; 59static const unsigned int REGULAR_JOB_CONTEXT=0x1;
60static const unsigned int IF_EXP_CONTEXT=0x2; 60static const unsigned int IF_TRUE_CONTEXT=0x2;
61static const unsigned int THEN_EXP_CONTEXT=0x4; 61static const unsigned int IF_FALSE_CONTEXT=0x4;
62static const unsigned int ELSE_EXP_CONTEXT=0x8; 62static const unsigned int THEN_EXP_CONTEXT=0x8;
63 63static const unsigned int ELSE_EXP_CONTEXT=0x10;
64 64
65enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
66};
67 65
68struct jobSet { 66struct jobSet {
69 struct job *head; /* head of list of running jobs */ 67 struct job *head; /* head of list of running jobs */
@@ -128,8 +126,7 @@ static int builtin_fi(struct job *cmd, struct jobSet *junk);
128/* function prototypes for shell stuff */ 126/* function prototypes for shell stuff */
129static void checkJobs(struct jobSet *jobList); 127static void checkJobs(struct jobSet *jobList);
130static int getCommand(FILE * source, char *command); 128static int getCommand(FILE * source, char *command);
131static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg); 129static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg);
132static int setupRedirections(struct childProgram *prog);
133static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]); 130static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]);
134static int busy_loop(FILE * input); 131static int busy_loop(FILE * input);
135 132
@@ -146,6 +143,12 @@ static struct builtInCommand bltins[] = {
146 {"export", "Set environment variable", builtin_export}, 143 {"export", "Set environment variable", builtin_export},
147 {"unset", "Unset environment variable", builtin_unset}, 144 {"unset", "Unset environment variable", builtin_unset},
148 {"read", "Input environment variable", builtin_read}, 145 {"read", "Input environment variable", builtin_read},
146#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
147 {"if", NULL, builtin_if},
148 {"then", NULL, builtin_then},
149 {"else", NULL, builtin_else},
150 {"fi", NULL, builtin_fi},
151#endif
149 {NULL, NULL, NULL} 152 {NULL, NULL, NULL}
150}; 153};
151 154
@@ -154,12 +157,6 @@ static struct builtInCommand bltins[] = {
154static struct builtInCommand bltins_forking[] = { 157static struct builtInCommand bltins_forking[] = {
155 {"env", "Print all environment variables", builtin_env}, 158 {"env", "Print all environment variables", builtin_env},
156 {"pwd", "Print current directory", builtin_pwd}, 159 {"pwd", "Print current directory", builtin_pwd},
157#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
158 {"if", NULL, builtin_if},
159 {"then", NULL, builtin_then},
160 {"else", NULL, builtin_else},
161 {"fi", NULL, builtin_fi},
162#endif
163 {".", "Source-in and run commands in a file", builtin_source}, 160 {".", "Source-in and run commands in a file", builtin_source},
164 {"help", "List shell built-in commands", builtin_help}, 161 {"help", "List shell built-in commands", builtin_help},
165 {NULL, NULL, NULL} 162 {NULL, NULL, NULL}
@@ -170,6 +167,13 @@ static char *cwd;
170static char *local_pending_command = NULL; 167static char *local_pending_command = NULL;
171static char *promptStr = NULL; 168static char *promptStr = NULL;
172static struct jobSet jobList = { NULL, NULL }; 169static struct jobSet jobList = { NULL, NULL };
170static int argc;
171static char **argv;
172#ifdef BB_FEATURE_SH_ENVIRONMENT
173static int lastBgPid=-1;
174static int lastReturnCode=-1;
175#endif
176
173 177
174#ifdef BB_FEATURE_SH_COMMAND_EDITING 178#ifdef BB_FEATURE_SH_COMMAND_EDITING
175void win_changed(int junk) 179void win_changed(int junk)
@@ -369,38 +373,91 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
369 373
370#ifdef BB_FEATURE_SH_IF_EXPRESSIONS 374#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
371/* Built-in handler for 'if' commands */ 375/* Built-in handler for 'if' commands */
372static int builtin_if(struct job *cmd, struct jobSet *junk) 376static int builtin_if(struct job *cmd, struct jobSet *jobList)
373{ 377{
374 cmd->jobContext |= IF_EXP_CONTEXT; 378 int status;
375 printf("Hit an if -- jobContext=%d\n", cmd->jobContext); 379 char* charptr1=cmd->text+3; /* skip over the leading 'if ' */
376 return TRUE; 380
381 /* Now run the 'if' command */
382 status=strlen(charptr1);
383 local_pending_command = xmalloc(status+1);
384 strncpy(local_pending_command, charptr1, status);
385 printf("'if' now running '%s'\n", charptr1);
386 status = busy_loop(NULL); /* Frees local_pending_command */
387 printf("if test returned ");
388 if (status == 0) {
389 printf("TRUE\n");
390 cmd->jobContext |= IF_TRUE_CONTEXT;
391 } else {
392 printf("FALSE\n");
393 cmd->jobContext |= IF_FALSE_CONTEXT;
394 }
395
396 return status;
377} 397}
378 398
379/* Built-in handler for 'then' (part of the 'if' command) */ 399/* Built-in handler for 'then' (part of the 'if' command) */
380static int builtin_then(struct job *cmd, struct jobSet *junk) 400static int builtin_then(struct job *cmd, struct jobSet *junk)
381{ 401{
382 if (cmd->jobContext & IF_EXP_CONTEXT) { 402 int status;
383 fprintf(stderr, "unexpected token `then'\n"); 403 char* charptr1=cmd->text+5; /* skip over the leading 'then ' */
384 fflush(stderr); 404
405 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
406 errorMsg("unexpected token `then'\n");
385 return FALSE; 407 return FALSE;
386 } 408 }
409 /* If the if result was FALSE, skip the 'then' stuff */
410 if (cmd->jobContext & IF_TRUE_CONTEXT) {
411 return TRUE;
412 }
413
387 cmd->jobContext |= THEN_EXP_CONTEXT; 414 cmd->jobContext |= THEN_EXP_CONTEXT;
388 printf("Hit an then -- jobContext=%d\n", cmd->jobContext); 415 //printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
389 return TRUE; 416
417 /* Now run the 'then' command */
418 status=strlen(charptr1);
419 local_pending_command = xmalloc(status+1);
420 strncpy(local_pending_command, charptr1, status);
421 printf("'then' now running '%s'\n", charptr1);
422 return( busy_loop(NULL));
390} 423}
391 424
392/* Built-in handler for 'else' (part of the 'if' command) */ 425/* Built-in handler for 'else' (part of the 'if' command) */
393static int builtin_else(struct job *cmd, struct jobSet *junk) 426static int builtin_else(struct job *cmd, struct jobSet *junk)
394{ 427{
395 printf("Hit an else\n"); 428 int status;
429 char* charptr1=cmd->text+5; /* skip over the leading 'else ' */
430
431 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
432 errorMsg("unexpected token `else'\n");
433 return FALSE;
434 }
435 /* If the if result was TRUE, skip the 'else' stuff */
436 if (cmd->jobContext & IF_FALSE_CONTEXT) {
437 return TRUE;
438 }
439
396 cmd->jobContext |= ELSE_EXP_CONTEXT; 440 cmd->jobContext |= ELSE_EXP_CONTEXT;
397 return TRUE; 441 //printf("Hit an else -- jobContext=%d\n", cmd->jobContext);
442
443 /* Now run the 'else' command */
444 status=strlen(charptr1);
445 local_pending_command = xmalloc(status+1);
446 strncpy(local_pending_command, charptr1, status);
447 printf("'else' now running '%s'\n", charptr1);
448 return( busy_loop(NULL));
398} 449}
399 450
400/* Built-in handler for 'fi' (part of the 'if' command) */ 451/* Built-in handler for 'fi' (part of the 'if' command) */
401static int builtin_fi(struct job *cmd, struct jobSet *junk) 452static int builtin_fi(struct job *cmd, struct jobSet *junk)
402{ 453{
403 printf("Hit an fi\n"); 454 if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
455 errorMsg("unexpected token `fi'\n");
456 return FALSE;
457 }
458 /* Clear out the if and then context bits */
459 cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
460 printf("Hit an fi -- jobContext=%d\n", cmd->jobContext);
404 return TRUE; 461 return TRUE;
405} 462}
406#endif 463#endif
@@ -521,6 +578,45 @@ static void checkJobs(struct jobSet *jobList)
521 perror("waitpid"); 578 perror("waitpid");
522} 579}
523 580
581static int setupRedirections(struct childProgram *prog)
582{
583 int i;
584 int openfd;
585 int mode = O_RDONLY;
586 struct redirectionSpecifier *redir = prog->redirections;
587
588 for (i = 0; i < prog->numRedirections; i++, redir++) {
589 switch (redir->type) {
590 case REDIRECT_INPUT:
591 mode = O_RDONLY;
592 break;
593 case REDIRECT_OVERWRITE:
594 mode = O_RDWR | O_CREAT | O_TRUNC;
595 break;
596 case REDIRECT_APPEND:
597 mode = O_RDWR | O_CREAT | O_APPEND;
598 break;
599 }
600
601 openfd = open(redir->filename, mode, 0666);
602 if (openfd < 0) {
603 /* this could get lost if stderr has been redirected, but
604 bash and ash both lose it as well (though zsh doesn't!) */
605 errorMsg("error opening %s: %s\n", redir->filename,
606 strerror(errno));
607 return 1;
608 }
609
610 if (openfd != redir->fd) {
611 dup2(openfd, redir->fd);
612 close(openfd);
613 }
614 }
615
616 return 0;
617}
618
619
524static int getCommand(FILE * source, char *command) 620static int getCommand(FILE * source, char *command)
525{ 621{
526 if (source == NULL) { 622 if (source == NULL) {
@@ -562,17 +658,40 @@ static int getCommand(FILE * source, char *command)
562 return 0; 658 return 0;
563} 659}
564 660
661#ifdef BB_FEATURE_SH_ENVIRONMENT
662#define __MAX_INT_CHARS 7
663static char* itoa(register int i)
664{
665 static char a[__MAX_INT_CHARS];
666 register char *b = a + sizeof(a) - 1;
667 int sign = (i < 0);
668
669 if (sign)
670 i = -i;
671 *b = 0;
672 do
673 {
674 *--b = '0' + (i % 10);
675 i /= 10;
676 }
677 while (i);
678 if (sign)
679 *--b = '-';
680 return b;
681}
682#endif
683
565static void globLastArgument(struct childProgram *prog, int *argcPtr, 684static void globLastArgument(struct childProgram *prog, int *argcPtr,
566 int *argcAllocedPtr) 685 int *argcAllocedPtr)
567{ 686{
568 int argc = *argcPtr; 687 int argc_l = *argcPtr;
569 int argcAlloced = *argcAllocedPtr; 688 int argcAlloced = *argcAllocedPtr;
570 int rc; 689 int rc;
571 int flags; 690 int flags;
572 int i; 691 int i;
573 char *src, *dst, *var; 692 char *src, *dst, *var;
574 693
575 if (argc > 1) { /* cmd->globResult is already initialized */ 694 if (argc_l > 1) { /* cmd->globResult is already initialized */
576 flags = GLOB_APPEND; 695 flags = GLOB_APPEND;
577 i = prog->globResult.gl_pathc; 696 i = prog->globResult.gl_pathc;
578 } else { 697 } else {
@@ -581,19 +700,54 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
581 i = 0; 700 i = 0;
582 } 701 }
583 /* do shell variable substitution */ 702 /* do shell variable substitution */
584 if(*prog->argv[argc - 1] == '$' && (var = getenv(prog->argv[argc - 1] + 1))) 703 if(*prog->argv[argc_l - 1] == '$') {
585 prog->argv[argc - 1] = var; 704 if ((var = getenv(prog->argv[argc_l - 1] + 1))) {
705 prog->argv[argc_l - 1] = var;
706 }
707#ifdef BB_FEATURE_SH_ENVIRONMENT
708 else {
709 switch(*(prog->argv[argc_l - 1] + 1)) {
710 case '?':
711 prog->argv[argc_l - 1] = itoa(lastReturnCode);
712 break;
713 case '$':
714 prog->argv[argc_l - 1] = itoa(getpid());
715 break;
716 case '#':
717 prog->argv[argc_l - 1] = itoa(argc-1);
718 break;
719 case '!':
720 if (lastBgPid==-1)
721 *(prog->argv[argc_l - 1])='\0';
722 else
723 prog->argv[argc_l - 1] = itoa(lastBgPid);
724 break;
725 case '0':case '1':case '2':case '3':case '4':
726 case '5':case '6':case '7':case '8':case '9':
727 {
728 int index=*(prog->argv[argc_l - 1] + 1)-48;
729 if (index >= argc) {
730 *(prog->argv[argc_l - 1])='\0';
731 } else {
732 prog->argv[argc_l - 1] = argv[index];
733 }
734 }
735 break;
736 }
737 }
738#endif
739 }
586 740
587 rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult); 741 rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult);
588 if (rc == GLOB_NOSPACE) { 742 if (rc == GLOB_NOSPACE) {
589 errorMsg("out of space during glob operation\n"); 743 errorMsg("out of space during glob operation\n");
590 return; 744 return;
591 } else if (rc == GLOB_NOMATCH || 745 } else if (rc == GLOB_NOMATCH ||
592 (!rc && (prog->globResult.gl_pathc - i) == 1 && 746 (!rc && (prog->globResult.gl_pathc - i) == 1 &&
593 strcmp(prog->argv[argc - 1], 747 strcmp(prog->argv[argc_l - 1],
594 prog->globResult.gl_pathv[i]) == 0)) { 748 prog->globResult.gl_pathv[i]) == 0)) {
595 /* we need to remove whatever \ quoting is still present */ 749 /* we need to remove whatever \ quoting is still present */
596 src = dst = prog->argv[argc - 1]; 750 src = dst = prog->argv[argc_l - 1];
597 while (*src) { 751 while (*src) {
598 if (*src != '\\') 752 if (*src != '\\')
599 *dst++ = *src; 753 *dst++ = *src;
@@ -604,13 +758,13 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
604 argcAlloced += (prog->globResult.gl_pathc - i); 758 argcAlloced += (prog->globResult.gl_pathc - i);
605 prog->argv = 759 prog->argv =
606 realloc(prog->argv, argcAlloced * sizeof(*prog->argv)); 760 realloc(prog->argv, argcAlloced * sizeof(*prog->argv));
607 memcpy(prog->argv + (argc - 1), prog->globResult.gl_pathv + i, 761 memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i,
608 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i)); 762 sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
609 argc += (prog->globResult.gl_pathc - i - 1); 763 argc_l += (prog->globResult.gl_pathc - i - 1);
610 } 764 }
611 765
612 *argcAllocedPtr = argcAlloced; 766 *argcAllocedPtr = argcAlloced;
613 *argcPtr = argc; 767 *argcPtr = argc_l;
614} 768}
615 769
616/* Return cmd->numProgs as 0 if no command is present (e.g. an empty 770/* Return cmd->numProgs as 0 if no command is present (e.g. an empty
@@ -618,12 +772,12 @@ static void globLastArgument(struct childProgram *prog, int *argcPtr,
618 the beginning of the next command (if the original command had more 772 the beginning of the next command (if the original command had more
619 then one job associated with it) or NULL if no more commands are 773 then one job associated with it) or NULL if no more commands are
620 present. */ 774 present. */
621static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *isBg) 775static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobList, int *inBg)
622{ 776{
623 char *command; 777 char *command;
624 char *returnCommand = NULL; 778 char *returnCommand = NULL;
625 char *src, *buf, *chptr; 779 char *src, *buf, *chptr;
626 int argc = 0; 780 int argc_l = 0;
627 int done = 0; 781 int done = 0;
628 int argvAlloced; 782 int argvAlloced;
629 int i; 783 int i;
@@ -641,7 +795,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
641 return 0; 795 return 0;
642 } 796 }
643 797
644 *isBg = 0; 798 *inBg = 0;
645 job->numProgs = 1; 799 job->numProgs = 1;
646 job->progs = xmalloc(sizeof(*job->progs)); 800 job->progs = xmalloc(sizeof(*job->progs));
647 801
@@ -654,7 +808,6 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
654 cleaner (though it is, admittedly, a tad less efficient) */ 808 cleaner (though it is, admittedly, a tad less efficient) */
655 job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); 809 job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
656 job->text = NULL; 810 job->text = NULL;
657 job->jobContext = REGULAR_JOB_CONTEXT;
658 811
659 prog = job->progs; 812 prog = job->progs;
660 prog->numRedirections = 0; 813 prog->numRedirections = 0;
@@ -687,17 +840,17 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
687 *src == ']') *buf++ = '\\'; 840 *src == ']') *buf++ = '\\';
688 *buf++ = *src; 841 *buf++ = *src;
689 } else if (isspace(*src)) { 842 } else if (isspace(*src)) {
690 if (*prog->argv[argc]) { 843 if (*prog->argv[argc_l]) {
691 buf++, argc++; 844 buf++, argc_l++;
692 /* +1 here leaves room for the NULL which ends argv */ 845 /* +1 here leaves room for the NULL which ends argv */
693 if ((argc + 1) == argvAlloced) { 846 if ((argc_l + 1) == argvAlloced) {
694 argvAlloced += 5; 847 argvAlloced += 5;
695 prog->argv = realloc(prog->argv, 848 prog->argv = realloc(prog->argv,
696 sizeof(*prog->argv) * 849 sizeof(*prog->argv) *
697 argvAlloced); 850 argvAlloced);
698 } 851 }
699 globLastArgument(prog, &argc, &argvAlloced); 852 globLastArgument(prog, &argc_l, &argvAlloced);
700 prog->argv[argc] = buf; 853 prog->argv[argc_l] = buf;
701 } 854 }
702 } else 855 } else
703 switch (*src) { 856 switch (*src) {
@@ -707,7 +860,10 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
707 break; 860 break;
708 861
709 case '#': /* comment */ 862 case '#': /* comment */
710 done = 1; 863 if (*(src-1)== '$')
864 *buf++ = *src;
865 else
866 done = 1;
711 break; 867 break;
712 868
713 case '>': /* redirections */ 869 case '>': /* redirections */
@@ -718,16 +874,16 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
718 (i + 1)); 874 (i + 1));
719 875
720 prog->redirections[i].fd = -1; 876 prog->redirections[i].fd = -1;
721 if (buf != prog->argv[argc]) { 877 if (buf != prog->argv[argc_l]) {
722 /* the stuff before this character may be the file number 878 /* the stuff before this character may be the file number
723 being redirected */ 879 being redirected */
724 prog->redirections[i].fd = 880 prog->redirections[i].fd =
725 strtol(prog->argv[argc], &chptr, 10); 881 strtol(prog->argv[argc_l], &chptr, 10);
726 882
727 if (*chptr && *prog->argv[argc]) { 883 if (*chptr && *prog->argv[argc_l]) {
728 buf++, argc++; 884 buf++, argc_l++;
729 globLastArgument(prog, &argc, &argvAlloced); 885 globLastArgument(prog, &argc_l, &argvAlloced);
730 prog->argv[argc] = buf; 886 prog->argv[argc_l] = buf;
731 } 887 }
732 } 888 }
733 889
@@ -765,20 +921,20 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
765 *buf++ = *chptr++; 921 *buf++ = *chptr++;
766 922
767 src = chptr - 1; /* we src++ later */ 923 src = chptr - 1; /* we src++ later */
768 prog->argv[argc] = ++buf; 924 prog->argv[argc_l] = ++buf;
769 break; 925 break;
770 926
771 case '|': /* pipe */ 927 case '|': /* pipe */
772 /* finish this command */ 928 /* finish this command */
773 if (*prog->argv[argc]) 929 if (*prog->argv[argc_l])
774 argc++; 930 argc_l++;
775 if (!argc) { 931 if (!argc_l) {
776 errorMsg("empty command in pipe\n"); 932 errorMsg("empty command in pipe\n");
777 freeJob(job); 933 freeJob(job);
778 job->numProgs=0; 934 job->numProgs=0;
779 return 1; 935 return 1;
780 } 936 }
781 prog->argv[argc] = NULL; 937 prog->argv[argc_l] = NULL;
782 938
783 /* and start the next */ 939 /* and start the next */
784 job->numProgs++; 940 job->numProgs++;
@@ -788,7 +944,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
788 prog->numRedirections = 0; 944 prog->numRedirections = 0;
789 prog->redirections = NULL; 945 prog->redirections = NULL;
790 prog->freeGlob = 0; 946 prog->freeGlob = 0;
791 argc = 0; 947 argc_l = 0;
792 948
793 argvAlloced = 5; 949 argvAlloced = 5;
794 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced); 950 prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
@@ -809,7 +965,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
809 break; 965 break;
810 966
811 case '&': /* background */ 967 case '&': /* background */
812 *isBg = 1; 968 *inBg = 1;
813 case ';': /* multiple commands */ 969 case ';': /* multiple commands */
814 done = 1; 970 done = 1;
815 returnCommand = *commandPtr + (src - *commandPtr) + 1; 971 returnCommand = *commandPtr + (src - *commandPtr) + 1;
@@ -848,7 +1004,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
848 snprintf(charptr1, 1+ptr-src, src); 1004 snprintf(charptr1, 1+ptr-src, src);
849 newJob = xmalloc(sizeof(struct job)); 1005 newJob = xmalloc(sizeof(struct job));
850 /* Now parse and run the backticked command */ 1006 /* Now parse and run the backticked command */
851 if (!parseCommand(&charptr1, newJob, &njobList, isBg) 1007 if (!parseCommand(&charptr1, newJob, &njobList, inBg)
852 && newJob->numProgs) { 1008 && newJob->numProgs) {
853 pipe(pipefd); 1009 pipe(pipefd);
854 runCommand(newJob, &njobList, 0, pipefd); 1010 runCommand(newJob, &njobList, 0, pipefd);
@@ -890,7 +1046,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
890 * and improved version of the command line with the backtick 1046 * and improved version of the command line with the backtick
891 * results expanded in place... */ 1047 * results expanded in place... */
892 freeJob(job); 1048 freeJob(job);
893 return(parseCommand(commandPtr, job, jobList, isBg)); 1049 return(parseCommand(commandPtr, job, jobList, inBg));
894 } 1050 }
895 break; 1051 break;
896#endif // BB_FEATURE_SH_BACKTICKS 1052#endif // BB_FEATURE_SH_BACKTICKS
@@ -901,15 +1057,15 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
901 src++; 1057 src++;
902 } 1058 }
903 1059
904 if (*prog->argv[argc]) { 1060 if (*prog->argv[argc_l]) {
905 argc++; 1061 argc_l++;
906 globLastArgument(prog, &argc, &argvAlloced); 1062 globLastArgument(prog, &argc_l, &argvAlloced);
907 } 1063 }
908 if (!argc) { 1064 if (!argc_l) {
909 freeJob(job); 1065 freeJob(job);
910 return 0; 1066 return 0;
911 } 1067 }
912 prog->argv[argc] = NULL; 1068 prog->argv[argc_l] = NULL;
913 1069
914 if (!returnCommand) { 1070 if (!returnCommand) {
915 job->text = xmalloc(strlen(*commandPtr) + 1); 1071 job->text = xmalloc(strlen(*commandPtr) + 1);
@@ -991,17 +1147,17 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
991 * works, but '/bin/cat' doesn't ) */ 1147 * works, but '/bin/cat' doesn't ) */
992 while (a->name != 0) { 1148 while (a->name != 0) {
993 if (strcmp(newJob->progs[i].argv[0], a->name) == 0) { 1149 if (strcmp(newJob->progs[i].argv[0], a->name) == 0) {
994 int argc; 1150 int argc_l;
995 char** argv=newJob->progs[i].argv; 1151 char** argv=newJob->progs[i].argv;
996 for(argc=0;*argv!=NULL; argv++, argc++); 1152 for(argc_l=0;*argv!=NULL; argv++, argc_l++);
997 exit((*(a->main)) (argc, newJob->progs[i].argv)); 1153 exit((*(a->main)) (argc_l, newJob->progs[i].argv));
998 } 1154 }
999 a++; 1155 a++;
1000 } 1156 }
1001#endif 1157#endif
1002 1158
1003 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv); 1159 execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
1004 fatalError("sh: %s: %s\n", newJob->progs[i].argv[0], 1160 fatalError("%s: %s\n", newJob->progs[i].argv[0],
1005 strerror(errno)); 1161 strerror(errno));
1006 } 1162 }
1007 if (outPipe[1]!=-1) { 1163 if (outPipe[1]!=-1) {
@@ -1048,6 +1204,9 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1048 to the list of backgrounded theJobs and leave it alone */ 1204 to the list of backgrounded theJobs and leave it alone */
1049 printf("[%d] %d\n", theJob->jobId, 1205 printf("[%d] %d\n", theJob->jobId,
1050 newJob->progs[newJob->numProgs - 1].pid); 1206 newJob->progs[newJob->numProgs - 1].pid);
1207#ifdef BB_FEATURE_SH_ENVIRONMENT
1208 lastBgPid=newJob->progs[newJob->numProgs - 1].pid;
1209#endif
1051 } else { 1210 } else {
1052 jobList->fg = theJob; 1211 jobList->fg = theJob;
1053 1212
@@ -1060,45 +1219,6 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
1060 return 0; 1219 return 0;
1061} 1220}
1062 1221
1063static int setupRedirections(struct childProgram *prog)
1064{
1065 int i;
1066 int openfd;
1067 int mode = O_RDONLY;
1068 struct redirectionSpecifier *redir = prog->redirections;
1069
1070 for (i = 0; i < prog->numRedirections; i++, redir++) {
1071 switch (redir->type) {
1072 case REDIRECT_INPUT:
1073 mode = O_RDONLY;
1074 break;
1075 case REDIRECT_OVERWRITE:
1076 mode = O_RDWR | O_CREAT | O_TRUNC;
1077 break;
1078 case REDIRECT_APPEND:
1079 mode = O_RDWR | O_CREAT | O_APPEND;
1080 break;
1081 }
1082
1083 openfd = open(redir->filename, mode, 0666);
1084 if (openfd < 0) {
1085 /* this could get lost if stderr has been redirected, but
1086 bash and ash both lose it as well (though zsh doesn't!) */
1087 errorMsg("error opening %s: %s\n", redir->filename,
1088 strerror(errno));
1089 return 1;
1090 }
1091
1092 if (openfd != redir->fd) {
1093 dup2(openfd, redir->fd);
1094 close(openfd);
1095 }
1096 }
1097
1098 return 0;
1099}
1100
1101
1102static int busy_loop(FILE * input) 1222static int busy_loop(FILE * input)
1103{ 1223{
1104 char *command; 1224 char *command;
@@ -1106,8 +1226,9 @@ static int busy_loop(FILE * input)
1106 struct job newJob; 1226 struct job newJob;
1107 pid_t parent_pgrp; 1227 pid_t parent_pgrp;
1108 int i; 1228 int i;
1109 int status;
1110 int inBg; 1229 int inBg;
1230 int status;
1231 newJob.jobContext = REGULAR_JOB_CONTEXT;
1111 1232
1112 /* save current owner of TTY so we can restore it on exit */ 1233 /* save current owner of TTY so we can restore it on exit */
1113 parent_pgrp = tcgetpgrp(0); 1234 parent_pgrp = tcgetpgrp(0);
@@ -1160,6 +1281,9 @@ static int busy_loop(FILE * input)
1160 removeJob(&jobList, jobList.fg); 1281 removeJob(&jobList, jobList.fg);
1161 jobList.fg = NULL; 1282 jobList.fg = NULL;
1162 } 1283 }
1284#ifdef BB_FEATURE_SH_ENVIRONMENT
1285 lastReturnCode=WEXITSTATUS(status);
1286#endif
1163 } else { 1287 } else {
1164 /* the child was stopped */ 1288 /* the child was stopped */
1165 jobList.fg->stoppedProgs++; 1289 jobList.fg->stoppedProgs++;
@@ -1211,9 +1335,11 @@ void free_memory(void)
1211#endif 1335#endif
1212 1336
1213 1337
1214int shell_main(int argc, char **argv) 1338int shell_main(int argc_l, char **argv_l)
1215{ 1339{
1216 FILE *input = stdin; 1340 FILE *input = stdin;
1341 argc = argc_l;
1342 argv = argv_l;
1217 1343
1218 /* initialize the cwd -- this is never freed...*/ 1344 /* initialize the cwd -- this is never freed...*/
1219 cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); 1345 cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);