- if (!**commandPtr || (**commandPtr=='#')) {
- job->numProgs = 0;
- *commandPtr = NULL;
- return 0;
- }
-
- *isBg = 0;
- job->numProgs = 1;
- job->progs = malloc(sizeof(*job->progs));
-
- /* We set the argv elements to point inside of this string. The
- memory is freed by freeJob().
-
- Getting clean memory relieves us of the task of NULL
- terminating things and makes the rest of this look a bit
- cleaner (though it is, admittedly, a tad less efficient) */
- job->cmdBuf = command = calloc(1, strlen(*commandPtr) + 1);
- job->text = NULL;
-
- prog = job->progs;
- prog->numRedirections = 0;
- prog->redirections = NULL;
- prog->freeGlob = 0;
- prog->isStopped = 0;
-
- argvAlloced = 5;
- prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
- prog->argv[0] = job->cmdBuf;
-
- buf = command;
- src = *commandPtr;
- while (*src && !done) {
- if (quote == *src) {
- quote = '\0';
- } else if (quote) {
- if (*src == '\\') {
- src++;
- if (!*src) {
- fprintf(stderr, "character expected after \\\n");
- freeJob(job);
- return 1;
- }
-
- /* in shell, "\'" should yield \' */
- if (*src != quote) *buf++ = '\\';
- } else if (*src == '*' || *src == '?' || *src == '[' ||
- *src == ']')
- *buf++ = '\\';
- *buf++ = *src;
- } else if (isspace(*src)) {
- if (*prog->argv[argc]) {
- buf++, argc++;
- /* +1 here leaves room for the NULL which ends argv */
- if ((argc + 1) == argvAlloced) {
- argvAlloced += 5;
- prog->argv = realloc(prog->argv,
- sizeof(*prog->argv) * argvAlloced);
- }
- prog->argv[argc] = buf;
-
- globLastArgument(prog, &argc, &argvAlloced);
- }
- } else switch (*src) {
- case '"':
- case '\'':
- quote = *src;
- break;
-
- case '#': /* comment */
- done = 1;
- break;
-
- case '>': /* redirections */
- case '<':
- i = prog->numRedirections++;
- prog->redirections = realloc(prog->redirections,
- sizeof(*prog->redirections) * (i + 1));
-
- prog->redirections[i].fd = -1;
- if (buf != prog->argv[argc]) {
- /* the stuff before this character may be the file number
- being redirected */
- prog->redirections[i].fd = strtol(prog->argv[argc], &chptr, 10);
-
- if (*chptr && *prog->argv[argc]) {
- buf++, argc++;
- globLastArgument(prog, &argc, &argvAlloced);
- }
- }
-
- if (prog->redirections[i].fd == -1) {
- if (*src == '>')
- prog->redirections[i].fd = 1;
- else
- prog->redirections[i].fd = 0;
- }
-
- if (*src++ == '>') {
- if (*src == '>')
- prog->redirections[i].type = REDIRECT_APPEND, src++;
- else
- prog->redirections[i].type = REDIRECT_OVERWRITE;
- } else {
- prog->redirections[i].type = REDIRECT_INPUT;
- }
-
- /* This isn't POSIX sh compliant. Oh well. */
- chptr = src;
- while (isspace(*chptr)) chptr++;
-
- if (!*chptr) {
- fprintf(stderr, "file name expected after %c\n", *src);
- freeJob(job);
- return 1;
- }
-
- prog->redirections[i].filename = buf;
- while (*chptr && !isspace(*chptr))
- *buf++ = *chptr++;
-
- src = chptr - 1; /* we src++ later */
- prog->argv[argc] = ++buf;
- break;
-
- case '|': /* pipe */
- /* finish this command */
- if (*prog->argv[argc]) argc++;
- if (!argc) {
- fprintf(stderr, "empty command in pipe\n");
- freeJob(job);
- return 1;
- }
- prog->argv[argc] = NULL;
-
- /* and start the next */
- job->numProgs++;
- job->progs = realloc(job->progs,
- sizeof(*job->progs) * job->numProgs);
- prog = job->progs + (job->numProgs - 1);
- prog->numRedirections = 0;
- prog->redirections = NULL;
- prog->freeGlob = 0;
- argc = 0;
-
- argvAlloced = 5;
- prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
- prog->argv[0] = ++buf;
-
- src++;
- while (*src && isspace(*src)) src++;
-
- if (!*src) {
- fprintf(stderr, "empty command in pipe\n");
- return 1;
- }
- src--; /* we'll ++ it at the end of the loop */
-
- break;
-
- case '&': /* background */
- *isBg = 1;
- case ';': /* multiple commands */
- done = 1;
- returnCommand = *commandPtr + (src - *commandPtr) + 1;
- break;
-
- case '\\':
- src++;
- if (!*src) {
- freeJob(job);
- fprintf(stderr, "character expected after \\\n");
- return 1;
- }
- if (*src == '*' || *src == '[' || *src == ']' || *src == '?')
- *buf++ = '\\';
- /* fallthrough */
- default:
- *buf++ = *src;
- }
-
- src++;
- }
-
- if (*prog->argv[argc]) {
- argc++;
- globLastArgument(prog, &argc, &argvAlloced);
- }
- if (!argc) {
- freeJob(job);
- return 0;
- }
- prog->argv[argc] = NULL;
-
- if (!returnCommand) {
- job->text = malloc(strlen(*commandPtr) + 1);
- strcpy(job->text, *commandPtr);
- } else {
- /* This leaves any trailing spaces, which is a bit sloppy */
-
- count = returnCommand - *commandPtr;
- job->text = malloc(count + 1);
- strncpy(job->text, *commandPtr, count);
- job->text[count] = '\0';
- }
-
- *commandPtr = returnCommand;
-
- return 0;
+ if (!**commandPtr || (**commandPtr == '#')) {
+ job->numProgs=0;
+ return 0;
+ }
+
+ *inBg = 0;
+ job->numProgs = 1;
+ job->progs = xmalloc(sizeof(*job->progs));
+
+ /* We set the argv elements to point inside of this string. The
+ memory is freed by freeJob(). Allocate twice the original
+ length in case we need to quote every single character.
+
+ Getting clean memory relieves us of the task of NULL
+ terminating things and makes the rest of this look a bit
+ cleaner (though it is, admittedly, a tad less efficient) */
+ job->cmdBuf = command = xcalloc(2*strlen(*commandPtr) + 1, sizeof(char));
+ job->text = NULL;
+
+ prog = job->progs;
+ prog->numRedirections = 0;
+ prog->redirections = NULL;
+ prog->freeGlob = 0;
+ prog->isStopped = 0;
+
+ argvAlloced = 5;
+ prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
+ prog->argv[0] = job->cmdBuf;
+
+ buf = command;
+ src = *commandPtr;
+ while (*src && !done) {
+ if (quote == *src) {
+ quote = '\0';
+ } else if (quote) {
+ if (*src == '\\') {
+ src++;
+ if (!*src) {
+ errorMsg("character expected after \\\n");
+ freeJob(job);
+ return 1;
+ }
+
+ /* in shell, "\'" should yield \' */
+ if (*src != quote)
+ *buf++ = '\\';
+ } else if (*src == '*' || *src == '?' || *src == '[' ||
+ *src == ']') *buf++ = '\\';
+ *buf++ = *src;
+ } else if (isspace(*src)) {
+ if (*prog->argv[argc_l]) {
+ buf++, argc_l++;
+ /* +1 here leaves room for the NULL which ends argv */
+ if ((argc_l + 1) == argvAlloced) {
+ argvAlloced += 5;
+ prog->argv = xrealloc(prog->argv,
+ sizeof(*prog->argv) *
+ argvAlloced);
+ }
+ globLastArgument(prog, &argc_l, &argvAlloced);
+ prog->argv[argc_l] = buf;
+ }
+ } else
+ switch (*src) {
+ case '"':
+ case '\'':
+ quote = *src;
+ break;
+
+ case '#': /* comment */
+ if (*(src-1)== '$')
+ *buf++ = *src;
+ else
+ done = 1;
+ break;
+
+ case '>': /* redirections */
+ case '<':
+ i = prog->numRedirections++;
+ prog->redirections = xrealloc(prog->redirections,
+ sizeof(*prog->redirections) *
+ (i + 1));
+
+ prog->redirections[i].fd = -1;
+ if (buf != prog->argv[argc_l]) {
+ /* the stuff before this character may be the file number
+ being redirected */
+ prog->redirections[i].fd =
+ strtol(prog->argv[argc_l], &chptr, 10);
+
+ if (*chptr && *prog->argv[argc_l]) {
+ buf++, argc_l++;
+ globLastArgument(prog, &argc_l, &argvAlloced);
+ prog->argv[argc_l] = buf;
+ }
+ }
+
+ if (prog->redirections[i].fd == -1) {
+ if (*src == '>')
+ prog->redirections[i].fd = 1;
+ else
+ prog->redirections[i].fd = 0;
+ }
+
+ if (*src++ == '>') {
+ if (*src == '>')
+ prog->redirections[i].type =
+ REDIRECT_APPEND, src++;
+ else
+ prog->redirections[i].type = REDIRECT_OVERWRITE;
+ } else {
+ prog->redirections[i].type = REDIRECT_INPUT;
+ }
+
+ /* This isn't POSIX sh compliant. Oh well. */
+ chptr = src;
+ while (isspace(*chptr))
+ chptr++;
+
+ if (!*chptr) {
+ errorMsg("file name expected after %c\n", *src);
+ freeJob(job);
+ job->numProgs=0;
+ return 1;
+ }
+
+ prog->redirections[i].filename = buf;
+ while (*chptr && !isspace(*chptr))
+ *buf++ = *chptr++;
+
+ src = chptr - 1; /* we src++ later */
+ prog->argv[argc_l] = ++buf;
+ break;
+
+ case '|': /* pipe */
+ /* finish this command */
+ if (*prog->argv[argc_l])
+ argc_l++;
+ if (!argc_l) {
+ errorMsg("empty command in pipe\n");
+ freeJob(job);
+ job->numProgs=0;
+ return 1;
+ }
+ prog->argv[argc_l] = NULL;
+
+ /* and start the next */
+ job->numProgs++;
+ job->progs = xrealloc(job->progs,
+ sizeof(*job->progs) * job->numProgs);
+ prog = job->progs + (job->numProgs - 1);
+ prog->numRedirections = 0;
+ prog->redirections = NULL;
+ prog->freeGlob = 0;
+ prog->isStopped = 0;
+ argc_l = 0;
+
+ argvAlloced = 5;
+ prog->argv = xmalloc(sizeof(*prog->argv) * argvAlloced);
+ prog->argv[0] = ++buf;
+
+ src++;
+ while (*src && isspace(*src))
+ src++;
+
+ if (!*src) {
+ errorMsg("empty command in pipe\n");
+ freeJob(job);
+ job->numProgs=0;
+ return 1;
+ }
+ src--; /* we'll ++ it at the end of the loop */
+
+ break;
+
+ case '&': /* background */
+ *inBg = 1;
+ case ';': /* multiple commands */
+ done = 1;
+ returnCommand = *commandPtr + (src - *commandPtr) + 1;
+ break;
+
+#ifdef BB_FEATURE_SH_BACKTICKS
+ case '`':
+ /* Exec a backtick-ed command */
+ {
+ char* charptr1=NULL, *charptr2;
+ char* ptr=NULL;
+ struct job *newJob;
+ struct jobSet njobList = { NULL, NULL };
+ int pipefd[2];
+ int size;
+
+ ptr=strchr(++src, '`');
+ if (ptr==NULL) {
+ fprintf(stderr, "Unmatched '`' in command\n");
+ freeJob(job);
+ return 1;
+ }
+
+ /* Make some space to hold just the backticked command */
+ charptr1 = charptr2 = xmalloc(1+ptr-src);
+ memcpy(charptr1, src, ptr-src);
+ charptr1[ptr-src] = '\0';
+ newJob = xmalloc(sizeof(struct job));
+ /* Now parse and run the backticked command */
+ if (!parseCommand(&charptr1, newJob, &njobList, inBg)
+ && newJob->numProgs) {
+ pipe(pipefd);
+ runCommand(newJob, &njobList, 0, pipefd);
+ }
+ checkJobs(jobList);
+ freeJob(newJob);
+ free(charptr2);
+
+ /* Make a copy of any stuff left over in the command
+ * line after the second backtick */
+ charptr2 = xmalloc(strlen(ptr)+1);
+ memcpy(charptr2, ptr+1, strlen(ptr));
+
+
+ /* Copy the output from the backtick-ed command into the
+ * command line, making extra room as needed */
+ --src;
+ charptr1 = xmalloc(BUFSIZ);
+ while ( (size=fullRead(pipefd[0], charptr1, BUFSIZ-1)) >0) {
+ int newSize=src - *commandPtr + size + 1 + strlen(charptr2);
+ if (newSize > BUFSIZ) {
+ *commandPtr=xrealloc(*commandPtr, src - *commandPtr +
+ size + 1 + strlen(charptr2));
+ }
+ memcpy(src, charptr1, size);
+ src+=size;
+ }
+ free(charptr1);
+ close(pipefd[0]);
+ if (*(src-1)=='\n')
+ --src;
+
+ /* Now paste into the *commandPtr all the stuff
+ * leftover after the second backtick */
+ memcpy(src, charptr2, strlen(charptr2)+1);
+ free(charptr2);
+
+ /* Now recursively call parseCommand to deal with the new
+ * and improved version of the command line with the backtick
+ * results expanded in place... */
+ freeJob(job);
+ return(parseCommand(commandPtr, job, jobList, inBg));
+ }
+ break;
+#endif // BB_FEATURE_SH_BACKTICKS
+
+ case '\\':
+ src++;
+ if (!*src) {
+ errorMsg("character expected after \\\n");
+ freeJob(job);
+ return 1;
+ }
+ if (*src == '*' || *src == '[' || *src == ']'
+ || *src == '?') *buf++ = '\\';
+ /* fallthrough */
+ default:
+ *buf++ = *src;
+ }
+
+ src++;
+ }
+
+ if (*prog->argv[argc_l]) {
+ argc_l++;
+ globLastArgument(prog, &argc_l, &argvAlloced);
+ }
+ if (!argc_l) {
+ freeJob(job);
+ return 0;
+ }
+ prog->argv[argc_l] = NULL;
+
+ if (!returnCommand) {
+ job->text = xmalloc(strlen(*commandPtr) + 1);
+ strcpy(job->text, *commandPtr);
+ } else {
+ /* This leaves any trailing spaces, which is a bit sloppy */
+ count = returnCommand - *commandPtr;
+ job->text = xmalloc(count + 1);
+ strncpy(job->text, *commandPtr, count);
+ job->text[count] = '\0';
+ }
+
+ *commandPtr = returnCommand;
+
+ return 0;