-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathconf.c
172 lines (149 loc) · 4.66 KB
/
conf.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* (c) 2008, Quest Software, Inc. All rights reserved. */
/*
* Simple key-value configuration file interface
*/
#include "common.h"
#include "conf.h"
#include "err.h"
#include "stream.h"
extern int verbose;
/* A configuration entry */
struct config {
char *key, *value;
struct config *next;
};
/* Prototypes */
static const struct config *config_get(const char *key);
static void config_load_stream(struct stream *stream);
/* A stack of configuration entries. New config entries are pushed onto the
* top of the stack. Searches are performed top-down into the stack. */
static struct config *Config;
/*------------------------------------------------------------
* Public functions
*/
/* Adds a key/value settings into the global configuration */
void
config_add(char *key, char *value)
{
struct config *config;
if (!(config = (struct config *)malloc(sizeof *config))) {
fprintf(stderr, "config_add: out of memory\n");
exit(1);
}
config->key = key;
config->value = value;
config->next = Config;
Config = config;
if (verbose > 2)
fprintf(stderr, "config_add: %s = %s\n", key, value);
}
/* Adds settings from a configuration file into the global configuration. */
void
config_load(const char *path)
{
struct stream stream;
if (verbose > 2)
fprintf(stderr, "config_load %s\n", path);
if (!stream_init_path(&stream, path)) {
if (verbose)
warn("%s", path);
return;
}
config_load_stream(&stream);
stream_fini(&stream);
}
/* Returns a configuration value as an integer.
* Returns def_value if no prior configuration is found.
* The strings 'yes', 'true', and 'on' are converted to 1.
* Numbers beginning with 0x are converted using base 16.
* Numbers beginning with 0 are converted using base 8.
* Non-numeric digits are otherwise ignored.
* A value with no digits is returned as zero. */
long
config_get_int(const char *key, long def_value)
{
const struct config *config;
if (!(config = config_get(key)))
return def_value;
if (strcmp(config->value, "yes") == 0 ||
strcmp(config->value, "true") == 0 ||
strcmp(config->value, "on") == 0)
return 1;
return strtol(config->value, NULL, 0);
}
/* Returns a configuration value as a nul-terminated C string.
* Returns def_value if the configuration is not found.
* Caller must NOT free or alter the returned string. */
const char *
config_get_string(const char *key, const char *def_value)
{
const struct config *config;
if (!(config = config_get(key)))
return def_value;
return config->value;
}
/* Returns nonzero if a configuration setting is set explicitly,
* or zero if it is not set.
*/
int
config_is_set(const char *key)
{
if (config_get(key))
return 1;
return 0;
}
/*------------------------------------------------------------
* Private config functions
*/
/* Returns a configuration entry for the given key, or NULL if not found */
static const struct config *
config_get(const char *key)
{
struct config *config;
for (config = Config; config; config = config->next)
if (strcmp(key, config->key) == 0)
return config;
return NULL;
}
/* Loads configuration statements from the stream into the global Config */
static void
config_load_stream(struct stream *stream)
{
char *key, *value;
struct buffer buffer;
buffer_init(&buffer);
#define WHITESPACE " \t"
#define ENDOFLINE "\n\r"
for (;;) {
/* Ignore to the end of the previous line */
stream_while(stream, ENDOFLINE, NULL); /* skip line end(s) */
stream_while(stream, WHITESPACE, NULL); /* skip lead whitespace */
if (!stream_ok(stream)) /* check for end of file */
break;
if (stream_nextch(stream) == '#') { /* comments start with # */
stream_until(stream, ENDOFLINE, NULL); /* skip to end of line */
continue;
}
buffer.len = 0;
stream_until(stream, "#=" WHITESPACE, &buffer); /* read key word */
if (!buffer.len) {
stream_error(stream, "missing key");
stream_until(stream, ENDOFLINE, NULL); /* skip to end of line */
continue;
}
stream_while(stream, WHITESPACE, NULL); /* skip whitespace */
if (stream_nextch(stream) != '=') { /* expect '=' */
stream_error(stream, "expected '='");
stream_until(stream, ENDOFLINE, NULL); /* skip to end of line */
continue;
}
stream_getch(stream); /* skip '=' */
key = buffer_string(&buffer); /* also clears buffer */
stream_while(stream, WHITESPACE, NULL); /* skip whitespace */
stream_until(stream, "#" ENDOFLINE, &buffer); /* read value */
buffer_rtrim(&buffer, WHITESPACE); /* remove trailing space */
value = buffer_string(&buffer); /* extract value */
config_add(key, value);
}
buffer_fini(&buffer);
}