15e53a4f9SPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
4b704025fSJordan K. Hubbard *
5b704025fSJordan K. Hubbard * Simple property list handling code.
6b704025fSJordan K. Hubbard *
7b704025fSJordan K. Hubbard * Copyright (c) 1998
8b704025fSJordan K. Hubbard * Jordan Hubbard. All rights reserved.
9b704025fSJordan K. Hubbard *
10b704025fSJordan K. Hubbard * Redistribution and use in source and binary forms, with or without
11b704025fSJordan K. Hubbard * modification, are permitted provided that the following conditions
12b704025fSJordan K. Hubbard * are met:
13b704025fSJordan K. Hubbard * 1. Redistributions of source code must retain the above copyright
14b704025fSJordan K. Hubbard * notice, this list of conditions and the following disclaimer,
15b704025fSJordan K. Hubbard * verbatim and that no modifications are made prior to this
16b704025fSJordan K. Hubbard * point in the file.
17b704025fSJordan K. Hubbard * 2. Redistributions in binary form must reproduce the above copyright
18b704025fSJordan K. Hubbard * notice, this list of conditions and the following disclaimer in the
19b704025fSJordan K. Hubbard * documentation and/or other materials provided with the distribution.
20b704025fSJordan K. Hubbard *
21b704025fSJordan K. Hubbard * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22b704025fSJordan K. Hubbard * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b704025fSJordan K. Hubbard * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b704025fSJordan K. Hubbard * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR HIS PETS BE LIABLE
25b704025fSJordan K. Hubbard * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b704025fSJordan K. Hubbard * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b704025fSJordan K. Hubbard * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
28b704025fSJordan K. Hubbard * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b704025fSJordan K. Hubbard * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b704025fSJordan K. Hubbard * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b704025fSJordan K. Hubbard * SUCH DAMAGE.
32b704025fSJordan K. Hubbard */
33b704025fSJordan K. Hubbard
3469761016SJordan K. Hubbard #include <sys/types.h>
350ebec5d3SMark Murray #include <ctype.h>
360ebec5d3SMark Murray #include <err.h>
37b704025fSJordan K. Hubbard #include <libutil.h>
380ebec5d3SMark Murray #include <stdio.h>
390ebec5d3SMark Murray #include <stdlib.h>
400ebec5d3SMark Murray #include <string.h>
410ebec5d3SMark Murray #include <unistd.h>
42b704025fSJordan K. Hubbard
43b704025fSJordan K. Hubbard static properties
property_alloc(char * name,char * value)44b704025fSJordan K. Hubbard property_alloc(char *name, char *value)
45b704025fSJordan K. Hubbard {
46b704025fSJordan K. Hubbard properties n;
47b704025fSJordan K. Hubbard
48779092a4SAndrey A. Chernov if ((n = (properties)malloc(sizeof(struct _property))) == NULL)
49779092a4SAndrey A. Chernov return (NULL);
50b704025fSJordan K. Hubbard n->next = NULL;
51779092a4SAndrey A. Chernov if (name != NULL) {
52779092a4SAndrey A. Chernov if ((n->name = strdup(name)) == NULL) {
53779092a4SAndrey A. Chernov free(n);
54779092a4SAndrey A. Chernov return (NULL);
55779092a4SAndrey A. Chernov }
56779092a4SAndrey A. Chernov } else
57779092a4SAndrey A. Chernov n->name = NULL;
58779092a4SAndrey A. Chernov if (value != NULL) {
59779092a4SAndrey A. Chernov if ((n->value = strdup(value)) == NULL) {
60779092a4SAndrey A. Chernov free(n->name);
61779092a4SAndrey A. Chernov free(n);
62779092a4SAndrey A. Chernov return (NULL);
63779092a4SAndrey A. Chernov }
64779092a4SAndrey A. Chernov } else
65779092a4SAndrey A. Chernov n->value = NULL;
66779092a4SAndrey A. Chernov return (n);
67b704025fSJordan K. Hubbard }
68b704025fSJordan K. Hubbard
69b704025fSJordan K. Hubbard properties
properties_read(int fd)7050dfa596SJordan K. Hubbard properties_read(int fd)
71b704025fSJordan K. Hubbard {
72b704025fSJordan K. Hubbard properties head, ptr;
73f9f81f78SMurray Stokely char hold_n[PROPERTY_MAX_NAME + 1];
74f9f81f78SMurray Stokely char hold_v[PROPERTY_MAX_VALUE + 1];
75b704025fSJordan K. Hubbard char buf[BUFSIZ * 4];
76b704025fSJordan K. Hubbard int bp, n, v, max;
77a54bb702SJohn Baldwin enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state, last_state;
78efbcb4aeSJordan K. Hubbard int ch = 0, blevel = 0;
79b704025fSJordan K. Hubbard
80b704025fSJordan K. Hubbard n = v = bp = max = 0;
81b704025fSJordan K. Hubbard head = ptr = NULL;
82a54bb702SJohn Baldwin state = last_state = LOOK;
83b704025fSJordan K. Hubbard while (state != STOP) {
84b704025fSJordan K. Hubbard if (state != COMMIT) {
85a54bb702SJohn Baldwin if (bp == max) {
86a54bb702SJohn Baldwin last_state = state;
87b704025fSJordan K. Hubbard state = FILL;
88a54bb702SJohn Baldwin } else
89b704025fSJordan K. Hubbard ch = buf[bp++];
90b704025fSJordan K. Hubbard }
91b704025fSJordan K. Hubbard switch(state) {
92b704025fSJordan K. Hubbard case FILL:
9333a155e4SAndrey A. Chernov if ((max = read(fd, buf, sizeof buf)) < 0) {
9433a155e4SAndrey A. Chernov properties_free(head);
9533a155e4SAndrey A. Chernov return (NULL);
9633a155e4SAndrey A. Chernov }
9733a155e4SAndrey A. Chernov if (max == 0) {
98b704025fSJordan K. Hubbard state = STOP;
9933a155e4SAndrey A. Chernov } else {
100a54bb702SJohn Baldwin /*
101a54bb702SJohn Baldwin * Restore the state from before the fill (which will be
102a54bb702SJohn Baldwin * initialised to LOOK for the first FILL). This ensures that
103a54bb702SJohn Baldwin * if we were part-way through eg., a VALUE state, when the
104a54bb702SJohn Baldwin * buffer ran out, that the previous operation will be allowed
105a54bb702SJohn Baldwin * to complete.
106a54bb702SJohn Baldwin */
107a54bb702SJohn Baldwin state = last_state;
108b704025fSJordan K. Hubbard ch = buf[0];
109a54bb702SJohn Baldwin bp = 0;
110b704025fSJordan K. Hubbard }
111a54bb702SJohn Baldwin continue;
112b704025fSJordan K. Hubbard
113b704025fSJordan K. Hubbard case LOOK:
114779092a4SAndrey A. Chernov if (isspace((unsigned char)ch))
115b704025fSJordan K. Hubbard continue;
116b704025fSJordan K. Hubbard /* Allow shell or lisp style comments */
117b704025fSJordan K. Hubbard else if (ch == '#' || ch == ';') {
118b704025fSJordan K. Hubbard state = COMMENT;
119b704025fSJordan K. Hubbard continue;
120b704025fSJordan K. Hubbard }
121779092a4SAndrey A. Chernov else if (isalnum((unsigned char)ch) || ch == '_') {
122f9f81f78SMurray Stokely if (n >= PROPERTY_MAX_NAME) {
123b704025fSJordan K. Hubbard n = 0;
124b704025fSJordan K. Hubbard state = COMMENT;
125b704025fSJordan K. Hubbard }
126b704025fSJordan K. Hubbard else {
127b704025fSJordan K. Hubbard hold_n[n++] = ch;
128b704025fSJordan K. Hubbard state = NAME;
129b704025fSJordan K. Hubbard }
130b704025fSJordan K. Hubbard }
131b704025fSJordan K. Hubbard else
132b704025fSJordan K. Hubbard state = COMMENT; /* Ignore the rest of the line */
133b704025fSJordan K. Hubbard break;
134b704025fSJordan K. Hubbard
135b704025fSJordan K. Hubbard case COMMENT:
136b704025fSJordan K. Hubbard if (ch == '\n')
137b704025fSJordan K. Hubbard state = LOOK;
138b704025fSJordan K. Hubbard break;
139b704025fSJordan K. Hubbard
140b704025fSJordan K. Hubbard case NAME:
141b704025fSJordan K. Hubbard if (ch == '\n' || !ch) {
142b704025fSJordan K. Hubbard hold_n[n] = '\0';
143b704025fSJordan K. Hubbard hold_v[0] = '\0';
144b704025fSJordan K. Hubbard v = n = 0;
145b704025fSJordan K. Hubbard state = COMMIT;
146b704025fSJordan K. Hubbard }
147779092a4SAndrey A. Chernov else if (isspace((unsigned char)ch))
148b704025fSJordan K. Hubbard continue;
149b704025fSJordan K. Hubbard else if (ch == '=') {
150b704025fSJordan K. Hubbard hold_n[n] = '\0';
151b704025fSJordan K. Hubbard v = n = 0;
152b704025fSJordan K. Hubbard state = VALUE;
153b704025fSJordan K. Hubbard }
154b704025fSJordan K. Hubbard else
155b704025fSJordan K. Hubbard hold_n[n++] = ch;
156b704025fSJordan K. Hubbard break;
157b704025fSJordan K. Hubbard
158b704025fSJordan K. Hubbard case VALUE:
15940863abaSMurray Stokely if (v == 0 && ch == '\n') {
16040863abaSMurray Stokely hold_v[v] = '\0';
16140863abaSMurray Stokely v = n = 0;
16240863abaSMurray Stokely state = COMMIT;
16340863abaSMurray Stokely }
164779092a4SAndrey A. Chernov else if (v == 0 && isspace((unsigned char)ch))
165b704025fSJordan K. Hubbard continue;
166efbcb4aeSJordan K. Hubbard else if (ch == '{') {
167b704025fSJordan K. Hubbard state = MVALUE;
168efbcb4aeSJordan K. Hubbard ++blevel;
169efbcb4aeSJordan K. Hubbard }
170b704025fSJordan K. Hubbard else if (ch == '\n' || !ch) {
171b704025fSJordan K. Hubbard hold_v[v] = '\0';
172b704025fSJordan K. Hubbard v = n = 0;
173b704025fSJordan K. Hubbard state = COMMIT;
174b704025fSJordan K. Hubbard }
175b704025fSJordan K. Hubbard else {
176f9f81f78SMurray Stokely if (v >= PROPERTY_MAX_VALUE) {
177b704025fSJordan K. Hubbard state = COMMENT;
178b704025fSJordan K. Hubbard v = n = 0;
179b704025fSJordan K. Hubbard break;
180b704025fSJordan K. Hubbard }
181b704025fSJordan K. Hubbard else
182b704025fSJordan K. Hubbard hold_v[v++] = ch;
183b704025fSJordan K. Hubbard }
184b704025fSJordan K. Hubbard break;
185b704025fSJordan K. Hubbard
186b704025fSJordan K. Hubbard case MVALUE:
187b704025fSJordan K. Hubbard /* multiline value */
188f9f81f78SMurray Stokely if (v >= PROPERTY_MAX_VALUE) {
189efbcb4aeSJordan K. Hubbard warn("properties_read: value exceeds max length");
190b704025fSJordan K. Hubbard state = COMMENT;
191b704025fSJordan K. Hubbard n = v = 0;
192b704025fSJordan K. Hubbard }
193efbcb4aeSJordan K. Hubbard else if (ch == '}' && !--blevel) {
194b704025fSJordan K. Hubbard hold_v[v] = '\0';
195b704025fSJordan K. Hubbard v = n = 0;
196b704025fSJordan K. Hubbard state = COMMIT;
197b704025fSJordan K. Hubbard }
198efbcb4aeSJordan K. Hubbard else {
199b704025fSJordan K. Hubbard hold_v[v++] = ch;
200efbcb4aeSJordan K. Hubbard if (ch == '{')
201efbcb4aeSJordan K. Hubbard ++blevel;
202efbcb4aeSJordan K. Hubbard }
203b704025fSJordan K. Hubbard break;
204b704025fSJordan K. Hubbard
205b704025fSJordan K. Hubbard case COMMIT:
206779092a4SAndrey A. Chernov if (head == NULL) {
207779092a4SAndrey A. Chernov if ((head = ptr = property_alloc(hold_n, hold_v)) == NULL)
208779092a4SAndrey A. Chernov return (NULL);
209779092a4SAndrey A. Chernov } else {
210779092a4SAndrey A. Chernov if ((ptr->next = property_alloc(hold_n, hold_v)) == NULL) {
211779092a4SAndrey A. Chernov properties_free(head);
212779092a4SAndrey A. Chernov return (NULL);
213779092a4SAndrey A. Chernov }
214b704025fSJordan K. Hubbard ptr = ptr->next;
215b704025fSJordan K. Hubbard }
216b704025fSJordan K. Hubbard state = LOOK;
217b704025fSJordan K. Hubbard v = n = 0;
218b704025fSJordan K. Hubbard break;
219b704025fSJordan K. Hubbard
220b704025fSJordan K. Hubbard case STOP:
221b704025fSJordan K. Hubbard /* we don't handle this here, but this prevents warnings */
222b704025fSJordan K. Hubbard break;
223b704025fSJordan K. Hubbard }
224b704025fSJordan K. Hubbard }
2255fe03abaSAndrey A. Chernov if (head == NULL && (head = property_alloc(NULL, NULL)) == NULL)
2265fe03abaSAndrey A. Chernov return (NULL);
2275fe03abaSAndrey A. Chernov
228779092a4SAndrey A. Chernov return (head);
229b704025fSJordan K. Hubbard }
230b704025fSJordan K. Hubbard
231b704025fSJordan K. Hubbard char *
property_find(properties list,const char * name)232b704025fSJordan K. Hubbard property_find(properties list, const char *name)
233b704025fSJordan K. Hubbard {
2345fe03abaSAndrey A. Chernov if (list == NULL || name == NULL || !name[0])
2355fe03abaSAndrey A. Chernov return (NULL);
2365fe03abaSAndrey A. Chernov while (list != NULL) {
2375fe03abaSAndrey A. Chernov if (list->name != NULL && strcmp(list->name, name) == 0)
2385fe03abaSAndrey A. Chernov return (list->value);
239b704025fSJordan K. Hubbard list = list->next;
240b704025fSJordan K. Hubbard }
2415fe03abaSAndrey A. Chernov return (NULL);
242b704025fSJordan K. Hubbard }
243b704025fSJordan K. Hubbard
244b704025fSJordan K. Hubbard void
properties_free(properties list)245b704025fSJordan K. Hubbard properties_free(properties list)
246b704025fSJordan K. Hubbard {
247b704025fSJordan K. Hubbard properties tmp;
248b704025fSJordan K. Hubbard
249b704025fSJordan K. Hubbard while (list) {
250b704025fSJordan K. Hubbard tmp = list->next;
251b704025fSJordan K. Hubbard if (list->name)
252b704025fSJordan K. Hubbard free(list->name);
253b704025fSJordan K. Hubbard if (list->value)
254b704025fSJordan K. Hubbard free(list->value);
255b704025fSJordan K. Hubbard free(list);
256b704025fSJordan K. Hubbard list = tmp;
257b704025fSJordan K. Hubbard }
258b704025fSJordan K. Hubbard }
259