diff --git a/c-programming/freadln.c b/c-programming/freadln.c new file mode 100644 index 0000000..144a1cc --- /dev/null +++ b/c-programming/freadln.c @@ -0,0 +1,62 @@ +/* + * 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 + * + * To-Do: figure out potential problems + */ + +#include "freadln.h" + +ssize_t freadln(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 stdin line + */ + + if (output == NULL) + return freadln_ERROR; + + freadln_length_type length = 0; + + *output = malloc((length + 1) * sizeof(char)); + if (*output == NULL) + return freadln_ERROR; + + int character; + while ((character = fgetc(stdin)) != 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 +} diff --git a/c-programming/freadln.h b/c-programming/freadln.h new file mode 100644 index 0000000..470f0cc --- /dev/null +++ b/c-programming/freadln.h @@ -0,0 +1,33 @@ +/* + * freadln.h + * + * Author: Intel A80486DX2-66 + * License: Creative Commons Zero 1.0 Universal + */ + +#ifndef _FREADLN_H +#define _FREADLN_H + +#include +#include +#include + +typedef size_t freadln_length_type; + +enum freadln_status { + freadln_OK = -2, + freadln_ERROR +}; + +#define freadln_success_epilogue do { \ + (*output)[length] = '\0'; \ + if (length_out == NULL) \ + return length; \ + else { \ + *length_out = length; \ + return freadln_OK; \ + } \ +} while (0); + +ssize_t freadln(char** output); +#endif /* _FREADLN_H */