property.c revision 41291
1/*
2 *
3 * Simple property list handling code.
4 *
5 * Copyright (c) 1998
6 *	Jordan Hubbard.  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
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer,
13 *    verbatim and that no modifications are made prior to this
14 *    point in the file.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR HIS PETS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 */
32
33#include <ctype.h>
34#include <unistd.h>
35#include <stdlib.h>
36#include <stdio.h>
37#include <string.h>
38#include <err.h>
39#include <sys/types.h>
40#include <libutil.h>
41
42#define MAX_NAME	64
43#define MAX_VALUE	512
44
45static properties
46property_alloc(char *name, char *value)
47{
48    properties n;
49
50    n = (properties)malloc(sizeof(struct _property));
51    n->next = NULL;
52    n->name = name ? strdup(name) : NULL;
53    n->value = value ? strdup(value) : NULL;
54    return n;
55}
56
57properties
58properties_read(int fd)
59{
60    properties head, ptr;
61    char hold_n[MAX_NAME + 1];
62    char hold_v[MAX_VALUE + 1];
63    char buf[BUFSIZ * 4];
64    int bp, n, v, max;
65    enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state;
66    int ch = 0, blevel = 0;
67
68    n = v = bp = max = 0;
69    head = ptr = NULL;
70    state = LOOK;
71    while (state != STOP) {
72	if (state != COMMIT) {
73	    if (bp == max)
74		state = FILL;
75	    else
76		ch = buf[bp++];
77	}
78	switch(state) {
79	case FILL:
80	    if ((max = read(fd, buf, sizeof buf)) <= 0) {
81		state = STOP;
82		break;
83	    }
84	    else {
85		state = LOOK;
86		ch = buf[0];
87		bp = 1;
88	    }
89	    /* Fall through deliberately since we already have a character and state == LOOK */
90
91	case LOOK:
92	    if (isspace(ch))
93		continue;
94	    /* Allow shell or lisp style comments */
95	    else if (ch == '#' || ch == ';') {
96		state = COMMENT;
97		continue;
98	    }
99	    else if (isalnum(ch) || ch == '_') {
100		if (n >= MAX_NAME) {
101		    n = 0;
102		    state = COMMENT;
103		}
104		else {
105		    hold_n[n++] = ch;
106		    state = NAME;
107		}
108	    }
109	    else
110		state = COMMENT;	/* Ignore the rest of the line */
111	    break;
112
113	case COMMENT:
114	    if (ch == '\n')
115		state = LOOK;
116	    break;
117
118	case NAME:
119	    if (ch == '\n' || !ch) {
120		hold_n[n] = '\0';
121		hold_v[0] = '\0';
122		v = n = 0;
123		state = COMMIT;
124	    }
125	    else if (isspace(ch))
126		continue;
127	    else if (ch == '=') {
128		hold_n[n] = '\0';
129		v = n = 0;
130		state = VALUE;
131	    }
132	    else
133		hold_n[n++] = ch;
134	    break;
135
136	case VALUE:
137	    if (v == 0 && isspace(ch))
138		continue;
139	    else if (ch == '{') {
140		state = MVALUE;
141		++blevel;
142	    }
143	    else if (ch == '\n' || !ch) {
144		hold_v[v] = '\0';
145		v = n = 0;
146		state = COMMIT;
147	    }
148	    else {
149		if (v >= MAX_VALUE) {
150		    state = COMMENT;
151		    v = n = 0;
152		    break;
153		}
154		else
155		    hold_v[v++] = ch;
156	    }
157	    break;
158
159	case MVALUE:
160	    /* multiline value */
161	    if (v >= MAX_VALUE) {
162		warn("properties_read: value exceeds max length");
163		state = COMMENT;
164		n = v = 0;
165	    }
166	    else if (ch == '}' && !--blevel) {
167		hold_v[v] = '\0';
168		v = n = 0;
169		state = COMMIT;
170	    }
171	    else {
172		hold_v[v++] = ch;
173		if (ch == '{')
174		    ++blevel;
175	    }
176	    break;
177
178	case COMMIT:
179	    if (!head)
180		head = ptr = property_alloc(hold_n, hold_v);
181	    else {
182		ptr->next = property_alloc(hold_n, hold_v);
183		ptr = ptr->next;
184	    }
185	    state = LOOK;
186	    v = n = 0;
187	    break;
188
189	case STOP:
190	    /* we don't handle this here, but this prevents warnings */
191	    break;
192	}
193    }
194    return head;
195}
196
197char *
198property_find(properties list, const char *name)
199{
200    if (!list || !name || !name[0])
201	return NULL;
202    while (list) {
203	if (!strcmp(list->name, name))
204	    return list->value;
205	list = list->next;
206    }
207    return NULL;
208}
209
210void
211properties_free(properties list)
212{
213    properties tmp;
214
215    while (list) {
216	tmp = list->next;
217	if (list->name)
218	    free(list->name);
219	if (list->value)
220	    free(list->value);
221	free(list);
222	list = tmp;
223    }
224}
225