298 lines
4.9 KiB
C
298 lines
4.9 KiB
C
|
/*
|
||
|
* Copyright (C) 2002, Simon Nieuviarts
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Backgrounding added. [PM] Ajout d'une rustine nécessaire : lignes 153 et 293 commentées
|
||
|
*/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stddef.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <errno.h>
|
||
|
#include <limits.h>
|
||
|
#include <string.h>
|
||
|
#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;
|
||
|
}
|