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