liblcf
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ini.cpp
Go to the documentation of this file.
1 /*
2  * inih -- simple .INI file parser
3  *
4  * Go to the project home page for more info:
5  * http://code.google.com/p/inih/
6  *
7  * inih and INIReader are released under the New BSD license:
8  *
9  * Copyright (c) 2009, Brush Technology
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in the
18  * documentation and/or other materials provided with the distribution.
19  * * Neither the name of Brush Technology nor the names of its contributors
20  * may be used to endorse or promote products derived from this software
21  * without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
24  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
27  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <cstdio>
36 #include <cctype>
37 #include <cstring>
38 
39 #include "ini.h"
40 
41 #define MAX_LINE 200
42 #define MAX_SECTION 50
43 #define MAX_NAME 50
44 
50 static unsigned char* rstrip(unsigned char* s)
51 {
52  unsigned char* p = s + strlen((char*)s);
53  while (p > s && isspace(*--p))
54  *p = '\0';
55  return s;
56 }
57 
61 static char* lskip(const unsigned char* s)
62 {
63  while (*s && isspace(*s))
64  s++;
65  return (char*)s;
66 }
67 
73 static char* find_char_or_comment(const unsigned char* s, char c)
74 {
75  int was_whitespace = 0;
76  while (*s && *s != c && !(was_whitespace && *s == ';')) {
77  was_whitespace = isspace(*s);
78  s++;
79  }
80  return (char*)s;
81 }
82 
86 static char* strncpy0(char* dest, const char* src, size_t size)
87 {
88  strncpy(dest, src, size);
89  dest[size - 1] = '\0';
90  return dest;
91 }
92 
93 // See documentation in header file.
94 int ini_parse(const char* filename,
95  int (*handler)(void*, const char*, const char*, const char*),
96  void* user)
97 {
98  // Uses a fair bit of stack (use heap instead if you need to)
99  char line[MAX_LINE];
100  char section[MAX_SECTION] = "";
101  char prev_name[MAX_NAME] = "";
102 
103  FILE* file;
104  char* start;
105  char* end;
106  char* name;
107  char* value;
108  int lineno = 0;
109  int error = 0;
110 
111  file = fopen(filename, "r");
112  if (!file)
113  return -1;
114 
115  // Scan through file line by line
116  while (fgets(line, sizeof(line), file) != NULL) {
117  lineno++;
118  start = lskip(rstrip((unsigned char*)line));
119 
120 #if INI_ALLOW_MULTILINE
121  if (*prev_name && *start && start > line) {
122  // Non-black line with leading whitespace, treat as continuation
123  // of previous name's value (as per Python ConfigParser).
124  if (!handler(user, section, prev_name, start) && !error)
125  error = lineno;
126  }
127  else
128 #endif
129  if (*start == ';' || *start == '#') {
130  // Per Python ConfigParser, allow '#' comments at start of line
131  }
132  else if (*start == '[') {
133  // A "[section]" line
134  end = find_char_or_comment((unsigned char*)start + 1, ']');
135  if (*end == ']') {
136  *end = '\0';
137  strncpy0(section, start + 1, sizeof(section));
138  *prev_name = '\0';
139  }
140  else if (!error) {
141  // No ']' found on section line
142  error = lineno;
143  }
144  }
145  else if (*start && *start != ';') {
146  // Not a comment, must be a name=value pair
147  end = find_char_or_comment((unsigned char*)start, '=');
148  if (*end == '=') {
149  *end = '\0';
150  name = (char*)rstrip((unsigned char*)start);
151  value = lskip((unsigned char*)end + 1);
152  end = find_char_or_comment((unsigned char*)value, '\0');
153  if (*end == ';')
154  *end = '\0';
155  rstrip((unsigned char*)value);
156 
157  // Valid name=value pair found, call handler
158  strncpy0(prev_name, name, sizeof(prev_name));
159  if (!handler(user, section, name, value) && !error)
160  error = lineno;
161  }
162  else if (!error) {
163  // No '=' found on name=value line
164  error = lineno;
165  }
166  }
167  }
168 
169  fclose(file);
170 
171  return error;
172 }
static char * find_char_or_comment(const unsigned char *s, char c)
Definition: ini.cpp:73
#define MAX_NAME
Definition: ini.cpp:43
#define MAX_SECTION
Definition: ini.cpp:42
static char * lskip(const unsigned char *s)
Definition: ini.cpp:61
int ini_parse(const char *filename, int(*handler)(void *, const char *, const char *, const char *), void *user)
Definition: ini.cpp:94
#define MAX_LINE
Definition: ini.cpp:41
static char * strncpy0(char *dest, const char *src, size_t size)
Definition: ini.cpp:86
static unsigned char * rstrip(unsigned char *s)
Definition: ini.cpp:50