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