blob: 1a7f2e9e090b3731da1bd674028c098d2b31c1da [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;
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000020 size_t maxsz = *maxsz_p;
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';
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000056 *maxsz_p = idx;
Denis Vlasenkoa6dbb082006-10-12 19:29:44 +000057 return linebuf;
Glenn L McGrath17822cd2001-06-13 07:34:03 +000058}
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000059
60/* Read up to TERMINATING_STRING from FILE and return it,
61 * including terminating string.
62 * Non-terminated string can be returned if EOF is reached.
63 * Return NULL if EOF is reached immediately. */
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000064char* FAST_FUNC xmalloc_fgets_str(FILE *file, const char *terminating_string)
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000065{
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000066 size_t maxsz = INT_MAX - 4095;
67 return xmalloc_fgets_internal(file, terminating_string, 0, &maxsz);
68}
69
70char* FAST_FUNC xmalloc_fgets_str_len(FILE *file, const char *terminating_string, size_t *maxsz_p)
71{
72 size_t maxsz;
73
74 if (!maxsz_p) {
75 maxsz = INT_MAX - 4095;
76 maxsz_p = &maxsz;
77 }
78 return xmalloc_fgets_internal(file, terminating_string, 0, maxsz_p);
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000079}
80
Denis Vlasenkodefc1ea2008-06-27 02:52:20 +000081char* FAST_FUNC xmalloc_fgetline_str(FILE *file, const char *terminating_string)
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000082{
Denis Vlasenko9f57cf62009-03-18 17:32:44 +000083 size_t maxsz = INT_MAX - 4095;
84 return xmalloc_fgets_internal(file, terminating_string, 1, &maxsz);
Denis Vlasenkoabee3d02007-12-26 20:44:45 +000085}