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