Search code examples
clinuxstdinctrl

C - Read from keyboard (controlled by Ctrl+D)


I'm trying to emulate a tail command in C but I have a problem.

I need to read some lines from keyboard (STDIN) (I don't care how many lines). This read will be interrupted when Ctrl+d is pressed. I have done this function but it doesn't work.

int tail(int N)
{
    int i, j, c;
    char ** lines;
    /* Char matrix dynamic declaration */
    lines=NULL; // Char matrix declaration
    lines=malloc(N*sizeof(char *));
    for (i=0; i<N; i++){ 
        lines[i]=malloc(80 * sizeof(char));
    }
    i=0;
    while (true){ // I tried this loop, but doesn't work
        /* This works. Lanes reading from the user's keyboard */
        if(i>=N){
            for(j=0; j<=N; j++){
                if (j<(N-1))
                    lines[j]=lines[j+1];
            }
            scanf(" %[^\n]", lines[N-1]);
        }else{
            scanf(" %[^\n]", lines[i]);
        }
        i++;
        /* ------------------------------------ */
        c=getchar(); // This doesn't work
        if(c==EOF)
        goto end;
    }
end:
    for (i=0; i<N; i++){
        printf("%s\n", lines[i]); // Showing those lanes
        free(lines[i]); // Free memory
    }    
    free(lines);
    lines = NULL;

    return 0;
}

My problem is about read user's keyboard lines and read ctrl+d at the same time. When I launch the function, it let me write some lines, but it doesn't detect when I press Ctrl+D. How can I do this?

EDIT:

I have tried a new method to capture Ctrl+d and now my program ends, but I have some problems. Here is the new code:

int tail(int N)
{
    int i, j, k, c;
    char ** lines;

    lines=NULL;
    lines=malloc(N*sizeof(char *));
    for (i=0; i<N; i++){ 
        lines[i]=malloc(MAXLON * sizeof(char));
    }
    i=0;
    while (true){
        /* Read lines from keyboard. */
        if(i<N)
            scanf(" %[^\n]", lines[i]);
        else{
            for(j=0; j<N-1; j++){
                for(k=0; k<MAXLON; k++){
                    lines[j][k]=lines[j+1][k];      
                }
            }
            scanf(" %[^\n]", lines[N-1]);
        }
        /* ------------------------------------ */
        if((c=getchar())==EOF) break;
        else i++;
    }

    for (i=0; i<N; i++){
        printf("%s\n", lines[i]);
        free(lines[i]);
    }
    free(lines);
    lines= NULL;

    return 0;

}

Right now, my program captures N lines from keyboard until I press 2 times Ctrl+d, but my problem now is: If I write 5 lines which are (with tail(3) for example, which shows the last 3 lines):

Line 1 
Line 2 
Line 3 
Line 4 
Line 5  
AND HERE I PRESS 2 TIMES CTRL+D

The function shows:

Line 4
Line 5
Line 5

Whats wrong? The function must show:

Line 3
Line 4
Line 5

Thank you so much!


Solution

  • Please see the following code as a working example:

    #include <stdio.h>
    
    int main(int argc, char* argvp[])
    {
        char buf[1024];
    
        while(gets(buf))
        {
            printf("Read: %s\n", buf);
        }
        if (ferror(stdin))
            puts("I/O error when reading");
        else if (feof(stdin))
            puts("End of file reached successfully");
    }
    

    Please note that

    1. The size of input buffer buf should not be hard-coded
    2. gets is deprecated and you should use something else like fgets
    3. The END-OF-FILE is not recognized by gets in the middle of a line. It has to be the first line symbol. It is so on my RHEL 7.1 but might be different on your system
    4. stdin should be replaced with your real input file descriptor