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	}
344d4a3aaf4Smrg	memcpy(str + cur, p, (size_t) len);
3451ab64890Smrg
3461ab64890Smrg	cur += len;
3471ab64890Smrg	str[cur] = '\0';
3481ab64890Smrg	if (!quoted && cur > 1 && str[cur - 2] == SYM_BACKSLASH &&
3491ab64890Smrg	    (str[cur - 1] == SYM_NEWLINE || str[cur-1] == SYM_CR)) {
3501ab64890Smrg	    /* the line is ended backslash followed by newline.
3511ab64890Smrg	       need to concatinate the next line. */
3521ab64890Smrg	    cur -= 2;
3531ab64890Smrg	    str[cur] = '\0';
3541ab64890Smrg	} else if (len < BUFSIZE - 1 || buf[len - 1] == SYM_NEWLINE ||
3551ab64890Smrg		   buf[len - 1] == SYM_CR) {
3561ab64890Smrg	    /* the line is shorter than BUFSIZE. */
3571ab64890Smrg	    break;
3581ab64890Smrg	}
3591ab64890Smrg    }
3601ab64890Smrg    if (quoted) {
3611ab64890Smrg	/* error.  still in quoted state. */
3621ab64890Smrg	return -1;
3631ab64890Smrg    }
3641ab64890Smrg    return line->cursize = cur;
3651ab64890Smrg}
3661ab64890Smrg
3671ab64890Smrg/************************************************************************/
3681ab64890Smrg
3691ab64890Smrgstatic Token
3701ab64890Smrgget_token(
3711ab64890Smrg    const char *str)
3721ab64890Smrg{
3731ab64890Smrg    switch (*str) {
3741ab64890Smrg    case SYM_NEWLINE:
3751ab64890Smrg    case SYM_CR:		return T_NEWLINE;
3761ab64890Smrg    case SYM_COMMENT:		return T_COMMENT;
3771ab64890Smrg    case SYM_SEMICOLON:		return T_SEMICOLON;
3781ab64890Smrg    case SYM_DOUBLE_QUOTE:	return T_DOUBLE_QUOTE;
3791ab64890Smrg    case SYM_LEFT_BRACE:	return T_LEFT_BRACE;
3801ab64890Smrg    case SYM_RIGHT_BRACE:	return T_RIGHT_BRACE;
3811ab64890Smrg    case SYM_SPACE:		return T_SPACE;
3821ab64890Smrg    case SYM_TAB:		return T_TAB;
3831ab64890Smrg    case SYM_BACKSLASH:
3841ab64890Smrg	switch (str[1]) {
3851ab64890Smrg	case 'x': return T_NUMERIC_HEX;
3861ab64890Smrg	case 'd': return T_NUMERIC_DEC;
3871ab64890Smrg	case 'o': return T_NUMERIC_OCT;
3881ab64890Smrg	}
3891ab64890Smrg	return T_BACKSLASH;
3901ab64890Smrg    default:
3911ab64890Smrg	return T_DEFAULT;
3921ab64890Smrg    }
3931ab64890Smrg}
3941ab64890Smrg
3951ab64890Smrgstatic int
3961ab64890Smrgget_word(
3971ab64890Smrg    const char *str,
3981ab64890Smrg    char *word)
3991ab64890Smrg{
4001ab64890Smrg    const char *p = str;
4011ab64890Smrg    char *w = word;
4021ab64890Smrg    Token token;
4031ab64890Smrg    int token_len;
4041ab64890Smrg
4051ab64890Smrg    while (*p != '\0') {
4061ab64890Smrg	token = get_token(p);
4071ab64890Smrg	token_len = token_tbl[token].len;
4081ab64890Smrg	if (token == T_BACKSLASH) {
4091ab64890Smrg	    p += token_len;
4101ab64890Smrg	    if (*p == '\0')
4111ab64890Smrg		break;
4121ab64890Smrg	    token = get_token(p);
4131ab64890Smrg	    token_len = token_tbl[token].len;
4141ab64890Smrg	} else if (token != T_COMMENT && token != T_DEFAULT) {
4151ab64890Smrg	    break;
4161ab64890Smrg	}
4179c019ec5Smaya	strncpy(w, p, (size_t) token_len);
4181ab64890Smrg	p += token_len; w += token_len;
4191ab64890Smrg    }
4201ab64890Smrg    *w = '\0';
4211ab64890Smrg    return p - str;	/* return number of scanned chars */
4221ab64890Smrg}
4231ab64890Smrg
4241ab64890Smrgstatic int
4251ab64890Smrgget_quoted_word(
4261ab64890Smrg    const char *str,
4271ab64890Smrg    char *word)
4281ab64890Smrg{
4291ab64890Smrg    const char *p = str;
4301ab64890Smrg    char *w = word;
4311ab64890Smrg    Token token;
4321ab64890Smrg    int token_len;
4331ab64890Smrg
4341ab64890Smrg    if (*p == SYM_DOUBLE_QUOTE) {
4351ab64890Smrg	++p;
4361ab64890Smrg    }
4371ab64890Smrg    while (*p != '\0') {
4381ab64890Smrg	token = get_token(p);
4391ab64890Smrg	token_len = token_tbl[token].len;
4401ab64890Smrg	if (token == T_DOUBLE_QUOTE) {
4411ab64890Smrg	    p += token_len;
4421ab64890Smrg	    goto found;
4431ab64890Smrg	}
4441ab64890Smrg	if (token == T_BACKSLASH) {
4451ab64890Smrg	    p += token_len;
4461ab64890Smrg	    if (*p == '\0') {
4471ab64890Smrg		break;
4481ab64890Smrg	    }
4491ab64890Smrg	    token = get_token(p);
4501ab64890Smrg	    token_len = token_tbl[token].len;
4511ab64890Smrg	}
4529c019ec5Smaya	strncpy(w, p, (size_t) token_len);
4531ab64890Smrg	p += token_len; w += token_len;
4541ab64890Smrg    }
4551ab64890Smrg    /* error. cannot detect next double quote */
4561ab64890Smrg    return 0;
4571ab64890Smrg
4581ab64890Smrg found:;
4591ab64890Smrg    *w = '\0';
4601ab64890Smrg    return p - str;
4611ab64890Smrg}
4621ab64890Smrg
4631ab64890Smrg/************************************************************************/
4641ab64890Smrg
4651ab64890Smrgstatic int
4661ab64890Smrgappend_value_list (void)
4671ab64890Smrg{
4681ab64890Smrg    char **value_list = parse_info.value;
4691ab64890Smrg    char *value;
4701ab64890Smrg    int value_num = parse_info.value_num;
4711ab64890Smrg    int value_len = parse_info.value_len;
4721ab64890Smrg    char *str = parse_info.buf;
4731ab64890Smrg    int len = parse_info.bufsize;
4741ab64890Smrg    char *p;
4751ab64890Smrg
4761ab64890Smrg    if (len < 1) {
4771ab64890Smrg	return 1; /* return with no error */
4781ab64890Smrg    }
4791ab64890Smrg
4801ab64890Smrg    if (value_list == (char **)NULL) {
481818534a1Smrg	value_list = Xmalloc(sizeof(char *) * 2);
4821ab64890Smrg	*value_list = NULL;
4831ab64890Smrg    } else {
4841ab64890Smrg	char **prev_list = value_list;
4851ab64890Smrg
4861ab64890Smrg	value_list = (char **)
487258a0ebeSmrg	    Xreallocarray(value_list, value_num + 2, sizeof(char *));
4881ab64890Smrg	if (value_list == NULL) {
4891ab64890Smrg	    Xfree(prev_list);
4901ab64890Smrg	}
4911ab64890Smrg    }
4921ab64890Smrg    if (value_list == (char **)NULL)
4931ab64890Smrg	goto err2;
4941ab64890Smrg
4951ab64890Smrg    value = *value_list;
4961ab64890Smrg    if (value == NULL) {
497818534a1Smrg	value = Xmalloc(value_len + len + 1);
4981ab64890Smrg    } else {
4991ab64890Smrg	char *prev_value = value;
5001ab64890Smrg
501818534a1Smrg	value = Xrealloc(value, value_len + len + 1);
5021ab64890Smrg	if (value == NULL) {
5031ab64890Smrg	    Xfree(prev_value);
5041ab64890Smrg	}
5051ab64890Smrg    }
5061ab64890Smrg    if (value == NULL) {
5071ab64890Smrg	goto err1;
5081ab64890Smrg    }
5091ab64890Smrg    if (value != *value_list) {
5101ab64890Smrg	int i;
511e9628295Smrg	char *old_list;
512e9628295Smrg	old_list = *value_list;
5131ab64890Smrg	*value_list = value;
514e9628295Smrg	/* Re-derive pointers from the new realloc() result to avoid undefined
515e9628295Smrg	   behaviour (and crashes on architectures with pointer bounds). */
5161ab64890Smrg	for (i = 1; i < value_num; ++i) {
517e9628295Smrg	    value_list[i] = value + (value_list[i] - old_list);
5181ab64890Smrg	}
5191ab64890Smrg    }
5201ab64890Smrg
5211ab64890Smrg    value_list[value_num] = p = &value[value_len];
5221ab64890Smrg    value_list[value_num + 1] = NULL;
5239c019ec5Smaya    strncpy(p, str, (size_t) len);
5241ab64890Smrg    p[len] = 0;
5251ab64890Smrg
5261ab64890Smrg    parse_info.value = value_list;
5271ab64890Smrg    parse_info.value_num = value_num + 1;
5281ab64890Smrg    parse_info.value_len = value_len + len + 1;
5291ab64890Smrg    parse_info.bufsize = 0;
5301ab64890Smrg    return 1;
5311ab64890Smrg
5321ab64890Smrg err1:
5331ab64890Smrg    if (value_list) {
5341ab64890Smrg	Xfree((char **)value_list);
5351ab64890Smrg    }
5361ab64890Smrg    if (value) {
5371ab64890Smrg	Xfree(value);
5381ab64890Smrg    }
5391ab64890Smrg err2:
5401ab64890Smrg    parse_info.value = (char **)NULL;
5411ab64890Smrg    parse_info.value_num = 0;
5421ab64890Smrg    parse_info.value_len = 0;
5431ab64890Smrg    parse_info.bufsize = 0;
5441ab64890Smrg    return 0;
5451ab64890Smrg}
5461ab64890Smrg
54761b2299dSmrgstatic int
5481ab64890Smrgconstruct_name(
5491ab64890Smrg    char *name,
5501ab64890Smrg    int size)
5511ab64890Smrg{
5521ab64890Smrg    int i;
5531ab64890Smrg    int len = 0;
5541ab64890Smrg    char *p = name;
5551ab64890Smrg
5561ab64890Smrg    for (i = 0; i <= parse_info.nest_depth; ++i) {
5579c019ec5Smaya	len = (int) ((size_t) len + (strlen(parse_info.name[i]) + 1));
5581ab64890Smrg    }
5591ab64890Smrg    if (len >= size)
5601ab64890Smrg	return 0;
5611ab64890Smrg
5621ab64890Smrg    strcpy(p, parse_info.name[0]);
5631ab64890Smrg    p += strlen(parse_info.name[0]);
5641ab64890Smrg    for (i = 1; i <= parse_info.nest_depth; ++i) {
5651ab64890Smrg	*p++ = '.';
5661ab64890Smrg	strcpy(p, parse_info.name[i]);
5671ab64890Smrg	p += strlen(parse_info.name[i]);
5681ab64890Smrg    }
5691ab64890Smrg    return *name != '\0';
5701ab64890Smrg}
5711ab64890Smrg
5721ab64890Smrgstatic int
5731ab64890Smrgstore_to_database(
5741ab64890Smrg    Database *db)
5751ab64890Smrg{
5761ab64890Smrg    Database new = (Database)NULL;
5771ab64890Smrg    char name[BUFSIZE];
5781ab64890Smrg
5791ab64890Smrg    if (parse_info.pre_state == S_VALUE) {
5801ab64890Smrg	if (! append_value_list()) {
5811ab64890Smrg	    goto err;
5821ab64890Smrg	}
5831ab64890Smrg    }
5841ab64890Smrg
5851ab64890Smrg    if (parse_info.name[parse_info.nest_depth] == NULL) {
5861ab64890Smrg	goto err;
5871ab64890Smrg    }
5881ab64890Smrg
5896cc2b21fSmrg    new = Xcalloc(1, sizeof(DatabaseRec));
5901ab64890Smrg    if (new == (Database)NULL) {
5911ab64890Smrg	goto err;
5921ab64890Smrg    }
5931ab64890Smrg
5946cc2b21fSmrg    new->category = strdup(parse_info.category);
5951ab64890Smrg    if (new->category == NULL) {
5961ab64890Smrg	goto err;
5971ab64890Smrg    }
5981ab64890Smrg
5991ab64890Smrg    if (! construct_name(name, sizeof(name))) {
6001ab64890Smrg	goto err;
6011ab64890Smrg    }
6026cc2b21fSmrg    new->name = strdup(name);
6031ab64890Smrg    if (new->name == NULL) {
6041ab64890Smrg	goto err;
6051ab64890Smrg    }
6061ab64890Smrg    new->next = *db;
6071ab64890Smrg    new->value = parse_info.value;
6081ab64890Smrg    new->value_num = parse_info.value_num;
6091ab64890Smrg    *db = new;
6101ab64890Smrg
6111ab64890Smrg    Xfree(parse_info.name[parse_info.nest_depth]);
6121ab64890Smrg    parse_info.name[parse_info.nest_depth] = NULL;
6131ab64890Smrg
6141ab64890Smrg    parse_info.value = (char **)NULL;
6151ab64890Smrg    parse_info.value_num = 0;
6161ab64890Smrg    parse_info.value_len = 0;
6171ab64890Smrg
6181ab64890Smrg    return 1;
6191ab64890Smrg
6201ab64890Smrg err:
6211ab64890Smrg    if (new) {
6221ab64890Smrg	if (new->category) {
6231ab64890Smrg	    Xfree(new->category);
6241ab64890Smrg	}
6251ab64890Smrg	if (new->name) {
6261ab64890Smrg	    Xfree(new->name);
6271ab64890Smrg	}
6281ab64890Smrg	Xfree(new);
6291ab64890Smrg    }
6301ab64890Smrg    if (parse_info.value) {
6311ab64890Smrg	if (*parse_info.value) {
6321ab64890Smrg	    Xfree(*parse_info.value);
6331ab64890Smrg	}
6341ab64890Smrg	Xfree((char **)parse_info.value);
6351ab64890Smrg	parse_info.value = (char **)NULL;
6361ab64890Smrg	parse_info.value_num = 0;
6371ab64890Smrg	parse_info.value_len = 0;
6381ab64890Smrg    }
6391ab64890Smrg    return 0;
6401ab64890Smrg}
6411ab64890Smrg
6421ab64890Smrg#define END_MARK	"END"
6431ab64890Smrg#define	END_MARK_LEN	3 /*strlen(END_MARK)*/
6441ab64890Smrg
6451ab64890Smrgstatic int
6461ab64890Smrgcheck_category_end(
6471ab64890Smrg    const char *str)
6481ab64890Smrg{
6491ab64890Smrg    const char *p;
6501ab64890Smrg    int len;
6511ab64890Smrg
6521ab64890Smrg    p = str;
6531ab64890Smrg    if (strncmp(p, END_MARK, END_MARK_LEN)) {
6541ab64890Smrg	return 0;
6551ab64890Smrg    }
6561ab64890Smrg    p += END_MARK_LEN;
6571ab64890Smrg
6581ab64890Smrg    while (iswhite(*p)) {
6591ab64890Smrg	++p;
6601ab64890Smrg    }
6619c019ec5Smaya    len = (int) strlen(parse_info.category);
6629c019ec5Smaya    if (strncmp(p, parse_info.category, (size_t) len)) {
6631ab64890Smrg	return 0;
6641ab64890Smrg    }
6651ab64890Smrg    p += len;
6661ab64890Smrg    return p - str;
6671ab64890Smrg}
6681ab64890Smrg
6691ab64890Smrg/************************************************************************/
6701ab64890Smrg
6711ab64890Smrgstatic int
6721ab64890Smrgf_newline(
6731ab64890Smrg    const char *str,
6741ab64890Smrg    Token token,
6751ab64890Smrg    Database *db)
6761ab64890Smrg{
6771ab64890Smrg    switch (parse_info.pre_state) {
6781ab64890Smrg    case S_NULL:
6791ab64890Smrg    case S_CATEGORY:
6801ab64890Smrg	break;
6811ab64890Smrg    case S_NAME:
6821ab64890Smrg	return 0; /* no value */
6831ab64890Smrg    case S_VALUE:
6841ab64890Smrg	if (!store_to_database(db))
6851ab64890Smrg	    return 0;
6861ab64890Smrg	parse_info.pre_state = S_CATEGORY;
6871ab64890Smrg	break;
6881ab64890Smrg    default:
6891ab64890Smrg	return 0;
6901ab64890Smrg    }
6911ab64890Smrg    return token_tbl[token].len;
6921ab64890Smrg}
6931ab64890Smrg
6941ab64890Smrgstatic int
6951ab64890Smrgf_comment(
6961ab64890Smrg    const char *str,
6971ab64890Smrg    Token token,
6981ab64890Smrg    Database *db)
6991ab64890Smrg{
7001ab64890Smrg    /* NOTE: comment is already handled in read_line(),
7011ab64890Smrg       so this function is not necessary. */
7021ab64890Smrg
7031ab64890Smrg    const char *p = str;
7041ab64890Smrg
7051ab64890Smrg    while (*p != SYM_NEWLINE && *p != SYM_CR && *p != '\0') {
7061ab64890Smrg	++p;	/* zap to the end of line */
7071ab64890Smrg    }
7081ab64890Smrg    return p - str;
7091ab64890Smrg}
7101ab64890Smrg
7111ab64890Smrgstatic int
7121ab64890Smrgf_white(
7131ab64890Smrg    const char *str,
7141ab64890Smrg    Token token,
7151ab64890Smrg    Database *db)
7161ab64890Smrg{
7171ab64890Smrg    const char *p = str;
7181ab64890Smrg
7191ab64890Smrg    while (iswhite(*p)) {
7201ab64890Smrg	++p;
7211ab64890Smrg    }
7221ab64890Smrg    return p - str;
7231ab64890Smrg}
7241ab64890Smrg
7251ab64890Smrgstatic int
7261ab64890Smrgf_semicolon(
7271ab64890Smrg    const char *str,
7281ab64890Smrg    Token token,
7291ab64890Smrg    Database *db)
7301ab64890Smrg{
7311ab64890Smrg    switch (parse_info.pre_state) {
7321ab64890Smrg    case S_NULL:
7331ab64890Smrg    case S_CATEGORY:
7341ab64890Smrg    case S_NAME:
7351ab64890Smrg	return 0;
7361ab64890Smrg    case S_VALUE:
7371ab64890Smrg	if (! append_value_list())
7381ab64890Smrg	    return 0;
7391ab64890Smrg	parse_info.pre_state = S_VALUE;
7401ab64890Smrg	break;
7411ab64890Smrg    default:
7421ab64890Smrg	return 0;
7431ab64890Smrg    }
7441ab64890Smrg    return token_tbl[token].len;
7451ab64890Smrg}
7461ab64890Smrg
7471ab64890Smrgstatic int
7481ab64890Smrgf_left_brace(
7491ab64890Smrg    const char *str,
7501ab64890Smrg    Token token,
7511ab64890Smrg    Database *db)
7521ab64890Smrg{
7531ab64890Smrg    switch (parse_info.pre_state) {
7541ab64890Smrg    case S_NULL:
7551ab64890Smrg    case S_CATEGORY:
7561ab64890Smrg    case S_VALUE:
7571ab64890Smrg	return 0;
7581ab64890Smrg    case S_NAME:
7591ab64890Smrg	if (parse_info.name[parse_info.nest_depth] == NULL
7601ab64890Smrg	    || parse_info.nest_depth + 1 > MAX_NAME_NEST)
7611ab64890Smrg	    return 0;
7621ab64890Smrg	++parse_info.nest_depth;
7631ab64890Smrg	parse_info.pre_state = S_CATEGORY;
7641ab64890Smrg	break;
7651ab64890Smrg    default:
7661ab64890Smrg	return 0;
7671ab64890Smrg    }
7681ab64890Smrg    return token_tbl[token].len;
7691ab64890Smrg}
7701ab64890Smrg
7711ab64890Smrgstatic int
7721ab64890Smrgf_right_brace(
7731ab64890Smrg    const char *str,
7741ab64890Smrg    Token token,
7751ab64890Smrg    Database *db)
7761ab64890Smrg{
7771ab64890Smrg    if (parse_info.nest_depth < 1)
7781ab64890Smrg	return 0;
7791ab64890Smrg
7801ab64890Smrg    switch (parse_info.pre_state) {
7811ab64890Smrg    case S_NULL:
7821ab64890Smrg    case S_NAME:
7831ab64890Smrg	return 0;
7841ab64890Smrg    case S_VALUE:
7851ab64890Smrg	if (! store_to_database(db))
7861ab64890Smrg	    return 0;
7873233502eSmrg	/* fall through - to next case */
7881ab64890Smrg    case S_CATEGORY:
7891ab64890Smrg	if (parse_info.name[parse_info.nest_depth] != NULL) {
7901ab64890Smrg	    Xfree(parse_info.name[parse_info.nest_depth]);
7911ab64890Smrg	    parse_info.name[parse_info.nest_depth] = NULL;
7921ab64890Smrg	}
7931ab64890Smrg	--parse_info.nest_depth;
7941ab64890Smrg	parse_info.pre_state = S_CATEGORY;
7951ab64890Smrg	break;
7961ab64890Smrg    default:
7971ab64890Smrg	return 0;
7981ab64890Smrg    }
7991ab64890Smrg    return token_tbl[token].len;
8001ab64890Smrg}
8011ab64890Smrg
8021ab64890Smrgstatic int
8031ab64890Smrgf_double_quote(
8041ab64890Smrg    const char *str,
8051ab64890Smrg    Token token,
8061ab64890Smrg    Database *db)
8071ab64890Smrg{
8081ab64890Smrg    char word[BUFSIZE];
8091ab64890Smrg    char* wordp;
8101ab64890Smrg    int len;
8111ab64890Smrg
8129c019ec5Smaya    if ((len = (int) strlen (str)) < sizeof word)
8131ab64890Smrg	wordp = word;
8141ab64890Smrg    else
8151ab64890Smrg	wordp = Xmalloc (len + 1);
8161ab64890Smrg    if (wordp == NULL)
8171ab64890Smrg	return 0;
8181ab64890Smrg
8191ab64890Smrg    len = 0;
8201ab64890Smrg    switch (parse_info.pre_state) {
8211ab64890Smrg    case S_NULL:
8221ab64890Smrg    case S_CATEGORY:
8231ab64890Smrg	goto err;
8241ab64890Smrg    case S_NAME:
8251ab64890Smrg    case S_VALUE:
8261ab64890Smrg	len = get_quoted_word(str, wordp);
8271ab64890Smrg	if (len < 1)
8281ab64890Smrg	    goto err;
82961b2299dSmrg	if ((parse_info.bufsize + (int)strlen(wordp) + 1)
8301ab64890Smrg					>= parse_info.bufMaxSize) {
8319c019ec5Smaya	    if (realloc_parse_info((int) strlen(wordp)+1) == False) {
8321ab64890Smrg		goto err;
8331ab64890Smrg	    }
8341ab64890Smrg	}
8351ab64890Smrg	strcpy(&parse_info.buf[parse_info.bufsize], wordp);
8369c019ec5Smaya	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + strlen(wordp));
8371ab64890Smrg	parse_info.pre_state = S_VALUE;
8381ab64890Smrg	break;
8391ab64890Smrg    default:
8401ab64890Smrg	goto err;
8411ab64890Smrg    }
8421ab64890Smrg    if (wordp != word)
8431ab64890Smrg	Xfree (wordp);
8441ab64890Smrg    return len;	/* including length of token */
8451ab64890Smrg
8461ab64890Smrgerr:
8471ab64890Smrg    if (wordp != word)
8481ab64890Smrg	Xfree (wordp);
8491ab64890Smrg    return 0;
8501ab64890Smrg}
8511ab64890Smrg
8521ab64890Smrgstatic int
8531ab64890Smrgf_backslash(
8541ab64890Smrg    const char *str,
8551ab64890Smrg    Token token,
8561ab64890Smrg    Database *db)
8571ab64890Smrg{
8581ab64890Smrg    return f_default(str, token, db);
8591ab64890Smrg}
8601ab64890Smrg
8611ab64890Smrgstatic int
8621ab64890Smrgf_numeric(
8631ab64890Smrg    const char *str,
8641ab64890Smrg    Token token,
8651ab64890Smrg    Database *db)
8661ab64890Smrg{
8671ab64890Smrg    char word[BUFSIZE];
8681ab64890Smrg    const char *p;
8691ab64890Smrg    char* wordp;
8701ab64890Smrg    int len;
8711ab64890Smrg    int token_len;
8721ab64890Smrg
8739c019ec5Smaya    if ((len = (int) strlen (str)) < sizeof word)
8741ab64890Smrg	wordp = word;
8751ab64890Smrg    else
8761ab64890Smrg	wordp = Xmalloc (len + 1);
8771ab64890Smrg    if (wordp == NULL)
8781ab64890Smrg	return 0;
8791ab64890Smrg
8801ab64890Smrg    switch (parse_info.pre_state) {
8811ab64890Smrg    case S_NULL:
8821ab64890Smrg    case S_CATEGORY:
8831ab64890Smrg	goto err;
8841ab64890Smrg    case S_NAME:
8851ab64890Smrg    case S_VALUE:
8861ab64890Smrg	token_len = token_tbl[token].len;
8871ab64890Smrg	p = str + token_len;
8881ab64890Smrg	len = get_word(p, wordp);
8891ab64890Smrg	if (len < 1)
8901ab64890Smrg	    goto err;
89161b2299dSmrg	if ((parse_info.bufsize + token_len + (int)strlen(wordp) + 1)
8921ab64890Smrg					>= parse_info.bufMaxSize) {
8939c019ec5Smaya	    if (realloc_parse_info((int)((size_t) token_len + strlen(wordp) + 1)) == False)
8941ab64890Smrg		goto err;
8951ab64890Smrg	}
8969c019ec5Smaya	strncpy(&parse_info.buf[parse_info.bufsize], str, (size_t) token_len);
8971ab64890Smrg	strcpy(&parse_info.buf[parse_info.bufsize + token_len], wordp);
8989c019ec5Smaya	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + ((size_t) token_len + strlen(wordp)));
8991ab64890Smrg	parse_info.pre_state = S_VALUE;
9001ab64890Smrg	break;
9011ab64890Smrg    default:
9021ab64890Smrg	goto err;
9031ab64890Smrg    }
9041ab64890Smrg    if (wordp != word)
9051ab64890Smrg	Xfree (wordp);
9061ab64890Smrg    return len + token_len;
9071ab64890Smrg
9081ab64890Smrgerr:
9091ab64890Smrg    if (wordp != word)
9101ab64890Smrg	Xfree (wordp);
9111ab64890Smrg    return 0;
9121ab64890Smrg}
9131ab64890Smrg
9141ab64890Smrgstatic int
9151ab64890Smrgf_default(
9161ab64890Smrg    const char *str,
9171ab64890Smrg    Token token,
9181ab64890Smrg    Database *db)
9191ab64890Smrg{
9201ab64890Smrg    char word[BUFSIZE], *p;
9211ab64890Smrg    char* wordp;
9221ab64890Smrg    int len;
9231ab64890Smrg
9249c019ec5Smaya    if ((len = (int) strlen (str)) < sizeof word)
9251ab64890Smrg	wordp = word;
9261ab64890Smrg    else
9271ab64890Smrg	wordp = Xmalloc (len + 1);
9281ab64890Smrg    if (wordp == NULL)
9291ab64890Smrg	return 0;
9301ab64890Smrg
9311ab64890Smrg    len = get_word(str, wordp);
9321ab64890Smrg    if (len < 1)
9331ab64890Smrg	goto err;
9341ab64890Smrg
9351ab64890Smrg    switch (parse_info.pre_state) {
9361ab64890Smrg    case S_NULL:
9371ab64890Smrg	if (parse_info.category != NULL)
9381ab64890Smrg	    goto err;
9396cc2b21fSmrg	p = strdup(wordp);
9401ab64890Smrg	if (p == NULL)
9411ab64890Smrg	    goto err;
9421ab64890Smrg	parse_info.category = p;
9431ab64890Smrg	parse_info.pre_state = S_CATEGORY;
9441ab64890Smrg	break;
9451ab64890Smrg    case S_CATEGORY:
9461ab64890Smrg	if (parse_info.nest_depth == 0) {
9471ab64890Smrg	    if (check_category_end(str)) {
9481ab64890Smrg		/* end of category is detected.
9491ab64890Smrg		   clear context and zap to end of this line */
9501ab64890Smrg		clear_parse_info();
9519c019ec5Smaya		len = (int) strlen(str);
9521ab64890Smrg		break;
9531ab64890Smrg	    }
9541ab64890Smrg	}
9556cc2b21fSmrg	p = strdup(wordp);
9561ab64890Smrg	if (p == NULL)
9571ab64890Smrg	    goto err;
9581ab64890Smrg	if (parse_info.name[parse_info.nest_depth] != NULL) {
9591ab64890Smrg	    Xfree(parse_info.name[parse_info.nest_depth]);
9601ab64890Smrg	}
9611ab64890Smrg	parse_info.name[parse_info.nest_depth] = p;
9621ab64890Smrg	parse_info.pre_state = S_NAME;
9631ab64890Smrg	break;
9641ab64890Smrg    case S_NAME:
9651ab64890Smrg    case S_VALUE:
96661b2299dSmrg	if ((parse_info.bufsize + (int)strlen(wordp) + 1)
9671ab64890Smrg					>= parse_info.bufMaxSize) {
9689c019ec5Smaya	    if (realloc_parse_info((int) strlen(wordp) + 1) == False)
9691ab64890Smrg		goto err;
9701ab64890Smrg	}
9711ab64890Smrg	strcpy(&parse_info.buf[parse_info.bufsize], wordp);
9729c019ec5Smaya	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + strlen(wordp));
9731ab64890Smrg	parse_info.pre_state = S_VALUE;
9741ab64890Smrg	break;
9751ab64890Smrg    default:
9761ab64890Smrg	goto err;
9771ab64890Smrg    }
9781ab64890Smrg    if (wordp != word)
9791ab64890Smrg	Xfree (wordp);
9801ab64890Smrg    return len;
9811ab64890Smrg
9821ab64890Smrgerr:
9831ab64890Smrg    if (wordp != word)
9841ab64890Smrg	Xfree (wordp);
9851ab64890Smrg    return 0;
9861ab64890Smrg}
9871ab64890Smrg
9881ab64890Smrg/************************************************************************/
9891ab64890Smrg
9901ab64890Smrg#ifdef DEBUG
9911ab64890Smrgstatic void
9921ab64890SmrgPrintDatabase(
9931ab64890Smrg    Database db)
9941ab64890Smrg{
9951ab64890Smrg    Database p = db;
9961ab64890Smrg    int i = 0, j;
9971ab64890Smrg
9981ab64890Smrg    printf("***\n*** BEGIN Database\n***\n");
9991ab64890Smrg    while (p) {
10001ab64890Smrg	printf("%3d: ", i++);
10011ab64890Smrg	printf("%s, %s, ", p->category, p->name);
10021ab64890Smrg	printf("\t[%d: ", p->value_num);
10031ab64890Smrg	for (j = 0; j < p->value_num; ++j) {
10041ab64890Smrg	    printf("%s, ", p->value[j]);
10051ab64890Smrg	}
10061ab64890Smrg	printf("]\n");
10071ab64890Smrg	p = p->next;
10081ab64890Smrg    }
10091ab64890Smrg    printf("***\n*** END   Database\n***\n");
10101ab64890Smrg}
10111ab64890Smrg#endif
10121ab64890Smrg
10131ab64890Smrgstatic void
10141ab64890SmrgDestroyDatabase(
10151ab64890Smrg    Database db)
10161ab64890Smrg{
10171ab64890Smrg    Database p = db;
10181ab64890Smrg
10191ab64890Smrg    while (p) {
10201ab64890Smrg	if (p->category != NULL) {
10211ab64890Smrg	    Xfree(p->category);
10221ab64890Smrg	}
10231ab64890Smrg	if (p->name != NULL) {
10241ab64890Smrg	    Xfree(p->name);
10251ab64890Smrg	}
10261ab64890Smrg	if (p->value != (char **)NULL) {
10271ab64890Smrg	    if (*p->value != NULL) {
10281ab64890Smrg		Xfree(*p->value);
10291ab64890Smrg	    }
1030818534a1Smrg	    Xfree(p->value);
10311ab64890Smrg	}
10321ab64890Smrg	db = p->next;
1033818534a1Smrg	Xfree(p);
10341ab64890Smrg	p = db;
10351ab64890Smrg    }
10361ab64890Smrg}
10371ab64890Smrg
10381ab64890Smrgstatic int
10391ab64890SmrgCountDatabase(
10401ab64890Smrg    Database db)
10411ab64890Smrg{
10421ab64890Smrg    Database p = db;
10431ab64890Smrg    int cnt = 0;
10441ab64890Smrg
10451ab64890Smrg    while (p) {
10461ab64890Smrg	++cnt;
10471ab64890Smrg	p = p->next;
10481ab64890Smrg    }
10491ab64890Smrg    return cnt;
10501ab64890Smrg}
10511ab64890Smrg
10521ab64890Smrgstatic Database
10531ab64890SmrgCreateDatabase(
10541ab64890Smrg    char *dbfile)
10551ab64890Smrg{
10561ab64890Smrg    Database db = (Database)NULL;
10571ab64890Smrg    FILE *fd;
10581ab64890Smrg    Line line;
10591ab64890Smrg    char *p;
10601ab64890Smrg    Token token;
10611ab64890Smrg    int len;
10621ab64890Smrg    int error = 0;
10631ab64890Smrg
10641ab64890Smrg    fd = _XFopenFile(dbfile, "r");
10651ab64890Smrg    if (fd == (FILE *)NULL)
10661ab64890Smrg	return NULL;
10671ab64890Smrg
10681ab64890Smrg    bzero(&line, sizeof(Line));
10691ab64890Smrg    init_parse_info();
10701ab64890Smrg
10711ab64890Smrg    do {
10721ab64890Smrg	int rc = read_line(fd, &line);
10731ab64890Smrg	if (rc < 0) {
10741ab64890Smrg	    error = 1;
10751ab64890Smrg	    break;
10761ab64890Smrg	} else if (rc == 0) {
10771ab64890Smrg	    break;
10781ab64890Smrg	}
10791ab64890Smrg	p = line.str;
10801ab64890Smrg	while (*p) {
10811ab64890Smrg            int (*parse_proc)(const char *str, Token token, Database *db) = NULL;
10821ab64890Smrg
10831ab64890Smrg	    token = get_token(p);
10841ab64890Smrg
10851ab64890Smrg            switch (token_tbl[token].token) {
10861ab64890Smrg            case T_NEWLINE:
10871ab64890Smrg                parse_proc = f_newline;
10881ab64890Smrg                break;
10891ab64890Smrg            case T_COMMENT:
10901ab64890Smrg                parse_proc = f_comment;
10911ab64890Smrg                break;
10921ab64890Smrg            case T_SEMICOLON:
10931ab64890Smrg                parse_proc = f_semicolon;
10941ab64890Smrg                break;
10951ab64890Smrg            case T_DOUBLE_QUOTE:
10961ab64890Smrg                parse_proc = f_double_quote;
10971ab64890Smrg                break;
10981ab64890Smrg            case T_LEFT_BRACE:
10991ab64890Smrg                parse_proc = f_left_brace;
11001ab64890Smrg                break;
11011ab64890Smrg            case T_RIGHT_BRACE:
11021ab64890Smrg                parse_proc = f_right_brace;
11031ab64890Smrg                break;
11041ab64890Smrg            case T_SPACE:
11051ab64890Smrg            case T_TAB:
11061ab64890Smrg                parse_proc = f_white;
11071ab64890Smrg                break;
11081ab64890Smrg            case T_BACKSLASH:
11091ab64890Smrg                parse_proc = f_backslash;
11101ab64890Smrg                break;
11111ab64890Smrg            case T_NUMERIC_HEX:
11121ab64890Smrg            case T_NUMERIC_DEC:
11131ab64890Smrg            case T_NUMERIC_OCT:
11141ab64890Smrg                parse_proc = f_numeric;
11151ab64890Smrg                break;
11161ab64890Smrg            case T_DEFAULT:
11171ab64890Smrg                parse_proc = f_default;
11181ab64890Smrg                break;
11191ab64890Smrg            }
11201ab64890Smrg
11211ab64890Smrg            len = parse_proc(p, token, &db);
11221ab64890Smrg
11231ab64890Smrg	    if (len < 1) {
11241ab64890Smrg		error = 1;
11251ab64890Smrg		break;
11261ab64890Smrg	    }
11271ab64890Smrg	    p += len;
11281ab64890Smrg	}
11291ab64890Smrg    } while (!error);
11301ab64890Smrg
11311ab64890Smrg    if (parse_info.pre_state != S_NULL) {
11321ab64890Smrg	clear_parse_info();
11331ab64890Smrg	error = 1;
11341ab64890Smrg    }
11351ab64890Smrg    if (error) {
11361ab64890Smrg#ifdef	DEBUG
11371ab64890Smrg	fprintf(stderr, "database format error at line %d.\n", line.seq);
11381ab64890Smrg#endif
11391ab64890Smrg	DestroyDatabase(db);
11401ab64890Smrg	db = (Database)NULL;
11411ab64890Smrg    }
11421ab64890Smrg
11431ab64890Smrg    fclose(fd);
11441ab64890Smrg    free_line(&line);
11451ab64890Smrg
11461ab64890Smrg#ifdef	DEBUG
11471ab64890Smrg    PrintDatabase(db);
11481ab64890Smrg#endif
11491ab64890Smrg
11501ab64890Smrg    return db;
11511ab64890Smrg}
11521ab64890Smrg
11531ab64890Smrg/************************************************************************/
11541ab64890Smrg
11551ab64890Smrg#ifndef	NOT_X_ENV
11561ab64890Smrg
11571ab64890Smrg/* locale framework functions */
11581ab64890Smrg
11591ab64890Smrgtypedef struct _XlcDatabaseRec {
11601ab64890Smrg    XrmQuark category_q;
11611ab64890Smrg    XrmQuark name_q;
11621ab64890Smrg    Database db;
11631ab64890Smrg    struct _XlcDatabaseRec *next;
11641ab64890Smrg} XlcDatabaseRec, *XlcDatabase;
11651ab64890Smrg
11661ab64890Smrgtypedef	struct _XlcDatabaseListRec {
11671ab64890Smrg    XrmQuark name_q;
11681ab64890Smrg    XlcDatabase lc_db;
11691ab64890Smrg    Database database;
11701ab64890Smrg    int ref_count;
11711ab64890Smrg    struct _XlcDatabaseListRec *next;
11721ab64890Smrg} XlcDatabaseListRec, *XlcDatabaseList;
11731ab64890Smrg
11741ab64890Smrg/* database cache list (per file) */
11751ab64890Smrgstatic XlcDatabaseList _db_list = (XlcDatabaseList)NULL;
11761ab64890Smrg
11771ab64890Smrg/************************************************************************/
11781ab64890Smrg/*	_XlcGetResource(lcd, category, class, value, count)		*/
11791ab64890Smrg/*----------------------------------------------------------------------*/
11801ab64890Smrg/*	This function retrieves XLocale database information.		*/
11811ab64890Smrg/************************************************************************/
11821ab64890Smrgvoid
11831ab64890Smrg_XlcGetResource(
11841ab64890Smrg    XLCd lcd,
11851ab64890Smrg    const char *category,
11861ab64890Smrg    const char *class,
11871ab64890Smrg    char ***value,
11881ab64890Smrg    int *count)
11891ab64890Smrg{
11901ab64890Smrg    XLCdPublicMethodsPart *methods = XLC_PUBLIC_METHODS(lcd);
11911ab64890Smrg
11921ab64890Smrg    (*methods->get_resource)(lcd, category, class, value, count);
11931ab64890Smrg    return;
11941ab64890Smrg}
11951ab64890Smrg
11961ab64890Smrg/************************************************************************/
11971ab64890Smrg/*	_XlcGetLocaleDataBase(lcd, category, class, value, count)	*/
11981ab64890Smrg/*----------------------------------------------------------------------*/
11991ab64890Smrg/*	This function retrieves XLocale database information.		*/
12001ab64890Smrg/************************************************************************/
12011ab64890Smrgvoid
12021ab64890Smrg_XlcGetLocaleDataBase(
12031ab64890Smrg    XLCd lcd,
12041ab64890Smrg    const char *category,
12051ab64890Smrg    const char *name,
12061ab64890Smrg    char ***value,
12071ab64890Smrg    int *count)
12081ab64890Smrg{
12091ab64890Smrg    XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
12101ab64890Smrg    XrmQuark category_q, name_q;
12111ab64890Smrg
12121ab64890Smrg    category_q = XrmStringToQuark(category);
12131ab64890Smrg    name_q = XrmStringToQuark(name);
12141ab64890Smrg    for (; lc_db->db; ++lc_db) {
12151ab64890Smrg	if (category_q == lc_db->category_q && name_q == lc_db->name_q) {
12161ab64890Smrg	    *value = lc_db->db->value;
12171ab64890Smrg	    *count = lc_db->db->value_num;
12181ab64890Smrg	    return;
12191ab64890Smrg	}
12201ab64890Smrg    }
12211ab64890Smrg    *value = (char **)NULL;
12221ab64890Smrg    *count = 0;
12231ab64890Smrg}
12241ab64890Smrg
12251ab64890Smrg/************************************************************************/
12261ab64890Smrg/*	_XlcDestroyLocaleDataBase(lcd)					*/
12271ab64890Smrg/*----------------------------------------------------------------------*/
12281ab64890Smrg/*	This function destroy the XLocale Database that bound to the 	*/
12299c019ec5Smaya/*	specified lcd.  If the XLocale Database is referred from some 	*/
12301ab64890Smrg/*	other lcd, this function just decreases reference count of 	*/
12311ab64890Smrg/*	the database.  If no locale refers the database, this function	*/
12321ab64890Smrg/*	remove it from the cache list and free work area.		*/
12331ab64890Smrg/************************************************************************/
12341ab64890Smrgvoid
12351ab64890Smrg_XlcDestroyLocaleDataBase(
12361ab64890Smrg    XLCd lcd)
12371ab64890Smrg{
12381ab64890Smrg    XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
12391ab64890Smrg    XlcDatabaseList p, prev;
12401ab64890Smrg
12411ab64890Smrg    for (p = _db_list, prev = (XlcDatabaseList)NULL; p;
12421ab64890Smrg	 prev = p, p = p->next) {
12431ab64890Smrg	if (p->lc_db == lc_db) {
12441ab64890Smrg	    if ((-- p->ref_count) < 1) {
12451ab64890Smrg		if (p->lc_db != (XlcDatabase)NULL) {
1246818534a1Smrg		    Xfree(p->lc_db);
12471ab64890Smrg		}
12481ab64890Smrg		DestroyDatabase(p->database);
12491ab64890Smrg		if (prev == (XlcDatabaseList)NULL) {
12501ab64890Smrg		    _db_list = p->next;
12511ab64890Smrg		} else {
12521ab64890Smrg		    prev->next = p->next;
12531ab64890Smrg		}
12541ab64890Smrg		Xfree((char*)p);
12551ab64890Smrg	    }
12561ab64890Smrg	    break;
12571ab64890Smrg	}
12581ab64890Smrg    }
12591ab64890Smrg    XLC_PUBLIC(lcd, xlocale_db) = (XPointer)NULL;
12601ab64890Smrg}
12611ab64890Smrg
12621ab64890Smrg/************************************************************************/
12631ab64890Smrg/*	_XlcCreateLocaleDataBase(lcd)					*/
12641ab64890Smrg/*----------------------------------------------------------------------*/
12651ab64890Smrg/*	This function create an XLocale database which correspond to	*/
12661ab64890Smrg/*	the specified XLCd.						*/
12671ab64890Smrg/************************************************************************/
12681ab64890SmrgXPointer
12691ab64890Smrg_XlcCreateLocaleDataBase(
12701ab64890Smrg    XLCd lcd)
12711ab64890Smrg{
12721ab64890Smrg    XlcDatabaseList list, new;
12731ab64890Smrg    Database p, database = (Database)NULL;
12741ab64890Smrg    XlcDatabase lc_db = (XlcDatabase)NULL;
12751ab64890Smrg    XrmQuark name_q;
12761ab64890Smrg    char *name;
12771ab64890Smrg    int i, n;
12781ab64890Smrg
12791ab64890Smrg    name = _XlcFileName(lcd, "locale");
12801ab64890Smrg    if (name == NULL)
12811ab64890Smrg	return (XPointer)NULL;
12821ab64890Smrg
12831ab64890Smrg    name_q = XrmStringToQuark(name);
12841ab64890Smrg    for (list = _db_list; list; list = list->next) {
12851ab64890Smrg	if (name_q == list->name_q) {
12861ab64890Smrg	    list->ref_count++;
12871ab64890Smrg	    Xfree (name);
12881ab64890Smrg	    return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)list->lc_db;
12891ab64890Smrg	}
12901ab64890Smrg    }
12911ab64890Smrg
12921ab64890Smrg    database = CreateDatabase(name);
12931ab64890Smrg    if (database == (Database)NULL) {
12941ab64890Smrg	Xfree (name);
12951ab64890Smrg	return (XPointer)NULL;
12961ab64890Smrg    }
12971ab64890Smrg    n = CountDatabase(database);
12986cc2b21fSmrg    lc_db = Xcalloc(n + 1, sizeof(XlcDatabaseRec));
12991ab64890Smrg    if (lc_db == (XlcDatabase)NULL)
13001ab64890Smrg	goto err;
13011ab64890Smrg    for (p = database, i = 0; p && i < n; p = p->next, ++i) {
13021ab64890Smrg	lc_db[i].category_q = XrmStringToQuark(p->category);
13031ab64890Smrg	lc_db[i].name_q = XrmStringToQuark(p->name);
13041ab64890Smrg	lc_db[i].db = p;
13051ab64890Smrg    }
13061ab64890Smrg
1307818534a1Smrg    new = Xmalloc(sizeof(XlcDatabaseListRec));
13081ab64890Smrg    if (new == (XlcDatabaseList)NULL) {
13091ab64890Smrg	goto err;
13101ab64890Smrg    }
13111ab64890Smrg    new->name_q = name_q;
13121ab64890Smrg    new->lc_db = lc_db;
13131ab64890Smrg    new->database = database;
13141ab64890Smrg    new->ref_count = 1;
13151ab64890Smrg    new->next = _db_list;
13161ab64890Smrg    _db_list = new;
13171ab64890Smrg
13181ab64890Smrg    Xfree (name);
13191ab64890Smrg    return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)lc_db;
13201ab64890Smrg
13211ab64890Smrg err:
13221ab64890Smrg    DestroyDatabase(database);
13231ab64890Smrg    if (lc_db != (XlcDatabase)NULL) {
1324818534a1Smrg	Xfree(lc_db);
13251ab64890Smrg    }
13261ab64890Smrg    Xfree (name);
13271ab64890Smrg    return (XPointer)NULL;
13281ab64890Smrg}
13291ab64890Smrg
13301ab64890Smrg#endif	/* NOT_X_ENV */
1331