2 * SPDX-License-Identifier: ISC
4 * Copyright (c) 2007, 2013-2016 Todd C. Miller <Todd.Miller@sudo.ws>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
26 #include <sys/types.h>
30 #endif /* HAVE_STRING_H */
33 #endif /* HAVE_STRING_H */
40 # include "compat/stdbool.h"
43 #include "sudo_compat.h"
44 #include "sudo_util.h"
45 #include "sudo_debug.h"
48 * Read a line of input, honoring line continuation chars.
49 * Remove comments and strip off leading and trailing spaces.
50 * Returns the line length and updates the buf and bufsize pointers.
51 * XXX - just use a struct w/ state, including getdelim buffer?
52 * could also make comment char and line continuation configurable
55 sudo_parseln_v2(char **bufp, size_t *bufsizep, unsigned int *lineno, FILE *fp, int flags)
57 size_t linesize = 0, total = 0;
59 char *cp, *line = NULL;
60 bool continued, comment;
61 debug_decl(sudo_parseln, SUDO_DEBUG_UTIL)
66 len = getdelim(&line, &linesize, '\n', fp);
72 /* Remove trailing newline(s) if present. */
73 while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
76 /* Remove comments or check for line continuation (but not both) */
77 if ((cp = strchr(line, '#')) != NULL) {
78 if (cp == line || !ISSET(flags, PARSELN_COMM_BOL)) {
80 len = (ssize_t)(cp - line);
84 if (!comment && !ISSET(flags, PARSELN_CONT_IGN)) {
85 if (len > 0 && line[len - 1] == '\\' && (len == 1 || line[len - 2] != '\\')) {
91 /* Trim leading and trailing whitespace */
93 while (len > 0 && isblank((unsigned char)line[len - 1]))
96 for (cp = line; isblank((unsigned char)*cp); cp++)
99 if (*bufp == NULL || total + len >= *bufsizep) {
101 size_t size = total + len + 1;
105 } else if (size <= 0x80000000) {
106 /* Round up to next highest power of two. */
115 if ((tmp = realloc(*bufp, size)) == NULL) {
116 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
117 "unable to allocate memory");
125 memcpy(*bufp + total, cp, len + 1);
129 if (len == -1 && total == 0)
130 debug_return_ssize_t(-1);
131 debug_return_ssize_t(total);
135 sudo_parseln_v1(char **bufp, size_t *bufsizep, unsigned int *lineno, FILE *fp)
137 return sudo_parseln_v2(bufp, bufsizep, lineno, fp, 0);