C Basics: Reject Oversized Lines Without Losing the Next Record
A truncated read is not necessarily a complete line. Apply a seven-byte record limit and discard an oversized record without interpreting its remainder as another record.
Prepare a scratch directory
Tested on Linux x86-64 with GCC 14.2.0. You need GCC, the C development headers, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. This example uses the C standard library and no external package.
Keep the same terminal open. Stop if setup fails, before saving the source:
start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1Run the example
Save this as fgets-line-boundaries-demo.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[8];
while (fgets(line, sizeof line, stdin) != NULL) {
char *newline = strchr(line, '\n');
if (newline != NULL) {
*newline = '\0';
} else {
int next_character = fgetc(stdin);
if (next_character != '\n' && next_character != EOF) {
do {
next_character = fgetc(stdin);
} while (next_character != '\n' && next_character != EOF);
if (ferror(stdin)) {
fputs("Input failed\n", stderr);
return EXIT_FAILURE;
}
puts("Rejected: line exceeds seven bytes");
continue;
}
if (ferror(stdin)) {
fputs("Input failed\n", stderr);
return EXIT_FAILURE;
}
}
printf("Accepted: [%s]\n", line);
}
if (ferror(stdin)) {
fputs("Input failed\n", stderr);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}Compile and run it. The && prevents running an old executable if compilation fails:
gcc -std=c17 -Wall -Wextra -Werror -pedantic fgets-line-boundaries-demo.c -o fgets-line-boundaries-demo &&
printf 'short\n1234567\n12345678\nnext\nfinal' | ./fgets-line-boundaries-demoObserved output:
Accepted: [short]
Accepted: [1234567]
Rejected: line exceeds seven bytes
Accepted: [next]
Accepted: [final]Read the result
fgets reserves one byte for the null terminator. A missing newline can mean a full buffer or a final line without a newline. Looking at one more character distinguishes a seven-byte line followed by newline or EOF from an oversized line. Draining the remainder keeps the next read aligned.
Apply it carefully
This is a bounded, newline-delimited, NUL-free text example. It counts bytes, not Unicode characters, and does not accept embedded null bytes or normalize CRLF. For arbitrary binary input, track explicit lengths instead of using strchr. Draining a long live stream can block until a delimiter or EOF; network protocols also need time and total-input limits.
The library reference describes the relevant behavior.
Clean up
Remove only the source and executable created here, then remove the empty scratch directory:
rm -- fgets-line-boundaries-demo.c fgets-line-boundaries-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directoryIf the directory is not empty, inspect what remains before removing anything else.
Acknowledgements
This post was created with assistance from AI.