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