property.c revision 68509
140040Sjkh/* 240040Sjkh * 340040Sjkh * Simple property list handling code. 440040Sjkh * 540040Sjkh * Copyright (c) 1998 640040Sjkh * Jordan Hubbard. All rights reserved. 740040Sjkh * 840040Sjkh * Redistribution and use in source and binary forms, with or without 940040Sjkh * modification, are permitted provided that the following conditions 1040040Sjkh * are met: 1140040Sjkh * 1. Redistributions of source code must retain the above copyright 1240040Sjkh * notice, this list of conditions and the following disclaimer, 1340040Sjkh * verbatim and that no modifications are made prior to this 1440040Sjkh * point in the file. 1540040Sjkh * 2. Redistributions in binary form must reproduce the above copyright 1640040Sjkh * notice, this list of conditions and the following disclaimer in the 1740040Sjkh * documentation and/or other materials provided with the distribution. 1840040Sjkh * 1940040Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2040040Sjkh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2140040Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2240040Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR HIS PETS BE LIABLE 2340040Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2440040Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2540040Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 2640040Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2740040Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2840040Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2940040Sjkh * SUCH DAMAGE. 3040040Sjkh * 3168488Smurray * $FreeBSD: head/lib/libutil/property.c 68509 2000-11-09 00:28:22Z murray $ 3268488Smurray * 3340040Sjkh */ 3440040Sjkh 3540040Sjkh#include <ctype.h> 3640117Sjkh#include <unistd.h> 3740117Sjkh#include <stdlib.h> 3840050Sjkh#include <stdio.h> 3940040Sjkh#include <string.h> 4041291Sjkh#include <err.h> 4140050Sjkh#include <sys/types.h> 4240040Sjkh#include <libutil.h> 4340040Sjkh 4440040Sjkhstatic properties 4540040Sjkhproperty_alloc(char *name, char *value) 4640040Sjkh{ 4740040Sjkh properties n; 4840040Sjkh 4940040Sjkh n = (properties)malloc(sizeof(struct _property)); 5040040Sjkh n->next = NULL; 5140040Sjkh n->name = name ? strdup(name) : NULL; 5240040Sjkh n->value = value ? strdup(value) : NULL; 5340040Sjkh return n; 5440040Sjkh} 5540040Sjkh 5640040Sjkhproperties 5740109Sjkhproperties_read(int fd) 5840040Sjkh{ 5940040Sjkh properties head, ptr; 6068488Smurray char hold_n[PROPERTY_MAX_NAME + 1]; 6168488Smurray char hold_v[PROPERTY_MAX_VALUE + 1]; 6240040Sjkh char buf[BUFSIZ * 4]; 6340040Sjkh int bp, n, v, max; 6440040Sjkh enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state; 6541291Sjkh int ch = 0, blevel = 0; 6640040Sjkh 6740040Sjkh n = v = bp = max = 0; 6840040Sjkh head = ptr = NULL; 6940040Sjkh state = LOOK; 7040040Sjkh while (state != STOP) { 7140040Sjkh if (state != COMMIT) { 7240040Sjkh if (bp == max) 7340040Sjkh state = FILL; 7440040Sjkh else 7540040Sjkh ch = buf[bp++]; 7640040Sjkh } 7740040Sjkh switch(state) { 7840040Sjkh case FILL: 7940109Sjkh if ((max = read(fd, buf, sizeof buf)) <= 0) { 8040040Sjkh state = STOP; 8140040Sjkh break; 8240040Sjkh } 8340040Sjkh else { 8440040Sjkh state = LOOK; 8540040Sjkh ch = buf[0]; 8640040Sjkh bp = 1; 8740040Sjkh } 8840040Sjkh /* Fall through deliberately since we already have a character and state == LOOK */ 8940040Sjkh 9040040Sjkh case LOOK: 9140040Sjkh if (isspace(ch)) 9240040Sjkh continue; 9340040Sjkh /* Allow shell or lisp style comments */ 9440040Sjkh else if (ch == '#' || ch == ';') { 9540040Sjkh state = COMMENT; 9640040Sjkh continue; 9740040Sjkh } 9840040Sjkh else if (isalnum(ch) || ch == '_') { 9968488Smurray if (n >= PROPERTY_MAX_NAME) { 10040040Sjkh n = 0; 10140040Sjkh state = COMMENT; 10240040Sjkh } 10340040Sjkh else { 10440040Sjkh hold_n[n++] = ch; 10540040Sjkh state = NAME; 10640040Sjkh } 10740040Sjkh } 10840040Sjkh else 10940040Sjkh state = COMMENT; /* Ignore the rest of the line */ 11040040Sjkh break; 11140040Sjkh 11240040Sjkh case COMMENT: 11340040Sjkh if (ch == '\n') 11440040Sjkh state = LOOK; 11540040Sjkh break; 11640040Sjkh 11740040Sjkh case NAME: 11840040Sjkh if (ch == '\n' || !ch) { 11940040Sjkh hold_n[n] = '\0'; 12040040Sjkh hold_v[0] = '\0'; 12140040Sjkh v = n = 0; 12240040Sjkh state = COMMIT; 12340040Sjkh } 12440040Sjkh else if (isspace(ch)) 12540040Sjkh continue; 12640040Sjkh else if (ch == '=') { 12740040Sjkh hold_n[n] = '\0'; 12840040Sjkh v = n = 0; 12940040Sjkh state = VALUE; 13040040Sjkh } 13140040Sjkh else 13240040Sjkh hold_n[n++] = ch; 13340040Sjkh break; 13440040Sjkh 13540040Sjkh case VALUE: 13668509Smurray if (v == 0 && ch == '\n') { 13768509Smurray hold_v[v] = '\0'; 13868509Smurray v = n = 0; 13968509Smurray state = COMMIT; 14068509Smurray } 14168509Smurray else if (v == 0 && isspace(ch)) 14240040Sjkh continue; 14341291Sjkh else if (ch == '{') { 14440040Sjkh state = MVALUE; 14541291Sjkh ++blevel; 14641291Sjkh } 14740040Sjkh else if (ch == '\n' || !ch) { 14840040Sjkh hold_v[v] = '\0'; 14940040Sjkh v = n = 0; 15040040Sjkh state = COMMIT; 15140040Sjkh } 15240040Sjkh else { 15368488Smurray if (v >= PROPERTY_MAX_VALUE) { 15440040Sjkh state = COMMENT; 15540040Sjkh v = n = 0; 15640040Sjkh break; 15740040Sjkh } 15840040Sjkh else 15940040Sjkh hold_v[v++] = ch; 16040040Sjkh } 16140040Sjkh break; 16240040Sjkh 16340040Sjkh case MVALUE: 16440040Sjkh /* multiline value */ 16568488Smurray if (v >= PROPERTY_MAX_VALUE) { 16641291Sjkh warn("properties_read: value exceeds max length"); 16740040Sjkh state = COMMENT; 16840040Sjkh n = v = 0; 16940040Sjkh } 17041291Sjkh else if (ch == '}' && !--blevel) { 17140040Sjkh hold_v[v] = '\0'; 17240040Sjkh v = n = 0; 17340040Sjkh state = COMMIT; 17440040Sjkh } 17541291Sjkh else { 17640040Sjkh hold_v[v++] = ch; 17741291Sjkh if (ch == '{') 17841291Sjkh ++blevel; 17941291Sjkh } 18040040Sjkh break; 18140040Sjkh 18240040Sjkh case COMMIT: 18340040Sjkh if (!head) 18440040Sjkh head = ptr = property_alloc(hold_n, hold_v); 18540040Sjkh else { 18640040Sjkh ptr->next = property_alloc(hold_n, hold_v); 18740040Sjkh ptr = ptr->next; 18840040Sjkh } 18940040Sjkh state = LOOK; 19040040Sjkh v = n = 0; 19140040Sjkh break; 19240040Sjkh 19340040Sjkh case STOP: 19440040Sjkh /* we don't handle this here, but this prevents warnings */ 19540040Sjkh break; 19640040Sjkh } 19740040Sjkh } 19840040Sjkh return head; 19940040Sjkh} 20040040Sjkh 20140040Sjkhchar * 20240040Sjkhproperty_find(properties list, const char *name) 20340040Sjkh{ 20440040Sjkh if (!list || !name || !name[0]) 20540040Sjkh return NULL; 20640040Sjkh while (list) { 20740040Sjkh if (!strcmp(list->name, name)) 20840040Sjkh return list->value; 20940040Sjkh list = list->next; 21040040Sjkh } 21140040Sjkh return NULL; 21240040Sjkh} 21340040Sjkh 21440040Sjkhvoid 21540040Sjkhproperties_free(properties list) 21640040Sjkh{ 21740040Sjkh properties tmp; 21840040Sjkh 21940040Sjkh while (list) { 22040040Sjkh tmp = list->next; 22140040Sjkh if (list->name) 22240040Sjkh free(list->name); 22340040Sjkh if (list->value) 22440040Sjkh free(list->value); 22540040Sjkh free(list); 22640040Sjkh list = tmp; 22740040Sjkh } 22840040Sjkh} 229