1
0
mirror of https://gitlab.com/80486DX2-66/gists synced 2024-12-26 11:30:03 +05:30
gists/c-programming/io/freadln.c

116 lines
2.7 KiB
C
Raw Normal View History

2024-02-20 04:08:45 +05:30
/*
* 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
*
2024-03-10 14:20:09 +05:30
* TODO: Figure out potential problems
2024-03-10 16:38:28 +05:30
* 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
2024-02-20 04:08:45 +05:30
*/
#include "freadln.h"
int freadln(FILE* f, char** output, size_t* length_out) {
2024-02-20 04:08:45 +05:30
/*
* 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
2024-02-20 04:08:45 +05:30
*/
if (output == NULL)
return freadln_ERROR;
2024-03-10 16:42:05 +05:30
// NOTE: if the file is STDIN, flush STDOUT before waiting for input to
// make sure a prompt is displayed
if (f == stdin)
fflush(stdout);
2024-03-10 16:42:05 +05:30
freadln_length_type length = 0; // initial length
2024-02-20 04:08:45 +05:30
*output = malloc((length + 1) * sizeof(char));
if (*output == NULL) {
errno = EINVAL;
2024-02-20 04:08:45 +05:30
return freadln_ERROR;
}
2024-02-20 04:08:45 +05:30
int character;
while ((character = fgetc(f)) != EOF
2024-02-20 04:08:45 +05:30
/* 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;
2024-03-10 16:42:51 +05:30
freadln_success_epilogue;
2024-02-20 04:08:45 +05:30
} 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;
2024-03-10 16:42:51 +05:30
freadln_success_epilogue;
2024-02-20 04:08:45 +05:30
}
*output = temp;
}
errno = 0;
2024-03-10 16:42:51 +05:30
freadln_success_epilogue;
2024-02-20 04:08:45 +05:30
}
2024-03-10 16:44:38 +05:30
#ifdef TEST
int main(void) {
// stdin test
2024-03-10 16:44:38 +05:30
printf("Type something> ");
char* line;
if (finreadln(&line, NULL) != freadln_OK) {
2024-03-10 16:44:38 +05:30
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);
2024-03-10 16:44:38 +05:30
return 0;
}
#endif