Add hidden attribute to some common functions
[lttng-tools.git] / src / common / config / ini.c
1 /*
2 * inih -- simple .INI file parser
3 *
4 * The "inih" library is distributed under the New BSD license:
5 *
6 * Copyright (c) 2009, Brush Technology - All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of Brush Technology nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
23 * EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * http://code.google.com/p/inih/
32 */
33
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <string.h>
37
38 #include "ini.h"
39
40 #if !INI_USE_STACK
41 #include <stdlib.h>
42 #endif
43
44 #define MAX_SECTION 50
45 #define MAX_NAME 50
46
47 /* Strip whitespace chars off end of given string, in place. Return s. */
48 static char* rstrip(char* s)
49 {
50 char* p = s + strlen(s);
51
52 while (p > s && isspace((unsigned char)(*--p)))
53 *p = '\0';
54 return s;
55 }
56
57 /* Return pointer to first non-whitespace char in given string. */
58 static char* lskip(const char* s)
59 {
60 while (*s && isspace((unsigned char)(*s)))
61 s++;
62 return (char*)s;
63 }
64
65 /*
66 * Return pointer to first char c or ';' comment in given string, or pointer to
67 * null at end of string if neither found. ';' must be prefixed by a whitespace
68 * character to register as a comment.
69 */
70 static char* find_char_or_comment(const char* s, char c)
71 {
72 int was_whitespace = 0;
73
74 while (*s && *s != c && !(was_whitespace && *s == ';')) {
75 was_whitespace = isspace((unsigned char)(*s));
76 s++;
77 }
78 return (char*)s;
79 }
80
81 /* Version of strncpy that ensures dest (size bytes) is null-terminated. */
82 static char* strncpy0(char* dest, const char* src, size_t size)
83 {
84 strncpy(dest, src, size);
85 dest[size - 1] = '\0';
86 return dest;
87 }
88
89 /* See documentation in header file. */
90 LTTNG_HIDDEN
91 int ini_parse_file(FILE* file, ini_entry_handler handler, void* user)
92 {
93 /* Uses a fair bit of stack (use heap instead if you need to) */
94 #if INI_USE_STACK
95 char line[INI_MAX_LINE];
96 #else
97 char* line;
98 #endif
99 char section[MAX_SECTION] = "";
100 char prev_name[MAX_NAME] = "";
101
102 char* start;
103 char* end;
104 char* name;
105 char* value;
106 int lineno = 0;
107 int error = 0;
108
109 #if !INI_USE_STACK
110 line = (char*)malloc(INI_MAX_LINE);
111 if (!line) {
112 return -2;
113 }
114 #endif
115
116 /* Scan through file line by line */
117 while (fgets(line, INI_MAX_LINE, file) != NULL) {
118 lineno++;
119
120 start = line;
121 #if INI_ALLOW_BOM
122 if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
123 (unsigned char)start[1] == 0xBB &&
124 (unsigned char)start[2] == 0xBF) {
125 start += 3;
126 }
127 #endif
128 start = lskip(rstrip(start));
129
130 if (*start == ';' || *start == '#') {
131 /*
132 * Per Python ConfigParser, allow '#' comments at
133 * start of line.
134 */
135 }
136 #if INI_ALLOW_MULTILINE
137 else if (*prev_name && *start && start > line) {
138 /* Non-black line with leading whitespace, treat as
139 * continuation of previous name's value
140 * (as per Python ConfigParser).
141 */
142 if (handler(user, section, prev_name, start) < 0 &&
143 !error) {
144 error = lineno;
145 }
146 }
147 #endif
148 else if (*start == '[') {
149 /* A "[section]" line */
150 end = find_char_or_comment(start + 1, ']');
151 if (*end == ']') {
152 *end = '\0';
153 strncpy0(section, start + 1, sizeof(section));
154 *prev_name = '\0';
155 }
156 else if (!error) {
157 /* No ']' found on section line */
158 error = lineno;
159 }
160 }
161 else if (*start && *start != ';') {
162 /* Not a comment, must be a name[=:]value pair */
163 end = find_char_or_comment(start, '=');
164 if (*end != '=') {
165 end = find_char_or_comment(start, ':');
166 }
167 if (*end == '=' || *end == ':') {
168 *end = '\0';
169 name = rstrip(start);
170 value = lskip(end + 1);
171 end = find_char_or_comment(value, '\0');
172 if (*end == ';') {
173 *end = '\0';
174 }
175
176 rstrip(value);
177
178 /*
179 * Valid name[=:]value pair found, call
180 * handler
181 */
182 strncpy0(prev_name, name, sizeof(prev_name));
183 if (handler(user, section, name, value) < 0 &&
184 !error) {
185 error = lineno;
186 }
187 }
188 else if (!error) {
189 /* No '=' or ':' found on name[=:]value line */
190 error = lineno;
191 }
192 }
193 }
194
195 #if !INI_USE_STACK
196 free(line);
197 #endif
198
199 return error;
200 }
201
202 /* See documentation in header file. */
203 LTTNG_HIDDEN
204 int ini_parse(const char* filename, ini_entry_handler handler, void* user)
205 {
206 FILE* file;
207 int error;
208
209 file = fopen(filename, "r");
210 if (!file) {
211 return -1;
212 }
213
214 error = ini_parse_file(file, handler, user);
215 fclose(file);
216 return error;
217 }
This page took 0.035843 seconds and 5 git commands to generate.