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