2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
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 $ */
27 * Copyright IBM Corporation 1993
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.
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
52 #include <X11/Xresource.h>
53 #include "_fallibint.h"
54 #include "_fallcPubI.h"
58 #define Xmalloc malloc
59 #define Xrealloc realloc
62 #endif /* NOT_X_ENV */
64 /* specifying NOT_X_ENV allows users to just use
65 the database parsing routine. */
75 #define BUFSIZE 6144 /* 2048*3 */
80 typedef struct _DatabaseRec {
85 struct _DatabaseRec *next;
86 } DatabaseRec, *Database;
89 S_NULL, /* outside category */
90 S_CATEGORY, /* inside category */
91 S_NAME, /* has name, expecting values */
112 Token token; /* token id */
113 char *name; /* token sequence */
114 int len; /* length of token sequence */
115 int (*parse_proc)(); /* parsing procedure */
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();
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 */
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 ' '
154 #define SYM_BACKSLASH '\\'
156 /************************************************************************/
158 #define MAX_NAME_NEST 64
161 ParseState pre_state;
163 char *name[MAX_NAME_NEST];
168 int bufsize; /* bufMaxSize >= bufsize >= 0 */
169 int bufMaxSize; /* default : BUFSIZE */
173 static DBParseInfo parse_info;
175 static void init_parse_info()
177 static int first = 1;
181 bzero(&parse_info, sizeof(DBParseInfo));
182 parse_info.buf = (char *)Xmalloc(BUFSIZE);
183 parse_info.bufMaxSize = BUFSIZE;
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;
200 parse_info.pre_state = S_NULL;
201 if(parse_info.category != NULL){
202 Xfree(parse_info.category);
204 for(i = 0; i <= parse_info.nest_depth; ++i){
205 if(parse_info.name[i]){
206 Xfree(parse_info.name[i]);
209 if(parse_info.value){
210 if(*parse_info.value){
211 Xfree(*parse_info.value);
213 Xfree((char *)parse_info.value);
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;
223 realloc_parse_info(len)
229 parse_info.bufMaxSize = BUFSIZE *
230 ((parse_info.bufsize + len)/BUFSIZE + 1);
231 p = (char *)Xrealloc(parse_info.buf, parse_info.bufMaxSize);
239 /************************************************************************/
240 typedef struct _Line {
251 if(line->str != NULL){
254 bzero(line, sizeof(Line));
258 realloc_line(line, size)
262 char *str = line->str;
265 str = (char *)Xrealloc(str, size);
267 str = (char *)Xmalloc(size);
271 bzero(line, sizeof(Line));
275 line->maxsize = size;
279 #define iswhite(ch) ((ch) == SYM_SPACE || (ch) == SYM_TAB)
282 zap_comment(str, quoted)
289 if(*p == SYM_COMMENT){
290 int len = strlen(str);
291 if(p[len - 1] == SYM_NEWLINE){
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;
304 if(*p == SYM_COMMENT && !*quoted){
307 iswhite(p[-1]) && (pos == 1 || p[-2] != SYM_BACKSLASH)){
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. */
328 char buf[BUFSIZE], *p;
330 int quoted = 0; /* quoted by double quote? */
335 cur = line->cursize = 0;
337 while((p = fgets(buf, BUFSIZE, fd)) != NULL){
339 zap_comment(p, "ed); /* remove comment line */
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. */
354 strncpy(str + cur, p, len);
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. */
371 /* error. still in quoted state. */
374 return line->cursize = cur;
380 /************************************************************************/
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;
397 case 'x': return T_NUMERIC_HEX;
398 case 'd': return T_NUMERIC_DEC;
399 case 'o': return T_NUMERIC_OCT;
412 char *p = str, *w = word;
417 token = get_token(p);
418 token_len = token_tbl[token].len;
419 if(token == T_BACKSLASH){
424 token = get_token(p);
425 token_len = token_tbl[token].len;
426 }else if(token != T_COMMENT &&
430 strncpy(w, p, token_len);
431 p += token_len; w += token_len;
434 return p - str; /* return number of scanned chars */
438 get_quoted_word(str, word)
442 char *p = str, *w = word;
446 if(*p == SYM_DOUBLE_QUOTE){
450 token = get_token(p);
451 token_len = token_tbl[token].len;
452 if(token == T_DOUBLE_QUOTE){
456 if(token == T_BACKSLASH){
461 token = get_token(p);
462 token_len = token_tbl[token].len;
464 strncpy(w, p, token_len);
465 p += token_len; w += token_len;
467 /* error. cannot detect next double quote */
475 /************************************************************************/
480 char **value_list = parse_info.value;
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;
489 return 1; /* return with no error */
492 if(value_list == (char **)NULL){
493 value_list = (char **)Xmalloc(sizeof(char *) * 2);
496 value_list = (char **)
497 Xrealloc(value_list, sizeof(char *) * (value_num + 2));
499 if(value_list == (char **)NULL){
505 value = (char *)Xmalloc(value_len + len + 1);
507 value = (char *)Xrealloc(value, value_len + len + 1);
512 if(value != *value_list){
514 delta = value - *value_list;
516 for(i = 1; i < value_num; ++i){
517 value_list[i] += delta;
521 value_list[value_num] = p = &value[value_len];
522 value_list[value_num + 1] = NULL;
523 strncpy(p, str, len);
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;
534 Xfree((char **)value_list);
539 parse_info.value = (char **)NULL;
540 parse_info.value_num = 0;
541 parse_info.value_len = 0;
542 parse_info.bufsize = 0;
550 register int i, len = 0;
553 for(i = 0; i <= parse_info.nest_depth; ++i){
554 len += strlen(parse_info.name[i]) + 1;
557 strcpy(p, parse_info.name[0]);
558 p += strlen(parse_info.name[0]);
559 for(i = 1; i <= parse_info.nest_depth; ++i){
561 strcpy(p, parse_info.name[i]);
562 p += strlen(parse_info.name[i]);
564 return *name != '\0';
568 store_to_database(db)
571 Database new = (Database)NULL;
574 if(parse_info.pre_state == S_VALUE){
575 if(! append_value_list()){
580 if(parse_info.name[parse_info.nest_depth] == NULL){
584 new = (Database)Xmalloc(sizeof(DatabaseRec));
585 if(new == (Database)NULL){
588 bzero(new, sizeof(DatabaseRec));
590 new->category = (char *)Xmalloc(strlen(parse_info.category) + 1);
591 if(new->category == NULL){
594 strcpy(new->category, parse_info.category);
596 if(! construct_name(name)){
599 new->name = (char *)Xmalloc(strlen(name) + 1);
600 if(new->name == NULL){
603 strcpy(new->name, name);
605 new->value = parse_info.value;
606 new->value_num = parse_info.value_num;
609 Xfree(parse_info.name[parse_info.nest_depth]);
610 parse_info.name[parse_info.nest_depth] = NULL;
612 parse_info.value = (char **)NULL;
613 parse_info.value_num = 0;
614 parse_info.value_len = 0;
621 Xfree(new->category);
628 if(parse_info.value){
629 if(*parse_info.value){
630 Xfree(*parse_info.value);
632 Xfree((char **)parse_info.value);
633 parse_info.value = (char **)NULL;
634 parse_info.value_num = 0;
635 parse_info.value_len = 0;
640 #define END_MARK "END"
641 #define END_MARK_LEN 3 /*strlen(END_MARK)*/
644 check_category_end(str)
651 if(strncmp(p, END_MARK, END_MARK_LEN)){
659 len = strlen(parse_info.category);
660 if(strncmp(p, parse_info.category, len)){
667 /************************************************************************/
670 f_newline(str, token, db)
675 switch(parse_info.pre_state){
680 goto err; /* no value */
682 if(!store_to_database(db)){
685 parse_info.pre_state = S_CATEGORY;
690 return token_tbl[token].len;
697 f_comment(str, token, db)
702 /* NOTE: comment is already handled in read_line(),
703 so this function is not necessary. */
707 while(*p != SYM_NEWLINE && *p != '\0'){
708 ++p; /* zap to the end of line */
714 f_white(str, token, db)
728 f_semicolon(str, token, db)
733 switch(parse_info.pre_state){
739 if(! append_value_list()){
742 parse_info.pre_state = S_VALUE;
747 return token_tbl[token].len;
754 f_left_brace(str, token, db)
759 switch(parse_info.pre_state){
764 if(parse_info.name[parse_info.nest_depth] == NULL ||
765 parse_info.nest_depth + 1 > MAX_NAME_NEST){
768 ++parse_info.nest_depth;
769 parse_info.pre_state = S_CATEGORY;
775 return token_tbl[token].len;
782 f_right_brace(str, token, db)
787 if(parse_info.nest_depth < 1){
791 switch(parse_info.pre_state){
796 if(! store_to_database(db)){
799 /* fall into next case */
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;
805 --parse_info.nest_depth;
806 parse_info.pre_state = S_CATEGORY;
811 return token_tbl[token].len;
818 f_double_quote(str, token, db)
826 switch(parse_info.pre_state){
832 len = get_quoted_word(str, word);
836 if( (parse_info.bufsize + (int)strlen(word) +1)
837 >= parse_info.bufMaxSize){
838 if(realloc_parse_info(strlen(word) +1) == False){
842 strcpy(&parse_info.buf[parse_info.bufsize], word);
843 parse_info.bufsize += strlen(word);
844 parse_info.pre_state = S_VALUE;
849 return len; /* including length of token */
856 f_backslash(str, token, db)
861 return f_default(str, token, db);
865 f_numeric(str, token, db)
870 char word[BUFSIZE], *p;
874 switch(parse_info.pre_state){
880 token_len = token_tbl[token].len;
882 len = get_word(p, word);
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){
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;
900 return len + token_len;
907 f_default(str, token, db)
912 char word[BUFSIZE], *p;
915 len = get_word(str, word);
920 switch(parse_info.pre_state){
922 if(parse_info.category != NULL){
925 p = (char *)Xmalloc(strlen(word) + 1);
930 parse_info.category = p;
931 parse_info.pre_state = 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 */
943 p = (char *)Xmalloc(strlen(word) + 1);
948 if(parse_info.name[parse_info.nest_depth] != NULL){
949 Xfree(parse_info.name[parse_info.nest_depth]);
951 parse_info.name[parse_info.nest_depth] = p;
952 parse_info.pre_state = S_NAME;
956 if( (parse_info.bufsize + (int)strlen(word) +1 )
957 >= parse_info.bufMaxSize){
958 if(realloc_parse_info(strlen(word) +1) == False){
962 strcpy(&parse_info.buf[parse_info.bufsize], word);
963 parse_info.bufsize += strlen(word);
964 parse_info.pre_state = S_VALUE;
975 /************************************************************************/
985 printf("***\n*** BEGIN Database\n***\n");
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]);
996 printf("***\n*** END Database\n***\n");
1007 if(p->category != NULL){
1010 if(p->name != NULL){
1013 if(p->value != (char **)NULL){
1014 if(*p->value != NULL){
1017 Xfree((char *)p->value);
1040 CreateDatabase(dbfile)
1043 Database db = (Database)NULL;
1052 fd = fopen(dbfile, "r");
1053 if(fd == (FILE *)NULL){
1057 bzero(&line, sizeof(Line));
1061 int rc = read_line(fd, &line);
1070 token = get_token(p);
1071 len = (*token_tbl[token].parse_proc)(p, token, &db);
1080 if(parse_info.pre_state != S_NULL){
1086 fprintf(stderr, "database format error at line %d.\n", line.seq);
1088 DestroyDatabase(db);
1089 db = (Database)NULL;
1102 /************************************************************************/
1106 /* locale framework functions */
1108 typedef struct _XlcDatabaseRec {
1109 XrmQuark category_q;
1112 struct _XlcDatabaseRec *next;
1113 } XlcDatabaseRec, *XlcDatabase;
1115 typedef struct _XlcDatabaseListRec {
1120 struct _XlcDatabaseListRec *next;
1121 } XlcDatabaseListRec, *XlcDatabaseList;
1123 /* database cache list (per file) */
1124 static XlcDatabaseList _db_list = (XlcDatabaseList)NULL;
1126 /************************************************************************/
1127 /* _fallcGetResource(lcd, category, class, value, count) */
1128 /*----------------------------------------------------------------------*/
1129 /* This function retrieves XLocale database information. */
1130 /************************************************************************/
1132 _fallcGetResource(lcd, category, class, value, count)
1139 XLCdPublicMethodsPart *methods = XLC_PUBLIC_METHODS(lcd);
1141 (*methods->get_resource)(lcd, category, class, value, count);
1145 /************************************************************************/
1146 /* _fallcGetLocaleDataBase(lcd, category, class, value, count) */
1147 /*----------------------------------------------------------------------*/
1148 /* This function retrieves XLocale database information. */
1149 /************************************************************************/
1151 _fallcGetLocaleDataBase(lcd, category, name, value, count)
1158 XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
1159 XrmQuark category_q, name_q;
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;
1170 *value = (char **)NULL;
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 /************************************************************************/
1184 _fallcDestroyLocaleDataBase(lcd)
1187 XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
1188 XlcDatabaseList p, prev;
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);
1197 DestroyDatabase(p->database);
1198 if(prev == (XlcDatabaseList)NULL){
1201 prev->next = p->next;
1208 XLC_PUBLIC(lcd, xlocale_db) = (XPointer)NULL;
1211 /************************************************************************/
1212 /* _fallcCreateLocaleDataBase(lcd) */
1213 /*----------------------------------------------------------------------*/
1214 /* This function create an XLocale database which correspond to */
1215 /* the specified XLCd. */
1216 /************************************************************************/
1218 _fallcCreateLocaleDataBase(lcd)
1221 XlcDatabaseList list, new;
1222 Database p, database = (Database)NULL;
1223 XlcDatabase lc_db = (XlcDatabase)NULL;
1225 char pathname[256], *name;
1228 name = _fallcFileName(lcd, "locale");
1230 return (XPointer)NULL;
1232 strcpy(pathname, name);
1235 name_q = falrmStringToQuark(pathname);
1236 for(list = _db_list; list; list = list->next){
1237 if(name_q == list->name_q){
1239 return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)list->lc_db;
1243 database = CreateDatabase(pathname);
1244 if(database == (Database)NULL){
1245 return (XPointer)NULL;
1247 n = CountDatabase(database);
1248 lc_db = (XlcDatabase)Xmalloc(sizeof(XlcDatabaseRec) * (n + 1));
1249 if(lc_db == (XlcDatabase)NULL){
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);
1259 new = (XlcDatabaseList)Xmalloc(sizeof(XlcDatabaseListRec));
1260 if(new == (XlcDatabaseList)NULL){
1263 new->name_q = name_q;
1265 new->database = database;
1267 new->next = _db_list;
1270 return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)lc_db;
1273 DestroyDatabase(database);
1274 if(lc_db != (XlcDatabase)NULL){
1275 Xfree((char *)lc_db);
1277 return (XPointer)NULL;
1280 #endif /* NOT_X_ENV */