Note that there are some explanatory texts on larger screens.

plurals
  1. POHow can I design a signal-safe shell interpreter
    text
    copied!<p>The code I have right now sends a prompt out to stdout, then reads a line from stdin. Receiving <code>SIGINT</code> at any point interrupts execution and exits the program. I am unsure where I should trap <code>SIGINT</code>, and I know that I cannot start a new prompt when the signal is received with my current code. Is there a proper way to accomplish that (ultimate goal would be for it to act like most shells (SIGINT cancels the current prompt and starts a new one))?</p> <p>This code will run on Linux, but the less platform independent, the better.</p> <p><code>get_line</code> reads a line from stdin into a buffer and generates a char[], which is assigned to line.<br> <code>split_args</code> takes a line and transforms it into an array of char[], splitting on whitespace.<br> <code>is_command_valid</code> determines if the user typed a known internal command. External programs cannot be executed.</p> <pre><code>static int run_interactive(char *user) { int done = 0; do { char *line, **args; int (*fn)(char *, char **); fprintf(stderr, "gitorium (%s)&gt; ", user); get_line(&amp;line); if (line[0] == '\0') { free(line); break; } split_args(&amp;args, line); if (!strcmp(args[0], "quit") || !strcmp(args[0], "exit") || !strcmp(args[0], "logout") || !strcmp(args[0], "bye")) done = 1; else if (NULL == args[0] || (!strcmp("help", args[0]) &amp;&amp; NULL == args[1])) interactive_help(); else if ((fn = is_command_valid(args)) != NULL) (*fn)(user, args); else error("The command does not exist."); free(line); free(args); } while (!done); return 0; } </code></pre> <p>Here are the two most important helper functions</p> <pre><code>static int split_args(char ***args, char *str) { char **res = NULL, *p = strtok(str, " "); int n_spaces = 0, i = 0; while (p) { res = realloc(res, sizeof (char*) * ++n_spaces); if (res == NULL) return GITORIUM_MEM_ALLOC; res[n_spaces-1] = p; i++; p = strtok(NULL, " "); } res = realloc(res, sizeof(char*) * (n_spaces+1)); if (res == NULL) return GITORIUM_MEM_ALLOC; res[n_spaces] = 0; *args = res; return i; } static int get_line(char **linep) { char *line = malloc(LINE_BUFFER_SIZE); int len = LINE_BUFFER_SIZE, c; *linep = line; if(line == NULL) return GITORIUM_MEM_ALLOC; for(;;) { c = fgetc(stdin); if(c == EOF || c == '\n') break; if(--len == 0) { char *linen = realloc(*linep, sizeof *linep + LINE_BUFFER_SIZE); if(linen == NULL) return GITORIUM_MEM_ALLOC; len = LINE_BUFFER_SIZE; line = linen + (line - *linep); *linep = linen; } *line++ = c; } *line = 0; return 0; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload