/* * Copyright (C) 2002, Simon Nieuviarts */ /* * Backgrounding added. [PM] Ajout d'une rustine nécessaire : lignes 153 et 293 commentées */ #include #include #include #include #include #include #include "readcmd.h" static void memory_error(void) { errno = ENOMEM; perror(0); exit(1); } static void *xmalloc(size_t size) { void *p = malloc(size); if (!p) memory_error(); return p; } static void *xrealloc(void *ptr, size_t size) { void *p = realloc(ptr, size); if (!p) memory_error(); return p; } /* Read a line from standard input and put it in a char[] */ static char *readline(void) { size_t buf_len = 16; char *buf = xmalloc(buf_len * sizeof(char)); if (fgets(buf, buf_len, stdin) == NULL) { free(buf); return NULL; } do { size_t l = strlen(buf); if ((l > 0) && (buf[l-1] == '\n')) { l--; buf[l] = 0; return buf; } if (buf_len >= (INT_MAX / 2)) memory_error(); buf_len *= 2; buf = xrealloc(buf, buf_len * sizeof(char)); if (fgets(buf + l, buf_len - l, stdin) == NULL) return buf; } while (1); } /* Split the string in words, according to the simple shell grammar. */ static char **split_in_words(char *line) { char *cur = line; char **tab = 0; size_t l = 0; char c; while ((c = *cur) != 0) { char *w = 0; char *start; switch (c) { case ' ': case '\t': /* Ignore any whitespace */ cur++; break; case '<': w = "<"; cur++; break; case '>': w = ">"; cur++; break; case '|': w = "|"; cur++; break; case '&': w = "&"; cur++; break; default: /* Another word */ start = cur; while (c) { c = *++cur; switch (c) { case 0: case ' ': case '\t': case '<': case '>': case '|': case '&': c = 0; break; default: ; } } w = xmalloc((cur - start + 1) * sizeof(char)); strncpy(w, start, cur - start); w[cur - start] = 0; } if (w) { tab = xrealloc(tab, (l + 1) * sizeof(char *)); tab[l++] = w; } } tab = xrealloc(tab, (l + 1) * sizeof(char *)); tab[l++] = 0; return tab; } static void freeseq(char ***seq) { int i, j; for (i=0; seq[i]!=0; i++) { char **cmd = seq[i]; for (j=0; cmd[j]!=0; j++) free(cmd[j]); free(cmd); } free(seq); } /* Free the fields of the structure but not the structure itself */ static void freecmd(struct cmdline *s) { if (s->in) free(s->in); if (s->out) free(s->out); // if (s->backgrounded) free(s->backgrounded); if (s->seq) freeseq(s->seq); } struct cmdline *readcmd(void) { static struct cmdline *static_cmdline = 0; struct cmdline *s = static_cmdline; char *line; char **words; int i; char *w; char **cmd; char ***seq; size_t cmd_len, seq_len; line = readline(); if (line == NULL) { if (s) { freecmd(s); free(s); } return static_cmdline = 0; } cmd = xmalloc(sizeof(char *)); cmd[0] = 0; cmd_len = 0; seq = xmalloc(sizeof(char **)); seq[0] = 0; seq_len = 0; words = split_in_words(line); free(line); if (!s) static_cmdline = s = xmalloc(sizeof(struct cmdline)); else freecmd(s); s->err = 0; s->in = 0; s->out = 0; s->backgrounded = 0; s->seq = 0; i = 0; while ((w = words[i++]) != 0) { switch (w[0]) { case '&': if(s->backgrounded){ s->err = "error on &"; goto error; } s->backgrounded = &w[0]; break; case '<': /* Tricky : the word can only be "<" */ if (s->in) { s->err = "only one input file supported"; goto error; } if (words[i] == 0) { s->err = "filename missing for input redirection"; goto error; } s->in = words[i++]; break; case '>': /* Tricky : the word can only be ">" */ if (s->out) { s->err = "only one output file supported"; goto error; } if (words[i] == 0) { s->err = "filename missing for output redirection"; goto error; } s->out = words[i++]; break; case '|': /* Tricky : the word can only be "|" */ if (cmd_len == 0) { s->err = "misplaced pipe"; goto error; } seq = xrealloc(seq, (seq_len + 2) * sizeof(char **)); seq[seq_len++] = cmd; seq[seq_len] = 0; cmd = xmalloc(sizeof(char *)); cmd[0] = 0; cmd_len = 0; break; default: cmd = xrealloc(cmd, (cmd_len + 2) * sizeof(char *)); cmd[cmd_len++] = w; cmd[cmd_len] = 0; } } if (cmd_len != 0) { seq = xrealloc(seq, (seq_len + 2) * sizeof(char **)); seq[seq_len++] = cmd; seq[seq_len] = 0; } else if (seq_len != 0) { s->err = "misplaced pipe"; i--; goto error; } else free(cmd); free(words); s->seq = seq; return s; error: while ((w = words[i++]) != 0) { switch (w[0]) { case '<': case '>': case '|': case '&': break; default: free(w); } } free(words); freeseq(seq); for (i=0; cmd[i]!=0; i++) free(cmd[i]); free(cmd); if (s->in) { free(s->in); s->in = 0; } if (s->out) { free(s->out); s->out = 0; } if (s->backgrounded) { // free(s->backgrounded); s->out = 0; } return s; }