0

I'm rewriting a shell in C and I fell on a problem.

When writing a command — for example echo "this — we got a new prompt ("dquote>", in zsh) and we can exit it with "Ctrl + c" and get back to our last command prompt.

I'm stuck there; I just can't get out of my read function (listen on "dquote>"), I tried to write on stdout an EOF when pressing "ctrl + c" but it doesn't read it.

I switched to non-canonical mode. I catch signal with signal(SIGINT, sig_hand);

then i execute this part of code when signal is catched:

static void sig_hand(int sig)
{
    if (g_shell.is_listen_bracket) // if is the first prompt or no
        putchar(4); // EOT
    else
    {
        putstr("\n");
        print_prompt();
    }
}

and my read function:

int     j;
char    command[ARG_MAX];
char    buff[3];

j = -1;
while (1)
{
    bzero(buff, 3);
    read(0, buff, 3);
    if (buff[0] == 4 && !buff[1] && !buff[2])
        return (ctrl_d(shell));
    else if (isprint(buff[0]) && !buff[1] && !buff[2]) // if is between 32 and 126 (ascii)
    {
        command[++j] = buff[0];
        putchar(buff[0]);
    }
}
command[++j] = '\0';
return (strdup(command));

So my code waiting on "read(0, buff, 3);", and i want to quit it when pressing ctrl + c.

Thanks for helping !

Victor D
  • 15
  • 6
  • `man siglongjmp` – wildplasser Mar 22 '17 at 18:57
  • thanks for your reply but is a school projet and this function is not allowed. – Victor D Mar 22 '17 at 19:02
  • 2
    It is not clear what your problem is since you've not shown any code or discussed whether you manipulate signal handling or terminal settings in your shell. You might find [Canonical vs non-canonical terminal input](https://stackoverflow.com/questions/358342/) helpful, or it might be a red-herring. You should discuss (better, show) how your shell is handling signals. Control-C should generate a SIGINT; if your shell is ignoring that, or mishandling it, it might account for your trouble. – Jonathan Leffler Mar 22 '17 at 19:13
  • Well, technically it is not a function, though it appears to be. – wildplasser Mar 22 '17 at 19:13
  • I edited my question. (Ctrl + d work well) – Victor D Mar 22 '17 at 20:23
  • If Ctrl+D *works well*, you must be running on DOS/Windows. – wildplasser Mar 22 '17 at 20:27
  • Note: `read(0, buff, 3)` can return {-1,0,1,2, or 3} Handle all cases. Also: `command[++j] = buff[0];` should *al least* be `command[j++] = buff[0];` (plus you may want to loop on 'j' upto the return value you got from `read()` ) – wildplasser Mar 22 '17 at 20:49

1 Answers1

0

Don't think of EOF as a character that you can 'print to stdout', it is a state that the file handle can be in, and it implies that there is no more data coming. To put your stdout into the EOF state, you would have to call close() - which is most likely not what you want.

Watch out - 0x04 is actually EOT, End of Transmission.

In any case, why do you want to send EOT to the stdout of your application? If this behaved the way it would appear you think it does, then the terminal emulator (or whatever is connected to your stdout) would quit - not your shell, and it certainly wouldn't revert your shell from the 'waiting for more input' state to the 'waiting for input' state.

You need to handle the ^C in the signal handler, and adjust your shell's state appropriately, getting it to abandon the current input mode and redraw the basic prompt.


Edit: What you need to remember is that your 'shell' is writing text (output) and control characters to the terminal emulator - the terminal emulator is writing text (input) and control characters to your 'shell'.

If you want to revert the prompt from dquote> to mysh$, then you must update the terminal by writing a new prompt to it.

To keep track of what you are currently doing, it might make most sense to use the State Machine approach. You might have a handful of states, including:

  1. INPUT_WAITING
  2. INPUT_WAITING_CONT
  3. COMMAND_RUN

When in the INPUT_WAITING state, you would print the mysh$ prompt, and handle input. When a newline is received, you would then decide 'do we have all of the information?' before advancing to the INPUT_WAITING_CONT state if not, or the COMMAND_RUN state if you do.

The INPUT_WAIT_CONT state would printout the dquote> prompt, and take similar actions... 'do we have enough information?' Yes: COMMAND_RUN, No: INPUT_WAIT_CONT.

It's then up to you to revert to the INPUT_WAIT state and redraw the mysh$ prompt when the user presses ^C, or when the command execution has completed.

Attie
  • 6,690
  • 2
  • 24
  • 34
  • I confused EOF and EOT sorry. Ctrl + d send a EOT which is read by `read` function. So I was thinking if i can write an EOT, `read` would read it and i could treat it properly like `^C`. "to abandon the current input" how ? That my question. – Victor D Mar 22 '17 at 22:04
  • `Ctrl + d send a EOT which is read by read function` Not on UNIX. Normally, ^D is handled by the terminal driver (and translated into an EOF *event*) , the 0x04 is never seen by the reading program. – wildplasser Mar 22 '17 at 22:18