property.c revision 40109
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 <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <sys/types.h>
38#include <libutil.h>
39
40#define MAX_NAME	64
41#define MAX_VALUE	512
42
43static properties
44property_alloc(char *name, char *value)
45{
46    properties n;
47
48    n = (properties)malloc(sizeof(struct _property));
49    n->next = NULL;
50    n->name = name ? strdup(name) : NULL;
51    n->value = value ? strdup(value) : NULL;
52    return n;
53}
54
55properties
56properties_read(int fd)
57{
58    properties head, ptr;
59    char hold_n[MAX_NAME + 1];
60    char hold_v[MAX_VALUE + 1];
61    char buf[BUFSIZ * 4];
62    int bp, n, v, max;
63    enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state;
64    int ch = 0;
65
66    n = v = bp = max = 0;
67    head = ptr = NULL;
68    state = LOOK;
69    while (state != STOP) {
70	if (state != COMMIT) {
71	    if (bp == max)
72		state = FILL;
73	    else
74		ch = buf[bp++];
75	}
76	switch(state) {
77	case FILL:
78	    if ((max = read(fd, buf, sizeof buf)) <= 0) {
79		state = STOP;
80		break;
81	    }
82	    else {
83		state = LOOK;
84		ch = buf[0];
85		bp = 1;
86	    }
87	    /* Fall through deliberately since we already have a character and state == LOOK */
88
89	case LOOK:
90	    if (isspace(ch))
91		continue;
92	    /* Allow shell or lisp style comments */
93	    else if (ch == '#' || ch == ';') {
94		state = COMMENT;
95		continue;
96	    }
97	    else if (isalnum(ch) || ch == '_') {
98		if (n >= MAX_NAME) {
99		    n = 0;
100		    state = COMMENT;
101		}
102		else {
103		    hold_n[n++] = ch;
104		    state = NAME;
105		}
106	    }
107	    else
108		state = COMMENT;	/* Ignore the rest of the line */
109	    break;
110
111	case COMMENT:
112	    if (ch == '\n')
113		state = LOOK;
114	    break;
115
116	case NAME:
117	    if (ch == '\n' || !ch) {
118		hold_n[n] = '\0';
119		hold_v[0] = '\0';
120		v = n = 0;
121		state = COMMIT;
122	    }
123	    else if (isspace(ch))
124		continue;
125	    else if (ch == '=') {
126		hold_n[n] = '\0';
127		v = n = 0;
128		state = VALUE;
129	    }
130	    else
131		hold_n[n++] = ch;
132	    break;
133
134	case VALUE:
135	    if (v == 0 && isspace(ch))
136		continue;
137	    else if (ch == '{')
138		state = MVALUE;
139	    else if (ch == '\n' || !ch) {
140		hold_v[v] = '\0';
141		v = n = 0;
142		state = COMMIT;
143	    }
144	    else {
145		if (v >= MAX_VALUE) {
146		    state = COMMENT;
147		    v = n = 0;
148		    break;
149		}
150		else
151		    hold_v[v++] = ch;
152	    }
153	    break;
154
155	case MVALUE:
156	    /* multiline value */
157	    if (v >= MAX_VALUE) {
158		state = COMMENT;
159		n = v = 0;
160	    }
161	    else if (ch == '}') {
162		hold_v[v] = '\0';
163		v = n = 0;
164		state = COMMIT;
165	    }
166	    else
167		hold_v[v++] = ch;
168	    break;
169
170	case COMMIT:
171	    if (!head)
172		head = ptr = property_alloc(hold_n, hold_v);
173	    else {
174		ptr->next = property_alloc(hold_n, hold_v);
175		ptr = ptr->next;
176	    }
177	    state = LOOK;
178	    v = n = 0;
179	    break;
180
181	case STOP:
182	    /* we don't handle this here, but this prevents warnings */
183	    break;
184	}
185    }
186    return head;
187}
188
189char *
190property_find(properties list, const char *name)
191{
192    if (!list || !name || !name[0])
193	return NULL;
194    while (list) {
195	if (!strcmp(list->name, name))
196	    return list->value;
197	list = list->next;
198    }
199    return NULL;
200}
201
202void
203properties_free(properties list)
204{
205    properties tmp;
206
207    while (list) {
208	tmp = list->next;
209	if (list->name)
210	    free(list->name);
211	if (list->value)
212	    free(list->value);
213	free(list);
214	list = tmp;
215    }
216}
217