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