diff options
author | Eric Andersen <andersen@codepoet.org> | 2000-07-25 18:06:52 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2000-07-25 18:06:52 +0000 |
commit | fad9c1198aa9486f2df01fe139afa329eb893b58 (patch) | |
tree | e4c1b0fdaff8f3b132213ddc85cd2b96a265c26d | |
parent | b040d4f3da1545225b9a58301deb29acee6aa7f3 (diff) | |
download | busybox-w32-fad9c1198aa9486f2df01fe139afa329eb893b58.tar.gz busybox-w32-fad9c1198aa9486f2df01fe139afa329eb893b58.tar.bz2 busybox-w32-fad9c1198aa9486f2df01fe139afa329eb893b58.zip |
Finish off fixing up the memleaks (I think). Added the beginnings of
some if-then-else-fi support (nonfunctional and turned off)
-Erik
-rw-r--r-- | lash.c | 161 | ||||
-rw-r--r-- | sh.c | 161 | ||||
-rw-r--r-- | shell/lash.c | 161 |
3 files changed, 369 insertions, 114 deletions
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | 28 | ||
29 | #define BB_FEATURE_SH_BACKTICKS | 29 | #define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | ||
30 | 31 | ||
31 | 32 | ||
32 | 33 | ||
@@ -55,6 +56,14 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |||
55 | REDIRECT_APPEND | 56 | REDIRECT_APPEND |
56 | }; | 57 | }; |
57 | 58 | ||
59 | #define REGULAR_JOB_CONTEXT 0x1 | ||
60 | #define IF_EXP_CONTEXT 0x2 | ||
61 | #define THEN_EXP_CONTEXT 0x4 | ||
62 | #define ELSE_EXP_CONTEXT 0x8 | ||
63 | |||
64 | enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT | ||
65 | }; | ||
66 | |||
58 | struct jobSet { | 67 | struct jobSet { |
59 | struct job *head; /* head of list of running jobs */ | 68 | struct job *head; /* head of list of running jobs */ |
60 | struct job *fg; /* current foreground job */ | 69 | struct job *fg; /* current foreground job */ |
@@ -86,12 +95,12 @@ struct job { | |||
86 | struct childProgram *progs; /* array of programs in job */ | 95 | struct childProgram *progs; /* array of programs in job */ |
87 | struct job *next; /* to track background commands */ | 96 | struct job *next; /* to track background commands */ |
88 | int stoppedProgs; /* number of programs alive, but stopped */ | 97 | int stoppedProgs; /* number of programs alive, but stopped */ |
98 | int jobContext; /* bitmask defining current context */ | ||
89 | }; | 99 | }; |
90 | 100 | ||
91 | struct builtInCommand { | 101 | struct builtInCommand { |
92 | char *cmd; /* name */ | 102 | char *cmd; /* name */ |
93 | char *descr; /* description */ | 103 | char *descr; /* description */ |
94 | char *usage; /* usage */ | ||
95 | int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ | 104 | int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ |
96 | }; | 105 | }; |
97 | 106 | ||
@@ -107,6 +116,12 @@ static int builtin_export(struct job *cmd, struct jobSet *junk); | |||
107 | static int builtin_source(struct job *cmd, struct jobSet *jobList); | 116 | static int builtin_source(struct job *cmd, struct jobSet *jobList); |
108 | static int builtin_unset(struct job *cmd, struct jobSet *junk); | 117 | static int builtin_unset(struct job *cmd, struct jobSet *junk); |
109 | static int builtin_read(struct job *cmd, struct jobSet *junk); | 118 | static int builtin_read(struct job *cmd, struct jobSet *junk); |
119 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
120 | static int builtin_if(struct job *cmd, struct jobSet *junk); | ||
121 | static int builtin_then(struct job *cmd, struct jobSet *junk); | ||
122 | static int builtin_else(struct job *cmd, struct jobSet *junk); | ||
123 | static int builtin_fi(struct job *cmd, struct jobSet *junk); | ||
124 | #endif | ||
110 | 125 | ||
111 | 126 | ||
112 | /* function prototypes for shell stuff */ | 127 | /* function prototypes for shell stuff */ |
@@ -122,30 +137,38 @@ static int busy_loop(FILE * input); | |||
122 | * can change global variables in the parent shell process but they will not | 137 | * can change global variables in the parent shell process but they will not |
123 | * work with pipes and redirects; 'unset foo | whatever' will not work) */ | 138 | * work with pipes and redirects; 'unset foo | whatever' will not work) */ |
124 | static struct builtInCommand bltins[] = { | 139 | static struct builtInCommand bltins[] = { |
125 | {"bg", "Resume a job in the background", "bg [%%job]", builtin_fg_bg}, | 140 | {"bg", "Resume a job in the background", builtin_fg_bg}, |
126 | {"cd", "Change working directory", "cd [dir]", builtin_cd}, | 141 | {"cd", "Change working directory", builtin_cd}, |
127 | {"exit", "Exit from shell()", "exit", builtin_exit}, | 142 | {"exit", "Exit from shell()", builtin_exit}, |
128 | {"fg", "Bring job into the foreground", "fg [%%job]", builtin_fg_bg}, | 143 | {"fg", "Bring job into the foreground", builtin_fg_bg}, |
129 | {"jobs", "Lists the active jobs", "jobs", builtin_jobs}, | 144 | {"jobs", "Lists the active jobs", builtin_jobs}, |
130 | {"export", "Set environment variable", "export [VAR=value]", builtin_export}, | 145 | {"export", "Set environment variable", builtin_export}, |
131 | {"unset", "Unset environment variable", "unset VAR", builtin_unset}, | 146 | {"unset", "Unset environment variable", builtin_unset}, |
132 | {"read", "Input environment variable", "read [VAR]", builtin_read}, | 147 | {"read", "Input environment variable", builtin_read}, |
133 | {NULL, NULL, NULL, NULL} | 148 | {NULL, NULL, NULL} |
134 | }; | 149 | }; |
135 | 150 | ||
136 | /* Table of forking built-in functions (things that fork cannot change global | 151 | /* Table of forking built-in functions (things that fork cannot change global |
137 | * variables in the parent process, such as the current working directory) */ | 152 | * variables in the parent process, such as the current working directory) */ |
138 | static struct builtInCommand bltins_forking[] = { | 153 | static struct builtInCommand bltins_forking[] = { |
139 | {"env", "Print all environment variables", "env", builtin_env}, | 154 | {"env", "Print all environment variables", builtin_env}, |
140 | {"pwd", "Print current directory", "pwd", builtin_pwd}, | 155 | {"pwd", "Print current directory", builtin_pwd}, |
141 | {".", "Source-in and run commands in a file", ". filename", builtin_source}, | 156 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
142 | {"help", "List shell built-in commands", "help", builtin_help}, | 157 | {"if", NULL, builtin_if}, |
143 | {NULL, NULL, NULL, NULL} | 158 | {"then", NULL, builtin_then}, |
159 | {"else", NULL, builtin_else}, | ||
160 | {"fi", NULL, builtin_fi}, | ||
161 | #endif | ||
162 | {".", "Source-in and run commands in a file", builtin_source}, | ||
163 | {"help", "List shell built-in commands", builtin_help}, | ||
164 | {NULL, NULL, NULL} | ||
144 | }; | 165 | }; |
145 | 166 | ||
146 | static char *prompt = "# "; | 167 | static char *prompt = "# "; |
147 | static char *cwd; | 168 | static char *cwd; |
148 | static char *local_pending_command = NULL; | 169 | static char *local_pending_command = NULL; |
170 | static char *promptStr = NULL; | ||
171 | static struct jobSet jobList = { NULL, NULL }; | ||
149 | 172 | ||
150 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 173 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
151 | void win_changed(int junk) | 174 | void win_changed(int junk) |
@@ -256,9 +279,13 @@ static int builtin_help(struct job *dummy, struct jobSet *junk) | |||
256 | fprintf(stdout, "\nBuilt-in commands:\n"); | 279 | fprintf(stdout, "\nBuilt-in commands:\n"); |
257 | fprintf(stdout, "-------------------\n"); | 280 | fprintf(stdout, "-------------------\n"); |
258 | for (x = bltins; x->cmd; x++) { | 281 | for (x = bltins; x->cmd; x++) { |
282 | if (x->descr==NULL) | ||
283 | continue; | ||
259 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); | 284 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); |
260 | } | 285 | } |
261 | for (x = bltins_forking; x->cmd; x++) { | 286 | for (x = bltins_forking; x->cmd; x++) { |
287 | if (x->descr==NULL) | ||
288 | continue; | ||
262 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); | 289 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); |
263 | } | 290 | } |
264 | fprintf(stdout, "\n\n"); | 291 | fprintf(stdout, "\n\n"); |
@@ -339,6 +366,44 @@ static int builtin_read(struct job *cmd, struct jobSet *junk) | |||
339 | return (res); | 366 | return (res); |
340 | } | 367 | } |
341 | 368 | ||
369 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
370 | /* Built-in handler for 'if' commands */ | ||
371 | static int builtin_if(struct job *cmd, struct jobSet *junk) | ||
372 | { | ||
373 | cmd->jobContext |= IF_EXP_CONTEXT; | ||
374 | printf("Hit an if -- jobContext=%d\n", cmd->jobContext); | ||
375 | return TRUE; | ||
376 | } | ||
377 | |||
378 | /* Built-in handler for 'then' (part of the 'if' command) */ | ||
379 | static int builtin_then(struct job *cmd, struct jobSet *junk) | ||
380 | { | ||
381 | if (cmd->jobContext & IF_EXP_CONTEXT) { | ||
382 | fprintf(stderr, "unexpected token `then'\n"); | ||
383 | fflush(stderr); | ||
384 | return FALSE; | ||
385 | } | ||
386 | cmd->jobContext |= THEN_EXP_CONTEXT; | ||
387 | printf("Hit an then -- jobContext=%d\n", cmd->jobContext); | ||
388 | return TRUE; | ||
389 | } | ||
390 | |||
391 | /* Built-in handler for 'else' (part of the 'if' command) */ | ||
392 | static int builtin_else(struct job *cmd, struct jobSet *junk) | ||
393 | { | ||
394 | printf("Hit an else\n"); | ||
395 | cmd->jobContext |= ELSE_EXP_CONTEXT; | ||
396 | return TRUE; | ||
397 | } | ||
398 | |||
399 | /* Built-in handler for 'fi' (part of the 'if' command) */ | ||
400 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | ||
401 | { | ||
402 | printf("Hit an fi\n"); | ||
403 | return TRUE; | ||
404 | } | ||
405 | #endif | ||
406 | |||
342 | /* Built-in '.' handler (read-in and execute commands from file) */ | 407 | /* Built-in '.' handler (read-in and execute commands from file) */ |
343 | static int builtin_source(struct job *cmd, struct jobSet *junk) | 408 | static int builtin_source(struct job *cmd, struct jobSet *junk) |
344 | { | 409 | { |
@@ -471,7 +536,6 @@ static int getCommand(FILE * source, char *command) | |||
471 | if (source == stdin) { | 536 | if (source == stdin) { |
472 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 537 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
473 | int len; | 538 | int len; |
474 | char *promptStr; | ||
475 | len=fprintf(stdout, "%s %s", cwd, prompt); | 539 | len=fprintf(stdout, "%s %s", cwd, prompt); |
476 | fflush(stdout); | 540 | fflush(stdout); |
477 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); | 541 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); |
@@ -587,8 +651,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
587 | Getting clean memory relieves us of the task of NULL | 651 | Getting clean memory relieves us of the task of NULL |
588 | terminating things and makes the rest of this look a bit | 652 | terminating things and makes the rest of this look a bit |
589 | cleaner (though it is, admittedly, a tad less efficient) */ | 653 | cleaner (though it is, admittedly, a tad less efficient) */ |
590 | job->cmdBuf = command = calloc(1, 2*strlen(*commandPtr) + 1); | 654 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); |
591 | job->text = NULL; | 655 | job->text = NULL; |
656 | job->jobContext = REGULAR_JOB_CONTEXT; | ||
592 | 657 | ||
593 | prog = job->progs; | 658 | prog = job->progs; |
594 | prog->numRedirections = 0; | 659 | prog->numRedirections = 0; |
@@ -863,7 +928,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
863 | 928 | ||
864 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) | 929 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) |
865 | { | 930 | { |
866 | struct job *job; | 931 | struct job *theJob; |
867 | int i; | 932 | int i; |
868 | int nextin, nextout; | 933 | int nextin, nextout; |
869 | int pipefds[2]; /* pipefd[0] is for reading */ | 934 | int pipefds[2]; /* pipefd[0] is for reading */ |
@@ -957,33 +1022,33 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
957 | 1022 | ||
958 | newJob->pgrp = newJob->progs[0].pid; | 1023 | newJob->pgrp = newJob->progs[0].pid; |
959 | 1024 | ||
960 | /* find the ID for the job to use */ | 1025 | /* find the ID for the theJob to use */ |
961 | newJob->jobId = 1; | 1026 | newJob->jobId = 1; |
962 | for (job = jobList->head; job; job = job->next) | 1027 | for (theJob = jobList->head; theJob; theJob = theJob->next) |
963 | if (job->jobId >= newJob->jobId) | 1028 | if (theJob->jobId >= newJob->jobId) |
964 | newJob->jobId = job->jobId + 1; | 1029 | newJob->jobId = theJob->jobId + 1; |
965 | 1030 | ||
966 | /* add the job to the list of running jobs */ | 1031 | /* add the theJob to the list of running jobs */ |
967 | if (!jobList->head) { | 1032 | if (!jobList->head) { |
968 | job = jobList->head = malloc(sizeof(*job)); | 1033 | theJob = jobList->head = malloc(sizeof(*theJob)); |
969 | } else { | 1034 | } else { |
970 | for (job = jobList->head; job->next; job = job->next); | 1035 | for (theJob = jobList->head; theJob->next; theJob = theJob->next); |
971 | job->next = malloc(sizeof(*job)); | 1036 | theJob->next = malloc(sizeof(*theJob)); |
972 | job = job->next; | 1037 | theJob = theJob->next; |
973 | } | 1038 | } |
974 | 1039 | ||
975 | *job = *newJob; | 1040 | *theJob = *newJob; |
976 | job->next = NULL; | 1041 | theJob->next = NULL; |
977 | job->runningProgs = job->numProgs; | 1042 | theJob->runningProgs = theJob->numProgs; |
978 | job->stoppedProgs = 0; | 1043 | theJob->stoppedProgs = 0; |
979 | 1044 | ||
980 | if (inBg) { | 1045 | if (inBg) { |
981 | /* we don't wait for background jobs to return -- append it | 1046 | /* we don't wait for background theJobs to return -- append it |
982 | to the list of backgrounded jobs and leave it alone */ | 1047 | to the list of backgrounded theJobs and leave it alone */ |
983 | printf("[%d] %d\n", job->jobId, | 1048 | printf("[%d] %d\n", theJob->jobId, |
984 | newJob->progs[newJob->numProgs - 1].pid); | 1049 | newJob->progs[newJob->numProgs - 1].pid); |
985 | } else { | 1050 | } else { |
986 | jobList->fg = job; | 1051 | jobList->fg = theJob; |
987 | 1052 | ||
988 | /* move the new process group into the foreground */ | 1053 | /* move the new process group into the foreground */ |
989 | /* suppress messages when run from /linuxrc mag@sysgo.de */ | 1054 | /* suppress messages when run from /linuxrc mag@sysgo.de */ |
@@ -1037,7 +1102,6 @@ static int busy_loop(FILE * input) | |||
1037 | { | 1102 | { |
1038 | char *command; | 1103 | char *command; |
1039 | char *nextCommand = NULL; | 1104 | char *nextCommand = NULL; |
1040 | struct jobSet jobList = { NULL, NULL }; | ||
1041 | struct job newJob; | 1105 | struct job newJob; |
1042 | pid_t parent_pgrp; | 1106 | pid_t parent_pgrp; |
1043 | int i; | 1107 | int i; |
@@ -1070,7 +1134,8 @@ static int busy_loop(FILE * input) | |||
1070 | newJob.numProgs) { | 1134 | newJob.numProgs) { |
1071 | int pipefds[2] = {-1,-1}; | 1135 | int pipefds[2] = {-1,-1}; |
1072 | runCommand(&newJob, &jobList, inBg, pipefds); | 1136 | runCommand(&newJob, &jobList, inBg, pipefds); |
1073 | } else { | 1137 | } |
1138 | else { | ||
1074 | free(command); | 1139 | free(command); |
1075 | command = (char *) calloc(BUFSIZ, sizeof(char)); | 1140 | command = (char *) calloc(BUFSIZ, sizeof(char)); |
1076 | nextCommand = NULL; | 1141 | nextCommand = NULL; |
@@ -1079,7 +1144,7 @@ static int busy_loop(FILE * input) | |||
1079 | /* a job is running in the foreground; wait for it */ | 1144 | /* a job is running in the foreground; wait for it */ |
1080 | i = 0; | 1145 | i = 0; |
1081 | while (!jobList.fg->progs[i].pid || | 1146 | while (!jobList.fg->progs[i].pid || |
1082 | jobList.fg->progs[i].isStopped) i++; | 1147 | jobList.fg->progs[i].isStopped == 1) i++; |
1083 | 1148 | ||
1084 | waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); | 1149 | waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); |
1085 | 1150 | ||
@@ -1128,6 +1193,22 @@ static int busy_loop(FILE * input) | |||
1128 | } | 1193 | } |
1129 | 1194 | ||
1130 | 1195 | ||
1196 | #ifdef BB_FEATURE_CLEAN_UP | ||
1197 | void free_memory(void) | ||
1198 | { | ||
1199 | if (promptStr) | ||
1200 | free(promptStr); | ||
1201 | if (cwd) | ||
1202 | free(cwd); | ||
1203 | if (local_pending_command) | ||
1204 | free(local_pending_command); | ||
1205 | |||
1206 | if (jobList.fg && !jobList.fg->runningProgs) { | ||
1207 | removeJob(&jobList, jobList.fg); | ||
1208 | } | ||
1209 | } | ||
1210 | #endif | ||
1211 | |||
1131 | 1212 | ||
1132 | int shell_main(int argc, char **argv) | 1213 | int shell_main(int argc, char **argv) |
1133 | { | 1214 | { |
@@ -1137,6 +1218,10 @@ int shell_main(int argc, char **argv) | |||
1137 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1218 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
1138 | getcwd(cwd, sizeof(char)*MAX_LINE); | 1219 | getcwd(cwd, sizeof(char)*MAX_LINE); |
1139 | 1220 | ||
1221 | #ifdef BB_FEATURE_CLEAN_UP | ||
1222 | atexit(free_memory); | ||
1223 | #endif | ||
1224 | |||
1140 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 1225 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
1141 | cmdedit_init(); | 1226 | cmdedit_init(); |
1142 | signal(SIGWINCH, win_changed); | 1227 | signal(SIGWINCH, win_changed); |
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | 28 | ||
29 | #define BB_FEATURE_SH_BACKTICKS | 29 | #define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | ||
30 | 31 | ||
31 | 32 | ||
32 | 33 | ||
@@ -55,6 +56,14 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |||
55 | REDIRECT_APPEND | 56 | REDIRECT_APPEND |
56 | }; | 57 | }; |
57 | 58 | ||
59 | #define REGULAR_JOB_CONTEXT 0x1 | ||
60 | #define IF_EXP_CONTEXT 0x2 | ||
61 | #define THEN_EXP_CONTEXT 0x4 | ||
62 | #define ELSE_EXP_CONTEXT 0x8 | ||
63 | |||
64 | enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT | ||
65 | }; | ||
66 | |||
58 | struct jobSet { | 67 | struct jobSet { |
59 | struct job *head; /* head of list of running jobs */ | 68 | struct job *head; /* head of list of running jobs */ |
60 | struct job *fg; /* current foreground job */ | 69 | struct job *fg; /* current foreground job */ |
@@ -86,12 +95,12 @@ struct job { | |||
86 | struct childProgram *progs; /* array of programs in job */ | 95 | struct childProgram *progs; /* array of programs in job */ |
87 | struct job *next; /* to track background commands */ | 96 | struct job *next; /* to track background commands */ |
88 | int stoppedProgs; /* number of programs alive, but stopped */ | 97 | int stoppedProgs; /* number of programs alive, but stopped */ |
98 | int jobContext; /* bitmask defining current context */ | ||
89 | }; | 99 | }; |
90 | 100 | ||
91 | struct builtInCommand { | 101 | struct builtInCommand { |
92 | char *cmd; /* name */ | 102 | char *cmd; /* name */ |
93 | char *descr; /* description */ | 103 | char *descr; /* description */ |
94 | char *usage; /* usage */ | ||
95 | int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ | 104 | int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ |
96 | }; | 105 | }; |
97 | 106 | ||
@@ -107,6 +116,12 @@ static int builtin_export(struct job *cmd, struct jobSet *junk); | |||
107 | static int builtin_source(struct job *cmd, struct jobSet *jobList); | 116 | static int builtin_source(struct job *cmd, struct jobSet *jobList); |
108 | static int builtin_unset(struct job *cmd, struct jobSet *junk); | 117 | static int builtin_unset(struct job *cmd, struct jobSet *junk); |
109 | static int builtin_read(struct job *cmd, struct jobSet *junk); | 118 | static int builtin_read(struct job *cmd, struct jobSet *junk); |
119 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
120 | static int builtin_if(struct job *cmd, struct jobSet *junk); | ||
121 | static int builtin_then(struct job *cmd, struct jobSet *junk); | ||
122 | static int builtin_else(struct job *cmd, struct jobSet *junk); | ||
123 | static int builtin_fi(struct job *cmd, struct jobSet *junk); | ||
124 | #endif | ||
110 | 125 | ||
111 | 126 | ||
112 | /* function prototypes for shell stuff */ | 127 | /* function prototypes for shell stuff */ |
@@ -122,30 +137,38 @@ static int busy_loop(FILE * input); | |||
122 | * can change global variables in the parent shell process but they will not | 137 | * can change global variables in the parent shell process but they will not |
123 | * work with pipes and redirects; 'unset foo | whatever' will not work) */ | 138 | * work with pipes and redirects; 'unset foo | whatever' will not work) */ |
124 | static struct builtInCommand bltins[] = { | 139 | static struct builtInCommand bltins[] = { |
125 | {"bg", "Resume a job in the background", "bg [%%job]", builtin_fg_bg}, | 140 | {"bg", "Resume a job in the background", builtin_fg_bg}, |
126 | {"cd", "Change working directory", "cd [dir]", builtin_cd}, | 141 | {"cd", "Change working directory", builtin_cd}, |
127 | {"exit", "Exit from shell()", "exit", builtin_exit}, | 142 | {"exit", "Exit from shell()", builtin_exit}, |
128 | {"fg", "Bring job into the foreground", "fg [%%job]", builtin_fg_bg}, | 143 | {"fg", "Bring job into the foreground", builtin_fg_bg}, |
129 | {"jobs", "Lists the active jobs", "jobs", builtin_jobs}, | 144 | {"jobs", "Lists the active jobs", builtin_jobs}, |
130 | {"export", "Set environment variable", "export [VAR=value]", builtin_export}, | 145 | {"export", "Set environment variable", builtin_export}, |
131 | {"unset", "Unset environment variable", "unset VAR", builtin_unset}, | 146 | {"unset", "Unset environment variable", builtin_unset}, |
132 | {"read", "Input environment variable", "read [VAR]", builtin_read}, | 147 | {"read", "Input environment variable", builtin_read}, |
133 | {NULL, NULL, NULL, NULL} | 148 | {NULL, NULL, NULL} |
134 | }; | 149 | }; |
135 | 150 | ||
136 | /* Table of forking built-in functions (things that fork cannot change global | 151 | /* Table of forking built-in functions (things that fork cannot change global |
137 | * variables in the parent process, such as the current working directory) */ | 152 | * variables in the parent process, such as the current working directory) */ |
138 | static struct builtInCommand bltins_forking[] = { | 153 | static struct builtInCommand bltins_forking[] = { |
139 | {"env", "Print all environment variables", "env", builtin_env}, | 154 | {"env", "Print all environment variables", builtin_env}, |
140 | {"pwd", "Print current directory", "pwd", builtin_pwd}, | 155 | {"pwd", "Print current directory", builtin_pwd}, |
141 | {".", "Source-in and run commands in a file", ". filename", builtin_source}, | 156 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
142 | {"help", "List shell built-in commands", "help", builtin_help}, | 157 | {"if", NULL, builtin_if}, |
143 | {NULL, NULL, NULL, NULL} | 158 | {"then", NULL, builtin_then}, |
159 | {"else", NULL, builtin_else}, | ||
160 | {"fi", NULL, builtin_fi}, | ||
161 | #endif | ||
162 | {".", "Source-in and run commands in a file", builtin_source}, | ||
163 | {"help", "List shell built-in commands", builtin_help}, | ||
164 | {NULL, NULL, NULL} | ||
144 | }; | 165 | }; |
145 | 166 | ||
146 | static char *prompt = "# "; | 167 | static char *prompt = "# "; |
147 | static char *cwd; | 168 | static char *cwd; |
148 | static char *local_pending_command = NULL; | 169 | static char *local_pending_command = NULL; |
170 | static char *promptStr = NULL; | ||
171 | static struct jobSet jobList = { NULL, NULL }; | ||
149 | 172 | ||
150 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 173 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
151 | void win_changed(int junk) | 174 | void win_changed(int junk) |
@@ -256,9 +279,13 @@ static int builtin_help(struct job *dummy, struct jobSet *junk) | |||
256 | fprintf(stdout, "\nBuilt-in commands:\n"); | 279 | fprintf(stdout, "\nBuilt-in commands:\n"); |
257 | fprintf(stdout, "-------------------\n"); | 280 | fprintf(stdout, "-------------------\n"); |
258 | for (x = bltins; x->cmd; x++) { | 281 | for (x = bltins; x->cmd; x++) { |
282 | if (x->descr==NULL) | ||
283 | continue; | ||
259 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); | 284 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); |
260 | } | 285 | } |
261 | for (x = bltins_forking; x->cmd; x++) { | 286 | for (x = bltins_forking; x->cmd; x++) { |
287 | if (x->descr==NULL) | ||
288 | continue; | ||
262 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); | 289 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); |
263 | } | 290 | } |
264 | fprintf(stdout, "\n\n"); | 291 | fprintf(stdout, "\n\n"); |
@@ -339,6 +366,44 @@ static int builtin_read(struct job *cmd, struct jobSet *junk) | |||
339 | return (res); | 366 | return (res); |
340 | } | 367 | } |
341 | 368 | ||
369 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
370 | /* Built-in handler for 'if' commands */ | ||
371 | static int builtin_if(struct job *cmd, struct jobSet *junk) | ||
372 | { | ||
373 | cmd->jobContext |= IF_EXP_CONTEXT; | ||
374 | printf("Hit an if -- jobContext=%d\n", cmd->jobContext); | ||
375 | return TRUE; | ||
376 | } | ||
377 | |||
378 | /* Built-in handler for 'then' (part of the 'if' command) */ | ||
379 | static int builtin_then(struct job *cmd, struct jobSet *junk) | ||
380 | { | ||
381 | if (cmd->jobContext & IF_EXP_CONTEXT) { | ||
382 | fprintf(stderr, "unexpected token `then'\n"); | ||
383 | fflush(stderr); | ||
384 | return FALSE; | ||
385 | } | ||
386 | cmd->jobContext |= THEN_EXP_CONTEXT; | ||
387 | printf("Hit an then -- jobContext=%d\n", cmd->jobContext); | ||
388 | return TRUE; | ||
389 | } | ||
390 | |||
391 | /* Built-in handler for 'else' (part of the 'if' command) */ | ||
392 | static int builtin_else(struct job *cmd, struct jobSet *junk) | ||
393 | { | ||
394 | printf("Hit an else\n"); | ||
395 | cmd->jobContext |= ELSE_EXP_CONTEXT; | ||
396 | return TRUE; | ||
397 | } | ||
398 | |||
399 | /* Built-in handler for 'fi' (part of the 'if' command) */ | ||
400 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | ||
401 | { | ||
402 | printf("Hit an fi\n"); | ||
403 | return TRUE; | ||
404 | } | ||
405 | #endif | ||
406 | |||
342 | /* Built-in '.' handler (read-in and execute commands from file) */ | 407 | /* Built-in '.' handler (read-in and execute commands from file) */ |
343 | static int builtin_source(struct job *cmd, struct jobSet *junk) | 408 | static int builtin_source(struct job *cmd, struct jobSet *junk) |
344 | { | 409 | { |
@@ -471,7 +536,6 @@ static int getCommand(FILE * source, char *command) | |||
471 | if (source == stdin) { | 536 | if (source == stdin) { |
472 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 537 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
473 | int len; | 538 | int len; |
474 | char *promptStr; | ||
475 | len=fprintf(stdout, "%s %s", cwd, prompt); | 539 | len=fprintf(stdout, "%s %s", cwd, prompt); |
476 | fflush(stdout); | 540 | fflush(stdout); |
477 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); | 541 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); |
@@ -587,8 +651,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
587 | Getting clean memory relieves us of the task of NULL | 651 | Getting clean memory relieves us of the task of NULL |
588 | terminating things and makes the rest of this look a bit | 652 | terminating things and makes the rest of this look a bit |
589 | cleaner (though it is, admittedly, a tad less efficient) */ | 653 | cleaner (though it is, admittedly, a tad less efficient) */ |
590 | job->cmdBuf = command = calloc(1, 2*strlen(*commandPtr) + 1); | 654 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); |
591 | job->text = NULL; | 655 | job->text = NULL; |
656 | job->jobContext = REGULAR_JOB_CONTEXT; | ||
592 | 657 | ||
593 | prog = job->progs; | 658 | prog = job->progs; |
594 | prog->numRedirections = 0; | 659 | prog->numRedirections = 0; |
@@ -863,7 +928,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
863 | 928 | ||
864 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) | 929 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) |
865 | { | 930 | { |
866 | struct job *job; | 931 | struct job *theJob; |
867 | int i; | 932 | int i; |
868 | int nextin, nextout; | 933 | int nextin, nextout; |
869 | int pipefds[2]; /* pipefd[0] is for reading */ | 934 | int pipefds[2]; /* pipefd[0] is for reading */ |
@@ -957,33 +1022,33 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
957 | 1022 | ||
958 | newJob->pgrp = newJob->progs[0].pid; | 1023 | newJob->pgrp = newJob->progs[0].pid; |
959 | 1024 | ||
960 | /* find the ID for the job to use */ | 1025 | /* find the ID for the theJob to use */ |
961 | newJob->jobId = 1; | 1026 | newJob->jobId = 1; |
962 | for (job = jobList->head; job; job = job->next) | 1027 | for (theJob = jobList->head; theJob; theJob = theJob->next) |
963 | if (job->jobId >= newJob->jobId) | 1028 | if (theJob->jobId >= newJob->jobId) |
964 | newJob->jobId = job->jobId + 1; | 1029 | newJob->jobId = theJob->jobId + 1; |
965 | 1030 | ||
966 | /* add the job to the list of running jobs */ | 1031 | /* add the theJob to the list of running jobs */ |
967 | if (!jobList->head) { | 1032 | if (!jobList->head) { |
968 | job = jobList->head = malloc(sizeof(*job)); | 1033 | theJob = jobList->head = malloc(sizeof(*theJob)); |
969 | } else { | 1034 | } else { |
970 | for (job = jobList->head; job->next; job = job->next); | 1035 | for (theJob = jobList->head; theJob->next; theJob = theJob->next); |
971 | job->next = malloc(sizeof(*job)); | 1036 | theJob->next = malloc(sizeof(*theJob)); |
972 | job = job->next; | 1037 | theJob = theJob->next; |
973 | } | 1038 | } |
974 | 1039 | ||
975 | *job = *newJob; | 1040 | *theJob = *newJob; |
976 | job->next = NULL; | 1041 | theJob->next = NULL; |
977 | job->runningProgs = job->numProgs; | 1042 | theJob->runningProgs = theJob->numProgs; |
978 | job->stoppedProgs = 0; | 1043 | theJob->stoppedProgs = 0; |
979 | 1044 | ||
980 | if (inBg) { | 1045 | if (inBg) { |
981 | /* we don't wait for background jobs to return -- append it | 1046 | /* we don't wait for background theJobs to return -- append it |
982 | to the list of backgrounded jobs and leave it alone */ | 1047 | to the list of backgrounded theJobs and leave it alone */ |
983 | printf("[%d] %d\n", job->jobId, | 1048 | printf("[%d] %d\n", theJob->jobId, |
984 | newJob->progs[newJob->numProgs - 1].pid); | 1049 | newJob->progs[newJob->numProgs - 1].pid); |
985 | } else { | 1050 | } else { |
986 | jobList->fg = job; | 1051 | jobList->fg = theJob; |
987 | 1052 | ||
988 | /* move the new process group into the foreground */ | 1053 | /* move the new process group into the foreground */ |
989 | /* suppress messages when run from /linuxrc mag@sysgo.de */ | 1054 | /* suppress messages when run from /linuxrc mag@sysgo.de */ |
@@ -1037,7 +1102,6 @@ static int busy_loop(FILE * input) | |||
1037 | { | 1102 | { |
1038 | char *command; | 1103 | char *command; |
1039 | char *nextCommand = NULL; | 1104 | char *nextCommand = NULL; |
1040 | struct jobSet jobList = { NULL, NULL }; | ||
1041 | struct job newJob; | 1105 | struct job newJob; |
1042 | pid_t parent_pgrp; | 1106 | pid_t parent_pgrp; |
1043 | int i; | 1107 | int i; |
@@ -1070,7 +1134,8 @@ static int busy_loop(FILE * input) | |||
1070 | newJob.numProgs) { | 1134 | newJob.numProgs) { |
1071 | int pipefds[2] = {-1,-1}; | 1135 | int pipefds[2] = {-1,-1}; |
1072 | runCommand(&newJob, &jobList, inBg, pipefds); | 1136 | runCommand(&newJob, &jobList, inBg, pipefds); |
1073 | } else { | 1137 | } |
1138 | else { | ||
1074 | free(command); | 1139 | free(command); |
1075 | command = (char *) calloc(BUFSIZ, sizeof(char)); | 1140 | command = (char *) calloc(BUFSIZ, sizeof(char)); |
1076 | nextCommand = NULL; | 1141 | nextCommand = NULL; |
@@ -1079,7 +1144,7 @@ static int busy_loop(FILE * input) | |||
1079 | /* a job is running in the foreground; wait for it */ | 1144 | /* a job is running in the foreground; wait for it */ |
1080 | i = 0; | 1145 | i = 0; |
1081 | while (!jobList.fg->progs[i].pid || | 1146 | while (!jobList.fg->progs[i].pid || |
1082 | jobList.fg->progs[i].isStopped) i++; | 1147 | jobList.fg->progs[i].isStopped == 1) i++; |
1083 | 1148 | ||
1084 | waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); | 1149 | waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); |
1085 | 1150 | ||
@@ -1128,6 +1193,22 @@ static int busy_loop(FILE * input) | |||
1128 | } | 1193 | } |
1129 | 1194 | ||
1130 | 1195 | ||
1196 | #ifdef BB_FEATURE_CLEAN_UP | ||
1197 | void free_memory(void) | ||
1198 | { | ||
1199 | if (promptStr) | ||
1200 | free(promptStr); | ||
1201 | if (cwd) | ||
1202 | free(cwd); | ||
1203 | if (local_pending_command) | ||
1204 | free(local_pending_command); | ||
1205 | |||
1206 | if (jobList.fg && !jobList.fg->runningProgs) { | ||
1207 | removeJob(&jobList, jobList.fg); | ||
1208 | } | ||
1209 | } | ||
1210 | #endif | ||
1211 | |||
1131 | 1212 | ||
1132 | int shell_main(int argc, char **argv) | 1213 | int shell_main(int argc, char **argv) |
1133 | { | 1214 | { |
@@ -1137,6 +1218,10 @@ int shell_main(int argc, char **argv) | |||
1137 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1218 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
1138 | getcwd(cwd, sizeof(char)*MAX_LINE); | 1219 | getcwd(cwd, sizeof(char)*MAX_LINE); |
1139 | 1220 | ||
1221 | #ifdef BB_FEATURE_CLEAN_UP | ||
1222 | atexit(free_memory); | ||
1223 | #endif | ||
1224 | |||
1140 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 1225 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
1141 | cmdedit_init(); | 1226 | cmdedit_init(); |
1142 | signal(SIGWINCH, win_changed); | 1227 | signal(SIGWINCH, win_changed); |
diff --git a/shell/lash.c b/shell/lash.c index 6029eaa5c..b2d1d43d3 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | 28 | ||
29 | #define BB_FEATURE_SH_BACKTICKS | 29 | #define BB_FEATURE_SH_BACKTICKS |
30 | //#define BB_FEATURE_SH_IF_EXPRESSIONS | ||
30 | 31 | ||
31 | 32 | ||
32 | 33 | ||
@@ -55,6 +56,14 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE, | |||
55 | REDIRECT_APPEND | 56 | REDIRECT_APPEND |
56 | }; | 57 | }; |
57 | 58 | ||
59 | #define REGULAR_JOB_CONTEXT 0x1 | ||
60 | #define IF_EXP_CONTEXT 0x2 | ||
61 | #define THEN_EXP_CONTEXT 0x4 | ||
62 | #define ELSE_EXP_CONTEXT 0x8 | ||
63 | |||
64 | enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT | ||
65 | }; | ||
66 | |||
58 | struct jobSet { | 67 | struct jobSet { |
59 | struct job *head; /* head of list of running jobs */ | 68 | struct job *head; /* head of list of running jobs */ |
60 | struct job *fg; /* current foreground job */ | 69 | struct job *fg; /* current foreground job */ |
@@ -86,12 +95,12 @@ struct job { | |||
86 | struct childProgram *progs; /* array of programs in job */ | 95 | struct childProgram *progs; /* array of programs in job */ |
87 | struct job *next; /* to track background commands */ | 96 | struct job *next; /* to track background commands */ |
88 | int stoppedProgs; /* number of programs alive, but stopped */ | 97 | int stoppedProgs; /* number of programs alive, but stopped */ |
98 | int jobContext; /* bitmask defining current context */ | ||
89 | }; | 99 | }; |
90 | 100 | ||
91 | struct builtInCommand { | 101 | struct builtInCommand { |
92 | char *cmd; /* name */ | 102 | char *cmd; /* name */ |
93 | char *descr; /* description */ | 103 | char *descr; /* description */ |
94 | char *usage; /* usage */ | ||
95 | int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ | 104 | int (*function) (struct job *, struct jobSet * jobList); /* function ptr */ |
96 | }; | 105 | }; |
97 | 106 | ||
@@ -107,6 +116,12 @@ static int builtin_export(struct job *cmd, struct jobSet *junk); | |||
107 | static int builtin_source(struct job *cmd, struct jobSet *jobList); | 116 | static int builtin_source(struct job *cmd, struct jobSet *jobList); |
108 | static int builtin_unset(struct job *cmd, struct jobSet *junk); | 117 | static int builtin_unset(struct job *cmd, struct jobSet *junk); |
109 | static int builtin_read(struct job *cmd, struct jobSet *junk); | 118 | static int builtin_read(struct job *cmd, struct jobSet *junk); |
119 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
120 | static int builtin_if(struct job *cmd, struct jobSet *junk); | ||
121 | static int builtin_then(struct job *cmd, struct jobSet *junk); | ||
122 | static int builtin_else(struct job *cmd, struct jobSet *junk); | ||
123 | static int builtin_fi(struct job *cmd, struct jobSet *junk); | ||
124 | #endif | ||
110 | 125 | ||
111 | 126 | ||
112 | /* function prototypes for shell stuff */ | 127 | /* function prototypes for shell stuff */ |
@@ -122,30 +137,38 @@ static int busy_loop(FILE * input); | |||
122 | * can change global variables in the parent shell process but they will not | 137 | * can change global variables in the parent shell process but they will not |
123 | * work with pipes and redirects; 'unset foo | whatever' will not work) */ | 138 | * work with pipes and redirects; 'unset foo | whatever' will not work) */ |
124 | static struct builtInCommand bltins[] = { | 139 | static struct builtInCommand bltins[] = { |
125 | {"bg", "Resume a job in the background", "bg [%%job]", builtin_fg_bg}, | 140 | {"bg", "Resume a job in the background", builtin_fg_bg}, |
126 | {"cd", "Change working directory", "cd [dir]", builtin_cd}, | 141 | {"cd", "Change working directory", builtin_cd}, |
127 | {"exit", "Exit from shell()", "exit", builtin_exit}, | 142 | {"exit", "Exit from shell()", builtin_exit}, |
128 | {"fg", "Bring job into the foreground", "fg [%%job]", builtin_fg_bg}, | 143 | {"fg", "Bring job into the foreground", builtin_fg_bg}, |
129 | {"jobs", "Lists the active jobs", "jobs", builtin_jobs}, | 144 | {"jobs", "Lists the active jobs", builtin_jobs}, |
130 | {"export", "Set environment variable", "export [VAR=value]", builtin_export}, | 145 | {"export", "Set environment variable", builtin_export}, |
131 | {"unset", "Unset environment variable", "unset VAR", builtin_unset}, | 146 | {"unset", "Unset environment variable", builtin_unset}, |
132 | {"read", "Input environment variable", "read [VAR]", builtin_read}, | 147 | {"read", "Input environment variable", builtin_read}, |
133 | {NULL, NULL, NULL, NULL} | 148 | {NULL, NULL, NULL} |
134 | }; | 149 | }; |
135 | 150 | ||
136 | /* Table of forking built-in functions (things that fork cannot change global | 151 | /* Table of forking built-in functions (things that fork cannot change global |
137 | * variables in the parent process, such as the current working directory) */ | 152 | * variables in the parent process, such as the current working directory) */ |
138 | static struct builtInCommand bltins_forking[] = { | 153 | static struct builtInCommand bltins_forking[] = { |
139 | {"env", "Print all environment variables", "env", builtin_env}, | 154 | {"env", "Print all environment variables", builtin_env}, |
140 | {"pwd", "Print current directory", "pwd", builtin_pwd}, | 155 | {"pwd", "Print current directory", builtin_pwd}, |
141 | {".", "Source-in and run commands in a file", ". filename", builtin_source}, | 156 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS |
142 | {"help", "List shell built-in commands", "help", builtin_help}, | 157 | {"if", NULL, builtin_if}, |
143 | {NULL, NULL, NULL, NULL} | 158 | {"then", NULL, builtin_then}, |
159 | {"else", NULL, builtin_else}, | ||
160 | {"fi", NULL, builtin_fi}, | ||
161 | #endif | ||
162 | {".", "Source-in and run commands in a file", builtin_source}, | ||
163 | {"help", "List shell built-in commands", builtin_help}, | ||
164 | {NULL, NULL, NULL} | ||
144 | }; | 165 | }; |
145 | 166 | ||
146 | static char *prompt = "# "; | 167 | static char *prompt = "# "; |
147 | static char *cwd; | 168 | static char *cwd; |
148 | static char *local_pending_command = NULL; | 169 | static char *local_pending_command = NULL; |
170 | static char *promptStr = NULL; | ||
171 | static struct jobSet jobList = { NULL, NULL }; | ||
149 | 172 | ||
150 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 173 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
151 | void win_changed(int junk) | 174 | void win_changed(int junk) |
@@ -256,9 +279,13 @@ static int builtin_help(struct job *dummy, struct jobSet *junk) | |||
256 | fprintf(stdout, "\nBuilt-in commands:\n"); | 279 | fprintf(stdout, "\nBuilt-in commands:\n"); |
257 | fprintf(stdout, "-------------------\n"); | 280 | fprintf(stdout, "-------------------\n"); |
258 | for (x = bltins; x->cmd; x++) { | 281 | for (x = bltins; x->cmd; x++) { |
282 | if (x->descr==NULL) | ||
283 | continue; | ||
259 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); | 284 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); |
260 | } | 285 | } |
261 | for (x = bltins_forking; x->cmd; x++) { | 286 | for (x = bltins_forking; x->cmd; x++) { |
287 | if (x->descr==NULL) | ||
288 | continue; | ||
262 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); | 289 | fprintf(stdout, "%s\t%s\n", x->cmd, x->descr); |
263 | } | 290 | } |
264 | fprintf(stdout, "\n\n"); | 291 | fprintf(stdout, "\n\n"); |
@@ -339,6 +366,44 @@ static int builtin_read(struct job *cmd, struct jobSet *junk) | |||
339 | return (res); | 366 | return (res); |
340 | } | 367 | } |
341 | 368 | ||
369 | #ifdef BB_FEATURE_SH_IF_EXPRESSIONS | ||
370 | /* Built-in handler for 'if' commands */ | ||
371 | static int builtin_if(struct job *cmd, struct jobSet *junk) | ||
372 | { | ||
373 | cmd->jobContext |= IF_EXP_CONTEXT; | ||
374 | printf("Hit an if -- jobContext=%d\n", cmd->jobContext); | ||
375 | return TRUE; | ||
376 | } | ||
377 | |||
378 | /* Built-in handler for 'then' (part of the 'if' command) */ | ||
379 | static int builtin_then(struct job *cmd, struct jobSet *junk) | ||
380 | { | ||
381 | if (cmd->jobContext & IF_EXP_CONTEXT) { | ||
382 | fprintf(stderr, "unexpected token `then'\n"); | ||
383 | fflush(stderr); | ||
384 | return FALSE; | ||
385 | } | ||
386 | cmd->jobContext |= THEN_EXP_CONTEXT; | ||
387 | printf("Hit an then -- jobContext=%d\n", cmd->jobContext); | ||
388 | return TRUE; | ||
389 | } | ||
390 | |||
391 | /* Built-in handler for 'else' (part of the 'if' command) */ | ||
392 | static int builtin_else(struct job *cmd, struct jobSet *junk) | ||
393 | { | ||
394 | printf("Hit an else\n"); | ||
395 | cmd->jobContext |= ELSE_EXP_CONTEXT; | ||
396 | return TRUE; | ||
397 | } | ||
398 | |||
399 | /* Built-in handler for 'fi' (part of the 'if' command) */ | ||
400 | static int builtin_fi(struct job *cmd, struct jobSet *junk) | ||
401 | { | ||
402 | printf("Hit an fi\n"); | ||
403 | return TRUE; | ||
404 | } | ||
405 | #endif | ||
406 | |||
342 | /* Built-in '.' handler (read-in and execute commands from file) */ | 407 | /* Built-in '.' handler (read-in and execute commands from file) */ |
343 | static int builtin_source(struct job *cmd, struct jobSet *junk) | 408 | static int builtin_source(struct job *cmd, struct jobSet *junk) |
344 | { | 409 | { |
@@ -471,7 +536,6 @@ static int getCommand(FILE * source, char *command) | |||
471 | if (source == stdin) { | 536 | if (source == stdin) { |
472 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 537 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
473 | int len; | 538 | int len; |
474 | char *promptStr; | ||
475 | len=fprintf(stdout, "%s %s", cwd, prompt); | 539 | len=fprintf(stdout, "%s %s", cwd, prompt); |
476 | fflush(stdout); | 540 | fflush(stdout); |
477 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); | 541 | promptStr=(char*)xmalloc(sizeof(char)*(len+1)); |
@@ -587,8 +651,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
587 | Getting clean memory relieves us of the task of NULL | 651 | Getting clean memory relieves us of the task of NULL |
588 | terminating things and makes the rest of this look a bit | 652 | terminating things and makes the rest of this look a bit |
589 | cleaner (though it is, admittedly, a tad less efficient) */ | 653 | cleaner (though it is, admittedly, a tad less efficient) */ |
590 | job->cmdBuf = command = calloc(1, 2*strlen(*commandPtr) + 1); | 654 | job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char)); |
591 | job->text = NULL; | 655 | job->text = NULL; |
656 | job->jobContext = REGULAR_JOB_CONTEXT; | ||
592 | 657 | ||
593 | prog = job->progs; | 658 | prog = job->progs; |
594 | prog->numRedirections = 0; | 659 | prog->numRedirections = 0; |
@@ -863,7 +928,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi | |||
863 | 928 | ||
864 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) | 929 | static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2]) |
865 | { | 930 | { |
866 | struct job *job; | 931 | struct job *theJob; |
867 | int i; | 932 | int i; |
868 | int nextin, nextout; | 933 | int nextin, nextout; |
869 | int pipefds[2]; /* pipefd[0] is for reading */ | 934 | int pipefds[2]; /* pipefd[0] is for reading */ |
@@ -957,33 +1022,33 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int | |||
957 | 1022 | ||
958 | newJob->pgrp = newJob->progs[0].pid; | 1023 | newJob->pgrp = newJob->progs[0].pid; |
959 | 1024 | ||
960 | /* find the ID for the job to use */ | 1025 | /* find the ID for the theJob to use */ |
961 | newJob->jobId = 1; | 1026 | newJob->jobId = 1; |
962 | for (job = jobList->head; job; job = job->next) | 1027 | for (theJob = jobList->head; theJob; theJob = theJob->next) |
963 | if (job->jobId >= newJob->jobId) | 1028 | if (theJob->jobId >= newJob->jobId) |
964 | newJob->jobId = job->jobId + 1; | 1029 | newJob->jobId = theJob->jobId + 1; |
965 | 1030 | ||
966 | /* add the job to the list of running jobs */ | 1031 | /* add the theJob to the list of running jobs */ |
967 | if (!jobList->head) { | 1032 | if (!jobList->head) { |
968 | job = jobList->head = malloc(sizeof(*job)); | 1033 | theJob = jobList->head = malloc(sizeof(*theJob)); |
969 | } else { | 1034 | } else { |
970 | for (job = jobList->head; job->next; job = job->next); | 1035 | for (theJob = jobList->head; theJob->next; theJob = theJob->next); |
971 | job->next = malloc(sizeof(*job)); | 1036 | theJob->next = malloc(sizeof(*theJob)); |
972 | job = job->next; | 1037 | theJob = theJob->next; |
973 | } | 1038 | } |
974 | 1039 | ||
975 | *job = *newJob; | 1040 | *theJob = *newJob; |
976 | job->next = NULL; | 1041 | theJob->next = NULL; |
977 | job->runningProgs = job->numProgs; | 1042 | theJob->runningProgs = theJob->numProgs; |
978 | job->stoppedProgs = 0; | 1043 | theJob->stoppedProgs = 0; |
979 | 1044 | ||
980 | if (inBg) { | 1045 | if (inBg) { |
981 | /* we don't wait for background jobs to return -- append it | 1046 | /* we don't wait for background theJobs to return -- append it |
982 | to the list of backgrounded jobs and leave it alone */ | 1047 | to the list of backgrounded theJobs and leave it alone */ |
983 | printf("[%d] %d\n", job->jobId, | 1048 | printf("[%d] %d\n", theJob->jobId, |
984 | newJob->progs[newJob->numProgs - 1].pid); | 1049 | newJob->progs[newJob->numProgs - 1].pid); |
985 | } else { | 1050 | } else { |
986 | jobList->fg = job; | 1051 | jobList->fg = theJob; |
987 | 1052 | ||
988 | /* move the new process group into the foreground */ | 1053 | /* move the new process group into the foreground */ |
989 | /* suppress messages when run from /linuxrc mag@sysgo.de */ | 1054 | /* suppress messages when run from /linuxrc mag@sysgo.de */ |
@@ -1037,7 +1102,6 @@ static int busy_loop(FILE * input) | |||
1037 | { | 1102 | { |
1038 | char *command; | 1103 | char *command; |
1039 | char *nextCommand = NULL; | 1104 | char *nextCommand = NULL; |
1040 | struct jobSet jobList = { NULL, NULL }; | ||
1041 | struct job newJob; | 1105 | struct job newJob; |
1042 | pid_t parent_pgrp; | 1106 | pid_t parent_pgrp; |
1043 | int i; | 1107 | int i; |
@@ -1070,7 +1134,8 @@ static int busy_loop(FILE * input) | |||
1070 | newJob.numProgs) { | 1134 | newJob.numProgs) { |
1071 | int pipefds[2] = {-1,-1}; | 1135 | int pipefds[2] = {-1,-1}; |
1072 | runCommand(&newJob, &jobList, inBg, pipefds); | 1136 | runCommand(&newJob, &jobList, inBg, pipefds); |
1073 | } else { | 1137 | } |
1138 | else { | ||
1074 | free(command); | 1139 | free(command); |
1075 | command = (char *) calloc(BUFSIZ, sizeof(char)); | 1140 | command = (char *) calloc(BUFSIZ, sizeof(char)); |
1076 | nextCommand = NULL; | 1141 | nextCommand = NULL; |
@@ -1079,7 +1144,7 @@ static int busy_loop(FILE * input) | |||
1079 | /* a job is running in the foreground; wait for it */ | 1144 | /* a job is running in the foreground; wait for it */ |
1080 | i = 0; | 1145 | i = 0; |
1081 | while (!jobList.fg->progs[i].pid || | 1146 | while (!jobList.fg->progs[i].pid || |
1082 | jobList.fg->progs[i].isStopped) i++; | 1147 | jobList.fg->progs[i].isStopped == 1) i++; |
1083 | 1148 | ||
1084 | waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); | 1149 | waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED); |
1085 | 1150 | ||
@@ -1128,6 +1193,22 @@ static int busy_loop(FILE * input) | |||
1128 | } | 1193 | } |
1129 | 1194 | ||
1130 | 1195 | ||
1196 | #ifdef BB_FEATURE_CLEAN_UP | ||
1197 | void free_memory(void) | ||
1198 | { | ||
1199 | if (promptStr) | ||
1200 | free(promptStr); | ||
1201 | if (cwd) | ||
1202 | free(cwd); | ||
1203 | if (local_pending_command) | ||
1204 | free(local_pending_command); | ||
1205 | |||
1206 | if (jobList.fg && !jobList.fg->runningProgs) { | ||
1207 | removeJob(&jobList, jobList.fg); | ||
1208 | } | ||
1209 | } | ||
1210 | #endif | ||
1211 | |||
1131 | 1212 | ||
1132 | int shell_main(int argc, char **argv) | 1213 | int shell_main(int argc, char **argv) |
1133 | { | 1214 | { |
@@ -1137,6 +1218,10 @@ int shell_main(int argc, char **argv) | |||
1137 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); | 1218 | cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1); |
1138 | getcwd(cwd, sizeof(char)*MAX_LINE); | 1219 | getcwd(cwd, sizeof(char)*MAX_LINE); |
1139 | 1220 | ||
1221 | #ifdef BB_FEATURE_CLEAN_UP | ||
1222 | atexit(free_memory); | ||
1223 | #endif | ||
1224 | |||
1140 | #ifdef BB_FEATURE_SH_COMMAND_EDITING | 1225 | #ifdef BB_FEATURE_SH_COMMAND_EDITING |
1141 | cmdedit_init(); | 1226 | cmdedit_init(); |
1142 | signal(SIGWINCH, win_changed); | 1227 | signal(SIGWINCH, win_changed); |