3 * Copyright IBM Corporation 1993
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.
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
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.
39 #include <X11/Xresource.h>
45 #define Xmalloc malloc
46 #define Xrealloc realloc
49 #endif /* NOT_X_ENV */
51 /* specifying NOT_X_ENV allows users to just use
52 the database parsing routine. */
62 #define BUFSIZE 6144 /* 2048*3 */
67 typedef struct _DatabaseRec {
72 struct _DatabaseRec *next;
73 } DatabaseRec, *Database;
76 S_NULL, /* outside category */
77 S_CATEGORY, /* inside category */
78 S_NAME, /* has name, expecting values */
99 Token token; /* token id */
100 int len; /* length of token sequence */
103 static int f_newline (const char *str, Token token, Database *db);
104 static int f_comment (const char *str, Token token, Database *db);
105 static int f_semicolon (const char *str, Token token, Database *db);
106 static int f_double_quote (const char *str, Token token, Database *db);
107 static int f_left_brace (const char *str, Token token, Database *db);
108 static int f_right_brace (const char *str, Token token, Database *db);
109 static int f_white (const char *str, Token token, Database *db);
110 static int f_backslash (const char *str, Token token, Database *db);
111 static int f_numeric (const char *str, Token token, Database *db);
112 static int f_default (const char *str, Token token, Database *db);
114 static const TokenTable token_tbl[] = {
118 { T_DOUBLE_QUOTE, 1 },
120 { T_RIGHT_BRACE, 1 },
124 { T_NUMERIC_HEX, 2 },
125 { T_NUMERIC_DEC, 2 },
126 { T_NUMERIC_OCT, 2 },
127 { T_DEFAULT, 1 } /* any character */
131 #define SYM_NEWLINE '\n'
132 #define SYM_COMMENT '#'
133 #define SYM_SEMICOLON ';'
134 #define SYM_DOUBLE_QUOTE '"'
135 #define SYM_LEFT_BRACE '{'
136 #define SYM_RIGHT_BRACE '}'
137 #define SYM_SPACE ' '
139 #define SYM_BACKSLASH '\\'
141 /************************************************************************/
143 #define MAX_NAME_NEST 64
146 ParseState pre_state;
148 char *name[MAX_NAME_NEST];
153 int bufsize; /* bufMaxSize >= bufsize >= 0 */
154 int bufMaxSize; /* default : BUFSIZE */
158 static DBParseInfo parse_info;
161 init_parse_info (void)
163 static int allocated /* = 0 */;
167 bzero(&parse_info, sizeof(DBParseInfo));
168 parse_info.buf = Xmalloc(BUFSIZE);
169 parse_info.bufMaxSize = BUFSIZE;
173 ptr = parse_info.buf;
174 size = parse_info.bufMaxSize;
175 bzero(&parse_info, sizeof(DBParseInfo));
176 parse_info.buf = ptr;
177 parse_info.bufMaxSize = size;
181 clear_parse_info (void)
186 parse_info.pre_state = S_NULL;
187 if (parse_info.category != NULL) {
188 Xfree(parse_info.category);
190 for (i = 0; i <= parse_info.nest_depth; ++i) {
191 if (parse_info.name[i]) {
192 Xfree(parse_info.name[i]);
195 if (parse_info.value) {
196 if (*parse_info.value) {
197 Xfree(*parse_info.value);
199 Xfree(parse_info.value);
201 ptr = parse_info.buf;
202 size = parse_info.bufMaxSize;
203 bzero(&parse_info, sizeof(DBParseInfo));
204 parse_info.buf = ptr;
205 parse_info.bufMaxSize = size;
213 int newsize = BUFSIZE * ((parse_info.bufsize + len)/BUFSIZE + 1);
215 p = Xrealloc(parse_info.buf, newsize);
218 parse_info.bufMaxSize = newsize;
224 /************************************************************************/
226 typedef struct _Line {
237 if (line->str != NULL) {
240 bzero(line, sizeof(Line));
248 char *str = line->str;
251 str = Xrealloc(str, size);
257 if (line->str != NULL) {
260 bzero(line, sizeof(Line));
264 line->maxsize = size;
268 #define iswhite(ch) ((ch) == SYM_SPACE || (ch) == SYM_TAB)
278 if (*p == SYM_COMMENT) {
279 int len = strlen(str);
280 if (p[len - 1] == SYM_NEWLINE || p[len - 1] == SYM_CR) {
287 if (*p == SYM_DOUBLE_QUOTE) {
288 if (p == str || p[-1] != SYM_BACKSLASH) {
289 /* unescaped double quote changes quoted state. */
290 *quoted = *quoted ? 0 : 1;
293 if (*p == SYM_COMMENT && !*quoted) {
296 (iswhite(p[-1]) && (pos == 1 || p[-2] != SYM_BACKSLASH))) {
298 if (len > 0 && (p[len - 1] == SYM_NEWLINE || p[len-1] == SYM_CR)) {
299 /* newline is the identifier for finding end of value.
300 therefore, it should not be removed. */
317 char buf[BUFSIZE], *p;
319 int quoted = 0; /* quoted by double quote? */
324 cur = line->cursize = 0;
326 while ((p = fgets(buf, BUFSIZE, fd)) != NULL) {
328 zap_comment(p, "ed); /* remove comment line */
336 if (cur + len + 1 > line->maxsize) {
337 /* need to reallocate buffer. */
338 if (! realloc_line(line, line->maxsize + BUFSIZE)) {
339 return -1; /* realloc error. */
343 strncpy(str + cur, p, len);
347 #ifdef __UNIXOS2__ /* Take out carriage returns under OS/2 */
349 if (str[cur-2] == '\r' && str[cur-1] == '\n') {
356 if (!quoted && cur > 1 && str[cur - 2] == SYM_BACKSLASH &&
357 (str[cur - 1] == SYM_NEWLINE || str[cur-1] == SYM_CR)) {
358 /* the line is ended backslash followed by newline.
359 need to concatinate the next line. */
362 } else if (len < BUFSIZE - 1 || buf[len - 1] == SYM_NEWLINE ||
363 buf[len - 1] == SYM_CR) {
364 /* the line is shorter than BUFSIZE. */
369 /* error. still in quoted state. */
372 return line->cursize = cur;
375 /************************************************************************/
383 case SYM_CR: return T_NEWLINE;
384 case SYM_COMMENT: return T_COMMENT;
385 case SYM_SEMICOLON: return T_SEMICOLON;
386 case SYM_DOUBLE_QUOTE: return T_DOUBLE_QUOTE;
387 case SYM_LEFT_BRACE: return T_LEFT_BRACE;
388 case SYM_RIGHT_BRACE: return T_RIGHT_BRACE;
389 case SYM_SPACE: return T_SPACE;
390 case SYM_TAB: return T_TAB;
393 case 'x': return T_NUMERIC_HEX;
394 case 'd': return T_NUMERIC_DEC;
395 case 'o': return T_NUMERIC_OCT;
414 token = get_token(p);
415 token_len = token_tbl[token].len;
416 if (token == T_BACKSLASH) {
420 token = get_token(p);
421 token_len = token_tbl[token].len;
422 } else if (token != T_COMMENT && token != T_DEFAULT) {
425 strncpy(w, p, token_len);
426 p += token_len; w += token_len;
429 return p - str; /* return number of scanned chars */
442 if (*p == SYM_DOUBLE_QUOTE) {
446 token = get_token(p);
447 token_len = token_tbl[token].len;
448 if (token == T_DOUBLE_QUOTE) {
452 if (token == T_BACKSLASH) {
457 token = get_token(p);
458 token_len = token_tbl[token].len;
460 strncpy(w, p, token_len);
461 p += token_len; w += token_len;
463 /* error. cannot detect next double quote */
471 /************************************************************************/
474 append_value_list (void)
476 char **value_list = parse_info.value;
478 int value_num = parse_info.value_num;
479 int value_len = parse_info.value_len;
480 char *str = parse_info.buf;
481 int len = parse_info.bufsize;
485 return 1; /* return with no error */
488 if (value_list == (char **)NULL) {
489 value_list = Xmalloc(sizeof(char *) * 2);
492 char **prev_list = value_list;
494 value_list = (char **)
495 Xrealloc(value_list, sizeof(char *) * (value_num + 2));
496 if (value_list == NULL) {
500 if (value_list == (char **)NULL)
505 value = Xmalloc(value_len + len + 1);
507 char *prev_value = value;
509 value = Xrealloc(value, value_len + len + 1);
517 if (value != *value_list) {
520 delta = value - *value_list;
522 for (i = 1; i < value_num; ++i) {
523 value_list[i] += delta;
527 value_list[value_num] = p = &value[value_len];
528 value_list[value_num + 1] = NULL;
529 strncpy(p, str, len);
532 parse_info.value = value_list;
533 parse_info.value_num = value_num + 1;
534 parse_info.value_len = value_len + len + 1;
535 parse_info.bufsize = 0;
540 Xfree((char **)value_list);
546 parse_info.value = (char **)NULL;
547 parse_info.value_num = 0;
548 parse_info.value_len = 0;
549 parse_info.bufsize = 0;
562 for (i = 0; i <= parse_info.nest_depth; ++i) {
563 len += strlen(parse_info.name[i]) + 1;
568 strcpy(p, parse_info.name[0]);
569 p += strlen(parse_info.name[0]);
570 for (i = 1; i <= parse_info.nest_depth; ++i) {
572 strcpy(p, parse_info.name[i]);
573 p += strlen(parse_info.name[i]);
575 return *name != '\0';
582 Database new = (Database)NULL;
585 if (parse_info.pre_state == S_VALUE) {
586 if (! append_value_list()) {
591 if (parse_info.name[parse_info.nest_depth] == NULL) {
595 new = Xcalloc(1, sizeof(DatabaseRec));
596 if (new == (Database)NULL) {
600 new->category = strdup(parse_info.category);
601 if (new->category == NULL) {
605 if (! construct_name(name, sizeof(name))) {
608 new->name = strdup(name);
609 if (new->name == NULL) {
613 new->value = parse_info.value;
614 new->value_num = parse_info.value_num;
617 Xfree(parse_info.name[parse_info.nest_depth]);
618 parse_info.name[parse_info.nest_depth] = NULL;
620 parse_info.value = (char **)NULL;
621 parse_info.value_num = 0;
622 parse_info.value_len = 0;
629 Xfree(new->category);
636 if (parse_info.value) {
637 if (*parse_info.value) {
638 Xfree(*parse_info.value);
640 Xfree((char **)parse_info.value);
641 parse_info.value = (char **)NULL;
642 parse_info.value_num = 0;
643 parse_info.value_len = 0;
648 #define END_MARK "END"
649 #define END_MARK_LEN 3 /*strlen(END_MARK)*/
659 if (strncmp(p, END_MARK, END_MARK_LEN)) {
664 while (iswhite(*p)) {
667 len = strlen(parse_info.category);
668 if (strncmp(p, parse_info.category, len)) {
675 /************************************************************************/
683 switch (parse_info.pre_state) {
688 return 0; /* no value */
690 if (!store_to_database(db))
692 parse_info.pre_state = S_CATEGORY;
697 return token_tbl[token].len;
706 /* NOTE: comment is already handled in read_line(),
707 so this function is not necessary. */
711 while (*p != SYM_NEWLINE && *p != SYM_CR && *p != '\0') {
712 ++p; /* zap to the end of line */
725 while (iswhite(*p)) {
737 switch (parse_info.pre_state) {
743 if (! append_value_list())
745 parse_info.pre_state = S_VALUE;
750 return token_tbl[token].len;
759 switch (parse_info.pre_state) {
765 if (parse_info.name[parse_info.nest_depth] == NULL
766 || parse_info.nest_depth + 1 > MAX_NAME_NEST)
768 ++parse_info.nest_depth;
769 parse_info.pre_state = S_CATEGORY;
774 return token_tbl[token].len;
783 if (parse_info.nest_depth < 1)
786 switch (parse_info.pre_state) {
791 if (! store_to_database(db))
793 /* fall into next case */
795 if (parse_info.name[parse_info.nest_depth] != NULL) {
796 Xfree(parse_info.name[parse_info.nest_depth]);
797 parse_info.name[parse_info.nest_depth] = NULL;
799 --parse_info.nest_depth;
800 parse_info.pre_state = S_CATEGORY;
805 return token_tbl[token].len;
818 if ((len = strlen (str)) < sizeof word)
821 wordp = Xmalloc (len + 1);
826 switch (parse_info.pre_state) {
832 len = get_quoted_word(str, wordp);
835 if ((parse_info.bufsize + (int)strlen(wordp) + 1)
836 >= parse_info.bufMaxSize) {
837 if (realloc_parse_info(strlen(wordp)+1) == False) {
841 strcpy(&parse_info.buf[parse_info.bufsize], wordp);
842 parse_info.bufsize += strlen(wordp);
843 parse_info.pre_state = S_VALUE;
850 return len; /* including length of token */
864 return f_default(str, token, db);
879 if ((len = strlen (str)) < sizeof word)
882 wordp = Xmalloc (len + 1);
886 switch (parse_info.pre_state) {
892 token_len = token_tbl[token].len;
894 len = get_word(p, wordp);
897 if ((parse_info.bufsize + token_len + (int)strlen(wordp) + 1)
898 >= parse_info.bufMaxSize) {
899 if (realloc_parse_info(token_len + strlen(wordp) + 1) == False)
902 strncpy(&parse_info.buf[parse_info.bufsize], str, token_len);
903 strcpy(&parse_info.buf[parse_info.bufsize + token_len], wordp);
904 parse_info.bufsize += token_len + strlen(wordp);
905 parse_info.pre_state = S_VALUE;
912 return len + token_len;
926 char word[BUFSIZE], *p;
930 if ((len = strlen (str)) < sizeof word)
933 wordp = Xmalloc (len + 1);
937 len = get_word(str, wordp);
941 switch (parse_info.pre_state) {
943 if (parse_info.category != NULL)
948 parse_info.category = p;
949 parse_info.pre_state = S_CATEGORY;
952 if (parse_info.nest_depth == 0) {
953 if (check_category_end(str)) {
954 /* end of category is detected.
955 clear context and zap to end of this line */
964 if (parse_info.name[parse_info.nest_depth] != NULL) {
965 Xfree(parse_info.name[parse_info.nest_depth]);
967 parse_info.name[parse_info.nest_depth] = p;
968 parse_info.pre_state = S_NAME;
972 if ((parse_info.bufsize + (int)strlen(wordp) + 1)
973 >= parse_info.bufMaxSize) {
974 if (realloc_parse_info(strlen(wordp) + 1) == False)
977 strcpy(&parse_info.buf[parse_info.bufsize], wordp);
978 parse_info.bufsize += strlen(wordp);
979 parse_info.pre_state = S_VALUE;
994 /************************************************************************/
1004 printf("***\n*** BEGIN Database\n***\n");
1006 printf("%3d: ", i++);
1007 printf("%s, %s, ", p->category, p->name);
1008 printf("\t[%d: ", p->value_num);
1009 for (j = 0; j < p->value_num; ++j) {
1010 printf("%s, ", p->value[j]);
1015 printf("***\n*** END Database\n***\n");
1026 if (p->category != NULL) {
1029 if (p->name != NULL) {
1032 if (p->value != (char **)NULL) {
1033 if (*p->value != NULL) {
1062 Database db = (Database)NULL;
1070 fd = _XFopenFile(dbfile, "r");
1071 if (fd == (FILE *)NULL)
1074 bzero(&line, sizeof(Line));
1078 int rc = read_line(fd, &line);
1082 } else if (rc == 0) {
1087 int (*parse_proc)(const char *str, Token token, Database *db) = NULL;
1089 token = get_token(p);
1091 switch (token_tbl[token].token) {
1093 parse_proc = f_newline;
1096 parse_proc = f_comment;
1099 parse_proc = f_semicolon;
1101 case T_DOUBLE_QUOTE:
1102 parse_proc = f_double_quote;
1105 parse_proc = f_left_brace;
1108 parse_proc = f_right_brace;
1112 parse_proc = f_white;
1115 parse_proc = f_backslash;
1120 parse_proc = f_numeric;
1123 parse_proc = f_default;
1127 len = parse_proc(p, token, &db);
1137 if (parse_info.pre_state != S_NULL) {
1143 fprintf(stderr, "database format error at line %d.\n", line.seq);
1145 DestroyDatabase(db);
1146 db = (Database)NULL;
1159 /************************************************************************/
1163 /* locale framework functions */
1165 typedef struct _XlcDatabaseRec {
1166 XrmQuark category_q;
1169 struct _XlcDatabaseRec *next;
1170 } XlcDatabaseRec, *XlcDatabase;
1172 typedef struct _XlcDatabaseListRec {
1177 struct _XlcDatabaseListRec *next;
1178 } XlcDatabaseListRec, *XlcDatabaseList;
1180 /* database cache list (per file) */
1181 static XlcDatabaseList _db_list = (XlcDatabaseList)NULL;
1183 /************************************************************************/
1184 /* _XlcGetResource(lcd, category, class, value, count) */
1185 /*----------------------------------------------------------------------*/
1186 /* This function retrieves XLocale database information. */
1187 /************************************************************************/
1191 const char *category,
1196 XLCdPublicMethodsPart *methods = XLC_PUBLIC_METHODS(lcd);
1198 (*methods->get_resource)(lcd, category, class, value, count);
1202 /************************************************************************/
1203 /* _XlcGetLocaleDataBase(lcd, category, class, value, count) */
1204 /*----------------------------------------------------------------------*/
1205 /* This function retrieves XLocale database information. */
1206 /************************************************************************/
1208 _XlcGetLocaleDataBase(
1210 const char *category,
1215 XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
1216 XrmQuark category_q, name_q;
1218 category_q = XrmStringToQuark(category);
1219 name_q = XrmStringToQuark(name);
1220 for (; lc_db->db; ++lc_db) {
1221 if (category_q == lc_db->category_q && name_q == lc_db->name_q) {
1222 *value = lc_db->db->value;
1223 *count = lc_db->db->value_num;
1227 *value = (char **)NULL;
1231 /************************************************************************/
1232 /* _XlcDestroyLocaleDataBase(lcd) */
1233 /*----------------------------------------------------------------------*/
1234 /* This function destroy the XLocale Database that bound to the */
1235 /* specified lcd. If the XLocale Database is refered from some */
1236 /* other lcd, this function just decreases reference count of */
1237 /* the database. If no locale refers the database, this function */
1238 /* remove it from the cache list and free work area. */
1239 /************************************************************************/
1241 _XlcDestroyLocaleDataBase(
1244 XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db);
1245 XlcDatabaseList p, prev;
1247 for (p = _db_list, prev = (XlcDatabaseList)NULL; p;
1248 prev = p, p = p->next) {
1249 if (p->lc_db == lc_db) {
1250 if ((-- p->ref_count) < 1) {
1251 if (p->lc_db != (XlcDatabase)NULL) {
1254 DestroyDatabase(p->database);
1255 if (prev == (XlcDatabaseList)NULL) {
1258 prev->next = p->next;
1265 XLC_PUBLIC(lcd, xlocale_db) = (XPointer)NULL;
1268 /************************************************************************/
1269 /* _XlcCreateLocaleDataBase(lcd) */
1270 /*----------------------------------------------------------------------*/
1271 /* This function create an XLocale database which correspond to */
1272 /* the specified XLCd. */
1273 /************************************************************************/
1275 _XlcCreateLocaleDataBase(
1278 XlcDatabaseList list, new;
1279 Database p, database = (Database)NULL;
1280 XlcDatabase lc_db = (XlcDatabase)NULL;
1285 name = _XlcFileName(lcd, "locale");
1287 return (XPointer)NULL;
1290 name_q = XrmStringToQuark(name);
1292 name_q = XrmStringToQuark((char*)__XOS2RedirRoot(name));
1294 for (list = _db_list; list; list = list->next) {
1295 if (name_q == list->name_q) {
1298 return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)list->lc_db;
1302 database = CreateDatabase(name);
1303 if (database == (Database)NULL) {
1305 return (XPointer)NULL;
1307 n = CountDatabase(database);
1308 lc_db = Xcalloc(n + 1, sizeof(XlcDatabaseRec));
1309 if (lc_db == (XlcDatabase)NULL)
1311 for (p = database, i = 0; p && i < n; p = p->next, ++i) {
1312 lc_db[i].category_q = XrmStringToQuark(p->category);
1313 lc_db[i].name_q = XrmStringToQuark(p->name);
1317 new = Xmalloc(sizeof(XlcDatabaseListRec));
1318 if (new == (XlcDatabaseList)NULL) {
1321 new->name_q = name_q;
1323 new->database = database;
1325 new->next = _db_list;
1329 return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)lc_db;
1332 DestroyDatabase(database);
1333 if (lc_db != (XlcDatabase)NULL) {
1337 return (XPointer)NULL;
1340 #endif /* NOT_X_ENV */