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