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 * $FreeBSD: src/lib/libutil/property.c,v 1.5.6.1 2000/11/22 03:49:49 murray Exp $ 32 * $DragonFly: src/lib/libutil/property.c,v 1.2 2003/06/17 04:26:52 dillon Exp $ 33 * 34 */ 35 36 #include <ctype.h> 37 #include <unistd.h> 38 #include <stdlib.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <err.h> 42 #include <sys/types.h> 43 #include <libutil.h> 44 45 static properties 46 property_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 57 properties 58 properties_read(int fd) 59 { 60 properties head, ptr; 61 char hold_n[PROPERTY_MAX_NAME + 1]; 62 char hold_v[PROPERTY_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 >= PROPERTY_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 && ch == '\n') { 138 hold_v[v] = '\0'; 139 v = n = 0; 140 state = COMMIT; 141 } 142 else if (v == 0 && isspace(ch)) 143 continue; 144 else if (ch == '{') { 145 state = MVALUE; 146 ++blevel; 147 } 148 else if (ch == '\n' || !ch) { 149 hold_v[v] = '\0'; 150 v = n = 0; 151 state = COMMIT; 152 } 153 else { 154 if (v >= PROPERTY_MAX_VALUE) { 155 state = COMMENT; 156 v = n = 0; 157 break; 158 } 159 else 160 hold_v[v++] = ch; 161 } 162 break; 163 164 case MVALUE: 165 /* multiline value */ 166 if (v >= PROPERTY_MAX_VALUE) { 167 warn("properties_read: value exceeds max length"); 168 state = COMMENT; 169 n = v = 0; 170 } 171 else if (ch == '}' && !--blevel) { 172 hold_v[v] = '\0'; 173 v = n = 0; 174 state = COMMIT; 175 } 176 else { 177 hold_v[v++] = ch; 178 if (ch == '{') 179 ++blevel; 180 } 181 break; 182 183 case COMMIT: 184 if (!head) 185 head = ptr = property_alloc(hold_n, hold_v); 186 else { 187 ptr->next = property_alloc(hold_n, hold_v); 188 ptr = ptr->next; 189 } 190 state = LOOK; 191 v = n = 0; 192 break; 193 194 case STOP: 195 /* we don't handle this here, but this prevents warnings */ 196 break; 197 } 198 } 199 return head; 200 } 201 202 char * 203 property_find(properties list, const char *name) 204 { 205 if (!list || !name || !name[0]) 206 return NULL; 207 while (list) { 208 if (!strcmp(list->name, name)) 209 return list->value; 210 list = list->next; 211 } 212 return NULL; 213 } 214 215 void 216 properties_free(properties list) 217 { 218 properties tmp; 219 220 while (list) { 221 tmp = list->next; 222 if (list->name) 223 free(list->name); 224 if (list->value) 225 free(list->value); 226 free(list); 227 list = tmp; 228 } 229 } 230