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, "ed); /* 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