1*5e53a4f9SPedro F. Giffuni /*- 2*5e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*5e53a4f9SPedro 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 348719c58fSMatthew Dillon #include <sys/cdefs.h> 358719c58fSMatthew Dillon __FBSDID("$FreeBSD$"); 368719c58fSMatthew Dillon 3769761016SJordan K. Hubbard #include <sys/types.h> 380ebec5d3SMark Murray #include <ctype.h> 390ebec5d3SMark Murray #include <err.h> 40b704025fSJordan K. Hubbard #include <libutil.h> 410ebec5d3SMark Murray #include <stdio.h> 420ebec5d3SMark Murray #include <stdlib.h> 430ebec5d3SMark Murray #include <string.h> 440ebec5d3SMark Murray #include <unistd.h> 45b704025fSJordan K. Hubbard 46b704025fSJordan K. Hubbard static properties 47b704025fSJordan K. Hubbard property_alloc(char *name, char *value) 48b704025fSJordan K. Hubbard { 49b704025fSJordan K. Hubbard properties n; 50b704025fSJordan K. Hubbard 51779092a4SAndrey A. Chernov if ((n = (properties)malloc(sizeof(struct _property))) == NULL) 52779092a4SAndrey A. Chernov return (NULL); 53b704025fSJordan K. Hubbard n->next = NULL; 54779092a4SAndrey A. Chernov if (name != NULL) { 55779092a4SAndrey A. Chernov if ((n->name = strdup(name)) == NULL) { 56779092a4SAndrey A. Chernov free(n); 57779092a4SAndrey A. Chernov return (NULL); 58779092a4SAndrey A. Chernov } 59779092a4SAndrey A. Chernov } else 60779092a4SAndrey A. Chernov n->name = NULL; 61779092a4SAndrey A. Chernov if (value != NULL) { 62779092a4SAndrey A. Chernov if ((n->value = strdup(value)) == NULL) { 63779092a4SAndrey A. Chernov free(n->name); 64779092a4SAndrey A. Chernov free(n); 65779092a4SAndrey A. Chernov return (NULL); 66779092a4SAndrey A. Chernov } 67779092a4SAndrey A. Chernov } else 68779092a4SAndrey A. Chernov n->value = NULL; 69779092a4SAndrey A. Chernov return (n); 70b704025fSJordan K. Hubbard } 71b704025fSJordan K. Hubbard 72b704025fSJordan K. Hubbard properties 7350dfa596SJordan K. Hubbard properties_read(int fd) 74b704025fSJordan K. Hubbard { 75b704025fSJordan K. Hubbard properties head, ptr; 76f9f81f78SMurray Stokely char hold_n[PROPERTY_MAX_NAME + 1]; 77f9f81f78SMurray Stokely char hold_v[PROPERTY_MAX_VALUE + 1]; 78b704025fSJordan K. Hubbard char buf[BUFSIZ * 4]; 79b704025fSJordan K. Hubbard int bp, n, v, max; 80a54bb702SJohn Baldwin enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state, last_state; 81efbcb4aeSJordan K. Hubbard int ch = 0, blevel = 0; 82b704025fSJordan K. Hubbard 83b704025fSJordan K. Hubbard n = v = bp = max = 0; 84b704025fSJordan K. Hubbard head = ptr = NULL; 85a54bb702SJohn Baldwin state = last_state = LOOK; 86b704025fSJordan K. Hubbard while (state != STOP) { 87b704025fSJordan K. Hubbard if (state != COMMIT) { 88a54bb702SJohn Baldwin if (bp == max) { 89a54bb702SJohn Baldwin last_state = state; 90b704025fSJordan K. Hubbard state = FILL; 91a54bb702SJohn Baldwin } else 92b704025fSJordan K. Hubbard ch = buf[bp++]; 93b704025fSJordan K. Hubbard } 94b704025fSJordan K. Hubbard switch(state) { 95b704025fSJordan K. Hubbard case FILL: 9633a155e4SAndrey A. Chernov if ((max = read(fd, buf, sizeof buf)) < 0) { 9733a155e4SAndrey A. Chernov properties_free(head); 9833a155e4SAndrey A. Chernov return (NULL); 9933a155e4SAndrey A. Chernov } 10033a155e4SAndrey A. Chernov if (max == 0) { 101b704025fSJordan K. Hubbard state = STOP; 10233a155e4SAndrey A. Chernov } else { 103a54bb702SJohn Baldwin /* 104a54bb702SJohn Baldwin * Restore the state from before the fill (which will be 105a54bb702SJohn Baldwin * initialised to LOOK for the first FILL). This ensures that 106a54bb702SJohn Baldwin * if we were part-way through eg., a VALUE state, when the 107a54bb702SJohn Baldwin * buffer ran out, that the previous operation will be allowed 108a54bb702SJohn Baldwin * to complete. 109a54bb702SJohn Baldwin */ 110a54bb702SJohn Baldwin state = last_state; 111b704025fSJordan K. Hubbard ch = buf[0]; 112a54bb702SJohn Baldwin bp = 0; 113b704025fSJordan K. Hubbard } 114a54bb702SJohn Baldwin continue; 115b704025fSJordan K. Hubbard 116b704025fSJordan K. Hubbard case LOOK: 117779092a4SAndrey A. Chernov if (isspace((unsigned char)ch)) 118b704025fSJordan K. Hubbard continue; 119b704025fSJordan K. Hubbard /* Allow shell or lisp style comments */ 120b704025fSJordan K. Hubbard else if (ch == '#' || ch == ';') { 121b704025fSJordan K. Hubbard state = COMMENT; 122b704025fSJordan K. Hubbard continue; 123b704025fSJordan K. Hubbard } 124779092a4SAndrey A. Chernov else if (isalnum((unsigned char)ch) || ch == '_') { 125f9f81f78SMurray Stokely if (n >= PROPERTY_MAX_NAME) { 126b704025fSJordan K. Hubbard n = 0; 127b704025fSJordan K. Hubbard state = COMMENT; 128b704025fSJordan K. Hubbard } 129b704025fSJordan K. Hubbard else { 130b704025fSJordan K. Hubbard hold_n[n++] = ch; 131b704025fSJordan K. Hubbard state = NAME; 132b704025fSJordan K. Hubbard } 133b704025fSJordan K. Hubbard } 134b704025fSJordan K. Hubbard else 135b704025fSJordan K. Hubbard state = COMMENT; /* Ignore the rest of the line */ 136b704025fSJordan K. Hubbard break; 137b704025fSJordan K. Hubbard 138b704025fSJordan K. Hubbard case COMMENT: 139b704025fSJordan K. Hubbard if (ch == '\n') 140b704025fSJordan K. Hubbard state = LOOK; 141b704025fSJordan K. Hubbard break; 142b704025fSJordan K. Hubbard 143b704025fSJordan K. Hubbard case NAME: 144b704025fSJordan K. Hubbard if (ch == '\n' || !ch) { 145b704025fSJordan K. Hubbard hold_n[n] = '\0'; 146b704025fSJordan K. Hubbard hold_v[0] = '\0'; 147b704025fSJordan K. Hubbard v = n = 0; 148b704025fSJordan K. Hubbard state = COMMIT; 149b704025fSJordan K. Hubbard } 150779092a4SAndrey A. Chernov else if (isspace((unsigned char)ch)) 151b704025fSJordan K. Hubbard continue; 152b704025fSJordan K. Hubbard else if (ch == '=') { 153b704025fSJordan K. Hubbard hold_n[n] = '\0'; 154b704025fSJordan K. Hubbard v = n = 0; 155b704025fSJordan K. Hubbard state = VALUE; 156b704025fSJordan K. Hubbard } 157b704025fSJordan K. Hubbard else 158b704025fSJordan K. Hubbard hold_n[n++] = ch; 159b704025fSJordan K. Hubbard break; 160b704025fSJordan K. Hubbard 161b704025fSJordan K. Hubbard case VALUE: 16240863abaSMurray Stokely if (v == 0 && ch == '\n') { 16340863abaSMurray Stokely hold_v[v] = '\0'; 16440863abaSMurray Stokely v = n = 0; 16540863abaSMurray Stokely state = COMMIT; 16640863abaSMurray Stokely } 167779092a4SAndrey A. Chernov else if (v == 0 && isspace((unsigned char)ch)) 168b704025fSJordan K. Hubbard continue; 169efbcb4aeSJordan K. Hubbard else if (ch == '{') { 170b704025fSJordan K. Hubbard state = MVALUE; 171efbcb4aeSJordan K. Hubbard ++blevel; 172efbcb4aeSJordan K. Hubbard } 173b704025fSJordan K. Hubbard else if (ch == '\n' || !ch) { 174b704025fSJordan K. Hubbard hold_v[v] = '\0'; 175b704025fSJordan K. Hubbard v = n = 0; 176b704025fSJordan K. Hubbard state = COMMIT; 177b704025fSJordan K. Hubbard } 178b704025fSJordan K. Hubbard else { 179f9f81f78SMurray Stokely if (v >= PROPERTY_MAX_VALUE) { 180b704025fSJordan K. Hubbard state = COMMENT; 181b704025fSJordan K. Hubbard v = n = 0; 182b704025fSJordan K. Hubbard break; 183b704025fSJordan K. Hubbard } 184b704025fSJordan K. Hubbard else 185b704025fSJordan K. Hubbard hold_v[v++] = ch; 186b704025fSJordan K. Hubbard } 187b704025fSJordan K. Hubbard break; 188b704025fSJordan K. Hubbard 189b704025fSJordan K. Hubbard case MVALUE: 190b704025fSJordan K. Hubbard /* multiline value */ 191f9f81f78SMurray Stokely if (v >= PROPERTY_MAX_VALUE) { 192efbcb4aeSJordan K. Hubbard warn("properties_read: value exceeds max length"); 193b704025fSJordan K. Hubbard state = COMMENT; 194b704025fSJordan K. Hubbard n = v = 0; 195b704025fSJordan K. Hubbard } 196efbcb4aeSJordan K. Hubbard else if (ch == '}' && !--blevel) { 197b704025fSJordan K. Hubbard hold_v[v] = '\0'; 198b704025fSJordan K. Hubbard v = n = 0; 199b704025fSJordan K. Hubbard state = COMMIT; 200b704025fSJordan K. Hubbard } 201efbcb4aeSJordan K. Hubbard else { 202b704025fSJordan K. Hubbard hold_v[v++] = ch; 203efbcb4aeSJordan K. Hubbard if (ch == '{') 204efbcb4aeSJordan K. Hubbard ++blevel; 205efbcb4aeSJordan K. Hubbard } 206b704025fSJordan K. Hubbard break; 207b704025fSJordan K. Hubbard 208b704025fSJordan K. Hubbard case COMMIT: 209779092a4SAndrey A. Chernov if (head == NULL) { 210779092a4SAndrey A. Chernov if ((head = ptr = property_alloc(hold_n, hold_v)) == NULL) 211779092a4SAndrey A. Chernov return (NULL); 212779092a4SAndrey A. Chernov } else { 213779092a4SAndrey A. Chernov if ((ptr->next = property_alloc(hold_n, hold_v)) == NULL) { 214779092a4SAndrey A. Chernov properties_free(head); 215779092a4SAndrey A. Chernov return (NULL); 216779092a4SAndrey A. Chernov } 217b704025fSJordan K. Hubbard ptr = ptr->next; 218b704025fSJordan K. Hubbard } 219b704025fSJordan K. Hubbard state = LOOK; 220b704025fSJordan K. Hubbard v = n = 0; 221b704025fSJordan K. Hubbard break; 222b704025fSJordan K. Hubbard 223b704025fSJordan K. Hubbard case STOP: 224b704025fSJordan K. Hubbard /* we don't handle this here, but this prevents warnings */ 225b704025fSJordan K. Hubbard break; 226b704025fSJordan K. Hubbard } 227b704025fSJordan K. Hubbard } 2285fe03abaSAndrey A. Chernov if (head == NULL && (head = property_alloc(NULL, NULL)) == NULL) 2295fe03abaSAndrey A. Chernov return (NULL); 2305fe03abaSAndrey A. Chernov 231779092a4SAndrey A. Chernov return (head); 232b704025fSJordan K. Hubbard } 233b704025fSJordan K. Hubbard 234b704025fSJordan K. Hubbard char * 235b704025fSJordan K. Hubbard property_find(properties list, const char *name) 236b704025fSJordan K. Hubbard { 2375fe03abaSAndrey A. Chernov if (list == NULL || name == NULL || !name[0]) 2385fe03abaSAndrey A. Chernov return (NULL); 2395fe03abaSAndrey A. Chernov while (list != NULL) { 2405fe03abaSAndrey A. Chernov if (list->name != NULL && strcmp(list->name, name) == 0) 2415fe03abaSAndrey A. Chernov return (list->value); 242b704025fSJordan K. Hubbard list = list->next; 243b704025fSJordan K. Hubbard } 2445fe03abaSAndrey A. Chernov return (NULL); 245b704025fSJordan K. Hubbard } 246b704025fSJordan K. Hubbard 247b704025fSJordan K. Hubbard void 248b704025fSJordan K. Hubbard properties_free(properties list) 249b704025fSJordan K. Hubbard { 250b704025fSJordan K. Hubbard properties tmp; 251b704025fSJordan K. Hubbard 252b704025fSJordan K. Hubbard while (list) { 253b704025fSJordan K. Hubbard tmp = list->next; 254b704025fSJordan K. Hubbard if (list->name) 255b704025fSJordan K. Hubbard free(list->name); 256b704025fSJordan K. Hubbard if (list->value) 257b704025fSJordan K. Hubbard free(list->value); 258b704025fSJordan K. Hubbard free(list); 259b704025fSJordan K. Hubbard list = tmp; 260b704025fSJordan K. Hubbard } 261b704025fSJordan K. Hubbard } 262