blob: d6fada1a17ee02d16695974611088e5c84939903 [file] [log] [blame]
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath17822cd2001-06-13 07:34:03 +00002/*
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003 * Utility routines.
Glenn L McGrath17822cd2001-06-13 07:34:03 +00004 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005 * Copyright (C) many different people.
Eric Andersencb81e642003-07-14 21:21:08 +00006 * If you wrote this, please acknowledge your work.
Glenn L McGrath17822cd2001-06-13 07:34:03 +00007 *
"Robert P. J. Day"5d8843e2006-07-10 11:41:19 +00008 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Glenn L McGrath17822cd2001-06-13 07:34:03 +00009 */
10
Matt Kraaibcca3312001-10-18 17:04:22 +000011#include "libbb.h"
12
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000013static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off)
Glenn L McGrath17822cd2001-06-13 07:34:03 +000014{
15 char *linebuf = NULL;
16 const int term_length = strlen(terminating_string);
17 int end_string_offset;
18 int linebufsz = 0;
19 int idx = 0;
20 int ch;
21
22 while (1) {
23 ch = fgetc(file);
24 if (ch == EOF) {
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000025 if (idx == 0)
26 return linebuf; /* NULL */
27 break;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000028 }
29
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000030 if (idx >= linebufsz) {
Denis Vlasenkoddec5af2006-10-26 23:25:17 +000031 linebufsz += 200;
32 linebuf = xrealloc(linebuf, linebufsz);
Glenn L McGrath17822cd2001-06-13 07:34:03 +000033 }
34
35 linebuf[idx] = ch;
36 idx++;
37
38 /* Check for terminating string */
39 end_string_offset = idx - term_length;
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000040 if (end_string_offset >= 0
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000041 && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
42 ) {
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000043 if (chop_off)
44 idx -= term_length;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000045 break;
46 }
47 }
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000048 /* Grow/shrink *first*, then store NUL */
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000049 linebuf = xrealloc(linebuf, idx + 1);
Glenn L McGrath17822cd2001-06-13 07:34:03 +000050 linebuf[idx] = '\0';
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000051 return linebuf;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000052}
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000053
54/* Read up to TERMINATING_STRING from FILE and return it,
55 * including terminating string.
56 * Non-terminated string can be returned if EOF is reached.
57 * Return NULL if EOF is reached immediately. */
58char *xmalloc_fgets_str(FILE *file, const char *terminating_string)
59{
60 return xmalloc_fgets_internal(file, terminating_string, 0);
61}
62
63char *xmalloc_fgetline_str(FILE *file, const char *terminating_string)
64{
65 return xmalloc_fgets_internal(file, terminating_string, 1);
66}