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