/**
* \file fgetsl.c Implementation file for NUL-proof fgets() replacement.
* Also usable as standalone test code when compiled with -DMAIN.
* \author Matthias Andree
* \date 2002 - 2003
*/
#include "common.h"
#include <stdlib.h>
#include <errno.h>
#include "fgetsl.h"
/* calls exit(EX_ERROR) on read error or when max_size < 2 */
int fgetsl(char *buf, int siz, /*@null@*/ FILE *in)
{
return xfgetsl(buf, siz, in, 0);
}
int xfgetsl(char *buf, int max_size, FILE *in, bool no_nul_terminate)
{
int c = 0;
int rc;
char *cp = buf;
char *end = buf + max_size; /* Physical end of buffer */
char *fin = end - (no_nul_terminate ? 0 : 1); /* Last available byte */
if (cp == fin && no_nul_terminate)
return 0;
if (cp >= fin) {
fprintf(stderr, "Invalid buffer size, exiting.\n");
abort();
}
if (in == NULL) {
errno = EBADF;
return(EOF);
}
if (feof(in))
return(EOF);
while ((cp < fin) && ((c = getc(in)) != EOF)) {
*cp++ = (char)c;
if (c == '\n')
break;
}
if (c == EOF && ferror(in)) {
perror("stdin");
exit(EX_ERROR);
}
if (cp < end)
*cp = '\0'; /* DO NOT ADD ++ HERE! */
rc = (cp != buf || !feof(in)) ? cp - buf : EOF;
return rc;
}
#ifdef MAIN
#include <string.h>
#include "xmalloc.h"
int main(int argc, char **argv) {
char *buf;
int size, count, non_nul_terminate;
if (argc != 3) {
fprintf(stderr, "%s <size> <non_nul_terminate>\n", argv[0]);
exit(EX_ERROR);
}
non_nul_terminate = atoi(argv[2]);
size = atoi(argv[1]);
buf = (char *)xmalloc(size);
for (;;) {
count = xfgetsl(buf, size, stdin, non_nul_terminate);
if (count == EOF) break;
printf("%d ", count);
if (count > 0) fwrite((char *)buf, 1, count, stdout);
if (count > 0 && !non_nul_terminate && buf[count] != '\0') {
printf(" (NUL terminator missing)");
}
putchar('\n');
}
xfree(buf);
exit(EXIT_SUCCESS);
}
#endif