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