/* * freadln.c * * The `freadln` function reads a line from STDIN into a string, allocating * memory for it. * * Author: Intel A80486DX2-66 * License: Creative Commons Zero 1.0 Universal * * TODO: Figure out potential problems * TODO: Add 'flushing' of STDIN (while there are characters, read them) before * the input reading loop to avoid input queues * [optional] TODO: Handle EOF in a special way to indicate EOF */ #include "freadln.h" int freadln(FILE* f, char** output, size_t* length_out) { /* * The length of STDIN line is counted without any terminating characters. * * return value: * freadln_OK: no errors, the length of STDIN line has been stored in * `length_out` * freadln_ERROR: an error occurred (see errno) * >= 0: length of read line */ if (output == NULL) return freadln_ERROR; // NOTE: if the file is STDIN, flush STDOUT before waiting for input to // make sure a prompt is displayed if (f == stdin) fflush(stdout); freadln_length_type length = 0; // initial length *output = malloc((length + 1) * sizeof(char)); if (*output == NULL) return freadln_ERROR; int character; while ((character = fgetc(f)) != EOF /* stop on a newline character: */ && character != '\n') { (*output)[length] = (char) character; // integer overflow and integer limit check, to keep array boundaries if ((freadln_length_type) (length + 2) <= (freadln_length_type) length) { errno = ERANGE; freadln_success_epilogue; } else length++; char* temp = realloc(*output, (length + 1) * sizeof(char)); // If the function fails to allocate new memory, return the string that // has already been accumulated. if (temp == NULL) { // keep errno; freadln_success_epilogue; } *output = temp; } errno = 0; freadln_success_epilogue; } #ifdef TEST int main(void) { // stdin test printf("Type something> "); char* line; if (finreadln(&line, NULL) != freadln_OK) { perror("freadln"); exit(EXIT_FAILURE); } printf("Input string: '%s'\n", line); // file test #define TEST_FILE "freadln_test.txt" FILE* f = fopen(TEST_FILE, "w"); if (f == NULL) { perror("fopen"); exit(EXIT_FAILURE); } fprintf(f, "Hello, world!\nAnother line\n\n"); FILE* new_f = freopen(TEST_FILE, "r", f); if (new_f == NULL) { perror("freopen"); exit(EXIT_FAILURE); } f = new_f; for (int i = 0; i < 4; i++) { size_t line_length; if (freadln(f, &line, &line_length) != freadln_OK) { perror("freadln"); exit(EXIT_FAILURE); } else if (feof(f)) { printf("File: EOF, breaking the loop\n"); break; } printf("File, line #%d: '%s' (%zu characters)\n", i + 1, line, line_length); } fclose(f); return 0; } #endif