Lu4
Lu4

Reputation: 15032

C stdin limitation is blocking me from reading a line with over 1200 characters

I have this simple program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

size_t strlen(const char *str)
{
    const char *s;
    for (s = str; *s; ++s);
    return(s - str);
}

/*
 * Initial size of the read buffer
 */
#define DEFAULT_BUFFER 1024

/*
 * Standard boolean type definition
 */
typedef enum { false = 0, true = 1 } bool;

/*
 * Flags errors in pointer returning functions
 */
bool has_err = false;

/*
 * Reads the next line of text from file and returns it.
 * The line must be free()d afterwards.
 *
 * This function will segfault on binary data.
 */
char *readline(FILE *file){
    char *buffer   = NULL;
    char *tmp_buf  = NULL;
    bool line_read = false;
    int  iteration = 0;
    int  offset    = 0;

    if(file == NULL){
        fprintf(stderr, "readLine: NULL file pointer passed!\n");
        has_err = true;

        return NULL;
    }

    while(!line_read){
        if((tmp_buf = malloc(DEFAULT_BUFFER)) == NULL){
            fprintf(stderr, "readLine: Unable to allocate temporary buffer!\n");
            if(buffer != NULL)
                free(buffer);
            has_err = true;

            return NULL;
        }

        if(fgets(tmp_buf, DEFAULT_BUFFER, file) == NULL){
            free(tmp_buf);

            break;
        }

        if(tmp_buf[strlen(tmp_buf) - 1] == '\n') /* we have an end of line */
            line_read = true;

        offset = DEFAULT_BUFFER * (iteration + 1);

        if((buffer = realloc(buffer, offset)) == NULL){
            fprintf(stderr, "readLine: Unable to reallocate buffer!\n");
            free(tmp_buf);
            has_err = true;

            return NULL;
        }

        offset = DEFAULT_BUFFER * iteration - iteration;

        if(memcpy(buffer + offset, tmp_buf, DEFAULT_BUFFER) == NULL){
            fprintf(stderr, "readLine: Cannot copy to buffer\n");
            free(tmp_buf);
            if(buffer != NULL)
                free(buffer);
            has_err = true;

            return NULL;
        }

        free(tmp_buf);
        iteration++;
    }

    return buffer;
}

int main (int argc, char *argv[])
{
    int rows = 0, cols = 0;
    char *line = readline(stdin);

    printf("%s", line);

    return 0;
}

However when I try entering more than 1200 characters in to console, the program stops working within this line of code: fgets(tmp_buf, DEFAULT_BUFFER, file)

The question: How to make C read from stdin without imposing any internal limitations?

P.S. Niether the program works if I try piping the content I need to enter into program with console pipe operators (i.e. <, ./myprogram <input.txt)

Thank you in advance!

Upvotes: 0

Views: 380

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 754920

The problem is not your program; it is the terminal driver. There is an upper limit on the number of unread characters that the terminal driver will hold. It expects lines to be shorter than some limit, which might be 1024 or 1200 or some other value. If you try to type more characters, they simply won't be accepted.

You can try pressing Control-D (on Unix; Control-Z on Windows) to send the pending line from the terminal driver, and then continuing with more characters. That should work, but it is a nuisance to have to keep counting to 1199 (or whatever number is one less than the limit) and then hit Control-D. It is doubly a nuisance if the data was copy'n'pasted from somewhere and therefore you don't have the option of hitting Control-D at appropriate intervals.

You can also try using a non-canonical input mode. That requires care — you need to restore the canonical mode before your program exits if you set non-canonical mode within the program. (Non-canonical mode is what is used by programs such as vim.)

Upvotes: 4

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53016

I don't know what you did in your code, but this is what your question title is about

#include <stdio.h>
#include <stdlib.h>

char *readline(FILE *file)
 {
    char  *line;
    size_t length;
    size_t count;
    int    chr;

    length = 100;
    line   = malloc(1 + length);
    if (line == NULL)
     {
        fprintf(stderr, "memory exhausted!\n");
        return NULL;
     }
    count = 0;
    while (((chr = fgetc(file)) != EOF) && (chr != '\n'))
     {
        if (count >= length)
         {
            void *pointer;
            length += length;
            pointer = realloc(line, 1 + length);
            if (pointer == NULL)
             {
                fprintf(stderr, "memory exhausted!\n");
                free(line);
                return NULL;
             }
            line = pointer;
         }
        line[count] = chr;
        count      += 1;
     }
    line[count] = '\0';

    return line;
 }

int main(void)
 {
    char *line = readline(stdin);
    if (line != NULL)
        printf("%s\n", line);
    free(line);
    return 0;
 }

The only limitation in this code is memory, and the code will not fail even if there isn't enough memory because that is taken care of as you can see.

Upvotes: 0

Related Questions