property.c revision 40050
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(FILE *fp) 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 = fread(buf, 1, sizeof buf, fp)) <= 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 218