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