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