1 /*
2  *
3  * Copyright IBM Corporation 1993
4  *
5  * All Rights Reserved
6  *
7  * License to use, copy, modify, and distribute this software and its
8  * documentation for any purpose and without fee is hereby granted,
9  * provided that the above copyright notice appear in all copies and that
10  * both that copyright notice and this permission notice appear in
11  * supporting documentation, and that the name of IBM not be
12  * used in advertising or publicity pertaining to distribution of the
13  * software without specific, written prior permission.
14  *
15  * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS, AND
17  * NONINFRINGEMENT OF THIRD PARTY RIGHTS, IN NO EVENT SHALL
18  * IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22  * SOFTWARE.
23  *
24 */
25 /*
26  *  (c) Copyright 1995 FUJITSU LIMITED
27  *  This is source code modified by FUJITSU LIMITED under the Joint
28  *  Development Agreement for the CDE/Motif PST.
29  */
30 
31 
32 
33 #ifndef	NOT_X_ENV
34 
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38 #include <X11/Xlib.h>
39 #include <X11/Xresource.h>
40 #include "Xlibint.h"
41 #include "XlcPubI.h"
42 #include "reallocarray.h"
43 
44 #else	/* NOT_X_ENV */
45 
46 #define	Xmalloc	malloc
47 #define	Xrealloc	realloc
48 #define	Xfree	free
49 
50 #endif	/* NOT_X_ENV */
51 
52 /* specifying NOT_X_ENV allows users to just use
53    the database parsing routine. */
54 /* For UDC/VW */
55 #ifndef	BUFSIZE
56 #define	BUFSIZE	2048
57 #endif
58 
59 #ifdef COMMENT
60 #ifdef  BUFSIZE
61 #undef BUFSIZE
62 #endif
63 #define BUFSIZE 6144 /* 2048*3 */
64 #endif
65 
66 #include <stdio.h>
67 
68 typedef struct _DatabaseRec {
69     char *category;
70     char *name;
71     char **value;
72     int value_num;
73     struct _DatabaseRec *next;
74 } DatabaseRec, *Database;
75 
76 typedef enum {
77     S_NULL,	/* outside category */
78     S_CATEGORY,	/* inside category */
79     S_NAME,	/* has name, expecting values */
80     S_VALUE
81 } ParseState;
82 
83 typedef enum {
84     T_NEWLINE,
85     T_COMMENT,
86     T_SEMICOLON,
87     T_DOUBLE_QUOTE,
88     T_LEFT_BRACE,
89     T_RIGHT_BRACE,
90     T_SPACE,
91     T_TAB,
92     T_BACKSLASH,
93     T_NUMERIC_HEX,
94     T_NUMERIC_DEC,
95     T_NUMERIC_OCT,
96     T_DEFAULT
97 } Token;
98 
99 typedef struct {
100     Token token;	/* token id */
101     int len;		/* length of token sequence */
102 } TokenTable;
103 
104 static int f_newline (const char *str, Token token, Database *db);
105 static int f_comment (const char *str, Token token, Database *db);
106 static int f_semicolon (const char *str, Token token, Database *db);
107 static int f_double_quote (const char *str, Token token, Database *db);
108 static int f_left_brace (const char *str, Token token, Database *db);
109 static int f_right_brace (const char *str, Token token, Database *db);
110 static int f_white (const char *str, Token token, Database *db);
111 static int f_backslash (const char *str, Token token, Database *db);
112 static int f_numeric (const char *str, Token token, Database *db);
113 static int f_default (const char *str, Token token, Database *db);
114 
115 static const TokenTable token_tbl[] = {
116     { T_NEWLINE,      1 },
117     { T_COMMENT,      1 },
118     { T_SEMICOLON,    1 },
119     { T_DOUBLE_QUOTE, 1 },
120     { T_LEFT_BRACE,   1 },
121     { T_RIGHT_BRACE,  1 },
122     { T_SPACE,        1 },
123     { T_TAB,          1 },
124     { T_BACKSLASH,    1 },
125     { T_NUMERIC_HEX,  2 },
126     { T_NUMERIC_DEC,  2 },
127     { T_NUMERIC_OCT,  2 },
128     { T_DEFAULT,      1 } /* any character */
129 };
130 
131 #define	SYM_CR          '\r'
132 #define	SYM_NEWLINE	'\n'
133 #define	SYM_COMMENT	'#'
134 #define	SYM_SEMICOLON	';'
135 #define	SYM_DOUBLE_QUOTE	'"'
136 #define	SYM_LEFT_BRACE	'{'
137 #define	SYM_RIGHT_BRACE	'}'
138 #define	SYM_SPACE	' '
139 #define	SYM_TAB		'\t'
140 #define	SYM_BACKSLASH	'\\'
141 
142 /************************************************************************/
143 
144 #define MAX_NAME_NEST	64
145 
146 typedef struct {
147     ParseState pre_state;
148     char *category;
149     char *name[MAX_NAME_NEST];
150     int nest_depth;
151     char **value;
152     int value_len;
153     int value_num;
154     int bufsize;        /* bufMaxSize >= bufsize >= 0 */
155     int bufMaxSize;     /* default : BUFSIZE */
156     char *buf;
157 } DBParseInfo;
158 
159 static DBParseInfo parse_info;
160 
161 static void
init_parse_info(void)162 init_parse_info (void)
163 {
164     static int allocated /* = 0 */;
165     char *ptr;
166     int size;
167     if (!allocated) {
168 	bzero(&parse_info, sizeof(DBParseInfo));
169 	parse_info.buf = Xmalloc(BUFSIZE);
170 	parse_info.bufMaxSize = BUFSIZE;
171 	allocated = 1;
172 	return;
173     }
174     ptr = parse_info.buf;
175     size = parse_info.bufMaxSize;
176     bzero(&parse_info, sizeof(DBParseInfo));
177     parse_info.buf = ptr;
178     parse_info.bufMaxSize = size;
179 }
180 
181 static void
clear_parse_info(void)182 clear_parse_info (void)
183 {
184     int i;
185     char *ptr;
186     int size;
187     parse_info.pre_state = S_NULL;
188     if (parse_info.category != NULL) {
189 	Xfree(parse_info.category);
190     }
191     for (i = 0; i <= parse_info.nest_depth; ++i) {
192 	if (parse_info.name[i]) {
193 	    Xfree(parse_info.name[i]);
194 	}
195     }
196     if (parse_info.value) {
197 	if (*parse_info.value) {
198 	    Xfree(*parse_info.value);
199 	}
200 	Xfree(parse_info.value);
201     }
202     ptr = parse_info.buf;
203     size = parse_info.bufMaxSize;
204     bzero(&parse_info, sizeof(DBParseInfo));
205     parse_info.buf = ptr;
206     parse_info.bufMaxSize = size;
207 }
208 
209 static Bool
realloc_parse_info(int len)210 realloc_parse_info(
211     int len)
212 {
213     char *p;
214     int newsize = BUFSIZE * ((parse_info.bufsize + len)/BUFSIZE + 1);
215 
216     p = Xrealloc(parse_info.buf, newsize);
217     if (p == NULL)
218         return False;
219     parse_info.bufMaxSize = newsize;
220     parse_info.buf = p;
221 
222     return True;
223 }
224 
225 /************************************************************************/
226 
227 typedef struct _Line {
228     char *str;
229     int cursize;
230     int maxsize;
231     int seq;
232 } Line;
233 
234 static void
free_line(Line * line)235 free_line(
236     Line *line)
237 {
238     if (line->str != NULL) {
239 	Xfree(line->str);
240     }
241     bzero(line, sizeof(Line));
242 }
243 
244 static int
realloc_line(Line * line,int size)245 realloc_line(
246     Line *line,
247     int size)
248 {
249     char *str = line->str;
250 
251     if (str != NULL) {
252 	str = Xrealloc(str, size);
253     } else {
254 	str = Xmalloc(size);
255     }
256     if (str == NULL) {
257 	/* malloc error */
258 	if (line->str != NULL) {
259 	    Xfree(line->str);
260 	}
261 	bzero(line, sizeof(Line));
262 	return 0;
263     }
264     line->str = str;
265     line->maxsize = size;
266     return 1;
267 }
268 
269 #define	iswhite(ch)	((ch) == SYM_SPACE   || (ch) == SYM_TAB)
270 
271 static void
zap_comment(char * str,int * quoted)272 zap_comment(
273     char *str,
274     int *quoted)
275 {
276     char *p = str;
277 #ifdef	never
278     *quoted = 0;
279     if (*p == SYM_COMMENT) {
280 	int len = strlen(str);
281 	if (p[len - 1] == SYM_NEWLINE || p[len - 1] == SYM_CR) {
282 	    *p++ = SYM_NEWLINE;
283 	}
284 	*p = '\0';
285     }
286 #else
287     while (*p) {
288 	if (*p == SYM_DOUBLE_QUOTE) {
289 	    if (p == str || p[-1] != SYM_BACKSLASH) {
290 		/* unescaped double quote changes quoted state. */
291 		*quoted = *quoted ? 0 : 1;
292 	    }
293 	}
294 	if (*p == SYM_COMMENT && !*quoted) {
295 	    int pos = p - str;
296 	    if (pos == 0 ||
297 	        (iswhite(p[-1]) && (pos == 1 || p[-2] != SYM_BACKSLASH))) {
298 		int len = (int) strlen(p);
299 		if (len > 0 && (p[len - 1] == SYM_NEWLINE || p[len-1] == SYM_CR)) {
300 		    /* newline is the identifier for finding end of value.
301 		       therefore, it should not be removed. */
302 		    *p++ = SYM_NEWLINE;
303 		}
304 		*p = '\0';
305 		break;
306 	    }
307 	}
308 	++p;
309     }
310 #endif
311 }
312 
313 static int
read_line(FILE * fd,Line * line)314 read_line(
315     FILE *fd,
316     Line *line)
317 {
318     char buf[BUFSIZE], *p;
319     int len;
320     int quoted = 0;	/* quoted by double quote? */
321     char *str;
322     int cur;
323 
324     str = line->str;
325     cur = line->cursize = 0;
326 
327     while ((p = fgets(buf, BUFSIZE, fd)) != NULL) {
328 	++line->seq;
329 	zap_comment(p, &quoted);	/* remove comment line */
330 	len = (int) strlen(p);
331 	if (len == 0) {
332 	    if (cur > 0) {
333 		break;
334 	    }
335 	    continue;
336 	}
337 	if (cur + len + 1 > line->maxsize) {
338 	    /* need to reallocate buffer. */
339 	    if (! realloc_line(line, line->maxsize + BUFSIZE)) {
340 		return -1;	/* realloc error. */
341 	    }
342 	    str = line->str;
343 	}
344 	memcpy(str + cur, p, (size_t) len);
345 
346 	cur += len;
347 	str[cur] = '\0';
348 #ifdef __UNIXOS2__  /* Take out carriage returns under OS/2 */
349 	if (cur>1) {
350 	   if (str[cur-2] == '\r' && str[cur-1] == '\n') {
351 	      str[cur-2] = '\n';
352 	      str[cur-1] = '\0';
353 	      cur--;
354 	   }
355 	}
356 #endif
357 	if (!quoted && cur > 1 && str[cur - 2] == SYM_BACKSLASH &&
358 	    (str[cur - 1] == SYM_NEWLINE || str[cur-1] == SYM_CR)) {
359 	    /* the line is ended backslash followed by newline.
360 	       need to concatinate the next line. */
361 	    cur -= 2;
362 	    str[cur] = '\0';
363 	} else if (len < BUFSIZE - 1 || buf[len - 1] == SYM_NEWLINE ||
364 		   buf[len - 1] == SYM_CR) {
365 	    /* the line is shorter than BUFSIZE. */
366 	    break;
367 	}
368     }
369     if (quoted) {
370 	/* error.  still in quoted state. */
371 	return -1;
372     }
373     return line->cursize = cur;
374 }
375 
376 /************************************************************************/
377 
378 static Token
get_token(const char * str)379 get_token(
380     const char *str)
381 {
382     switch (*str) {
383     case SYM_NEWLINE:
384     case SYM_CR:		return T_NEWLINE;
385     case SYM_COMMENT:		return T_COMMENT;
386     case SYM_SEMICOLON:		return T_SEMICOLON;
387     case SYM_DOUBLE_QUOTE:	return T_DOUBLE_QUOTE;
388     case SYM_LEFT_BRACE:	return T_LEFT_BRACE;
389     case SYM_RIGHT_BRACE:	return T_RIGHT_BRACE;
390     case SYM_SPACE:		return T_SPACE;
391     case SYM_TAB:		return T_TAB;
392     case SYM_BACKSLASH:
393 	switch (str[1]) {
394 	case 'x': return T_NUMERIC_HEX;
395 	case 'd': return T_NUMERIC_DEC;
396 	case 'o': return T_NUMERIC_OCT;
397 	}
398 	return T_BACKSLASH;
399     default:
400 	return T_DEFAULT;
401     }
402 }
403 
404 static int
get_word(const char * str,char * word)405 get_word(
406     const char *str,
407     char *word)
408 {
409     const char *p = str;
410     char *w = word;
411     Token token;
412     int token_len;
413 
414     while (*p != '\0') {
415 	token = get_token(p);
416 	token_len = token_tbl[token].len;
417 	if (token == T_BACKSLASH) {
418 	    p += token_len;
419 	    if (*p == '\0')
420 		break;
421 	    token = get_token(p);
422 	    token_len = token_tbl[token].len;
423 	} else if (token != T_COMMENT && token != T_DEFAULT) {
424 	    break;
425 	}
426 	strncpy(w, p, (size_t) token_len);
427 	p += token_len; w += token_len;
428     }
429     *w = '\0';
430     return p - str;	/* return number of scanned chars */
431 }
432 
433 static int
get_quoted_word(const char * str,char * word)434 get_quoted_word(
435     const char *str,
436     char *word)
437 {
438     const char *p = str;
439     char *w = word;
440     Token token;
441     int token_len;
442 
443     if (*p == SYM_DOUBLE_QUOTE) {
444 	++p;
445     }
446     while (*p != '\0') {
447 	token = get_token(p);
448 	token_len = token_tbl[token].len;
449 	if (token == T_DOUBLE_QUOTE) {
450 	    p += token_len;
451 	    goto found;
452 	}
453 	if (token == T_BACKSLASH) {
454 	    p += token_len;
455 	    if (*p == '\0') {
456 		break;
457 	    }
458 	    token = get_token(p);
459 	    token_len = token_tbl[token].len;
460 	}
461 	strncpy(w, p, (size_t) token_len);
462 	p += token_len; w += token_len;
463     }
464     /* error. cannot detect next double quote */
465     return 0;
466 
467  found:;
468     *w = '\0';
469     return p - str;
470 }
471 
472 /************************************************************************/
473 
474 static int
append_value_list(void)475 append_value_list (void)
476 {
477     char **value_list = parse_info.value;
478     char *value;
479     int value_num = parse_info.value_num;
480     int value_len = parse_info.value_len;
481     char *str = parse_info.buf;
482     int len = parse_info.bufsize;
483     char *p;
484 
485     if (len < 1) {
486 	return 1; /* return with no error */
487     }
488 
489     if (value_list == (char **)NULL) {
490 	value_list = Xmalloc(sizeof(char *) * 2);
491 	*value_list = NULL;
492     } else {
493 	char **prev_list = value_list;
494 
495 	value_list = (char **)
496 	    Xreallocarray(value_list, value_num + 2, sizeof(char *));
497 	if (value_list == NULL) {
498 	    Xfree(prev_list);
499 	}
500     }
501     if (value_list == (char **)NULL)
502 	goto err2;
503 
504     value = *value_list;
505     if (value == NULL) {
506 	value = Xmalloc(value_len + len + 1);
507     } else {
508 	char *prev_value = value;
509 
510 	value = Xrealloc(value, value_len + len + 1);
511 	if (value == NULL) {
512 	    Xfree(prev_value);
513 	}
514     }
515     if (value == NULL) {
516 	goto err1;
517     }
518     if (value != *value_list) {
519 	int i;
520 	ssize_t delta;
521 	delta = value - *value_list;
522 	*value_list = value;
523 	for (i = 1; i < value_num; ++i) {
524 	    value_list[i] += delta;
525 	}
526     }
527 
528     value_list[value_num] = p = &value[value_len];
529     value_list[value_num + 1] = NULL;
530     strncpy(p, str, (size_t) len);
531     p[len] = 0;
532 
533     parse_info.value = value_list;
534     parse_info.value_num = value_num + 1;
535     parse_info.value_len = value_len + len + 1;
536     parse_info.bufsize = 0;
537     return 1;
538 
539  err1:
540     if (value_list) {
541 	Xfree((char **)value_list);
542     }
543     if (value) {
544 	Xfree(value);
545     }
546  err2:
547     parse_info.value = (char **)NULL;
548     parse_info.value_num = 0;
549     parse_info.value_len = 0;
550     parse_info.bufsize = 0;
551     return 0;
552 }
553 
554 static int
construct_name(char * name,int size)555 construct_name(
556     char *name,
557     int size)
558 {
559     int i;
560     int len = 0;
561     char *p = name;
562 
563     for (i = 0; i <= parse_info.nest_depth; ++i) {
564 	len = (int) ((size_t) len + (strlen(parse_info.name[i]) + 1));
565     }
566     if (len >= size)
567 	return 0;
568 
569     strcpy(p, parse_info.name[0]);
570     p += strlen(parse_info.name[0]);
571     for (i = 1; i <= parse_info.nest_depth; ++i) {
572 	*p++ = '.';
573 	strcpy(p, parse_info.name[i]);
574 	p += strlen(parse_info.name[i]);
575     }
576     return *name != '\0';
577 }
578 
579 static int
store_to_database(Database * db)580 store_to_database(
581     Database *db)
582 {
583     Database new = (Database)NULL;
584     char name[BUFSIZE];
585 
586     if (parse_info.pre_state == S_VALUE) {
587 	if (! append_value_list()) {
588 	    goto err;
589 	}
590     }
591 
592     if (parse_info.name[parse_info.nest_depth] == NULL) {
593 	goto err;
594     }
595 
596     new = Xcalloc(1, sizeof(DatabaseRec));
597     if (new == (Database)NULL) {
598 	goto err;
599     }
600 
601     new->category = strdup(parse_info.category);
602     if (new->category == NULL) {
603 	goto err;
604     }
605 
606     if (! construct_name(name, sizeof(name))) {
607 	goto err;
608     }
609     new->name = strdup(name);
610     if (new->name == NULL) {
611 	goto err;
612     }
613     new->next = *db;
614     new->value = parse_info.value;
615     new->value_num = parse_info.value_num;
616     *db = new;
617 
618     Xfree(parse_info.name[parse_info.nest_depth]);
619     parse_info.name[parse_info.nest_depth] = NULL;
620 
621     parse_info.value = (char **)NULL;
622     parse_info.value_num = 0;
623     parse_info.value_len = 0;
624 
625     return 1;
626 
627  err:
628     if (new) {
629 	if (new->category) {
630 	    Xfree(new->category);
631 	}
632 	if (new->name) {
633 	    Xfree(new->name);
634 	}
635 	Xfree(new);
636     }
637     if (parse_info.value) {
638 	if (*parse_info.value) {
639 	    Xfree(*parse_info.value);
640 	}
641 	Xfree((char **)parse_info.value);
642 	parse_info.value = (char **)NULL;
643 	parse_info.value_num = 0;
644 	parse_info.value_len = 0;
645     }
646     return 0;
647 }
648 
649 #define END_MARK	"END"
650 #define	END_MARK_LEN	3 /*strlen(END_MARK)*/
651 
652 static int
check_category_end(const char * str)653 check_category_end(
654     const char *str)
655 {
656     const char *p;
657     int len;
658 
659     p = str;
660     if (strncmp(p, END_MARK, END_MARK_LEN)) {
661 	return 0;
662     }
663     p += END_MARK_LEN;
664 
665     while (iswhite(*p)) {
666 	++p;
667     }
668     len = (int) strlen(parse_info.category);
669     if (strncmp(p, parse_info.category, (size_t) len)) {
670 	return 0;
671     }
672     p += len;
673     return p - str;
674 }
675 
676 /************************************************************************/
677 
678 static int
f_newline(const char * str,Token token,Database * db)679 f_newline(
680     const char *str,
681     Token token,
682     Database *db)
683 {
684     switch (parse_info.pre_state) {
685     case S_NULL:
686     case S_CATEGORY:
687 	break;
688     case S_NAME:
689 	return 0; /* no value */
690     case S_VALUE:
691 	if (!store_to_database(db))
692 	    return 0;
693 	parse_info.pre_state = S_CATEGORY;
694 	break;
695     default:
696 	return 0;
697     }
698     return token_tbl[token].len;
699 }
700 
701 static int
f_comment(const char * str,Token token,Database * db)702 f_comment(
703     const char *str,
704     Token token,
705     Database *db)
706 {
707     /* NOTE: comment is already handled in read_line(),
708        so this function is not necessary. */
709 
710     const char *p = str;
711 
712     while (*p != SYM_NEWLINE && *p != SYM_CR && *p != '\0') {
713 	++p;	/* zap to the end of line */
714     }
715     return p - str;
716 }
717 
718 static int
f_white(const char * str,Token token,Database * db)719 f_white(
720     const char *str,
721     Token token,
722     Database *db)
723 {
724     const char *p = str;
725 
726     while (iswhite(*p)) {
727 	++p;
728     }
729     return p - str;
730 }
731 
732 static int
f_semicolon(const char * str,Token token,Database * db)733 f_semicolon(
734     const char *str,
735     Token token,
736     Database *db)
737 {
738     switch (parse_info.pre_state) {
739     case S_NULL:
740     case S_CATEGORY:
741     case S_NAME:
742 	return 0;
743     case S_VALUE:
744 	if (! append_value_list())
745 	    return 0;
746 	parse_info.pre_state = S_VALUE;
747 	break;
748     default:
749 	return 0;
750     }
751     return token_tbl[token].len;
752 }
753 
754 static int
f_left_brace(const char * str,Token token,Database * db)755 f_left_brace(
756     const char *str,
757     Token token,
758     Database *db)
759 {
760     switch (parse_info.pre_state) {
761     case S_NULL:
762     case S_CATEGORY:
763     case S_VALUE:
764 	return 0;
765     case S_NAME:
766 	if (parse_info.name[parse_info.nest_depth] == NULL
767 	    || parse_info.nest_depth + 1 > MAX_NAME_NEST)
768 	    return 0;
769 	++parse_info.nest_depth;
770 	parse_info.pre_state = S_CATEGORY;
771 	break;
772     default:
773 	return 0;
774     }
775     return token_tbl[token].len;
776 }
777 
778 static int
f_right_brace(const char * str,Token token,Database * db)779 f_right_brace(
780     const char *str,
781     Token token,
782     Database *db)
783 {
784     if (parse_info.nest_depth < 1)
785 	return 0;
786 
787     switch (parse_info.pre_state) {
788     case S_NULL:
789     case S_NAME:
790 	return 0;
791     case S_VALUE:
792 	if (! store_to_database(db))
793 	    return 0;
794 	/* fall through - to next case */
795     case S_CATEGORY:
796 	if (parse_info.name[parse_info.nest_depth] != NULL) {
797 	    Xfree(parse_info.name[parse_info.nest_depth]);
798 	    parse_info.name[parse_info.nest_depth] = NULL;
799 	}
800 	--parse_info.nest_depth;
801 	parse_info.pre_state = S_CATEGORY;
802 	break;
803     default:
804 	return 0;
805     }
806     return token_tbl[token].len;
807 }
808 
809 static int
f_double_quote(const char * str,Token token,Database * db)810 f_double_quote(
811     const char *str,
812     Token token,
813     Database *db)
814 {
815     char word[BUFSIZE];
816     char* wordp;
817     int len;
818 
819     if ((len = (int) strlen (str)) < sizeof word)
820 	wordp = word;
821     else
822 	wordp = Xmalloc (len + 1);
823     if (wordp == NULL)
824 	return 0;
825 
826     len = 0;
827     switch (parse_info.pre_state) {
828     case S_NULL:
829     case S_CATEGORY:
830 	goto err;
831     case S_NAME:
832     case S_VALUE:
833 	len = get_quoted_word(str, wordp);
834 	if (len < 1)
835 	    goto err;
836 	if ((parse_info.bufsize + (int)strlen(wordp) + 1)
837 					>= parse_info.bufMaxSize) {
838 	    if (realloc_parse_info((int) strlen(wordp)+1) == False) {
839 		goto err;
840 	    }
841 	}
842 	strcpy(&parse_info.buf[parse_info.bufsize], wordp);
843 	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + strlen(wordp));
844 	parse_info.pre_state = S_VALUE;
845 	break;
846     default:
847 	goto err;
848     }
849     if (wordp != word)
850 	Xfree (wordp);
851     return len;	/* including length of token */
852 
853 err:
854     if (wordp != word)
855 	Xfree (wordp);
856     return 0;
857 }
858 
859 static int
f_backslash(const char * str,Token token,Database * db)860 f_backslash(
861     const char *str,
862     Token token,
863     Database *db)
864 {
865     return f_default(str, token, db);
866 }
867 
868 static int
f_numeric(const char * str,Token token,Database * db)869 f_numeric(
870     const char *str,
871     Token token,
872     Database *db)
873 {
874     char word[BUFSIZE];
875     const char *p;
876     char* wordp;
877     int len;
878     int token_len;
879 
880     if ((len = (int) strlen (str)) < sizeof word)
881 	wordp = word;
882     else
883 	wordp = Xmalloc (len + 1);
884     if (wordp == NULL)
885 	return 0;
886 
887     switch (parse_info.pre_state) {
888     case S_NULL:
889     case S_CATEGORY:
890 	goto err;
891     case S_NAME:
892     case S_VALUE:
893 	token_len = token_tbl[token].len;
894 	p = str + token_len;
895 	len = get_word(p, wordp);
896 	if (len < 1)
897 	    goto err;
898 	if ((parse_info.bufsize + token_len + (int)strlen(wordp) + 1)
899 					>= parse_info.bufMaxSize) {
900 	    if (realloc_parse_info((int)((size_t) token_len + strlen(wordp) + 1)) == False)
901 		goto err;
902 	}
903 	strncpy(&parse_info.buf[parse_info.bufsize], str, (size_t) token_len);
904 	strcpy(&parse_info.buf[parse_info.bufsize + token_len], wordp);
905 	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + ((size_t) token_len + strlen(wordp)));
906 	parse_info.pre_state = S_VALUE;
907 	break;
908     default:
909 	goto err;
910     }
911     if (wordp != word)
912 	Xfree (wordp);
913     return len + token_len;
914 
915 err:
916     if (wordp != word)
917 	Xfree (wordp);
918     return 0;
919 }
920 
921 static int
f_default(const char * str,Token token,Database * db)922 f_default(
923     const char *str,
924     Token token,
925     Database *db)
926 {
927     char word[BUFSIZE], *p;
928     char* wordp;
929     int len;
930 
931     if ((len = (int) strlen (str)) < sizeof word)
932 	wordp = word;
933     else
934 	wordp = Xmalloc (len + 1);
935     if (wordp == NULL)
936 	return 0;
937 
938     len = get_word(str, wordp);
939     if (len < 1)
940 	goto err;
941 
942     switch (parse_info.pre_state) {
943     case S_NULL:
944 	if (parse_info.category != NULL)
945 	    goto err;
946 	p = strdup(wordp);
947 	if (p == NULL)
948 	    goto err;
949 	parse_info.category = p;
950 	parse_info.pre_state = S_CATEGORY;
951 	break;
952     case S_CATEGORY:
953 	if (parse_info.nest_depth == 0) {
954 	    if (check_category_end(str)) {
955 		/* end of category is detected.
956 		   clear context and zap to end of this line */
957 		clear_parse_info();
958 		len = (int) strlen(str);
959 		break;
960 	    }
961 	}
962 	p = strdup(wordp);
963 	if (p == NULL)
964 	    goto err;
965 	if (parse_info.name[parse_info.nest_depth] != NULL) {
966 	    Xfree(parse_info.name[parse_info.nest_depth]);
967 	}
968 	parse_info.name[parse_info.nest_depth] = p;
969 	parse_info.pre_state = S_NAME;
970 	break;
971     case S_NAME:
972     case S_VALUE:
973 	if ((parse_info.bufsize + (int)strlen(wordp) + 1)
974 					>= parse_info.bufMaxSize) {
975 	    if (realloc_parse_info((int) strlen(wordp) + 1) == False)
976 		goto err;
977 	}
978 	strcpy(&parse_info.buf[parse_info.bufsize], wordp);
979 	parse_info.bufsize = (int) ((size_t) parse_info.bufsize + strlen(wordp));
980 	parse_info.pre_state = S_VALUE;
981 	break;
982     default:
983 	goto err;
984     }
985     if (wordp != word)
986 	Xfree (wordp);
987     return len;
988 
989 err:
990     if (wordp != word)
991 	Xfree (wordp);
992     return 0;
993 }
994 
995 /************************************************************************/
996 
997 #ifdef DEBUG
998 static void
PrintDatabase(Database db)999 PrintDatabase(
1000     Database db)
1001 {
1002     Database p = db;
1003     int i = 0, j;
1004 
1005     printf("***\n*** BEGIN Database\n***\n");
1006     while (p) {
1007 	printf("%3d: ", i++);
1008 	printf("%s, %s, ", p->category, p->name);
1009 	printf("\t[%d: ", p->value_num);
1010 	for (j = 0; j < p->value_num; ++j) {
1011 	    printf("%s, ", p->value[j]);
1012 	}
1013 	printf("]\n");
1014 	p = p->next;
1015     }
1016     printf("***\n*** END   Database\n***\n");
1017 }
1018 #endif
1019 
1020 static void
DestroyDatabase(Database db)1021 DestroyDatabase(
1022     Database db)
1023 {
1024     Database p = db;
1025 
1026     while (p) {
1027 	if (p->category != NULL) {
1028 	    Xfree(p->category);
1029 	}
1030 	if (p->name != NULL) {
1031 	    Xfree(p->name);
1032 	}
1033 	if (p->value != (char **)NULL) {
1034 	    if (*p->value != NULL) {
1035 		Xfree(*p->value);
1036 	    }
1037 	    Xfree(p->value);
1038 	}
1039 	db = p->next;
1040 	Xfree(p);
1041 	p = db;
1042     }
1043 }
1044 
1045 static int
CountDatabase(Database db)1046 CountDatabase(
1047     Database db)
1048 {
1049     Database p = db;
1050     int cnt = 0;
1051 
1052     while (p) {
1053 	++cnt;
1054 	p = p->next;
1055     }
1056     return cnt;
1057 }
1058 
1059 static Database
CreateDatabase(char * dbfile)1060 CreateDatabase(
1061     char *dbfile)
1062 {
1063     Database db = (Database)NULL;
1064     FILE *fd;
1065     Line line;
1066     char *p;
1067     Token token;
1068     int len;
1069     int error = 0;
1070 
1071     fd = _XFopenFile(dbfile, "r");
1072     if (fd == (FILE *)NULL)
1073 	return NULL;
1074 
1075     bzero(&line, sizeof(Line));
1076     init_parse_info();
1077 
1078     do {
1079 	int rc = read_line(fd, &line);
1080 	if (rc < 0) {
1081 	    error = 1;
1082 	    break;
1083 	} else if (rc == 0) {
1084 	    break;
1085 	}
1086 	p = line.str;
1087 	while (*p) {
1088             int (*parse_proc)(const char *str, Token token, Database *db) = NULL;
1089 
1090 	    token = get_token(p);
1091 
1092             switch (token_tbl[token].token) {
1093             case T_NEWLINE:
1094                 parse_proc = f_newline;
1095                 break;
1096             case T_COMMENT:
1097                 parse_proc = f_comment;
1098                 break;
1099             case T_SEMICOLON:
1100                 parse_proc = f_semicolon;
1101                 break;
1102             case T_DOUBLE_QUOTE:
1103                 parse_proc = f_double_quote;
1104                 break;
1105             case T_LEFT_BRACE:
1106                 parse_proc = f_left_brace;
1107                 break;
1108             case T_RIGHT_BRACE:
1109                 parse_proc = f_right_brace;
1110                 break;
1111             case T_SPACE:
1112             case T_TAB:
1113                 parse_proc = f_white;
1114                 break;
1115             case T_BACKSLASH:
1116                 parse_proc = f_backslash;
1117                 break;
1118             case T_NUMERIC_HEX:
1119             case T_NUMERIC_DEC:
1120             case T_NUMERIC_OCT:
1121                 parse_proc = f_numeric;
1122                 break;
1123             case T_DEFAULT:
1124                 parse_proc = f_default;
1125                 break;
1126             }
1127 
1128             len = parse_proc(p, token, &db);
1129 
1130 	    if (len < 1) {
1131 		error = 1;
1132 		break;
1133 	    }
1134 	    p += len;
1135 	}
1136     } while (!error);
1137 
1138     if (parse_info.pre_state != S_NULL) {
1139 	clear_parse_info();
1140 	error = 1;
1141     }
1142     if (error) {
1143 #ifdef	DEBUG
1144 	fprintf(stderr, "database format error at line %d.\n", line.seq);
1145 #endif
1146 	DestroyDatabase(db);
1147 	db = (Database)NULL;
1148     }
1149 
1150     fclose(fd);
1151     free_line(&line);
1152 
1153 #ifdef	DEBUG
1154     PrintDatabase(db);
1155 #endif
1156 
1157     return db;
1158 }
1159 
1160 /************************************************************************/
1161 
1162 #ifndef	NOT_X_ENV
1163 
1164 /* locale framework functions */
1165 
1166 typedef struct _XlcDatabaseRec {
1167     XrmQuark category_q;
1168     XrmQuark name_q;
1169     Database db;
1170     struct _XlcDatabaseRec *next;
1171 } XlcDatabaseRec, *XlcDatabase;
1172 
1173 typedef	struct _XlcDatabaseListRec {
1174     XrmQuark name_q;
1175     XlcDatabase lc_db;
1176     Database database;
1177     int ref_count;
1178     struct _XlcDatabaseListRec *next;
1179 } XlcDatabaseListRec, *XlcDatabaseList;
1180 
1181 /* database cache list (per file) */
1182 static XlcDatabaseList _db_list = (XlcDatabaseList)NULL;
1183 
1184 /************************************************************************/
1185 /*	_XlcGetResource(lcd, category, class, value, count)		*/
1186 /*----------------------------------------------------------------------*/
1187 /*	This function retrieves XLocale database information.		*/
1188 /************************************************************************/
1189 void
_XlcGetResource(XLCd lcd,const char * category,const char * class,char *** value,int * count)1190 _XlcGetResource(
1191     XLCd lcd,
1192     const char *category,
1193     const char *class,
1194     char ***value,
1195     int *count)
1196 {
1197     XLCdPublicMethodsPart *methods = XLC_PUBLIC_METHODS(lcd);
1198 
1199     (*methods->get_resource)(lcd, category, class, value, count);
1200     return;
1201 }
1202 
1203 /************************************************************************/
1204 /*	_XlcGetLocaleDataBase(lcd, category, class, value, count)	*/
1205 /*----------------------------------------------------------------------*/
1206 /*	This function retrieves XLocale database information.		*/
1207 /************************************************************************/
1208 void
_XlcGetLocaleDataBase(XLCd lcd,const char * category,const char * name,char *** value,int * count)1209 _XlcGetLocaleDataBase(
1210     XLCd lcd,
1211     const char *category,
1212     const char *name,
1213     char ***value,
1214     int *count)
1215 {
1216     XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
1217     XrmQuark category_q, name_q;
1218 
1219     category_q = XrmStringToQuark(category);
1220     name_q = XrmStringToQuark(name);
1221     for (; lc_db->db; ++lc_db) {
1222 	if (category_q == lc_db->category_q && name_q == lc_db->name_q) {
1223 	    *value = lc_db->db->value;
1224 	    *count = lc_db->db->value_num;
1225 	    return;
1226 	}
1227     }
1228     *value = (char **)NULL;
1229     *count = 0;
1230 }
1231 
1232 /************************************************************************/
1233 /*	_XlcDestroyLocaleDataBase(lcd)					*/
1234 /*----------------------------------------------------------------------*/
1235 /*	This function destroy the XLocale Database that bound to the 	*/
1236 /*	specified lcd.  If the XLocale Database is referred from some 	*/
1237 /*	other lcd, this function just decreases reference count of 	*/
1238 /*	the database.  If no locale refers the database, this function	*/
1239 /*	remove it from the cache list and free work area.		*/
1240 /************************************************************************/
1241 void
_XlcDestroyLocaleDataBase(XLCd lcd)1242 _XlcDestroyLocaleDataBase(
1243     XLCd lcd)
1244 {
1245     XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
1246     XlcDatabaseList p, prev;
1247 
1248     for (p = _db_list, prev = (XlcDatabaseList)NULL; p;
1249 	 prev = p, p = p->next) {
1250 	if (p->lc_db == lc_db) {
1251 	    if ((-- p->ref_count) < 1) {
1252 		if (p->lc_db != (XlcDatabase)NULL) {
1253 		    Xfree(p->lc_db);
1254 		}
1255 		DestroyDatabase(p->database);
1256 		if (prev == (XlcDatabaseList)NULL) {
1257 		    _db_list = p->next;
1258 		} else {
1259 		    prev->next = p->next;
1260 		}
1261 		Xfree((char*)p);
1262 	    }
1263 	    break;
1264 	}
1265     }
1266     XLC_PUBLIC(lcd, xlocale_db) = (XPointer)NULL;
1267 }
1268 
1269 /************************************************************************/
1270 /*	_XlcCreateLocaleDataBase(lcd)					*/
1271 /*----------------------------------------------------------------------*/
1272 /*	This function create an XLocale database which correspond to	*/
1273 /*	the specified XLCd.						*/
1274 /************************************************************************/
1275 XPointer
_XlcCreateLocaleDataBase(XLCd lcd)1276 _XlcCreateLocaleDataBase(
1277     XLCd lcd)
1278 {
1279     XlcDatabaseList list, new;
1280     Database p, database = (Database)NULL;
1281     XlcDatabase lc_db = (XlcDatabase)NULL;
1282     XrmQuark name_q;
1283     char *name;
1284     int i, n;
1285 
1286     name = _XlcFileName(lcd, "locale");
1287     if (name == NULL)
1288 	return (XPointer)NULL;
1289 
1290 #ifndef __UNIXOS2__
1291     name_q = XrmStringToQuark(name);
1292 #else
1293     name_q = XrmStringToQuark((char*)__XOS2RedirRoot(name));
1294 #endif
1295     for (list = _db_list; list; list = list->next) {
1296 	if (name_q == list->name_q) {
1297 	    list->ref_count++;
1298 	    Xfree (name);
1299 	    return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)list->lc_db;
1300 	}
1301     }
1302 
1303     database = CreateDatabase(name);
1304     if (database == (Database)NULL) {
1305 	Xfree (name);
1306 	return (XPointer)NULL;
1307     }
1308     n = CountDatabase(database);
1309     lc_db = Xcalloc(n + 1, sizeof(XlcDatabaseRec));
1310     if (lc_db == (XlcDatabase)NULL)
1311 	goto err;
1312     for (p = database, i = 0; p && i < n; p = p->next, ++i) {
1313 	lc_db[i].category_q = XrmStringToQuark(p->category);
1314 	lc_db[i].name_q = XrmStringToQuark(p->name);
1315 	lc_db[i].db = p;
1316     }
1317 
1318     new = Xmalloc(sizeof(XlcDatabaseListRec));
1319     if (new == (XlcDatabaseList)NULL) {
1320 	goto err;
1321     }
1322     new->name_q = name_q;
1323     new->lc_db = lc_db;
1324     new->database = database;
1325     new->ref_count = 1;
1326     new->next = _db_list;
1327     _db_list = new;
1328 
1329     Xfree (name);
1330     return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)lc_db;
1331 
1332  err:
1333     DestroyDatabase(database);
1334     if (lc_db != (XlcDatabase)NULL) {
1335 	Xfree(lc_db);
1336     }
1337     Xfree (name);
1338     return (XPointer)NULL;
1339 }
1340 
1341 #endif	/* NOT_X_ENV */
1342