lcDB.c revision 9c019ec5
11ab64890Smrg/*
21ab64890Smrg *
31ab64890Smrg * Copyright IBM Corporation 1993
41ab64890Smrg *
51ab64890Smrg * All Rights Reserved
61ab64890Smrg *
71ab64890Smrg * License to use, copy, modify, and distribute this software and its
81ab64890Smrg * documentation for any purpose and without fee is hereby granted,
91ab64890Smrg * provided that the above copyright notice appear in all copies and that
101ab64890Smrg * both that copyright notice and this permission notice appear in
111ab64890Smrg * supporting documentation, and that the name of IBM not be
121ab64890Smrg * used in advertising or publicity pertaining to distribution of the
131ab64890Smrg * software without specific, written prior permission.
141ab64890Smrg *
151ab64890Smrg * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1661b2299dSmrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS, AND
171ab64890Smrg * NONINFRINGEMENT OF THIRD PARTY RIGHTS, IN NO EVENT SHALL
181ab64890Smrg * IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
191ab64890Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
201ab64890Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
211ab64890Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
221ab64890Smrg * SOFTWARE.
231ab64890Smrg *
241ab64890Smrg*/
251ab64890Smrg/*
261ab64890Smrg *  (c) Copyright 1995 FUJITSU LIMITED
271ab64890Smrg *  This is source code modified by FUJITSU LIMITED under the Joint
281ab64890Smrg *  Development Agreement for the CDE/Motif PST.
291ab64890Smrg */
301ab64890Smrg
311ab64890Smrg
321ab64890Smrg
331ab64890Smrg#ifndef	NOT_X_ENV
341ab64890Smrg
351ab64890Smrg#ifdef HAVE_CONFIG_H
361ab64890Smrg#include <config.h>
371ab64890Smrg#endif
381ab64890Smrg#include <X11/Xlib.h>
391ab64890Smrg#include <X11/Xresource.h>
401ab64890Smrg#include "Xlibint.h"
411ab64890Smrg#include "XlcPubI.h"
42258a0ebeSmrg#include "reallocarray.h"
431ab64890Smrg
441ab64890Smrg#else	/* NOT_X_ENV */
451ab64890Smrg
461ab64890Smrg#define	Xmalloc	malloc
471ab64890Smrg#define	Xrealloc	realloc
481ab64890Smrg#define	Xfree	free
491ab64890Smrg
501ab64890Smrg#endif	/* NOT_X_ENV */
511ab64890Smrg
521ab64890Smrg/* specifying NOT_X_ENV allows users to just use
531ab64890Smrg   the database parsing routine. */
541ab64890Smrg/* For UDC/VW */
551ab64890Smrg#ifndef	BUFSIZE
561ab64890Smrg#define	BUFSIZE	2048
571ab64890Smrg#endif
581ab64890Smrg
591ab64890Smrg#ifdef COMMENT
601ab64890Smrg#ifdef  BUFSIZE
611ab64890Smrg#undef BUFSIZE
621ab64890Smrg#endif
631ab64890Smrg#define BUFSIZE 6144 /* 2048*3 */
641ab64890Smrg#endif
651ab64890Smrg
661ab64890Smrg#include <stdio.h>
671ab64890Smrg
681ab64890Smrgtypedef struct _DatabaseRec {
691ab64890Smrg    char *category;
701ab64890Smrg    char *name;
711ab64890Smrg    char **value;
721ab64890Smrg    int value_num;
731ab64890Smrg    struct _DatabaseRec *next;
741ab64890Smrg} DatabaseRec, *Database;
751ab64890Smrg
761ab64890Smrgtypedef enum {
771ab64890Smrg    S_NULL,	/* outside category */
781ab64890Smrg    S_CATEGORY,	/* inside category */
791ab64890Smrg    S_NAME,	/* has name, expecting values */
801ab64890Smrg    S_VALUE
811ab64890Smrg} ParseState;
821ab64890Smrg
831ab64890Smrgtypedef enum {
841ab64890Smrg    T_NEWLINE,
851ab64890Smrg    T_COMMENT,
861ab64890Smrg    T_SEMICOLON,
871ab64890Smrg    T_DOUBLE_QUOTE,
881ab64890Smrg    T_LEFT_BRACE,
891ab64890Smrg    T_RIGHT_BRACE,
901ab64890Smrg    T_SPACE,
911ab64890Smrg    T_TAB,
921ab64890Smrg    T_BACKSLASH,
931ab64890Smrg    T_NUMERIC_HEX,
941ab64890Smrg    T_NUMERIC_DEC,
951ab64890Smrg    T_NUMERIC_OCT,
961ab64890Smrg    T_DEFAULT
971ab64890Smrg} Token;
981ab64890Smrg
991ab64890Smrgtypedef struct {
1001ab64890Smrg    Token token;	/* token id */
1011ab64890Smrg    int len;		/* length of token sequence */
1021ab64890Smrg} TokenTable;
1031ab64890Smrg
1041ab64890Smrgstatic int f_newline (const char *str, Token token, Database *db);
1051ab64890Smrgstatic int f_comment (const char *str, Token token, Database *db);
1061ab64890Smrgstatic int f_semicolon (const char *str, Token token, Database *db);
1071ab64890Smrgstatic int f_double_quote (const char *str, Token token, Database *db);
1081ab64890Smrgstatic int f_left_brace (const char *str, Token token, Database *db);
1091ab64890Smrgstatic int f_right_brace (const char *str, Token token, Database *db);
1101ab64890Smrgstatic int f_white (const char *str, Token token, Database *db);
1111ab64890Smrgstatic int f_backslash (const char *str, Token token, Database *db);
1121ab64890Smrgstatic int f_numeric (const char *str, Token token, Database *db);
1131ab64890Smrgstatic int f_default (const char *str, Token token, Database *db);
1141ab64890Smrg
1151ab64890Smrgstatic const TokenTable token_tbl[] = {
1161ab64890Smrg    { T_NEWLINE,      1 },
1171ab64890Smrg    { T_COMMENT,      1 },
1181ab64890Smrg    { T_SEMICOLON,    1 },
1191ab64890Smrg    { T_DOUBLE_QUOTE, 1 },
1201ab64890Smrg    { T_LEFT_BRACE,   1 },
1211ab64890Smrg    { T_RIGHT_BRACE,  1 },
1221ab64890Smrg    { T_SPACE,        1 },
1231ab64890Smrg    { T_TAB,          1 },
1241ab64890Smrg    { T_BACKSLASH,    1 },
1251ab64890Smrg    { T_NUMERIC_HEX,  2 },
1261ab64890Smrg    { T_NUMERIC_DEC,  2 },
1271ab64890Smrg    { T_NUMERIC_OCT,  2 },
1281ab64890Smrg    { T_DEFAULT,      1 } /* any character */
1291ab64890Smrg};
1301ab64890Smrg
1311ab64890Smrg#define	SYM_CR          '\r'
1321ab64890Smrg#define	SYM_NEWLINE	'\n'
1331ab64890Smrg#define	SYM_COMMENT	'#'
1341ab64890Smrg#define	SYM_SEMICOLON	';'
1351ab64890Smrg#define	SYM_DOUBLE_QUOTE	'"'
1361ab64890Smrg#define	SYM_LEFT_BRACE	'{'
1371ab64890Smrg#define	SYM_RIGHT_BRACE	'}'
1381ab64890Smrg#define	SYM_SPACE	' '
1391ab64890Smrg#define	SYM_TAB		'\t'
1401ab64890Smrg#define	SYM_BACKSLASH	'\\'
1411ab64890Smrg
1421ab64890Smrg/************************************************************************/
1431ab64890Smrg
1441ab64890Smrg#define MAX_NAME_NEST	64
1451ab64890Smrg
1461ab64890Smrgtypedef struct {
1471ab64890Smrg    ParseState pre_state;
1481ab64890Smrg    char *category;
1491ab64890Smrg    char *name[MAX_NAME_NEST];
1501ab64890Smrg    int nest_depth;
1511ab64890Smrg    char **value;
1521ab64890Smrg    int value_len;
1531ab64890Smrg    int value_num;
1541ab64890Smrg    int bufsize;        /* bufMaxSize >= bufsize >= 0 */
1551ab64890Smrg    int bufMaxSize;     /* default : BUFSIZE */
1561ab64890Smrg    char *buf;
1571ab64890Smrg} DBParseInfo;
1581ab64890Smrg
1591ab64890Smrgstatic DBParseInfo parse_info;
1601ab64890Smrg
1611ab64890Smrgstatic void
1621ab64890Smrginit_parse_info (void)
1631ab64890Smrg{
1641ab64890Smrg    static int allocated /* = 0 */;
1651ab64890Smrg    char *ptr;
1661ab64890Smrg    int size;
1671ab64890Smrg    if (!allocated) {
1681ab64890Smrg	bzero(&parse_info, sizeof(DBParseInfo));
169818534a1Smrg	parse_info.buf = Xmalloc(BUFSIZE);
1701ab64890Smrg	parse_info.bufMaxSize = BUFSIZE;
1711ab64890Smrg	allocated = 1;
1721ab64890Smrg	return;
1731ab64890Smrg    }
1741ab64890Smrg    ptr = parse_info.buf;
1751ab64890Smrg    size = parse_info.bufMaxSize;
1761ab64890Smrg    bzero(&parse_info, sizeof(DBParseInfo));
1771ab64890Smrg    parse_info.buf = ptr;
1781ab64890Smrg    parse_info.bufMaxSize = size;
1791ab64890Smrg}
1801ab64890Smrg
1811ab64890Smrgstatic void
1821ab64890Smrgclear_parse_info (void)
1831ab64890Smrg{
1841ab64890Smrg    int i;
1851ab64890Smrg    char *ptr;
1861ab64890Smrg    int size;
1871ab64890Smrg    parse_info.pre_state = S_NULL;
1881ab64890Smrg    if (parse_info.category != NULL) {
1891ab64890Smrg	Xfree(parse_info.category);
1901ab64890Smrg    }
1911ab64890Smrg    for (i = 0; i <= parse_info.nest_depth; ++i) {
1921ab64890Smrg	if (parse_info.name[i]) {
1931ab64890Smrg	    Xfree(parse_info.name[i]);
1941ab64890Smrg	}
1951ab64890Smrg    }
1961ab64890Smrg    if (parse_info.value) {
1971ab64890Smrg	if (*parse_info.value) {
1981ab64890Smrg	    Xfree(*parse_info.value);
1991ab64890Smrg	}
200818534a1Smrg	Xfree(parse_info.value);
2011ab64890Smrg    }
2021ab64890Smrg    ptr = parse_info.buf;
2031ab64890Smrg    size = parse_info.bufMaxSize;
2041ab64890Smrg    bzero(&parse_info, sizeof(DBParseInfo));
2051ab64890Smrg    parse_info.buf = ptr;
2061ab64890Smrg    parse_info.bufMaxSize = size;
2071ab64890Smrg}
2081ab64890Smrg
2091ab64890Smrgstatic Bool
2101ab64890Smrgrealloc_parse_info(
2111ab64890Smrg    int len)
2121ab64890Smrg{
2131ab64890Smrg    char *p;
214818534a1Smrg    int newsize = BUFSIZE * ((parse_info.bufsize + len)/BUFSIZE + 1);
2151ab64890Smrg
216818534a1Smrg    p = Xrealloc(parse_info.buf, newsize);
2171ab64890Smrg    if (p == NULL)
2181ab64890Smrg        return False;
219818534a1Smrg    parse_info.bufMaxSize = newsize;
2201ab64890Smrg    parse_info.buf = p;
2211ab64890Smrg
2221ab64890Smrg    return True;
2231ab64890Smrg}
2241ab64890Smrg
2251ab64890Smrg/************************************************************************/
2261ab64890Smrg
2271ab64890Smrgtypedef struct _Line {
2281ab64890Smrg    char *str;
2291ab64890Smrg    int cursize;
2301ab64890Smrg    int maxsize;
2311ab64890Smrg    int seq;
2321ab64890Smrg} Line;
2331ab64890Smrg
2341ab64890Smrgstatic void
2351ab64890Smrgfree_line(
2361ab64890Smrg    Line *line)
2371ab64890Smrg{
2381ab64890Smrg    if (line->str != NULL) {
2391ab64890Smrg	Xfree(line->str);
2401ab64890Smrg    }
2411ab64890Smrg    bzero(line, sizeof(Line));
2421ab64890Smrg}
2431ab64890Smrg
2441ab64890Smrgstatic int
2451ab64890Smrgrealloc_line(
2461ab64890Smrg    Line *line,
2471ab64890Smrg    int size)
2481ab64890Smrg{
2491ab64890Smrg    char *str = line->str;
2501ab64890Smrg
2511ab64890Smrg    if (str != NULL) {
252818534a1Smrg	str = Xrealloc(str, size);
2531ab64890Smrg    } else {
254818534a1Smrg	str = Xmalloc(size);
2551ab64890Smrg    }
2561ab64890Smrg    if (str == NULL) {
2571ab64890Smrg	/* malloc error */
2581ab64890Smrg	if (line->str != NULL) {
2591ab64890Smrg	    Xfree(line->str);
2601ab64890Smrg	}
2611ab64890Smrg	bzero(line, sizeof(Line));
2621ab64890Smrg	return 0;
2631ab64890Smrg    }
2641ab64890Smrg    line->str = str;
2651ab64890Smrg    line->maxsize = size;
2661ab64890Smrg    return 1;
2671ab64890Smrg}
2681ab64890Smrg
2691ab64890Smrg#define	iswhite(ch)	((ch) == SYM_SPACE   || (ch) == SYM_TAB)
2701ab64890Smrg
2711ab64890Smrgstatic void
2721ab64890Smrgzap_comment(
2731ab64890Smrg    char *str,
2741ab64890Smrg    int *quoted)
2751ab64890Smrg{
2761ab64890Smrg    char *p = str;
2771ab64890Smrg#ifdef	never
2781ab64890Smrg    *quoted = 0;
2791ab64890Smrg    if (*p == SYM_COMMENT) {
2801ab64890Smrg	int len = strlen(str);
2811ab64890Smrg	if (p[len - 1] == SYM_NEWLINE || p[len - 1] == SYM_CR) {
2821ab64890Smrg	    *p++ = SYM_NEWLINE;
2831ab64890Smrg	}
2841ab64890Smrg	*p = '\0';
2851ab64890Smrg    }
2861ab64890Smrg#else
2871ab64890Smrg    while (*p) {
2881ab64890Smrg	if (*p == SYM_DOUBLE_QUOTE) {
2891ab64890Smrg	    if (p == str || p[-1] != SYM_BACKSLASH) {
2901ab64890Smrg		/* unescaped double quote changes quoted state. */
2911ab64890Smrg		*quoted = *quoted ? 0 : 1;
2921ab64890Smrg	    }
2931ab64890Smrg	}
2941ab64890Smrg	if (*p == SYM_COMMENT && !*quoted) {
2951ab64890Smrg	    int pos = p - str;
2961ab64890Smrg	    if (pos == 0 ||
2971ab64890Smrg	        (iswhite(p[-1]) && (pos == 1 || p[-2] != SYM_BACKSLASH))) {
2989c019ec5Smaya		int len = (int) strlen(p);
2991ab64890Smrg		if (len > 0 && (p[len - 1] == SYM_NEWLINE || p[len-1] == SYM_CR)) {
3001ab64890Smrg		    /* newline is the identifier for finding end of value.
3011ab64890Smrg		       therefore, it should not be removed. */
3021ab64890Smrg		    *p++ = SYM_NEWLINE;
3031ab64890Smrg		}
3041ab64890Smrg		*p = '\0';
3051ab64890Smrg		break;
3061ab64890Smrg	    }
3071ab64890Smrg	}
3081ab64890Smrg	++p;
3091ab64890Smrg    }
3101ab64890Smrg#endif
3111ab64890Smrg}
3121ab64890Smrg
3131ab64890Smrgstatic int
3141ab64890Smrgread_line(
3151ab64890Smrg    FILE *fd,
3161ab64890Smrg    Line *line)
3171ab64890Smrg{
3181ab64890Smrg    char buf[BUFSIZE], *p;
3191ab64890Smrg    int len;
3201ab64890Smrg    int quoted = 0;	/* quoted by double quote? */
3211ab64890Smrg    char *str;
3221ab64890Smrg    int cur;
3231ab64890Smrg
3241ab64890Smrg    str = line->str;
3251ab64890Smrg    cur = line->cursize = 0;
3261ab64890Smrg
3271ab64890Smrg    while ((p = fgets(buf, BUFSIZE, fd)) != NULL) {
3281ab64890Smrg	++line->seq;
3291ab64890Smrg	zap_comment(p, &quoted);	/* remove comment line */
3309c019ec5Smaya	len = (int) strlen(p);
3311ab64890Smrg	if (len == 0) {
3321ab64890Smrg	    if (cur > 0) {
3331ab64890Smrg		break;
3341ab64890Smrg	    }
3351ab64890Smrg	    continue;
3361ab64890Smrg	}
3371ab64890Smrg	if (cur + len + 1 > line->maxsize) {
3381ab64890Smrg	    /* need to reallocate buffer. */
3391ab64890Smrg	    if (! realloc_line(line, line->maxsize + BUFSIZE)) {
3401ab64890Smrg		return -1;	/* realloc error. */
3411ab64890Smrg	    }
3421ab64890Smrg	    str = line->str;
3431ab64890Smrg	}
3449c019ec5Smaya	strncpy(str + cur, p, (size_t) len);
3451ab64890Smrg
3461ab64890Smrg	cur += len;
3471ab64890Smrg	str[cur] = '\0';
3481ab64890Smrg#ifdef __UNIXOS2__  /* Take out carriage returns under OS/2 */
3491ab64890Smrg	if (cur>1) {
3501ab64890Smrg	   if (str[cur-2] == '\r' && str[cur-1] == '\n') {
3511ab64890Smrg	      str[cur-2] = '\n';
3521ab64890Smrg	      str[cur-1] = '\0';
3531ab64890Smrg	      cur--;
3541ab64890Smrg	   }
3551ab64890Smrg	}
3561ab64890Smrg#endif
3571ab64890Smrg	if (!quoted && cur > 1 && str[cur - 2] == SYM_BACKSLASH &&
3581ab64890Smrg	    (str[cur - 1] == SYM_NEWLINE || str[cur-1] == SYM_CR)) {
3591ab64890Smrg	    /* the line is ended backslash followed by newline.
3601ab64890Smrg	       need to concatinate the next line. */
3611ab64890Smrg	    cur -= 2;
3621ab64890Smrg	    str[cur] = '\0';
3631ab64890Smrg	} else if (len < BUFSIZE - 1 || buf[len - 1] == SYM_NEWLINE ||
3641ab64890Smrg		   buf[len - 1] == SYM_CR) {
3651ab64890Smrg	    /* the line is shorter than BUFSIZE. */
3661ab64890Smrg	    break;
3671ab64890Smrg	}
3681ab64890Smrg    }
3691ab64890Smrg    if (quoted) {
3701ab64890Smrg	/* error.  still in quoted state. */
3711ab64890Smrg	return -1;
3721ab64890Smrg    }
3731ab64890Smrg    return line->cursize = cur;
3741ab64890Smrg}
3751ab64890Smrg
3761ab64890Smrg/************************************************************************/
3771ab64890Smrg
3781ab64890Smrgstatic Token
3791ab64890Smrgget_token(
3801ab64890Smrg    const char *str)
3811ab64890Smrg{
3821ab64890Smrg    switch (*str) {
3831ab64890Smrg    case SYM_NEWLINE:
3841ab64890Smrg    case SYM_CR:		return T_NEWLINE;
3851ab64890Smrg    case SYM_COMMENT:		return T_COMMENT;
3861ab64890Smrg    case SYM_SEMICOLON:		return T_SEMICOLON;
3871ab64890Smrg    case SYM_DOUBLE_QUOTE:	return T_DOUBLE_QUOTE;
3881ab64890Smrg    case SYM_LEFT_BRACE:	return T_LEFT_BRACE;
3891ab64890Smrg    case SYM_RIGHT_BRACE:	return T_RIGHT_BRACE;
3901ab64890Smrg    case SYM_SPACE:		return T_SPACE;
3911ab64890Smrg    case SYM_TAB:		return T_TAB;
3921ab64890Smrg    case SYM_BACKSLASH:
3931ab64890Smrg	switch (str[1]) {
3941ab64890Smrg	case 'x': return T_NUMERIC_HEX;
3951ab64890Smrg	case 'd': return T_NUMERIC_DEC;
3961ab64890Smrg	case 'o': return T_NUMERIC_OCT;
3971ab64890Smrg	}
3981ab64890Smrg	return T_BACKSLASH;
3991ab64890Smrg    default:
4001ab64890Smrg	return T_DEFAULT;
4011ab64890Smrg    }
4021ab64890Smrg}
4031ab64890Smrg
4041ab64890Smrgstatic int
4051ab64890Smrgget_word(
4061ab64890Smrg    const char *str,
4071ab64890Smrg    char *word)
4081ab64890Smrg{
4091ab64890Smrg    const char *p = str;
4101ab64890Smrg    char *w = word;
4111ab64890Smrg    Token token;
4121ab64890Smrg    int token_len;
4131ab64890Smrg
4141ab64890Smrg    while (*p != '\0') {
4151ab64890Smrg	token = get_token(p);
4161ab64890Smrg	token_len = token_tbl[token].len;
4171ab64890Smrg	if (token == T_BACKSLASH) {
4181ab64890Smrg	    p += token_len;
4191ab64890Smrg	    if (*p == '\0')
4201ab64890Smrg		break;
4211ab64890Smrg	    token = get_token(p);
4221ab64890Smrg	    token_len = token_tbl[token].len;
4231ab64890Smrg	} else if (token != T_COMMENT && token != T_DEFAULT) {
4241ab64890Smrg	    break;
4251ab64890Smrg	}
4269c019ec5Smaya	strncpy(w, p, (size_t) token_len);
4271ab64890Smrg	p += token_len; w += token_len;
4281ab64890Smrg    }
4291ab64890Smrg    *w = '\0';
4301ab64890Smrg    return p - str;	/* return number of scanned chars */
4311ab64890Smrg}
4321ab64890Smrg
4331ab64890Smrgstatic int
4341ab64890Smrgget_quoted_word(
4351ab64890Smrg    const char *str,
4361ab64890Smrg    char *word)
4371ab64890Smrg{
4381ab64890Smrg    const char *p = str;
4391ab64890Smrg    char *w = word;
4401ab64890Smrg    Token token;
4411ab64890Smrg    int token_len;
4421ab64890Smrg
4431ab64890Smrg    if (*p == SYM_DOUBLE_QUOTE) {
4441ab64890Smrg	++p;
4451ab64890Smrg    }
4461ab64890Smrg    while (*p != '\0') {
4471ab64890Smrg	token = get_token(p);
4481ab64890Smrg	token_len = token_tbl[token].len;
4491ab64890Smrg	if (token == T_DOUBLE_QUOTE) {
4501ab64890Smrg	    p += token_len;
4511ab64890Smrg	    goto found;
4521ab64890Smrg	}
4531ab64890Smrg	if (token == T_BACKSLASH) {
4541ab64890Smrg	    p += token_len;
4551ab64890Smrg	    if (*p == '\0') {
4561ab64890Smrg		break;
4571ab64890Smrg	    }
4581ab64890Smrg	    token = get_token(p);
4591ab64890Smrg	    token_len = token_tbl[token].len;
4601ab64890Smrg	}
4619c019ec5Smaya	strncpy(w, p, (size_t) token_len);
4621ab64890Smrg	p += token_len; w += token_len;
4631ab64890Smrg    }
4641ab64890Smrg    /* error. cannot detect next double quote */
4651ab64890Smrg    return 0;
4661ab64890Smrg
4671ab64890Smrg found:;
4681ab64890Smrg    *w = '\0';
4691ab64890Smrg    return p - str;
4701ab64890Smrg}
4711ab64890Smrg
4721ab64890Smrg/************************************************************************/
4731ab64890Smrg
4741ab64890Smrgstatic int
4751ab64890Smrgappend_value_list (void)
4761ab64890Smrg{
4771ab64890Smrg    char **value_list = parse_info.value;
4781ab64890Smrg    char *value;
4791ab64890Smrg    int value_num = parse_info.value_num;
4801ab64890Smrg    int value_len = parse_info.value_len;
4811ab64890Smrg    char *str = parse_info.buf;
4821ab64890Smrg    int len = parse_info.bufsize;
4831ab64890Smrg    char *p;
4841ab64890Smrg
4851ab64890Smrg    if (len < 1) {
4861ab64890Smrg	return 1; /* return with no error */
4871ab64890Smrg    }
4881ab64890Smrg
4891ab64890Smrg    if (value_list == (char **)NULL) {
490818534a1Smrg	value_list = Xmalloc(sizeof(char *) * 2);
4911ab64890Smrg	*value_list = NULL;
4921ab64890Smrg    } else {
4931ab64890Smrg	char **prev_list = value_list;
4941ab64890Smrg
4951ab64890Smrg	value_list = (char **)
496258a0ebeSmrg	    Xreallocarray(value_list, value_num + 2, sizeof(char *));
4971ab64890Smrg	if (value_list == NULL) {
4981ab64890Smrg	    Xfree(prev_list);
4991ab64890Smrg	}
5001ab64890Smrg    }
5011ab64890Smrg    if (value_list == (char **)NULL)
5021ab64890Smrg	goto err2;
5031ab64890Smrg
5041ab64890Smrg    value = *value_list;
5051ab64890Smrg    if (value == NULL) {
506818534a1Smrg	value = Xmalloc(value_len + len + 1);
5071ab64890Smrg    } else {
5081ab64890Smrg	char *prev_value = value;
5091ab64890Smrg
510818534a1Smrg	value = Xrealloc(value, value_len + len + 1);
5111ab64890Smrg	if (value == NULL) {
5121ab64890Smrg	    Xfree(prev_value);
5131ab64890Smrg	}
5141ab64890Smrg    }
5151ab64890Smrg    if (value == NULL) {
5161ab64890Smrg	goto err1;
5171ab64890Smrg    }
5181ab64890Smrg    if (value != *value_list) {
5191ab64890Smrg	int i;
5201ab64890Smrg	ssize_t delta;
5211ab64890Smrg	delta = value - *value_list;
5221ab64890Smrg	*value_list = value;
5231ab64890Smrg	for (i = 1; i < value_num; ++i) {
5241ab64890Smrg	    value_list[i] += delta;
5251ab64890Smrg	}
5261ab64890Smrg    }
5271ab64890Smrg
5281ab64890Smrg    value_list[value_num] = p = &value[value_len];
5291ab64890Smrg    value_list[value_num + 1] = NULL;
5309c019ec5Smaya    strncpy(p, str, (size_t) len);
5311ab64890Smrg    p[len] = 0;
5321ab64890Smrg
5331ab64890Smrg    parse_info.value = value_list;
5341ab64890Smrg    parse_info.value_num = value_num + 1;
5351ab64890Smrg    parse_info.value_len = value_len + len + 1;
5361ab64890Smrg    parse_info.bufsize = 0;
5371ab64890Smrg    return 1;
5381ab64890Smrg
5391ab64890Smrg err1:
5401ab64890Smrg    if (value_list) {
5411ab64890Smrg	Xfree((char **)value_list);
5421ab64890Smrg    }
5431ab64890Smrg    if (value) {
5441ab64890Smrg	Xfree(value);
5451ab64890Smrg    }
5461ab64890Smrg err2:
5471ab64890Smrg    parse_info.value = (char **)NULL;
5481ab64890Smrg    parse_info.value_num = 0;
5491ab64890Smrg    parse_info.value_len = 0;
5501ab64890Smrg    parse_info.bufsize = 0;
5511ab64890Smrg    return 0;
5521ab64890Smrg}
5531ab64890Smrg
55461b2299dSmrgstatic int
5551ab64890Smrgconstruct_name(
5561ab64890Smrg    char *name,
5571ab64890Smrg    int size)
5581ab64890Smrg{
5591ab64890Smrg    int i;
5601ab64890Smrg    int len = 0;
5611ab64890Smrg    char *p = name;
5621ab64890Smrg
5631ab64890Smrg    for (i = 0; i <= parse_info.nest_depth; ++i) {
5649c019ec5Smaya	len = (int) ((size_t) len + (strlen(parse_info.name[i]) + 1));
5651ab64890Smrg    }
5661ab64890Smrg    if (len >= size)
5671ab64890Smrg	return 0;
5681ab64890Smrg
5691ab64890Smrg    strcpy(p, parse_info.name[0]);
5701ab64890Smrg    p += strlen(parse_info.name[0]);
5711ab64890Smrg    for (i = 1; i <= parse_info.nest_depth; ++i) {
5721ab64890Smrg	*p++ = '.';
5731ab64890Smrg	strcpy(p, parse_info.name[i]);
5741ab64890Smrg	p += strlen(parse_info.name[i]);
5751ab64890Smrg    }
5761ab64890Smrg    return *name != '\0';
5771ab64890Smrg}
5781ab64890Smrg
5791ab64890Smrgstatic int
5801ab64890Smrgstore_to_database(
5811ab64890Smrg    Database *db)
5821ab64890Smrg{
5831ab64890Smrg    Database new = (Database)NULL;
5841ab64890Smrg    char name[BUFSIZE];
5851ab64890Smrg
5861ab64890Smrg    if (parse_info.pre_state == S_VALUE) {
5871ab64890Smrg	if (! append_value_list()) {
5881ab64890Smrg	    goto err;
5891ab64890Smrg	}
5901ab64890Smrg    }
5911ab64890Smrg
5921ab64890Smrg    if (parse_info.name[parse_info.nest_depth] == NULL) {
5931ab64890Smrg	goto err;
5941ab64890Smrg    }
5951ab64890Smrg
5966cc2b21fSmrg    new = Xcalloc(1, sizeof(DatabaseRec));
5971ab64890Smrg    if (new == (Database)NULL) {
5981ab64890Smrg	goto err;
5991ab64890Smrg    }
6001ab64890Smrg
6016cc2b21fSmrg    new->category = strdup(parse_info.category);
6021ab64890Smrg    if (new->category == NULL) {
6031ab64890Smrg	goto err;
6041ab64890Smrg    }
6051ab64890Smrg
6061ab64890Smrg    if (! construct_name(name, sizeof(name))) {
6071ab64890Smrg	goto err;
6081ab64890Smrg    }
6096cc2b21fSmrg    new->name = strdup(name);
6101ab64890Smrg    if (new->name == NULL) {
6111ab64890Smrg	goto err;
6121ab64890Smrg    }
6131ab64890Smrg    new->next = *db;
6141ab64890Smrg    new->value = parse_info.value;
6151ab64890Smrg    new->value_num = parse_info.value_num;
6161ab64890Smrg    *db = new;
6171ab64890Smrg
6181ab64890Smrg    Xfree(parse_info.name[parse_info.nest_depth]);
6191ab64890Smrg    parse_info.name[parse_info.nest_depth] = NULL;
6201ab64890Smrg
6211ab64890Smrg    parse_info.value = (char **)NULL;
6221ab64890Smrg    parse_info.value_num = 0;
6231ab64890Smrg    parse_info.value_len = 0;
6241ab64890Smrg
6251ab64890Smrg    return 1;
6261ab64890Smrg
6271ab64890Smrg err:
6281ab64890Smrg    if (new) {
6291ab64890Smrg	if (new->category) {
6301ab64890Smrg	    Xfree(new->category);
6311ab64890Smrg	}
6321ab64890Smrg	if (new->name) {
6331ab64890Smrg	    Xfree(new->name);
6341ab64890Smrg	}
6351ab64890Smrg	Xfree(new);
6361ab64890Smrg    }
6371ab64890Smrg    if (parse_info.value) {
6381ab64890Smrg	if (*parse_info.value) {
6391ab64890Smrg	    Xfree(*parse_info.value);
6401ab64890Smrg	}
6411ab64890Smrg	Xfree((char **)parse_info.value);
6421ab64890Smrg	parse_info.value = (char **)NULL;
6431ab64890Smrg	parse_info.value_num = 0;
6441ab64890Smrg	parse_info.value_len = 0;
6451ab64890Smrg    }
6461ab64890Smrg    return 0;
6471ab64890Smrg}
6481ab64890Smrg
6491ab64890Smrg#define END_MARK	"END"
6501ab64890Smrg#define	END_MARK_LEN	3 /*strlen(END_MARK)*/
6511ab64890Smrg
6521ab64890Smrgstatic int
6531ab64890Smrgcheck_category_end(
6541ab64890Smrg    const char *str)
6551ab64890Smrg{
6561ab64890Smrg    const char *p;
6571ab64890Smrg    int len;
6581ab64890Smrg
6591ab64890Smrg    p = str;
6601ab64890Smrg    if (strncmp(p, END_MARK, END_MARK_LEN)) {
6611ab64890Smrg	return 0;
6621ab64890Smrg    }
6631ab64890Smrg    p += END_MARK_LEN;
6641ab64890Smrg
6651ab64890Smrg    while (iswhite(*p)) {
6661ab64890Smrg	++p;
6671ab64890Smrg    }
6689c019ec5Smaya    len = (int) strlen(parse_info.category);
6699c019ec5Smaya    if (strncmp(p, parse_info.category, (size_t) len)) {
6701ab64890Smrg	return 0;
6711ab64890Smrg    }
6721ab64890Smrg    p += len;
6731ab64890Smrg    return p - str;
6741ab64890Smrg}
6751ab64890Smrg
6761ab64890Smrg/************************************************************************/
6771ab64890Smrg
6781ab64890Smrgstatic int
6791ab64890Smrgf_newline(
6801ab64890Smrg    const char *str,
6811ab64890Smrg    Token token,
6821ab64890Smrg    Database *db)
6831ab64890Smrg{
6841ab64890Smrg    switch (parse_info.pre_state) {
6851ab64890Smrg    case S_NULL:
6861ab64890Smrg    case S_CATEGORY:
6871ab64890Smrg	break;
6881ab64890Smrg    case S_NAME:
6891ab64890Smrg	return 0; /* no value */
6901ab64890Smrg    case S_VALUE:
6911ab64890Smrg	if (!store_to_database(db))
6921ab64890Smrg	    return 0;
6931ab64890Smrg	parse_info.pre_state = S_CATEGORY;
6941ab64890Smrg	break;
6951ab64890Smrg    default:
6961ab64890Smrg	return 0;
6971ab64890Smrg    }
6981ab64890Smrg    return token_tbl[token].len;
6991ab64890Smrg}
7001ab64890Smrg
7011ab64890Smrgstatic int
7021ab64890Smrgf_comment(
7031ab64890Smrg    const char *str,
7041ab64890Smrg    Token token,
7051ab64890Smrg    Database *db)
7061ab64890Smrg{
7071ab64890Smrg    /* NOTE: comment is already handled in read_line(),
7081ab64890Smrg       so this function is not necessary. */
7091ab64890Smrg
7101ab64890Smrg    const char *p = str;
7111ab64890Smrg
7121ab64890Smrg    while (*p != SYM_NEWLINE && *p != SYM_CR && *p != '\0') {
7131ab64890Smrg	++p;	/* zap to the end of line */
7141ab64890Smrg    }
7151ab64890Smrg    return p - str;
7161ab64890Smrg}
7171ab64890Smrg
7181ab64890Smrgstatic int
7191ab64890Smrgf_white(
7201ab64890Smrg    const char *str,
7211ab64890Smrg    Token token,
7221ab64890Smrg    Database *db)
7231ab64890Smrg{
7241ab64890Smrg    const char *p = str;
7251ab64890Smrg
7261ab64890Smrg    while (iswhite(*p)) {
7271ab64890Smrg	++p;
7281ab64890Smrg    }
7291ab64890Smrg    return p - str;
7301ab64890Smrg}
7311ab64890Smrg
7321ab64890Smrgstatic int
7331ab64890Smrgf_semicolon(
7341ab64890Smrg    const char *str,
7351ab64890Smrg    Token token,
7361ab64890Smrg    Database *db)
7371ab64890Smrg{
7381ab64890Smrg    switch (parse_info.pre_state) {
7391ab64890Smrg    case S_NULL:
7401ab64890Smrg    case S_CATEGORY:
7411ab64890Smrg    case S_NAME:
7421ab64890Smrg	return 0;
7431ab64890Smrg    case S_VALUE:
7441ab64890Smrg	if (! append_value_list())
7451ab64890Smrg	    return 0;
7461ab64890Smrg	parse_info.pre_state = S_VALUE;
7471ab64890Smrg	break;
7481ab64890Smrg    default:
7491ab64890Smrg	return 0;
7501ab64890Smrg    }
7511ab64890Smrg    return token_tbl[token].len;
7521ab64890Smrg}
7531ab64890Smrg
7541ab64890Smrgstatic int
7551ab64890Smrgf_left_brace(
7561ab64890Smrg    const char *str,
7571ab64890Smrg    Token token,
7581ab64890Smrg    Database *db)
7591ab64890Smrg{
7601ab64890Smrg    switch (parse_info.pre_state) {
7611ab64890Smrg    case S_NULL:
7621ab64890Smrg    case S_CATEGORY:
7631ab64890Smrg    case S_VALUE:
7641ab64890Smrg	return 0;
7651ab64890Smrg    case S_NAME:
7661ab64890Smrg	if (parse_info.name[parse_info.nest_depth] == NULL
7671ab64890Smrg	    || parse_info.nest_depth + 1 > MAX_NAME_NEST)
7681ab64890Smrg	    return 0;
7691ab64890Smrg	++parse_info.nest_depth;
7701ab64890Smrg	parse_info.pre_state = S_CATEGORY;
7711ab64890Smrg	break;
7721ab64890Smrg    default:
7731ab64890Smrg	return 0;
7741ab64890Smrg    }
7751ab64890Smrg    return token_tbl[token].len;
7761ab64890Smrg}
7771ab64890Smrg
7781ab64890Smrgstatic int
7791ab64890Smrgf_right_brace(
7801ab64890Smrg    const char *str,
7811ab64890Smrg    Token token,
7821ab64890Smrg    Database *db)
7831ab64890Smrg{
7841ab64890Smrg    if (parse_info.nest_depth < 1)
7851ab64890Smrg	return 0;
7861ab64890Smrg
7871ab64890Smrg    switch (parse_info.pre_state) {
7881ab64890Smrg    case S_NULL:
7891ab64890Smrg    case S_NAME:
7901ab64890Smrg	return 0;
7911ab64890Smrg    case S_VALUE:
7921ab64890Smrg	if (! store_to_database(db))
7931ab64890Smrg	    return 0;
7943233502eSmrg	/* fall through - to next case */
7951ab64890Smrg    case S_CATEGORY:
7961ab64890Smrg	if (parse_info.name[parse_info.nest_depth] != NULL) {
7971ab64890Smrg	    Xfree(parse_info.name[parse_info.nest_depth]);
7981ab64890Smrg	    parse_info.name[parse_info.nest_depth] = NULL;
7991ab64890Smrg	}
8001ab64890Smrg	--parse_info.nest_depth;
8011ab64890Smrg	parse_info.pre_state = S_CATEGORY;
8021ab64890Smrg	break;
8031ab64890Smrg    default:
8041ab64890Smrg	return 0;
8051ab64890Smrg    }
8061ab64890Smrg    return token_tbl[token].len;
8071ab64890Smrg}
8081ab64890Smrg
8091ab64890Smrgstatic int
8101ab64890Smrgf_double_quote(
8111ab64890Smrg    const char *str,
8121ab64890Smrg    Token token,
8131ab64890Smrg    Database *db)
8141ab64890Smrg{
8151ab64890Smrg    char word[BUFSIZE];
8161ab64890Smrg    char* wordp;
8171ab64890Smrg    int len;
8181ab64890Smrg
8199c019ec5Smaya    if ((len = (int) strlen (str)) < sizeof word)
8201ab64890Smrg	wordp = word;
8211ab64890Smrg    else
8221ab64890Smrg	wordp = Xmalloc (len + 1);
8231ab64890Smrg    if (wordp == NULL)
8241ab64890Smrg	return 0;
8251ab64890Smrg
8261ab64890Smrg    len = 0;
8271ab64890Smrg    switch (parse_info.pre_state) {
8281ab64890Smrg    case S_NULL:
8291ab64890Smrg    case S_CATEGORY:
8301ab64890Smrg	goto err;
8311ab64890Smrg    case S_NAME:
8321ab64890Smrg    case S_VALUE:
8331ab64890Smrg	len = get_quoted_word(str, wordp);
8341ab64890Smrg	if (len < 1)
8351ab64890Smrg	    goto err;
83661b2299dSmrg	if ((parse_info.bufsize + (int)strlen(wordp) + 1)
8371ab64890Smrg					>= parse_info.bufMaxSize) {
8389c019ec5Smaya	    if (realloc_parse_info((int) strlen(wordp)+1) == False) {
8391ab64890Smrg		goto err;
8401ab64890Smrg	    }
8411ab64890Smrg	}
8421ab64890Smrg	strcpy(&parse_info.buf[parse_info.bufsize], wordp);
8439c019ec5Smaya	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + strlen(wordp));
8441ab64890Smrg	parse_info.pre_state = S_VALUE;
8451ab64890Smrg	break;
8461ab64890Smrg    default:
8471ab64890Smrg	goto err;
8481ab64890Smrg    }
8491ab64890Smrg    if (wordp != word)
8501ab64890Smrg	Xfree (wordp);
8511ab64890Smrg    return len;	/* including length of token */
8521ab64890Smrg
8531ab64890Smrgerr:
8541ab64890Smrg    if (wordp != word)
8551ab64890Smrg	Xfree (wordp);
8561ab64890Smrg    return 0;
8571ab64890Smrg}
8581ab64890Smrg
8591ab64890Smrgstatic int
8601ab64890Smrgf_backslash(
8611ab64890Smrg    const char *str,
8621ab64890Smrg    Token token,
8631ab64890Smrg    Database *db)
8641ab64890Smrg{
8651ab64890Smrg    return f_default(str, token, db);
8661ab64890Smrg}
8671ab64890Smrg
8681ab64890Smrgstatic int
8691ab64890Smrgf_numeric(
8701ab64890Smrg    const char *str,
8711ab64890Smrg    Token token,
8721ab64890Smrg    Database *db)
8731ab64890Smrg{
8741ab64890Smrg    char word[BUFSIZE];
8751ab64890Smrg    const char *p;
8761ab64890Smrg    char* wordp;
8771ab64890Smrg    int len;
8781ab64890Smrg    int token_len;
8791ab64890Smrg
8809c019ec5Smaya    if ((len = (int) strlen (str)) < sizeof word)
8811ab64890Smrg	wordp = word;
8821ab64890Smrg    else
8831ab64890Smrg	wordp = Xmalloc (len + 1);
8841ab64890Smrg    if (wordp == NULL)
8851ab64890Smrg	return 0;
8861ab64890Smrg
8871ab64890Smrg    switch (parse_info.pre_state) {
8881ab64890Smrg    case S_NULL:
8891ab64890Smrg    case S_CATEGORY:
8901ab64890Smrg	goto err;
8911ab64890Smrg    case S_NAME:
8921ab64890Smrg    case S_VALUE:
8931ab64890Smrg	token_len = token_tbl[token].len;
8941ab64890Smrg	p = str + token_len;
8951ab64890Smrg	len = get_word(p, wordp);
8961ab64890Smrg	if (len < 1)
8971ab64890Smrg	    goto err;
89861b2299dSmrg	if ((parse_info.bufsize + token_len + (int)strlen(wordp) + 1)
8991ab64890Smrg					>= parse_info.bufMaxSize) {
9009c019ec5Smaya	    if (realloc_parse_info((int)((size_t) token_len + strlen(wordp) + 1)) == False)
9011ab64890Smrg		goto err;
9021ab64890Smrg	}
9039c019ec5Smaya	strncpy(&parse_info.buf[parse_info.bufsize], str, (size_t) token_len);
9041ab64890Smrg	strcpy(&parse_info.buf[parse_info.bufsize + token_len], wordp);
9059c019ec5Smaya	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + ((size_t) token_len + strlen(wordp)));
9061ab64890Smrg	parse_info.pre_state = S_VALUE;
9071ab64890Smrg	break;
9081ab64890Smrg    default:
9091ab64890Smrg	goto err;
9101ab64890Smrg    }
9111ab64890Smrg    if (wordp != word)
9121ab64890Smrg	Xfree (wordp);
9131ab64890Smrg    return len + token_len;
9141ab64890Smrg
9151ab64890Smrgerr:
9161ab64890Smrg    if (wordp != word)
9171ab64890Smrg	Xfree (wordp);
9181ab64890Smrg    return 0;
9191ab64890Smrg}
9201ab64890Smrg
9211ab64890Smrgstatic int
9221ab64890Smrgf_default(
9231ab64890Smrg    const char *str,
9241ab64890Smrg    Token token,
9251ab64890Smrg    Database *db)
9261ab64890Smrg{
9271ab64890Smrg    char word[BUFSIZE], *p;
9281ab64890Smrg    char* wordp;
9291ab64890Smrg    int len;
9301ab64890Smrg
9319c019ec5Smaya    if ((len = (int) strlen (str)) < sizeof word)
9321ab64890Smrg	wordp = word;
9331ab64890Smrg    else
9341ab64890Smrg	wordp = Xmalloc (len + 1);
9351ab64890Smrg    if (wordp == NULL)
9361ab64890Smrg	return 0;
9371ab64890Smrg
9381ab64890Smrg    len = get_word(str, wordp);
9391ab64890Smrg    if (len < 1)
9401ab64890Smrg	goto err;
9411ab64890Smrg
9421ab64890Smrg    switch (parse_info.pre_state) {
9431ab64890Smrg    case S_NULL:
9441ab64890Smrg	if (parse_info.category != NULL)
9451ab64890Smrg	    goto err;
9466cc2b21fSmrg	p = strdup(wordp);
9471ab64890Smrg	if (p == NULL)
9481ab64890Smrg	    goto err;
9491ab64890Smrg	parse_info.category = p;
9501ab64890Smrg	parse_info.pre_state = S_CATEGORY;
9511ab64890Smrg	break;
9521ab64890Smrg    case S_CATEGORY:
9531ab64890Smrg	if (parse_info.nest_depth == 0) {
9541ab64890Smrg	    if (check_category_end(str)) {
9551ab64890Smrg		/* end of category is detected.
9561ab64890Smrg		   clear context and zap to end of this line */
9571ab64890Smrg		clear_parse_info();
9589c019ec5Smaya		len = (int) strlen(str);
9591ab64890Smrg		break;
9601ab64890Smrg	    }
9611ab64890Smrg	}
9626cc2b21fSmrg	p = strdup(wordp);
9631ab64890Smrg	if (p == NULL)
9641ab64890Smrg	    goto err;
9651ab64890Smrg	if (parse_info.name[parse_info.nest_depth] != NULL) {
9661ab64890Smrg	    Xfree(parse_info.name[parse_info.nest_depth]);
9671ab64890Smrg	}
9681ab64890Smrg	parse_info.name[parse_info.nest_depth] = p;
9691ab64890Smrg	parse_info.pre_state = S_NAME;
9701ab64890Smrg	break;
9711ab64890Smrg    case S_NAME:
9721ab64890Smrg    case S_VALUE:
97361b2299dSmrg	if ((parse_info.bufsize + (int)strlen(wordp) + 1)
9741ab64890Smrg					>= parse_info.bufMaxSize) {
9759c019ec5Smaya	    if (realloc_parse_info((int) strlen(wordp) + 1) == False)
9761ab64890Smrg		goto err;
9771ab64890Smrg	}
9781ab64890Smrg	strcpy(&parse_info.buf[parse_info.bufsize], wordp);
9799c019ec5Smaya	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + strlen(wordp));
9801ab64890Smrg	parse_info.pre_state = S_VALUE;
9811ab64890Smrg	break;
9821ab64890Smrg    default:
9831ab64890Smrg	goto err;
9841ab64890Smrg    }
9851ab64890Smrg    if (wordp != word)
9861ab64890Smrg	Xfree (wordp);
9871ab64890Smrg    return len;
9881ab64890Smrg
9891ab64890Smrgerr:
9901ab64890Smrg    if (wordp != word)
9911ab64890Smrg	Xfree (wordp);
9921ab64890Smrg    return 0;
9931ab64890Smrg}
9941ab64890Smrg
9951ab64890Smrg/************************************************************************/
9961ab64890Smrg
9971ab64890Smrg#ifdef DEBUG
9981ab64890Smrgstatic void
9991ab64890SmrgPrintDatabase(
10001ab64890Smrg    Database db)
10011ab64890Smrg{
10021ab64890Smrg    Database p = db;
10031ab64890Smrg    int i = 0, j;
10041ab64890Smrg
10051ab64890Smrg    printf("***\n*** BEGIN Database\n***\n");
10061ab64890Smrg    while (p) {
10071ab64890Smrg	printf("%3d: ", i++);
10081ab64890Smrg	printf("%s, %s, ", p->category, p->name);
10091ab64890Smrg	printf("\t[%d: ", p->value_num);
10101ab64890Smrg	for (j = 0; j < p->value_num; ++j) {
10111ab64890Smrg	    printf("%s, ", p->value[j]);
10121ab64890Smrg	}
10131ab64890Smrg	printf("]\n");
10141ab64890Smrg	p = p->next;
10151ab64890Smrg    }
10161ab64890Smrg    printf("***\n*** END   Database\n***\n");
10171ab64890Smrg}
10181ab64890Smrg#endif
10191ab64890Smrg
10201ab64890Smrgstatic void
10211ab64890SmrgDestroyDatabase(
10221ab64890Smrg    Database db)
10231ab64890Smrg{
10241ab64890Smrg    Database p = db;
10251ab64890Smrg
10261ab64890Smrg    while (p) {
10271ab64890Smrg	if (p->category != NULL) {
10281ab64890Smrg	    Xfree(p->category);
10291ab64890Smrg	}
10301ab64890Smrg	if (p->name != NULL) {
10311ab64890Smrg	    Xfree(p->name);
10321ab64890Smrg	}
10331ab64890Smrg	if (p->value != (char **)NULL) {
10341ab64890Smrg	    if (*p->value != NULL) {
10351ab64890Smrg		Xfree(*p->value);
10361ab64890Smrg	    }
1037818534a1Smrg	    Xfree(p->value);
10381ab64890Smrg	}
10391ab64890Smrg	db = p->next;
1040818534a1Smrg	Xfree(p);
10411ab64890Smrg	p = db;
10421ab64890Smrg    }
10431ab64890Smrg}
10441ab64890Smrg
10451ab64890Smrgstatic int
10461ab64890SmrgCountDatabase(
10471ab64890Smrg    Database db)
10481ab64890Smrg{
10491ab64890Smrg    Database p = db;
10501ab64890Smrg    int cnt = 0;
10511ab64890Smrg
10521ab64890Smrg    while (p) {
10531ab64890Smrg	++cnt;
10541ab64890Smrg	p = p->next;
10551ab64890Smrg    }
10561ab64890Smrg    return cnt;
10571ab64890Smrg}
10581ab64890Smrg
10591ab64890Smrgstatic Database
10601ab64890SmrgCreateDatabase(
10611ab64890Smrg    char *dbfile)
10621ab64890Smrg{
10631ab64890Smrg    Database db = (Database)NULL;
10641ab64890Smrg    FILE *fd;
10651ab64890Smrg    Line line;
10661ab64890Smrg    char *p;
10671ab64890Smrg    Token token;
10681ab64890Smrg    int len;
10691ab64890Smrg    int error = 0;
10701ab64890Smrg
10711ab64890Smrg    fd = _XFopenFile(dbfile, "r");
10721ab64890Smrg    if (fd == (FILE *)NULL)
10731ab64890Smrg	return NULL;
10741ab64890Smrg
10751ab64890Smrg    bzero(&line, sizeof(Line));
10761ab64890Smrg    init_parse_info();
10771ab64890Smrg
10781ab64890Smrg    do {
10791ab64890Smrg	int rc = read_line(fd, &line);
10801ab64890Smrg	if (rc < 0) {
10811ab64890Smrg	    error = 1;
10821ab64890Smrg	    break;
10831ab64890Smrg	} else if (rc == 0) {
10841ab64890Smrg	    break;
10851ab64890Smrg	}
10861ab64890Smrg	p = line.str;
10871ab64890Smrg	while (*p) {
10881ab64890Smrg            int (*parse_proc)(const char *str, Token token, Database *db) = NULL;
10891ab64890Smrg
10901ab64890Smrg	    token = get_token(p);
10911ab64890Smrg
10921ab64890Smrg            switch (token_tbl[token].token) {
10931ab64890Smrg            case T_NEWLINE:
10941ab64890Smrg                parse_proc = f_newline;
10951ab64890Smrg                break;
10961ab64890Smrg            case T_COMMENT:
10971ab64890Smrg                parse_proc = f_comment;
10981ab64890Smrg                break;
10991ab64890Smrg            case T_SEMICOLON:
11001ab64890Smrg                parse_proc = f_semicolon;
11011ab64890Smrg                break;
11021ab64890Smrg            case T_DOUBLE_QUOTE:
11031ab64890Smrg                parse_proc = f_double_quote;
11041ab64890Smrg                break;
11051ab64890Smrg            case T_LEFT_BRACE:
11061ab64890Smrg                parse_proc = f_left_brace;
11071ab64890Smrg                break;
11081ab64890Smrg            case T_RIGHT_BRACE:
11091ab64890Smrg                parse_proc = f_right_brace;
11101ab64890Smrg                break;
11111ab64890Smrg            case T_SPACE:
11121ab64890Smrg            case T_TAB:
11131ab64890Smrg                parse_proc = f_white;
11141ab64890Smrg                break;
11151ab64890Smrg            case T_BACKSLASH:
11161ab64890Smrg                parse_proc = f_backslash;
11171ab64890Smrg                break;
11181ab64890Smrg            case T_NUMERIC_HEX:
11191ab64890Smrg            case T_NUMERIC_DEC:
11201ab64890Smrg            case T_NUMERIC_OCT:
11211ab64890Smrg                parse_proc = f_numeric;
11221ab64890Smrg                break;
11231ab64890Smrg            case T_DEFAULT:
11241ab64890Smrg                parse_proc = f_default;
11251ab64890Smrg                break;
11261ab64890Smrg            }
11271ab64890Smrg
11281ab64890Smrg            len = parse_proc(p, token, &db);
11291ab64890Smrg
11301ab64890Smrg	    if (len < 1) {
11311ab64890Smrg		error = 1;
11321ab64890Smrg		break;
11331ab64890Smrg	    }
11341ab64890Smrg	    p += len;
11351ab64890Smrg	}
11361ab64890Smrg    } while (!error);
11371ab64890Smrg
11381ab64890Smrg    if (parse_info.pre_state != S_NULL) {
11391ab64890Smrg	clear_parse_info();
11401ab64890Smrg	error = 1;
11411ab64890Smrg    }
11421ab64890Smrg    if (error) {
11431ab64890Smrg#ifdef	DEBUG
11441ab64890Smrg	fprintf(stderr, "database format error at line %d.\n", line.seq);
11451ab64890Smrg#endif
11461ab64890Smrg	DestroyDatabase(db);
11471ab64890Smrg	db = (Database)NULL;
11481ab64890Smrg    }
11491ab64890Smrg
11501ab64890Smrg    fclose(fd);
11511ab64890Smrg    free_line(&line);
11521ab64890Smrg
11531ab64890Smrg#ifdef	DEBUG
11541ab64890Smrg    PrintDatabase(db);
11551ab64890Smrg#endif
11561ab64890Smrg
11571ab64890Smrg    return db;
11581ab64890Smrg}
11591ab64890Smrg
11601ab64890Smrg/************************************************************************/
11611ab64890Smrg
11621ab64890Smrg#ifndef	NOT_X_ENV
11631ab64890Smrg
11641ab64890Smrg/* locale framework functions */
11651ab64890Smrg
11661ab64890Smrgtypedef struct _XlcDatabaseRec {
11671ab64890Smrg    XrmQuark category_q;
11681ab64890Smrg    XrmQuark name_q;
11691ab64890Smrg    Database db;
11701ab64890Smrg    struct _XlcDatabaseRec *next;
11711ab64890Smrg} XlcDatabaseRec, *XlcDatabase;
11721ab64890Smrg
11731ab64890Smrgtypedef	struct _XlcDatabaseListRec {
11741ab64890Smrg    XrmQuark name_q;
11751ab64890Smrg    XlcDatabase lc_db;
11761ab64890Smrg    Database database;
11771ab64890Smrg    int ref_count;
11781ab64890Smrg    struct _XlcDatabaseListRec *next;
11791ab64890Smrg} XlcDatabaseListRec, *XlcDatabaseList;
11801ab64890Smrg
11811ab64890Smrg/* database cache list (per file) */
11821ab64890Smrgstatic XlcDatabaseList _db_list = (XlcDatabaseList)NULL;
11831ab64890Smrg
11841ab64890Smrg/************************************************************************/
11851ab64890Smrg/*	_XlcGetResource(lcd, category, class, value, count)		*/
11861ab64890Smrg/*----------------------------------------------------------------------*/
11871ab64890Smrg/*	This function retrieves XLocale database information.		*/
11881ab64890Smrg/************************************************************************/
11891ab64890Smrgvoid
11901ab64890Smrg_XlcGetResource(
11911ab64890Smrg    XLCd lcd,
11921ab64890Smrg    const char *category,
11931ab64890Smrg    const char *class,
11941ab64890Smrg    char ***value,
11951ab64890Smrg    int *count)
11961ab64890Smrg{
11971ab64890Smrg    XLCdPublicMethodsPart *methods = XLC_PUBLIC_METHODS(lcd);
11981ab64890Smrg
11991ab64890Smrg    (*methods->get_resource)(lcd, category, class, value, count);
12001ab64890Smrg    return;
12011ab64890Smrg}
12021ab64890Smrg
12031ab64890Smrg/************************************************************************/
12041ab64890Smrg/*	_XlcGetLocaleDataBase(lcd, category, class, value, count)	*/
12051ab64890Smrg/*----------------------------------------------------------------------*/
12061ab64890Smrg/*	This function retrieves XLocale database information.		*/
12071ab64890Smrg/************************************************************************/
12081ab64890Smrgvoid
12091ab64890Smrg_XlcGetLocaleDataBase(
12101ab64890Smrg    XLCd lcd,
12111ab64890Smrg    const char *category,
12121ab64890Smrg    const char *name,
12131ab64890Smrg    char ***value,
12141ab64890Smrg    int *count)
12151ab64890Smrg{
12161ab64890Smrg    XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
12171ab64890Smrg    XrmQuark category_q, name_q;
12181ab64890Smrg
12191ab64890Smrg    category_q = XrmStringToQuark(category);
12201ab64890Smrg    name_q = XrmStringToQuark(name);
12211ab64890Smrg    for (; lc_db->db; ++lc_db) {
12221ab64890Smrg	if (category_q == lc_db->category_q && name_q == lc_db->name_q) {
12231ab64890Smrg	    *value = lc_db->db->value;
12241ab64890Smrg	    *count = lc_db->db->value_num;
12251ab64890Smrg	    return;
12261ab64890Smrg	}
12271ab64890Smrg    }
12281ab64890Smrg    *value = (char **)NULL;
12291ab64890Smrg    *count = 0;
12301ab64890Smrg}
12311ab64890Smrg
12321ab64890Smrg/************************************************************************/
12331ab64890Smrg/*	_XlcDestroyLocaleDataBase(lcd)					*/
12341ab64890Smrg/*----------------------------------------------------------------------*/
12351ab64890Smrg/*	This function destroy the XLocale Database that bound to the 	*/
12369c019ec5Smaya/*	specified lcd.  If the XLocale Database is referred from some 	*/
12371ab64890Smrg/*	other lcd, this function just decreases reference count of 	*/
12381ab64890Smrg/*	the database.  If no locale refers the database, this function	*/
12391ab64890Smrg/*	remove it from the cache list and free work area.		*/
12401ab64890Smrg/************************************************************************/
12411ab64890Smrgvoid
12421ab64890Smrg_XlcDestroyLocaleDataBase(
12431ab64890Smrg    XLCd lcd)
12441ab64890Smrg{
12451ab64890Smrg    XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
12461ab64890Smrg    XlcDatabaseList p, prev;
12471ab64890Smrg
12481ab64890Smrg    for (p = _db_list, prev = (XlcDatabaseList)NULL; p;
12491ab64890Smrg	 prev = p, p = p->next) {
12501ab64890Smrg	if (p->lc_db == lc_db) {
12511ab64890Smrg	    if ((-- p->ref_count) < 1) {
12521ab64890Smrg		if (p->lc_db != (XlcDatabase)NULL) {
1253818534a1Smrg		    Xfree(p->lc_db);
12541ab64890Smrg		}
12551ab64890Smrg		DestroyDatabase(p->database);
12561ab64890Smrg		if (prev == (XlcDatabaseList)NULL) {
12571ab64890Smrg		    _db_list = p->next;
12581ab64890Smrg		} else {
12591ab64890Smrg		    prev->next = p->next;
12601ab64890Smrg		}
12611ab64890Smrg		Xfree((char*)p);
12621ab64890Smrg	    }
12631ab64890Smrg	    break;
12641ab64890Smrg	}
12651ab64890Smrg    }
12661ab64890Smrg    XLC_PUBLIC(lcd, xlocale_db) = (XPointer)NULL;
12671ab64890Smrg}
12681ab64890Smrg
12691ab64890Smrg/************************************************************************/
12701ab64890Smrg/*	_XlcCreateLocaleDataBase(lcd)					*/
12711ab64890Smrg/*----------------------------------------------------------------------*/
12721ab64890Smrg/*	This function create an XLocale database which correspond to	*/
12731ab64890Smrg/*	the specified XLCd.						*/
12741ab64890Smrg/************************************************************************/
12751ab64890SmrgXPointer
12761ab64890Smrg_XlcCreateLocaleDataBase(
12771ab64890Smrg    XLCd lcd)
12781ab64890Smrg{
12791ab64890Smrg    XlcDatabaseList list, new;
12801ab64890Smrg    Database p, database = (Database)NULL;
12811ab64890Smrg    XlcDatabase lc_db = (XlcDatabase)NULL;
12821ab64890Smrg    XrmQuark name_q;
12831ab64890Smrg    char *name;
12841ab64890Smrg    int i, n;
12851ab64890Smrg
12861ab64890Smrg    name = _XlcFileName(lcd, "locale");
12871ab64890Smrg    if (name == NULL)
12881ab64890Smrg	return (XPointer)NULL;
12891ab64890Smrg
12901ab64890Smrg#ifndef __UNIXOS2__
12911ab64890Smrg    name_q = XrmStringToQuark(name);
12921ab64890Smrg#else
12931ab64890Smrg    name_q = XrmStringToQuark((char*)__XOS2RedirRoot(name));
12941ab64890Smrg#endif
12951ab64890Smrg    for (list = _db_list; list; list = list->next) {
12961ab64890Smrg	if (name_q == list->name_q) {
12971ab64890Smrg	    list->ref_count++;
12981ab64890Smrg	    Xfree (name);
12991ab64890Smrg	    return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)list->lc_db;
13001ab64890Smrg	}
13011ab64890Smrg    }
13021ab64890Smrg
13031ab64890Smrg    database = CreateDatabase(name);
13041ab64890Smrg    if (database == (Database)NULL) {
13051ab64890Smrg	Xfree (name);
13061ab64890Smrg	return (XPointer)NULL;
13071ab64890Smrg    }
13081ab64890Smrg    n = CountDatabase(database);
13096cc2b21fSmrg    lc_db = Xcalloc(n + 1, sizeof(XlcDatabaseRec));
13101ab64890Smrg    if (lc_db == (XlcDatabase)NULL)
13111ab64890Smrg	goto err;
13121ab64890Smrg    for (p = database, i = 0; p && i < n; p = p->next, ++i) {
13131ab64890Smrg	lc_db[i].category_q = XrmStringToQuark(p->category);
13141ab64890Smrg	lc_db[i].name_q = XrmStringToQuark(p->name);
13151ab64890Smrg	lc_db[i].db = p;
13161ab64890Smrg    }
13171ab64890Smrg
1318818534a1Smrg    new = Xmalloc(sizeof(XlcDatabaseListRec));
13191ab64890Smrg    if (new == (XlcDatabaseList)NULL) {
13201ab64890Smrg	goto err;
13211ab64890Smrg    }
13221ab64890Smrg    new->name_q = name_q;
13231ab64890Smrg    new->lc_db = lc_db;
13241ab64890Smrg    new->database = database;
13251ab64890Smrg    new->ref_count = 1;
13261ab64890Smrg    new->next = _db_list;
13271ab64890Smrg    _db_list = new;
13281ab64890Smrg
13291ab64890Smrg    Xfree (name);
13301ab64890Smrg    return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)lc_db;
13311ab64890Smrg
13321ab64890Smrg err:
13331ab64890Smrg    DestroyDatabase(database);
13341ab64890Smrg    if (lc_db != (XlcDatabase)NULL) {
1335818534a1Smrg	Xfree(lc_db);
13361ab64890Smrg    }
13371ab64890Smrg    Xfree (name);
13381ab64890Smrg    return (XPointer)NULL;
13391ab64890Smrg}
13401ab64890Smrg
13411ab64890Smrg#endif	/* NOT_X_ENV */
1342