-3

I am writing a simple C program which reads one line of text at a time from the keyboard (in a loop) using the gets() function.

The loop must exit immediately if the user presses CTRL-C. I know how to write a sig handler which can set a flag to exit the loop...but how do I make the gets() function return immediately when this signal arrives?

TSG
  • 4,242
  • 9
  • 61
  • 121
  • 2
    No instead, "*don't use `gets()`*". – Iharob Al Asimi Jan 25 '16 at 14:39
  • @iharob if you're going to post a comment like that, at least include [A Link Explaining Why](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) – Ieuan Stanley Jan 25 '16 at 14:45
  • Ok - I need to read one line of text (up to CR). What function should I use that would be interrupted by a signal? – TSG Jan 25 '16 at 14:45
  • I think people are a bit fast jumping on the downrating. Pointing out a risky command is great, but the question is clear and useful. Using a risky function doesn't make the QUESTION bad! – TSG Jan 25 '16 at 17:13

1 Answers1

1

You should use select() to check if data is available before reading from stdin:

void handler (int arg) {
    // handle signal
}

int main (void) {
    char buf[100];
    signal(SIGINT, handler);
    do {
       fd_set f;
       FD_ZERO(&f);
       FD_SET(fileno(stdin), &f);
       int st = select(fileno(stdin)+1, &f, NULL, NULL, NULL);
       if (st == 1) {
          fgets(buf, sizeof(buf), stdin);
          // Handle input
       }
    } while (st >= 0);

    exit(EXIT_SUCCESS);
}

select() will return with -1 (errno EINTR) after returning from the signal handler whereas the read() (invoked by (f)gets) would be automatically resumed.

With linux, there is another possibility using sigaction():

void handler (int arg) {
    // handle signal
}

int main (void) {
    char buf[100], *p;
    struct sigaction sa = { .sa_handler = handler, .sa_flags = 0, .sa_mask = 0 };
    sigaction(SIGINT, &sa, NULL);

    do {    
            p = fgets(buf, sizeof(buf), stdin);
            // handle input
    } while (p);
    printf("Byebye\n");

    exit(EXIT_SUCCESS);
}

Since the flag SA_RESTART is not specified in the sa_flags for the signal handler, a read() on a slow device (i.e. terminals, pipes, sockets) will return with -1 (EINTR), too (see also signal(7)).

While being a bit simpler, the behaviour may vary between the different unix-flavors (and even kernel-versions), so the first version is a safer and more portable/reliable way.

Ctx
  • 18,090
  • 24
  • 36
  • 51