1*e89934bbSchristos /* $NetBSD: readlline.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */
241fbaed0Stron
341fbaed0Stron /*++
441fbaed0Stron /* NAME
541fbaed0Stron /* readlline 3
641fbaed0Stron /* SUMMARY
741fbaed0Stron /* read logical line
841fbaed0Stron /* SYNOPSIS
941fbaed0Stron /* #include <readlline.h>
1041fbaed0Stron /*
11e262b48eSchristos /* VSTRING *readllines(buf, fp, lineno, first_line)
12e262b48eSchristos /* VSTRING *buf;
13e262b48eSchristos /* VSTREAM *fp;
14e262b48eSchristos /* int *lineno;
15e262b48eSchristos /* int *first_line;
16e262b48eSchristos /*
1741fbaed0Stron /* VSTRING *readlline(buf, fp, lineno)
1841fbaed0Stron /* VSTRING *buf;
1941fbaed0Stron /* VSTREAM *fp;
2041fbaed0Stron /* int *lineno;
2141fbaed0Stron /* DESCRIPTION
22e262b48eSchristos /* readllines() reads one logical line from the named stream.
2341fbaed0Stron /* .IP "blank lines and comments"
2441fbaed0Stron /* Empty lines and whitespace-only lines are ignored, as
2541fbaed0Stron /* are lines whose first non-whitespace character is a `#'.
2641fbaed0Stron /* .IP "multi-line text"
2741fbaed0Stron /* A logical line starts with non-whitespace text. A line that
2841fbaed0Stron /* starts with whitespace continues a logical line.
2941fbaed0Stron /* .PP
3041fbaed0Stron /* The result value is the input buffer argument or a null pointer
3141fbaed0Stron /* when no input is found.
3241fbaed0Stron /*
33e262b48eSchristos /* readlline() is a backwards-compatibility wrapper.
34e262b48eSchristos /*
3541fbaed0Stron /* Arguments:
3641fbaed0Stron /* .IP buf
3741fbaed0Stron /* A variable-length buffer for input. The result is null terminated.
3841fbaed0Stron /* .IP fp
3941fbaed0Stron /* Handle to an open stream.
4041fbaed0Stron /* .IP lineno
4141fbaed0Stron /* A null pointer, or a pointer to an integer that is incremented
42e262b48eSchristos /* after reading a physical line.
43e262b48eSchristos /* .IP first_line
44e262b48eSchristos /* A null pointer, or a pointer to an integer that will contain
45e262b48eSchristos /* the line number of the first non-blank, non-comment line
46e262b48eSchristos /* in the result logical line.
4741fbaed0Stron /* DIAGNOSTICS
4841fbaed0Stron /* Warning: a continuation line that does not continue preceding text.
4941fbaed0Stron /* The invalid input is ignored, to avoid complicating caller code.
5041fbaed0Stron /* SECURITY
5141fbaed0Stron /* .ad
5241fbaed0Stron /* .fi
5341fbaed0Stron /* readlline() imposes no logical line length limit therefore it
5441fbaed0Stron /* should be used for reading trusted information only.
5541fbaed0Stron /* LICENSE
5641fbaed0Stron /* .ad
5741fbaed0Stron /* .fi
5841fbaed0Stron /* The Secure Mailer license must be distributed with this software.
5941fbaed0Stron /* AUTHOR(S)
6041fbaed0Stron /* Wietse Venema
6141fbaed0Stron /* IBM T.J. Watson Research
6241fbaed0Stron /* P.O. Box 704
6341fbaed0Stron /* Yorktown Heights, NY 10598, USA
6441fbaed0Stron /*--*/
6541fbaed0Stron
6641fbaed0Stron /* System library. */
6741fbaed0Stron
6841fbaed0Stron #include <sys_defs.h>
6941fbaed0Stron #include <ctype.h>
7041fbaed0Stron
7141fbaed0Stron /* Utility library. */
7241fbaed0Stron
7341fbaed0Stron #include "msg.h"
7441fbaed0Stron #include "vstream.h"
7541fbaed0Stron #include "vstring.h"
7641fbaed0Stron #include "readlline.h"
7741fbaed0Stron
7841fbaed0Stron #define STR(x) vstring_str(x)
7941fbaed0Stron #define LEN(x) VSTRING_LEN(x)
8041fbaed0Stron #define END(x) vstring_end(x)
8141fbaed0Stron
82e262b48eSchristos /* readllines - read one logical line */
8341fbaed0Stron
readllines(VSTRING * buf,VSTREAM * fp,int * lineno,int * first_line)84e262b48eSchristos VSTRING *readllines(VSTRING *buf, VSTREAM *fp, int *lineno, int *first_line)
8541fbaed0Stron {
8641fbaed0Stron int ch;
8741fbaed0Stron int next;
8841fbaed0Stron ssize_t start;
8941fbaed0Stron char *cp;
9041fbaed0Stron
9141fbaed0Stron VSTRING_RESET(buf);
9241fbaed0Stron
9341fbaed0Stron /*
9441fbaed0Stron * Ignore comment lines, all whitespace lines, and empty lines. Terminate
9541fbaed0Stron * at EOF or at the beginning of the next logical line.
9641fbaed0Stron */
9741fbaed0Stron for (;;) {
9841fbaed0Stron /* Read one line, possibly not newline terminated. */
9941fbaed0Stron start = LEN(buf);
10041fbaed0Stron while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n')
10141fbaed0Stron VSTRING_ADDCH(buf, ch);
102e262b48eSchristos if (lineno != 0 && (ch == '\n' || LEN(buf) > start))
10341fbaed0Stron *lineno += 1;
10441fbaed0Stron /* Ignore comment line, all whitespace line, or empty line. */
10541fbaed0Stron for (cp = STR(buf) + start; cp < END(buf) && ISSPACE(*cp); cp++)
10641fbaed0Stron /* void */ ;
10741fbaed0Stron if (cp == END(buf) || *cp == '#')
10841fbaed0Stron vstring_truncate(buf, start);
109e262b48eSchristos else if (start == 0 && lineno != 0 && first_line != 0)
110e262b48eSchristos *first_line = *lineno;
11141fbaed0Stron /* Terminate at EOF or at the beginning of the next logical line. */
11241fbaed0Stron if (ch == VSTREAM_EOF)
11341fbaed0Stron break;
11441fbaed0Stron if (LEN(buf) > 0) {
11541fbaed0Stron if ((next = VSTREAM_GETC(fp)) != VSTREAM_EOF)
11641fbaed0Stron vstream_ungetc(fp, next);
11741fbaed0Stron if (next != '#' && !ISSPACE(next))
11841fbaed0Stron break;
11941fbaed0Stron }
12041fbaed0Stron }
12141fbaed0Stron VSTRING_TERMINATE(buf);
12241fbaed0Stron
12341fbaed0Stron /*
12441fbaed0Stron * Invalid input: continuing text without preceding text. Allowing this
12541fbaed0Stron * would complicate "postconf -e", which implements its own multi-line
12641fbaed0Stron * parsing routine. Do not abort, just warn, so that critical programs
12741fbaed0Stron * like postmap do not leave behind a truncated table.
12841fbaed0Stron */
12941fbaed0Stron if (LEN(buf) > 0 && ISSPACE(*STR(buf))) {
13041fbaed0Stron msg_warn("%s: logical line must not start with whitespace: \"%.30s%s\"",
13141fbaed0Stron VSTREAM_PATH(fp), STR(buf),
13241fbaed0Stron LEN(buf) > 30 ? "..." : "");
133e262b48eSchristos return (readllines(buf, fp, lineno, first_line));
13441fbaed0Stron }
13541fbaed0Stron
13641fbaed0Stron /*
13741fbaed0Stron * Done.
13841fbaed0Stron */
13941fbaed0Stron return (LEN(buf) > 0 ? buf : 0);
14041fbaed0Stron }
141