blob: 89210a3c9cf5a2d3f519c401dfdb0fdfc495d921 [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 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02008 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath17822cd2001-06-13 07:34:03 +00009 */
10
Matt Kraaibcca3312001-10-18 17:04:22 +000011#include "libbb.h"
12
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000013static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off, size_t *maxsz_p)
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;
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000021 size_t maxsz = *maxsz_p;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000022
23 while (1) {
24 ch = fgetc(file);
25 if (ch == EOF) {
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000026 if (idx == 0)
27 return linebuf; /* NULL */
28 break;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000029 }
30
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000031 if (idx >= linebufsz) {
Denis Vlasenkoddec5af2006-10-26 23:25:17 +000032 linebufsz += 200;
33 linebuf = xrealloc(linebuf, linebufsz);
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000034 if (idx >= maxsz) {
35 linebuf[idx] = ch;
36 idx++;
37 break;
38 }
Glenn L McGrath17822cd2001-06-13 07:34:03 +000039 }
40
41 linebuf[idx] = ch;
42 idx++;
43
44 /* Check for terminating string */
45 end_string_offset = idx - term_length;
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000046 if (end_string_offset >= 0
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000047 && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
48 ) {
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000049 if (chop_off)
50 idx -= term_length;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000051 break;
52 }
53 }
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000054 /* Grow/shrink *first*, then store NUL */
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000055 linebuf = xrealloc(linebuf, idx + 1);
Glenn L McGrath17822cd2001-06-13 07:34:03 +000056 linebuf[idx] = '\0';
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000057 *maxsz_p = idx;
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000058 return linebuf;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000059}
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000060
61/* Read up to TERMINATING_STRING from FILE and return it,
62 * including terminating string.
63 * Non-terminated string can be returned if EOF is reached.
64 * Return NULL if EOF is reached immediately. */
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000065char* FAST_FUNC xmalloc_fgets_str(FILE *file, const char *terminating_string)
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000066{
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000067 size_t maxsz = INT_MAX - 4095;
68 return xmalloc_fgets_internal(file, terminating_string, 0, &maxsz);
69}
70
71char* FAST_FUNC xmalloc_fgets_str_len(FILE *file, const char *terminating_string, size_t *maxsz_p)
72{
73 size_t maxsz;
74
75 if (!maxsz_p) {
76 maxsz = INT_MAX - 4095;
77 maxsz_p = &maxsz;
78 }
79 return xmalloc_fgets_internal(file, terminating_string, 0, maxsz_p);
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000080}
81
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000082char* FAST_FUNC xmalloc_fgetline_str(FILE *file, const char *terminating_string)
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000083{
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000084 size_t maxsz = INT_MAX - 4095;
85 return xmalloc_fgets_internal(file, terminating_string, 1, &maxsz);
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000086}