1/*
2 * Configuration parsing
3 * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "utils/config.h"
12#include "common.h"
13
14
15static int newline_terminated(const char *buf, size_t buflen)
16{
17	size_t len = os_strlen(buf);
18	if (len == 0)
19		return 0;
20	if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
21	    buf[len - 1] != '\n')
22		return 0;
23	return 1;
24}
25
26
27static void skip_line_end(FILE *stream)
28{
29	char buf[100];
30	while (fgets(buf, sizeof(buf), stream)) {
31		buf[sizeof(buf) - 1] = '\0';
32		if (newline_terminated(buf, sizeof(buf)))
33			return;
34	}
35}
36
37
38char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
39			   char **_pos)
40{
41	char *pos, *end, *sstart;
42
43	while (fgets(s, size, stream)) {
44		(*line)++;
45		s[size - 1] = '\0';
46		if (!newline_terminated(s, size)) {
47			/*
48			 * The line was truncated - skip rest of it to avoid
49			 * confusing error messages.
50			 */
51			wpa_printf(MSG_INFO, "Long line in configuration file "
52				   "truncated");
53			skip_line_end(stream);
54		}
55		pos = s;
56
57		/* Skip white space from the beginning of line. */
58		while (*pos == ' ' || *pos == '\t' || *pos == '\r')
59			pos++;
60
61		/* Skip comment lines and empty lines */
62		if (*pos == '#' || *pos == '\n' || *pos == '\0')
63			continue;
64
65		/*
66		 * Remove # comments unless they are within a double quoted
67		 * string.
68		 */
69		sstart = pos;
70		end = os_strchr(sstart, '#');
71		while (end) {
72			sstart = os_strchr(sstart, '"');
73			if (!sstart || sstart > end)
74				break;
75			sstart = os_strchr(sstart + 1, '"');
76			if (!sstart)
77				break;
78			sstart++;
79			if (sstart > end)
80				end = os_strchr(sstart, '#');
81		}
82
83		if (end)
84			*end-- = '\0';
85		else
86			end = pos + os_strlen(pos) - 1;
87
88		/* Remove trailing white space. */
89		while (end > pos &&
90		       (*end == '\n' || *end == ' ' || *end == '\t' ||
91			*end == '\r'))
92			*end-- = '\0';
93
94		if (*pos == '\0')
95			continue;
96
97		if (_pos)
98			*_pos = pos;
99		return pos;
100	}
101
102	if (_pos)
103		*_pos = NULL;
104	return NULL;
105}
106