From abee3d0e0dc7c7e4b733b0145c56bf8159a37a69 Mon Sep 17 00:00:00 2001
From: Denis Vlasenko <vda.linux@googlemail.com>
Date: Wed, 26 Dec 2007 20:44:45 +0000
Subject: Fix xmalloc_fgets_str so that it really does NOT strip terminator.
 Add xmalloc_fgetline_str which does strip terminator, and use it in dpkg
 instead of xmalloc_fgets_str. netstat: use xmalloc_fgets_str - allows to eat
 strings with NULs (this fixes bug with some weird /proc/net/unix input)

function                                             old     new   delta
xmalloc_fgets_internal                                 -     191    +191
xmalloc_fgetline_str                                   -      18     +18
do_info                                              116     120      +4
unix_do_one                                          451     447      -4
tcp_do_one                                           423     419      -4
send_tree                                            369     365      -4
xmalloc_fgets_str                                    178      15    -163
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 1/4 up/down: 213/-175)           Total: 38 bytes
   text    data     bss     dec     hex filename
 778445     832    7344  786621   c00bd busybox_old
 778483     832    7344  786659   c00e3 busybox_unstripped
---
 libbb/fgets_str.c          | 33 +++++++++++++++++++++++----------
 libbb/get_line_from_file.c |  5 ++---
 2 files changed, 25 insertions(+), 13 deletions(-)

(limited to 'libbb')

diff --git a/libbb/fgets_str.c b/libbb/fgets_str.c
index 1bc6c3b1c..d6fada1a1 100644
--- a/libbb/fgets_str.c
+++ b/libbb/fgets_str.c
@@ -10,10 +10,7 @@
 
 #include "libbb.h"
 
-/* Read up to (and including) TERMINATING_STRING from FILE and return it.
- * Return NULL on EOF.  */
-
-char *xmalloc_fgets_str(FILE *file, const char *terminating_string)
+static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string, int chop_off)
 {
 	char *linebuf = NULL;
 	const int term_length = strlen(terminating_string);
@@ -25,12 +22,12 @@ char *xmalloc_fgets_str(FILE *file, const char *terminating_string)
 	while (1) {
 		ch = fgetc(file);
 		if (ch == EOF) {
-			free(linebuf);
-			return NULL;
+			if (idx == 0)
+				return linebuf; /* NULL */
+			break;
 		}
 
-		/* grow the line buffer as necessary */
-		while (idx > linebufsz - 2) {
+		if (idx >= linebufsz) {
 			linebufsz += 200;
 			linebuf = xrealloc(linebuf, linebufsz);
 		}
@@ -40,14 +37,30 @@ char *xmalloc_fgets_str(FILE *file, const char *terminating_string)
 
 		/* Check for terminating string */
 		end_string_offset = idx - term_length;
-		if (end_string_offset > 0
+		if (end_string_offset >= 0
 		 && memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0
 		) {
-			idx -= term_length;
+			if (chop_off)
+				idx -= term_length;
 			break;
 		}
 	}
+	/* Grow/shrink *first*, then store NUL */
 	linebuf = xrealloc(linebuf, idx + 1);
 	linebuf[idx] = '\0';
 	return linebuf;
 }
+
+/* Read up to TERMINATING_STRING from FILE and return it,
+ * including terminating string.
+ * Non-terminated string can be returned if EOF is reached.
+ * Return NULL if EOF is reached immediately.  */
+char *xmalloc_fgets_str(FILE *file, const char *terminating_string)
+{
+	return xmalloc_fgets_internal(file, terminating_string, 0);
+}
+
+char *xmalloc_fgetline_str(FILE *file, const char *terminating_string)
+{
+	return xmalloc_fgets_internal(file, terminating_string, 1);
+}
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
index 1eb4af13c..ac4d14b1f 100644
--- a/libbb/get_line_from_file.c
+++ b/libbb/get_line_from_file.c
@@ -12,11 +12,10 @@
 #include "libbb.h"
 
 /* This function reads an entire line from a text file, up to a newline
- * or NUL byte, inclusive.  It returns a malloc'ed char * which must be
- * stored and free'ed by the caller.  If end is NULL '\n' isn't considered
+ * or NUL byte, inclusive.  It returns a malloc'ed char * which
+ * must be free'ed by the caller.  If end is NULL '\n' isn't considered
  * end of line.  If end isn't NULL, length of the chunk read is stored in it.
  * Return NULL if EOF/error */
-
 char *bb_get_chunk_from_file(FILE *file, int *end)
 {
 	int ch;
-- 
cgit v1.2.3-55-g6feb