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