lcDB.c revision 1ab64890
1/* $Xorg: lcDB.c,v 1.6 2000/08/17 19:45:17 cpqbld Exp $ */ 2/* 3 * 4 * Copyright IBM Corporation 1993 5 * 6 * All Rights Reserved 7 * 8 * License to use, copy, modify, and distribute this software and its 9 * documentation for any purpose and without fee is hereby granted, 10 * provided that the above copyright notice appear in all copies and that 11 * both that copyright notice and this permission notice appear in 12 * supporting documentation, and that the name of IBM not be 13 * used in advertising or publicity pertaining to distribution of the 14 * software without specific, written prior permission. 15 * 16 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 17 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS, AND 18 * NONINFRINGEMENT OF THIRD PARTY RIGHTS, IN NO EVENT SHALL 19 * IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 20 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 21 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 22 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 23 * SOFTWARE. 24 * 25*/ 26/* 27 * (c) Copyright 1995 FUJITSU LIMITED 28 * This is source code modified by FUJITSU LIMITED under the Joint 29 * Development Agreement for the CDE/Motif PST. 30 */ 31/* $XFree86: xc/lib/X11/lcDB.c,v 3.15tsi Exp $ */ 32 33 34 35#ifndef NOT_X_ENV 36 37#ifdef HAVE_CONFIG_H 38#include <config.h> 39#endif 40#include <X11/Xlib.h> 41#include <X11/Xresource.h> 42#include "Xlibint.h" 43#include "XlcPubI.h" 44 45#else /* NOT_X_ENV */ 46 47#define Xmalloc malloc 48#define Xrealloc realloc 49#define Xfree free 50 51#endif /* NOT_X_ENV */ 52 53/* specifying NOT_X_ENV allows users to just use 54 the database parsing routine. */ 55/* For UDC/VW */ 56#ifndef BUFSIZE 57#define BUFSIZE 2048 58#endif 59 60#ifdef COMMENT 61#ifdef BUFSIZE 62#undef BUFSIZE 63#endif 64#define BUFSIZE 6144 /* 2048*3 */ 65#endif 66 67#include <stdio.h> 68 69typedef struct _DatabaseRec { 70 char *category; 71 char *name; 72 char **value; 73 int value_num; 74 struct _DatabaseRec *next; 75} DatabaseRec, *Database; 76 77typedef enum { 78 S_NULL, /* outside category */ 79 S_CATEGORY, /* inside category */ 80 S_NAME, /* has name, expecting values */ 81 S_VALUE 82} ParseState; 83 84typedef enum { 85 T_NEWLINE, 86 T_COMMENT, 87 T_SEMICOLON, 88 T_DOUBLE_QUOTE, 89 T_LEFT_BRACE, 90 T_RIGHT_BRACE, 91 T_SPACE, 92 T_TAB, 93 T_BACKSLASH, 94 T_NUMERIC_HEX, 95 T_NUMERIC_DEC, 96 T_NUMERIC_OCT, 97 T_DEFAULT 98} Token; 99 100typedef struct { 101 Token token; /* token id */ 102 int len; /* length of token sequence */ 103} TokenTable; 104 105static int f_newline (const char *str, Token token, Database *db); 106static int f_comment (const char *str, Token token, Database *db); 107static int f_semicolon (const char *str, Token token, Database *db); 108static int f_double_quote (const char *str, Token token, Database *db); 109static int f_left_brace (const char *str, Token token, Database *db); 110static int f_right_brace (const char *str, Token token, Database *db); 111static int f_white (const char *str, Token token, Database *db); 112static int f_backslash (const char *str, Token token, Database *db); 113static int f_numeric (const char *str, Token token, Database *db); 114static int f_default (const char *str, Token token, Database *db); 115 116static const TokenTable token_tbl[] = { 117 { T_NEWLINE, 1 }, 118 { T_COMMENT, 1 }, 119 { T_SEMICOLON, 1 }, 120 { T_DOUBLE_QUOTE, 1 }, 121 { T_LEFT_BRACE, 1 }, 122 { T_RIGHT_BRACE, 1 }, 123 { T_SPACE, 1 }, 124 { T_TAB, 1 }, 125 { T_BACKSLASH, 1 }, 126 { T_NUMERIC_HEX, 2 }, 127 { T_NUMERIC_DEC, 2 }, 128 { T_NUMERIC_OCT, 2 }, 129 { T_DEFAULT, 1 } /* any character */ 130}; 131 132#define SYM_CR '\r' 133#define SYM_NEWLINE '\n' 134#define SYM_COMMENT '#' 135#define SYM_SEMICOLON ';' 136#define SYM_DOUBLE_QUOTE '"' 137#define SYM_LEFT_BRACE '{' 138#define SYM_RIGHT_BRACE '}' 139#define SYM_SPACE ' ' 140#define SYM_TAB '\t' 141#define SYM_BACKSLASH '\\' 142 143/************************************************************************/ 144 145#define MAX_NAME_NEST 64 146 147typedef struct { 148 ParseState pre_state; 149 char *category; 150 char *name[MAX_NAME_NEST]; 151 int nest_depth; 152 char **value; 153 int value_len; 154 int value_num; 155 int bufsize; /* bufMaxSize >= bufsize >= 0 */ 156 int bufMaxSize; /* default : BUFSIZE */ 157 char *buf; 158} DBParseInfo; 159 160static DBParseInfo parse_info; 161 162static void 163init_parse_info (void) 164{ 165 static int allocated /* = 0 */; 166 char *ptr; 167 int size; 168 if (!allocated) { 169 bzero(&parse_info, sizeof(DBParseInfo)); 170 parse_info.buf = (char *)Xmalloc(BUFSIZE); 171 parse_info.bufMaxSize = BUFSIZE; 172 allocated = 1; 173 return; 174 } 175 ptr = parse_info.buf; 176 size = parse_info.bufMaxSize; 177 bzero(&parse_info, sizeof(DBParseInfo)); 178 parse_info.buf = ptr; 179 parse_info.bufMaxSize = size; 180} 181 182static void 183clear_parse_info (void) 184{ 185 int i; 186 char *ptr; 187 int size; 188 parse_info.pre_state = S_NULL; 189 if (parse_info.category != NULL) { 190 Xfree(parse_info.category); 191 } 192 for (i = 0; i <= parse_info.nest_depth; ++i) { 193 if (parse_info.name[i]) { 194 Xfree(parse_info.name[i]); 195 } 196 } 197 if (parse_info.value) { 198 if (*parse_info.value) { 199 Xfree(*parse_info.value); 200 } 201 Xfree((char *)parse_info.value); 202 } 203 ptr = parse_info.buf; 204 size = parse_info.bufMaxSize; 205 bzero(&parse_info, sizeof(DBParseInfo)); 206 parse_info.buf = ptr; 207 parse_info.bufMaxSize = size; 208} 209 210static Bool 211realloc_parse_info( 212 int len) 213{ 214 char *p; 215 216 parse_info.bufMaxSize = BUFSIZE * ((parse_info.bufsize + len)/BUFSIZE + 1); 217 p = (char *)Xrealloc(parse_info.buf, parse_info.bufMaxSize); 218 if (p == NULL) 219 return False; 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 = (char *)Xrealloc(str, size); 253 } else { 254 str = (char *)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 = 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 = 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, 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, 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, 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 = (char **)Xmalloc(sizeof(char *) * 2); 491 *value_list = NULL; 492 } else { 493 char **prev_list = value_list; 494 495 value_list = (char **) 496 Xrealloc(value_list, sizeof(char *) * (value_num + 2)); 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 = (char *)Xmalloc(value_len + len + 1); 507 } else { 508 char *prev_value = value; 509 510 value = (char *)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, 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 += 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 = (Database)Xmalloc(sizeof(DatabaseRec)); 597 if (new == (Database)NULL) { 598 goto err; 599 } 600 bzero(new, sizeof(DatabaseRec)); 601 602 new->category = (char *)Xmalloc(strlen(parse_info.category) + 1); 603 if (new->category == NULL) { 604 goto err; 605 } 606 strcpy(new->category, parse_info.category); 607 608 if (! construct_name(name, sizeof(name))) { 609 goto err; 610 } 611 new->name = (char *)Xmalloc(strlen(name) + 1); 612 if (new->name == NULL) { 613 goto err; 614 } 615 strcpy(new->name, name); 616 new->next = *db; 617 new->value = parse_info.value; 618 new->value_num = parse_info.value_num; 619 *db = new; 620 621 Xfree(parse_info.name[parse_info.nest_depth]); 622 parse_info.name[parse_info.nest_depth] = NULL; 623 624 parse_info.value = (char **)NULL; 625 parse_info.value_num = 0; 626 parse_info.value_len = 0; 627 628 return 1; 629 630 err: 631 if (new) { 632 if (new->category) { 633 Xfree(new->category); 634 } 635 if (new->name) { 636 Xfree(new->name); 637 } 638 Xfree(new); 639 } 640 if (parse_info.value) { 641 if (*parse_info.value) { 642 Xfree(*parse_info.value); 643 } 644 Xfree((char **)parse_info.value); 645 parse_info.value = (char **)NULL; 646 parse_info.value_num = 0; 647 parse_info.value_len = 0; 648 } 649 return 0; 650} 651 652#define END_MARK "END" 653#define END_MARK_LEN 3 /*strlen(END_MARK)*/ 654 655static int 656check_category_end( 657 const char *str) 658{ 659 const char *p; 660 int len; 661 662 p = str; 663 if (strncmp(p, END_MARK, END_MARK_LEN)) { 664 return 0; 665 } 666 p += END_MARK_LEN; 667 668 while (iswhite(*p)) { 669 ++p; 670 } 671 len = strlen(parse_info.category); 672 if (strncmp(p, parse_info.category, len)) { 673 return 0; 674 } 675 p += len; 676 return p - str; 677} 678 679/************************************************************************/ 680 681static int 682f_newline( 683 const char *str, 684 Token token, 685 Database *db) 686{ 687 switch (parse_info.pre_state) { 688 case S_NULL: 689 case S_CATEGORY: 690 break; 691 case S_NAME: 692 return 0; /* no value */ 693 case S_VALUE: 694 if (!store_to_database(db)) 695 return 0; 696 parse_info.pre_state = S_CATEGORY; 697 break; 698 default: 699 return 0; 700 } 701 return token_tbl[token].len; 702} 703 704static int 705f_comment( 706 const char *str, 707 Token token, 708 Database *db) 709{ 710 /* NOTE: comment is already handled in read_line(), 711 so this function is not necessary. */ 712 713 const char *p = str; 714 715 while (*p != SYM_NEWLINE && *p != SYM_CR && *p != '\0') { 716 ++p; /* zap to the end of line */ 717 } 718 return p - str; 719} 720 721static int 722f_white( 723 const char *str, 724 Token token, 725 Database *db) 726{ 727 const char *p = str; 728 729 while (iswhite(*p)) { 730 ++p; 731 } 732 return p - str; 733} 734 735static int 736f_semicolon( 737 const char *str, 738 Token token, 739 Database *db) 740{ 741 switch (parse_info.pre_state) { 742 case S_NULL: 743 case S_CATEGORY: 744 case S_NAME: 745 return 0; 746 case S_VALUE: 747 if (! append_value_list()) 748 return 0; 749 parse_info.pre_state = S_VALUE; 750 break; 751 default: 752 return 0; 753 } 754 return token_tbl[token].len; 755} 756 757static int 758f_left_brace( 759 const char *str, 760 Token token, 761 Database *db) 762{ 763 switch (parse_info.pre_state) { 764 case S_NULL: 765 case S_CATEGORY: 766 case S_VALUE: 767 return 0; 768 case S_NAME: 769 if (parse_info.name[parse_info.nest_depth] == NULL 770 || parse_info.nest_depth + 1 > MAX_NAME_NEST) 771 return 0; 772 ++parse_info.nest_depth; 773 parse_info.pre_state = S_CATEGORY; 774 break; 775 default: 776 return 0; 777 } 778 return token_tbl[token].len; 779} 780 781static int 782f_right_brace( 783 const char *str, 784 Token token, 785 Database *db) 786{ 787 if (parse_info.nest_depth < 1) 788 return 0; 789 790 switch (parse_info.pre_state) { 791 case S_NULL: 792 case S_NAME: 793 return 0; 794 case S_VALUE: 795 if (! store_to_database(db)) 796 return 0; 797 /* fall into next case */ 798 case S_CATEGORY: 799 if (parse_info.name[parse_info.nest_depth] != NULL) { 800 Xfree(parse_info.name[parse_info.nest_depth]); 801 parse_info.name[parse_info.nest_depth] = NULL; 802 } 803 --parse_info.nest_depth; 804 parse_info.pre_state = S_CATEGORY; 805 break; 806 default: 807 return 0; 808 } 809 return token_tbl[token].len; 810} 811 812static int 813f_double_quote( 814 const char *str, 815 Token token, 816 Database *db) 817{ 818 char word[BUFSIZE]; 819 char* wordp; 820 int len; 821 822 if ((len = strlen (str)) < sizeof word) 823 wordp = word; 824 else 825 wordp = Xmalloc (len + 1); 826 if (wordp == NULL) 827 return 0; 828 829 len = 0; 830 switch (parse_info.pre_state) { 831 case S_NULL: 832 case S_CATEGORY: 833 goto err; 834 case S_NAME: 835 case S_VALUE: 836 len = get_quoted_word(str, wordp); 837 if (len < 1) 838 goto err; 839 if ((parse_info.bufsize + (int)strlen(wordp) + 1) 840 >= parse_info.bufMaxSize) { 841 if (realloc_parse_info(strlen(wordp)+1) == False) { 842 goto err; 843 } 844 } 845 strcpy(&parse_info.buf[parse_info.bufsize], wordp); 846 parse_info.bufsize += strlen(wordp); 847 parse_info.pre_state = S_VALUE; 848 break; 849 default: 850 goto err; 851 } 852 if (wordp != word) 853 Xfree (wordp); 854 return len; /* including length of token */ 855 856err: 857 if (wordp != word) 858 Xfree (wordp); 859 return 0; 860} 861 862static int 863f_backslash( 864 const char *str, 865 Token token, 866 Database *db) 867{ 868 return f_default(str, token, db); 869} 870 871static int 872f_numeric( 873 const char *str, 874 Token token, 875 Database *db) 876{ 877 char word[BUFSIZE]; 878 const char *p; 879 char* wordp; 880 int len; 881 int token_len; 882 883 if ((len = strlen (str)) < sizeof word) 884 wordp = word; 885 else 886 wordp = Xmalloc (len + 1); 887 if (wordp == NULL) 888 return 0; 889 890 switch (parse_info.pre_state) { 891 case S_NULL: 892 case S_CATEGORY: 893 goto err; 894 case S_NAME: 895 case S_VALUE: 896 token_len = token_tbl[token].len; 897 p = str + token_len; 898 len = get_word(p, wordp); 899 if (len < 1) 900 goto err; 901 if ((parse_info.bufsize + token_len + (int)strlen(wordp) + 1) 902 >= parse_info.bufMaxSize) { 903 if (realloc_parse_info(token_len + strlen(wordp) + 1) == False) 904 goto err; 905 } 906 strncpy(&parse_info.buf[parse_info.bufsize], str, token_len); 907 strcpy(&parse_info.buf[parse_info.bufsize + token_len], wordp); 908 parse_info.bufsize += token_len + strlen(wordp); 909 parse_info.pre_state = S_VALUE; 910 break; 911 default: 912 goto err; 913 } 914 if (wordp != word) 915 Xfree (wordp); 916 return len + token_len; 917 918err: 919 if (wordp != word) 920 Xfree (wordp); 921 return 0; 922} 923 924static int 925f_default( 926 const char *str, 927 Token token, 928 Database *db) 929{ 930 char word[BUFSIZE], *p; 931 char* wordp; 932 int len; 933 934 if ((len = strlen (str)) < sizeof word) 935 wordp = word; 936 else 937 wordp = Xmalloc (len + 1); 938 if (wordp == NULL) 939 return 0; 940 941 len = get_word(str, wordp); 942 if (len < 1) 943 goto err; 944 945 switch (parse_info.pre_state) { 946 case S_NULL: 947 if (parse_info.category != NULL) 948 goto err; 949 p = (char *)Xmalloc(strlen(wordp) + 1); 950 if (p == NULL) 951 goto err; 952 strcpy(p, wordp); 953 parse_info.category = p; 954 parse_info.pre_state = S_CATEGORY; 955 break; 956 case S_CATEGORY: 957 if (parse_info.nest_depth == 0) { 958 if (check_category_end(str)) { 959 /* end of category is detected. 960 clear context and zap to end of this line */ 961 clear_parse_info(); 962 len = strlen(str); 963 break; 964 } 965 } 966 p = (char *)Xmalloc(strlen(wordp) + 1); 967 if (p == NULL) 968 goto err; 969 strcpy(p, wordp); 970 if (parse_info.name[parse_info.nest_depth] != NULL) { 971 Xfree(parse_info.name[parse_info.nest_depth]); 972 } 973 parse_info.name[parse_info.nest_depth] = p; 974 parse_info.pre_state = S_NAME; 975 break; 976 case S_NAME: 977 case S_VALUE: 978 if ((parse_info.bufsize + (int)strlen(wordp) + 1) 979 >= parse_info.bufMaxSize) { 980 if (realloc_parse_info(strlen(wordp) + 1) == False) 981 goto err; 982 } 983 strcpy(&parse_info.buf[parse_info.bufsize], wordp); 984 parse_info.bufsize += strlen(wordp); 985 parse_info.pre_state = S_VALUE; 986 break; 987 default: 988 goto err; 989 } 990 if (wordp != word) 991 Xfree (wordp); 992 return len; 993 994err: 995 if (wordp != word) 996 Xfree (wordp); 997 return 0; 998} 999 1000/************************************************************************/ 1001 1002#ifdef DEBUG 1003static void 1004PrintDatabase( 1005 Database db) 1006{ 1007 Database p = db; 1008 int i = 0, j; 1009 1010 printf("***\n*** BEGIN Database\n***\n"); 1011 while (p) { 1012 printf("%3d: ", i++); 1013 printf("%s, %s, ", p->category, p->name); 1014 printf("\t[%d: ", p->value_num); 1015 for (j = 0; j < p->value_num; ++j) { 1016 printf("%s, ", p->value[j]); 1017 } 1018 printf("]\n"); 1019 p = p->next; 1020 } 1021 printf("***\n*** END Database\n***\n"); 1022} 1023#endif 1024 1025static void 1026DestroyDatabase( 1027 Database db) 1028{ 1029 Database p = db; 1030 1031 while (p) { 1032 if (p->category != NULL) { 1033 Xfree(p->category); 1034 } 1035 if (p->name != NULL) { 1036 Xfree(p->name); 1037 } 1038 if (p->value != (char **)NULL) { 1039 if (*p->value != NULL) { 1040 Xfree(*p->value); 1041 } 1042 Xfree((char *)p->value); 1043 } 1044 db = p->next; 1045 Xfree((char *)p); 1046 p = db; 1047 } 1048} 1049 1050static int 1051CountDatabase( 1052 Database db) 1053{ 1054 Database p = db; 1055 int cnt = 0; 1056 1057 while (p) { 1058 ++cnt; 1059 p = p->next; 1060 } 1061 return cnt; 1062} 1063 1064static Database 1065CreateDatabase( 1066 char *dbfile) 1067{ 1068 Database db = (Database)NULL; 1069 FILE *fd; 1070 Line line; 1071 char *p; 1072 Token token; 1073 int len; 1074 int error = 0; 1075 1076 fd = _XFopenFile(dbfile, "r"); 1077 if (fd == (FILE *)NULL) 1078 return NULL; 1079 1080 bzero(&line, sizeof(Line)); 1081 init_parse_info(); 1082 1083 do { 1084 int rc = read_line(fd, &line); 1085 if (rc < 0) { 1086 error = 1; 1087 break; 1088 } else if (rc == 0) { 1089 break; 1090 } 1091 p = line.str; 1092 while (*p) { 1093 int (*parse_proc)(const char *str, Token token, Database *db) = NULL; 1094 1095 token = get_token(p); 1096 1097 switch (token_tbl[token].token) { 1098 case T_NEWLINE: 1099 parse_proc = f_newline; 1100 break; 1101 case T_COMMENT: 1102 parse_proc = f_comment; 1103 break; 1104 case T_SEMICOLON: 1105 parse_proc = f_semicolon; 1106 break; 1107 case T_DOUBLE_QUOTE: 1108 parse_proc = f_double_quote; 1109 break; 1110 case T_LEFT_BRACE: 1111 parse_proc = f_left_brace; 1112 break; 1113 case T_RIGHT_BRACE: 1114 parse_proc = f_right_brace; 1115 break; 1116 case T_SPACE: 1117 case T_TAB: 1118 parse_proc = f_white; 1119 break; 1120 case T_BACKSLASH: 1121 parse_proc = f_backslash; 1122 break; 1123 case T_NUMERIC_HEX: 1124 case T_NUMERIC_DEC: 1125 case T_NUMERIC_OCT: 1126 parse_proc = f_numeric; 1127 break; 1128 case T_DEFAULT: 1129 parse_proc = f_default; 1130 break; 1131 } 1132 1133 len = parse_proc(p, token, &db); 1134 1135 if (len < 1) { 1136 error = 1; 1137 break; 1138 } 1139 p += len; 1140 } 1141 } while (!error); 1142 1143 if (parse_info.pre_state != S_NULL) { 1144 clear_parse_info(); 1145 error = 1; 1146 } 1147 if (error) { 1148#ifdef DEBUG 1149 fprintf(stderr, "database format error at line %d.\n", line.seq); 1150#endif 1151 DestroyDatabase(db); 1152 db = (Database)NULL; 1153 } 1154 1155 fclose(fd); 1156 free_line(&line); 1157 1158#ifdef DEBUG 1159 PrintDatabase(db); 1160#endif 1161 1162 return db; 1163} 1164 1165/************************************************************************/ 1166 1167#ifndef NOT_X_ENV 1168 1169/* locale framework functions */ 1170 1171typedef struct _XlcDatabaseRec { 1172 XrmQuark category_q; 1173 XrmQuark name_q; 1174 Database db; 1175 struct _XlcDatabaseRec *next; 1176} XlcDatabaseRec, *XlcDatabase; 1177 1178typedef struct _XlcDatabaseListRec { 1179 XrmQuark name_q; 1180 XlcDatabase lc_db; 1181 Database database; 1182 int ref_count; 1183 struct _XlcDatabaseListRec *next; 1184} XlcDatabaseListRec, *XlcDatabaseList; 1185 1186/* database cache list (per file) */ 1187static XlcDatabaseList _db_list = (XlcDatabaseList)NULL; 1188 1189/************************************************************************/ 1190/* _XlcGetResource(lcd, category, class, value, count) */ 1191/*----------------------------------------------------------------------*/ 1192/* This function retrieves XLocale database information. */ 1193/************************************************************************/ 1194void 1195_XlcGetResource( 1196 XLCd lcd, 1197 const char *category, 1198 const char *class, 1199 char ***value, 1200 int *count) 1201{ 1202 XLCdPublicMethodsPart *methods = XLC_PUBLIC_METHODS(lcd); 1203 1204 (*methods->get_resource)(lcd, category, class, value, count); 1205 return; 1206} 1207 1208/************************************************************************/ 1209/* _XlcGetLocaleDataBase(lcd, category, class, value, count) */ 1210/*----------------------------------------------------------------------*/ 1211/* This function retrieves XLocale database information. */ 1212/************************************************************************/ 1213void 1214_XlcGetLocaleDataBase( 1215 XLCd lcd, 1216 const char *category, 1217 const char *name, 1218 char ***value, 1219 int *count) 1220{ 1221 XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db); 1222 XrmQuark category_q, name_q; 1223 1224 category_q = XrmStringToQuark(category); 1225 name_q = XrmStringToQuark(name); 1226 for (; lc_db->db; ++lc_db) { 1227 if (category_q == lc_db->category_q && name_q == lc_db->name_q) { 1228 *value = lc_db->db->value; 1229 *count = lc_db->db->value_num; 1230 return; 1231 } 1232 } 1233 *value = (char **)NULL; 1234 *count = 0; 1235} 1236 1237/************************************************************************/ 1238/* _XlcDestroyLocaleDataBase(lcd) */ 1239/*----------------------------------------------------------------------*/ 1240/* This function destroy the XLocale Database that bound to the */ 1241/* specified lcd. If the XLocale Database is refered from some */ 1242/* other lcd, this function just decreases reference count of */ 1243/* the database. If no locale refers the database, this function */ 1244/* remove it from the cache list and free work area. */ 1245/************************************************************************/ 1246void 1247_XlcDestroyLocaleDataBase( 1248 XLCd lcd) 1249{ 1250 XlcDatabase lc_db = (XlcDatabase)XLC_PUBLIC(lcd, xlocale_db); 1251 XlcDatabaseList p, prev; 1252 1253 for (p = _db_list, prev = (XlcDatabaseList)NULL; p; 1254 prev = p, p = p->next) { 1255 if (p->lc_db == lc_db) { 1256 if ((-- p->ref_count) < 1) { 1257 if (p->lc_db != (XlcDatabase)NULL) { 1258 Xfree((char *)p->lc_db); 1259 } 1260 DestroyDatabase(p->database); 1261 if (prev == (XlcDatabaseList)NULL) { 1262 _db_list = p->next; 1263 } else { 1264 prev->next = p->next; 1265 } 1266 Xfree((char*)p); 1267 } 1268 break; 1269 } 1270 } 1271 XLC_PUBLIC(lcd, xlocale_db) = (XPointer)NULL; 1272} 1273 1274/************************************************************************/ 1275/* _XlcCreateLocaleDataBase(lcd) */ 1276/*----------------------------------------------------------------------*/ 1277/* This function create an XLocale database which correspond to */ 1278/* the specified XLCd. */ 1279/************************************************************************/ 1280XPointer 1281_XlcCreateLocaleDataBase( 1282 XLCd lcd) 1283{ 1284 XlcDatabaseList list, new; 1285 Database p, database = (Database)NULL; 1286 XlcDatabase lc_db = (XlcDatabase)NULL; 1287 XrmQuark name_q; 1288 char *name; 1289 int i, n; 1290 1291 name = _XlcFileName(lcd, "locale"); 1292 if (name == NULL) 1293 return (XPointer)NULL; 1294 1295#ifndef __UNIXOS2__ 1296 name_q = XrmStringToQuark(name); 1297#else 1298 name_q = XrmStringToQuark((char*)__XOS2RedirRoot(name)); 1299#endif 1300 for (list = _db_list; list; list = list->next) { 1301 if (name_q == list->name_q) { 1302 list->ref_count++; 1303 Xfree (name); 1304 return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)list->lc_db; 1305 } 1306 } 1307 1308 database = CreateDatabase(name); 1309 if (database == (Database)NULL) { 1310 Xfree (name); 1311 return (XPointer)NULL; 1312 } 1313 n = CountDatabase(database); 1314 lc_db = (XlcDatabase)Xmalloc(sizeof(XlcDatabaseRec) * (n + 1)); 1315 if (lc_db == (XlcDatabase)NULL) 1316 goto err; 1317 bzero(lc_db, sizeof(XlcDatabaseRec) * (n + 1)); 1318 for (p = database, i = 0; p && i < n; p = p->next, ++i) { 1319 lc_db[i].category_q = XrmStringToQuark(p->category); 1320 lc_db[i].name_q = XrmStringToQuark(p->name); 1321 lc_db[i].db = p; 1322 } 1323 1324 new = (XlcDatabaseList)Xmalloc(sizeof(XlcDatabaseListRec)); 1325 if (new == (XlcDatabaseList)NULL) { 1326 goto err; 1327 } 1328 new->name_q = name_q; 1329 new->lc_db = lc_db; 1330 new->database = database; 1331 new->ref_count = 1; 1332 new->next = _db_list; 1333 _db_list = new; 1334 1335 Xfree (name); 1336 return XLC_PUBLIC(lcd, xlocale_db) = (XPointer)lc_db; 1337 1338 err: 1339 DestroyDatabase(database); 1340 if (lc_db != (XlcDatabase)NULL) { 1341 Xfree((char *)lc_db); 1342 } 1343 Xfree (name); 1344 return (XPointer)NULL; 1345} 1346 1347#endif /* NOT_X_ENV */ 1348