xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/readlline.c (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
1 /*	$NetBSD: readlline.c,v 1.1.1.1 2009/06/23 10:09:00 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	readlline 3
6 /* SUMMARY
7 /*	read logical line
8 /* SYNOPSIS
9 /*	#include <readlline.h>
10 /*
11 /*	VSTRING	*readlline(buf, fp, lineno)
12 /*	VSTRING	*buf;
13 /*	VSTREAM	*fp;
14 /*	int	*lineno;
15 /* DESCRIPTION
16 /*	readlline() reads one logical line from the named stream.
17 /* .IP "blank lines and comments"
18 /*	Empty lines and whitespace-only lines are ignored, as
19 /*	are lines whose first non-whitespace character is a `#'.
20 /* .IP "multi-line text"
21 /*	A logical line starts with non-whitespace text. A line that
22 /*	starts with whitespace continues a logical line.
23 /* .PP
24 /*	The result value is the input buffer argument or a null pointer
25 /*	when no input is found.
26 /*
27 /*	Arguments:
28 /* .IP buf
29 /*	A variable-length buffer for input. The result is null terminated.
30 /* .IP fp
31 /*	Handle to an open stream.
32 /* .IP lineno
33 /*	A null pointer, or a pointer to an integer that is incremented
34 /*	after reading a newline character.
35 /* .RE
36 /* DIAGNOSTICS
37 /*	Warning: a continuation line that does not continue preceding text.
38 /*	The invalid input is ignored, to avoid complicating caller code.
39 /* SECURITY
40 /* .ad
41 /* .fi
42 /*	readlline() imposes no logical line length limit therefore it
43 /*	should be used for reading trusted information only.
44 /* LICENSE
45 /* .ad
46 /* .fi
47 /*	The Secure Mailer license must be distributed with this software.
48 /* AUTHOR(S)
49 /*	Wietse Venema
50 /*	IBM T.J. Watson Research
51 /*	P.O. Box 704
52 /*	Yorktown Heights, NY 10598, USA
53 /*--*/
54 
55 /* System library. */
56 
57 #include <sys_defs.h>
58 #include <ctype.h>
59 
60 /* Utility library. */
61 
62 #include "msg.h"
63 #include "vstream.h"
64 #include "vstring.h"
65 #include "readlline.h"
66 
67 #define STR(x) vstring_str(x)
68 #define LEN(x) VSTRING_LEN(x)
69 #define END(x) vstring_end(x)
70 
71 /* readlline - read one logical line */
72 
73 VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
74 {
75     int     ch;
76     int     next;
77     ssize_t start;
78     char   *cp;
79 
80     VSTRING_RESET(buf);
81 
82     /*
83      * Ignore comment lines, all whitespace lines, and empty lines. Terminate
84      * at EOF or at the beginning of the next logical line.
85      */
86     for (;;) {
87 	/* Read one line, possibly not newline terminated. */
88 	start = LEN(buf);
89 	while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n')
90 	    VSTRING_ADDCH(buf, ch);
91 	if (ch == '\n' && lineno != 0)
92 	    *lineno += 1;
93 	/* Ignore comment line, all whitespace line, or empty line. */
94 	for (cp = STR(buf) + start; cp < END(buf) && ISSPACE(*cp); cp++)
95 	     /* void */ ;
96 	if (cp == END(buf) || *cp == '#')
97 	    vstring_truncate(buf, start);
98 	/* Terminate at EOF or at the beginning of the next logical line. */
99 	if (ch == VSTREAM_EOF)
100 	    break;
101 	if (LEN(buf) > 0) {
102 	    if ((next = VSTREAM_GETC(fp)) != VSTREAM_EOF)
103 		vstream_ungetc(fp, next);
104 	    if (next != '#' && !ISSPACE(next))
105 		break;
106 	}
107     }
108     VSTRING_TERMINATE(buf);
109 
110     /*
111      * Invalid input: continuing text without preceding text. Allowing this
112      * would complicate "postconf -e", which implements its own multi-line
113      * parsing routine. Do not abort, just warn, so that critical programs
114      * like postmap do not leave behind a truncated table.
115      */
116     if (LEN(buf) > 0 && ISSPACE(*STR(buf))) {
117 	msg_warn("%s: logical line must not start with whitespace: \"%.30s%s\"",
118 		 VSTREAM_PATH(fp), STR(buf),
119 		 LEN(buf) > 30 ? "..." : "");
120 	return (readlline(buf, fp, lineno));
121     }
122 
123     /*
124      * Done.
125      */
126     return (LEN(buf) > 0 ? buf : 0);
127 }
128