Search code examples
cif-statementsignalsinterruptctrl

Catch CTRL-\ signal


I have a user defined shell project where I'm trying to implement the cat command but allow the user to click CTRL-/ to display the next x-lines. I'm new to signals so I think I have some syntax wrong somewhere...

in main...

    while (fgets(buf, sizeof(buf), file) != NULL){ //CITE
        //print out first four lines
        if (j == 0){
          for (i = 0; i < 4; i++){
            printf("%s", buf);
            fgets(buf, sizeof(buf), file);
          }
          j++;
        }
        signal(SIGQUIT, sig_int);
        //now check for user input for the next x lines
        if (keepRunning){
          for (i = 0; i < 4; i++){
            printf("%s", buf);
            if (i < 3){
              if (fgets(buf, sizeof(buf), file) == NULL){
                fclose(file);
                return 0;
              }
            }
          }
          keepRunning = 0;
        }

Then I have the following sig_int function defined...

static volatile int keepRunning = 0;
void sig_int(int sig){
  keepRunning = 1;
}

Solution

  • The main problem is that you don't slow down or stop anywhere when the signal is not received. You might use pause(), for example; it only returns when a signal is received. You'd then use that in place of the if (keepRunning) block (including the condition).

    Alternatively, you might modify the terminal modes so that characters are sent as they're typed ('raw' mode), and attempt to read a character before continuing. However, if you do that, the onus is on you to ensure that the terminal mode is reset before the program exits under as many circumstances as possible. The good news is that there won't be any signals generated from the keyboard in raw mode, but you have to worry about signals from elsewhere.

    You might want to let other signals wake the program and exit the loop, but if you don't set a signal handler for them, that'll happen automatically. That is, after pause() returns (it will always return with an error status and errno set to EINTR), you might check whether keepRunning is now 1 and exit the loop if not.