property.c revision 40040
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 *
3140040Sjkh */
3240040Sjkh
3340040Sjkh#include <ctype.h>
3440040Sjkh#include <stdlib.h>
3540040Sjkh#include <string.h>
3640040Sjkh#include <libutil.h>
3740040Sjkh
3840040Sjkh#define MAX_NAME	64
3940040Sjkh#define MAX_VALUE	512
4040040Sjkh
4140040Sjkhstatic properties
4240040Sjkhproperty_alloc(char *name, char *value)
4340040Sjkh{
4440040Sjkh    properties n;
4540040Sjkh
4640040Sjkh    n = (properties)malloc(sizeof(struct _property));
4740040Sjkh    n->next = NULL;
4840040Sjkh    n->name = name ? strdup(name) : NULL;
4940040Sjkh    n->value = value ? strdup(value) : NULL;
5040040Sjkh    return n;
5140040Sjkh}
5240040Sjkh
5340040Sjkhproperties
5440040Sjkhproperties_read(FILE *fp)
5540040Sjkh{
5640040Sjkh    properties head, ptr;
5740040Sjkh    char hold_n[MAX_NAME + 1];
5840040Sjkh    char hold_v[MAX_VALUE + 1];
5940040Sjkh    char buf[BUFSIZ * 4];
6040040Sjkh    int bp, n, v, max;
6140040Sjkh    enum { LOOK, COMMENT, NAME, VALUE, MVALUE, COMMIT, FILL, STOP } state;
6240040Sjkh    int ch = 0;
6340040Sjkh
6440040Sjkh    n = v = bp = max = 0;
6540040Sjkh    head = ptr = NULL;
6640040Sjkh    state = LOOK;
6740040Sjkh    while (state != STOP) {
6840040Sjkh	if (state != COMMIT) {
6940040Sjkh	    if (bp == max)
7040040Sjkh		state = FILL;
7140040Sjkh	    else
7240040Sjkh		ch = buf[bp++];
7340040Sjkh	}
7440040Sjkh	switch(state) {
7540040Sjkh	case FILL:
7640040Sjkh	    if ((max = fread(buf, 1, sizeof buf, fp)) <= 0) {
7740040Sjkh		state = STOP;
7840040Sjkh		break;
7940040Sjkh	    }
8040040Sjkh	    else {
8140040Sjkh		state = LOOK;
8240040Sjkh		ch = buf[0];
8340040Sjkh		bp = 1;
8440040Sjkh	    }
8540040Sjkh	    /* Fall through deliberately since we already have a character and state == LOOK */
8640040Sjkh
8740040Sjkh	case LOOK:
8840040Sjkh	    if (isspace(ch))
8940040Sjkh		continue;
9040040Sjkh	    /* Allow shell or lisp style comments */
9140040Sjkh	    else if (ch == '#' || ch == ';') {
9240040Sjkh		state = COMMENT;
9340040Sjkh		continue;
9440040Sjkh	    }
9540040Sjkh	    else if (isalnum(ch) || ch == '_') {
9640040Sjkh		if (n >= MAX_NAME) {
9740040Sjkh		    n = 0;
9840040Sjkh		    state = COMMENT;
9940040Sjkh		}
10040040Sjkh		else {
10140040Sjkh		    hold_n[n++] = ch;
10240040Sjkh		    state = NAME;
10340040Sjkh		}
10440040Sjkh	    }
10540040Sjkh	    else
10640040Sjkh		state = COMMENT;	/* Ignore the rest of the line */
10740040Sjkh	    break;
10840040Sjkh
10940040Sjkh	case COMMENT:
11040040Sjkh	    if (ch == '\n')
11140040Sjkh		state = LOOK;
11240040Sjkh	    break;
11340040Sjkh
11440040Sjkh	case NAME:
11540040Sjkh	    if (ch == '\n' || !ch) {
11640040Sjkh		hold_n[n] = '\0';
11740040Sjkh		hold_v[0] = '\0';
11840040Sjkh		v = n = 0;
11940040Sjkh		state = COMMIT;
12040040Sjkh	    }
12140040Sjkh	    else if (isspace(ch))
12240040Sjkh		continue;
12340040Sjkh	    else if (ch == '=') {
12440040Sjkh		hold_n[n] = '\0';
12540040Sjkh		v = n = 0;
12640040Sjkh		state = VALUE;
12740040Sjkh	    }
12840040Sjkh	    else
12940040Sjkh		hold_n[n++] = ch;
13040040Sjkh	    break;
13140040Sjkh
13240040Sjkh	case VALUE:
13340040Sjkh	    if (v == 0 && isspace(ch))
13440040Sjkh		continue;
13540040Sjkh	    else if (ch == '{')
13640040Sjkh		state = MVALUE;
13740040Sjkh	    else if (ch == '\n' || !ch) {
13840040Sjkh		hold_v[v] = '\0';
13940040Sjkh		v = n = 0;
14040040Sjkh		state = COMMIT;
14140040Sjkh	    }
14240040Sjkh	    else {
14340040Sjkh		if (v >= MAX_VALUE) {
14440040Sjkh		    state = COMMENT;
14540040Sjkh		    v = n = 0;
14640040Sjkh		    break;
14740040Sjkh		}
14840040Sjkh		else
14940040Sjkh		    hold_v[v++] = ch;
15040040Sjkh	    }
15140040Sjkh	    break;
15240040Sjkh
15340040Sjkh	case MVALUE:
15440040Sjkh	    /* multiline value */
15540040Sjkh	    if (v >= MAX_VALUE) {
15640040Sjkh		state = COMMENT;
15740040Sjkh		n = v = 0;
15840040Sjkh	    }
15940040Sjkh	    else if (ch == '}') {
16040040Sjkh		hold_v[v] = '\0';
16140040Sjkh		v = n = 0;
16240040Sjkh		state = COMMIT;
16340040Sjkh	    }
16440040Sjkh	    else
16540040Sjkh		hold_v[v++] = ch;
16640040Sjkh	    break;
16740040Sjkh
16840040Sjkh	case COMMIT:
16940040Sjkh	    if (!head)
17040040Sjkh		head = ptr = property_alloc(hold_n, hold_v);
17140040Sjkh	    else {
17240040Sjkh		ptr->next = property_alloc(hold_n, hold_v);
17340040Sjkh		ptr = ptr->next;
17440040Sjkh	    }
17540040Sjkh	    state = LOOK;
17640040Sjkh	    v = n = 0;
17740040Sjkh	    break;
17840040Sjkh
17940040Sjkh	case STOP:
18040040Sjkh	    /* we don't handle this here, but this prevents warnings */
18140040Sjkh	    break;
18240040Sjkh	}
18340040Sjkh    }
18440040Sjkh    return head;
18540040Sjkh}
18640040Sjkh
18740040Sjkhchar *
18840040Sjkhproperty_find(properties list, const char *name)
18940040Sjkh{
19040040Sjkh    if (!list || !name || !name[0])
19140040Sjkh	return NULL;
19240040Sjkh    while (list) {
19340040Sjkh	if (!strcmp(list->name, name))
19440040Sjkh	    return list->value;
19540040Sjkh	list = list->next;
19640040Sjkh    }
19740040Sjkh    return NULL;
19840040Sjkh}
19940040Sjkh
20040040Sjkhvoid
20140040Sjkhproperties_free(properties list)
20240040Sjkh{
20340040Sjkh    properties tmp;
20440040Sjkh
20540040Sjkh    while (list) {
20640040Sjkh	tmp = list->next;
20740040Sjkh	if (list->name)
20840040Sjkh	    free(list->name);
20940040Sjkh	if (list->value)
21040040Sjkh	    free(list->value);
21140040Sjkh	free(list);
21240040Sjkh	list = tmp;
21340040Sjkh    }
21440040Sjkh}
21540040Sjkh
216