blob: c884ef8af23bf00f31d990017f2a33ff853deb98 [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 */
Matt Kraaibcca3312001-10-18 17:04:22 +000010#include "libbb.h"
11
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000012static 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 +000013{
14 char *linebuf = NULL;
15 const int term_length = strlen(terminating_string);
16 int end_string_offset;
17 int linebufsz = 0;
18 int idx = 0;
19 int ch;
Ron Yorston6ad38d62021-01-23 13:22:33 +000020 size_t maxsz = maxsz_p ? *maxsz_p : INT_MAX - 4095;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000021
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);
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000033 if (idx >= maxsz) {
34 linebuf[idx] = ch;
35 idx++;
36 break;
37 }
Glenn L McGrath17822cd2001-06-13 07:34:03 +000038 }
39
40 linebuf[idx] = ch;
41 idx++;
42
43 /* Check for terminating string */
44 end_string_offset = idx - term_length;
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000045 if (end_string_offset >= 0
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000046 && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
47 ) {
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000048 if (chop_off)
49 idx -= term_length;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000050 break;
51 }
52 }
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000053 /* Grow/shrink *first*, then store NUL */
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000054 linebuf = xrealloc(linebuf, idx + 1);
Glenn L McGrath17822cd2001-06-13 07:34:03 +000055 linebuf[idx] = '\0';
Ron Yorston6ad38d62021-01-23 13:22:33 +000056 if (maxsz_p)
57 *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{
Ron Yorston6ad38d62021-01-23 13:22:33 +000067 return xmalloc_fgets_internal(file, terminating_string, 0, NULL);
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000068}
69
70char* FAST_FUNC xmalloc_fgets_str_len(FILE *file, const char *terminating_string, size_t *maxsz_p)
71{
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000072 return xmalloc_fgets_internal(file, terminating_string, 0, maxsz_p);
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000073}
74
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000075char* FAST_FUNC xmalloc_fgetline_str(FILE *file, const char *terminating_string)
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000076{
Ron Yorston6ad38d62021-01-23 13:22:33 +000077 return xmalloc_fgets_internal(file, terminating_string, 1, NULL);
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000078}