Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / readlline.c
blob5cc5c3d1cf0fb4b40e8aa83676cf1f45d91850b1
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* readlline 3
6 /* SUMMARY
7 /* read logical line
8 /* SYNOPSIS
9 /* #include <readlline.h>
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.
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 /*--*/
55 /* System library. */
57 #include <sys_defs.h>
58 #include <ctype.h>
60 /* Utility library. */
62 #include "msg.h"
63 #include "vstream.h"
64 #include "vstring.h"
65 #include "readlline.h"
67 #define STR(x) vstring_str(x)
68 #define LEN(x) VSTRING_LEN(x)
69 #define END(x) vstring_end(x)
71 /* readlline - read one logical line */
73 VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno)
75 int ch;
76 int next;
77 ssize_t start;
78 char *cp;
80 VSTRING_RESET(buf);
83 * Ignore comment lines, all whitespace lines, and empty lines. Terminate
84 * at EOF or at the beginning of the next logical line.
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;
108 VSTRING_TERMINATE(buf);
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.
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));
124 * Done.
126 return (LEN(buf) > 0 ? buf : 0);