1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "synonyms.h" 30 #include "mtlib.h" 31 #include <ctype.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <sys/types.h> 36 #include <thread.h> 37 #include <synch.h> 38 #include <limits.h> 39 #include <unistd.h> 40 #include <sys/mman.h> 41 #include <langinfo.h> 42 #include "libc.h" 43 #include "_loc_path.h" 44 #include "msgfmt.h" 45 #include "gettext.h" 46 47 #ifdef GETTEXT_DEBUG 48 #include "plural_parser.h" 49 #include <stdarg.h> 50 #endif 51 52 static const char *category_name[] = { 53 "LC_CTYPE", 54 "LC_NUMERIC", 55 "LC_TIME", 56 "LC_COLLATE", 57 "LC_MONETARY", 58 "LC_MESSAGES" 59 }; 60 61 static const int category_name_len[] = { 62 8, 63 10, 64 7, 65 10, 66 11, 67 11 68 }; 69 70 static int 71 setmo(Msg_node *mnp, char *addr, int type) 72 { 73 #ifdef GETTEXT_DEBUG 74 (void) printf("*************** setmo(0x%p, %d)\n", 75 (void *)mnp, ret); 76 printmnp(mnp, 0); 77 #endif 78 79 switch (type) { 80 case T_ILL_MO: 81 /* invalid MO */ 82 mnp->type = T_ILL_MO; 83 #ifdef GETTEXT_DEBUG 84 (void) printf("*************** exiting setmo\n"); 85 printmnp(mnp, 0); 86 #endif 87 return (0); 88 case T_SUN_MO: 89 { 90 struct msg_info *sun_header; 91 int struct_size, info_size, count; 92 Msg_s_node *p; 93 p = (Msg_s_node *)calloc(1, sizeof (Msg_s_node)); 94 if (!p) { 95 return (-1); 96 } 97 /* LINTED */ 98 sun_header = (struct msg_info *)addr; 99 count = sun_header->msg_count; 100 struct_size = (int)(MSG_STRUCT_SIZE * count); 101 info_size = (int)(sizeof (struct msg_info)); 102 p->msg_file_info = sun_header; 103 /* LINTED */ 104 p->msg_list = (struct msg_struct *)(((char *)addr) + 105 info_size); 106 p->msg_ids = (char *)(((char *)addr) + info_size + 107 struct_size); 108 p->msg_strs = (char *)(((char *)addr) + info_size + 109 struct_size + sun_header->str_count_msgid); 110 111 mnp->msg.sunmsg = p; 112 mnp->type = T_SUN_MO; 113 #ifdef GETTEXT_DEBUG 114 (void) printf("*************** exiting setmo\n"); 115 printmnp(mnp, 0); 116 #endif 117 return (0); 118 } 119 /* NOTREACHED */ 120 case T_GNU_MO: 121 case T_GNU_SWAPPED_MO: 122 { 123 struct gnu_msg_info *gnu_header; 124 Msg_g_node *p; 125 p = (Msg_g_node *)calloc(1, sizeof (Msg_g_node)); 126 if (!p) { 127 return (-1); 128 } 129 /* LINTED */ 130 gnu_header = (struct gnu_msg_info *)addr; 131 p->msg_file_info = gnu_header; 132 if (type == T_GNU_SWAPPED_MO) { 133 /* 134 * This MO file has been created on 135 * the reversed endian system 136 */ 137 p->flag |= ST_SWP; 138 } 139 /* LINTED */ 140 p->hash_table = (unsigned int *)(((char *)addr) + 141 SWAP(p, gnu_header->off_hashtbl)); 142 143 mnp->msg.gnumsg = p; 144 mnp->type = T_GNU_MO; 145 #ifdef GETTEXT_DEBUG 146 (void) printf("*************** exiting setmo\n"); 147 printmnp(mnp, 0); 148 #endif 149 return (0); 150 } 151 /* NOTREACHED */ 152 } 153 /* NOTREACHED */ 154 return (0); /* keep gcc happy */ 155 } 156 157 /* 158 * setmsg 159 * 160 * INPUT 161 * mnp - message node 162 * addr - address to the mmapped file 163 * size - size of the file 164 * 165 * RETURN 166 * 0 - succeeded 167 * -1 - failed 168 */ 169 int 170 setmsg(Msg_node *mnp, char *addr, size_t size) 171 { 172 struct msg_info *sun_header; 173 struct gnu_msg_info *gnu_header; 174 unsigned int first_4bytes; 175 int mid, count; 176 int struct_size, struct_size_old; 177 int msg_struct_size; 178 179 if (size < sizeof (struct msg_info)) { 180 /* invalid mo file */ 181 return (setmo(mnp, addr, T_ILL_MO)); 182 } 183 184 /* LINTED */ 185 first_4bytes = *((unsigned int *)addr); 186 if (first_4bytes <= INT_MAX) { 187 /* candidate for sun mo */ 188 /* LINTED */ 189 sun_header = (struct msg_info *)addr; 190 mid = sun_header->msg_mid; 191 count = sun_header->msg_count; 192 msg_struct_size = sun_header->msg_struct_size; 193 struct_size_old = (int)(OLD_MSG_STRUCT_SIZE * count); 194 struct_size = (int)(MSG_STRUCT_SIZE * count); 195 196 if ((((count - 1) / 2) == mid) && 197 ((msg_struct_size == struct_size_old) || 198 (msg_struct_size == struct_size))) { 199 /* valid sun mo file */ 200 return (setmo(mnp, addr, T_SUN_MO)); 201 } 202 /* invalid mo file */ 203 return (setmo(mnp, addr, T_ILL_MO)); 204 } 205 206 /* checks the GNU MAGIC number */ 207 if (size < sizeof (struct gnu_msg_info)) { 208 /* invalid mo file */ 209 return (setmo(mnp, addr, T_ILL_MO)); 210 } 211 212 /* LINTED */ 213 gnu_header = (struct gnu_msg_info *)addr; 214 if ((gnu_header->magic == GNU_MAGIC) && 215 (gnu_header->revision == GNU_REVISION)) { 216 /* GNU mo file */ 217 return (setmo(mnp, addr, T_GNU_MO)); 218 } else if ((gnu_header->magic == GNU_MAGIC_SWAPPED) && 219 (gnu_header->revision == GNU_REVISION_SWAPPED)) { 220 /* endian-swapped GNU mo file */ 221 return (setmo(mnp, addr, T_GNU_SWAPPED_MO)); 222 } 223 224 /* invalid mo file */ 225 return (setmo(mnp, addr, T_ILL_MO)); 226 } 227 228 /* 229 * mk_msgfile 230 * 231 * INPUT 232 * mp - uses the following members: 233 * msgfile - buffer to store the pathname to the message file 234 * binding - directory pathname bound to specified domain 235 * cblen - length of binding 236 * locale - locale name 237 * domain - domain name 238 * category - category 239 * locale_len - length of locale name 240 * domain_len - length of domain name 241 * 242 * OUTPUT 243 * mp->msgfile - pathname to the message file is stored 244 * mp->msgfile_len - length of mp->msgfile without null termination 245 * 246 * RETURN 247 * mp->msgfile is returned 248 */ 249 char * 250 mk_msgfile(struct msg_pack *mp) 251 { 252 char *p, *q; 253 const char *catstr; 254 size_t cblen, catlen, totallen; 255 256 #ifdef GETTEXT_DEBUG 257 (void) printf("*************** mk_msgfile(0x%p)\n", 258 (void *)mp); 259 printmp(mp, 0); 260 #endif 261 262 p = mp->msgfile; 263 q = mp->binding; 264 while (*p = *q++) 265 p++; 266 cblen = (size_t)(p - mp->msgfile); 267 if (*(p - 1) != '/') { 268 /* 269 * if the last character of binding 270 * isn't a '/', adding '/'. 271 */ 272 if (cblen + 1 >= MAXPATHLEN) { 273 /* MAXPATHLEN includes a null termination */ 274 return (NULL); 275 } 276 *p++ = '/'; 277 cblen++; 278 } 279 280 catstr = category_name[mp->category]; 281 catlen = (size_t)category_name_len[mp->category]; 282 /* 283 * totallen is the length of the msgfile 284 * pathname excluding a null termination. 285 */ 286 287 totallen = cblen + mp->locale_len + 1 + catlen + 1 + 288 mp->domain_len + MSGFILESUFFIXLEN; 289 if (totallen >= MAXPATHLEN) 290 return (NULL); 291 292 q = mp->locale; 293 while (*p++ = *q++) 294 ; 295 *(p - 1) = '/'; 296 while (*p++ = *catstr++) 297 ; 298 *(p - 1) = '/'; 299 q = mp->domain; 300 while (*p++ = *q++) 301 ; 302 *(p - 1) = '.'; 303 *p = 'm'; 304 *(p + 1) = 'o'; 305 *(p + 2) = '\0'; 306 307 mp->msgfile_len = totallen; 308 309 #ifdef GETTEXT_DEBUG 310 (void) printf("*************** Exiting mk_msgfile\n"); 311 (void) printf("mp->msgfile: \"%s\"\n", mp->msgfile); 312 #endif 313 314 return (mp->msgfile); 315 } 316 317 318 /* 319 * check_cache 320 * 321 * INPUT 322 * cp - may use the following members: 323 * node_hash - pointer to the Cache_node object having this locale 324 * 325 * mp - may use the following members: 326 * msgfile - pathname to the message catalog file 327 * hash_locale - hash id of this locale 328 * 329 * OUTPUT 330 * cp - may update the following members: 331 * mnp - pointer to a Msg_node object 332 * cnp - pointer to a Cache_node object 333 * node_hash - pointer to the Cache_node object having this locale 334 * cacheline - flag to show if the Cache_node for this locale exists 335 * 336 * RETURN 337 * 1 - Entry for this message catalog exists in the cache 338 * 0 - Entry for this message catalog doesn't exist in the cache 339 */ 340 int 341 check_cache(struct cache_pack *cp, struct msg_pack *mp) 342 { 343 Msg_node *cur_msg; 344 Gettext_t *gt = global_gt; 345 346 #ifdef GETTEXT_DEBUG 347 { 348 int level = 0; 349 350 (void) printf("*************** check_cache(0x%p, 0x%p)\n", 351 (void *)cp, (void *)mp); 352 printcp(cp, 0); 353 printmp(mp, 0); 354 } 355 #endif 356 357 cur_msg = gt->c_m_node; 358 if (cur_msg && 359 (strcmp(cur_msg->path, mp->msgfile) == 0)) { 360 /* 361 * msgfile is the same as the previous message file 362 */ 363 cp->mnp = cur_msg; 364 cp->cnp = gt->c_node; 365 cp->cacheline = 1; 366 #ifdef GETTEXT_DEBUG 367 (void) printf("************* exiting check_cache\n"); 368 (void) printf("cache found\n"); 369 printmnp(cp->mnp, 0); 370 #endif 371 return (1); 372 } 373 if (cp->node_hash) { 374 /* 375 * already cache_node having the same 376 * hash id found 377 */ 378 cp->cnp = cp->node_hash; 379 cp->mnp = cp->cnp->m_node; 380 cp->cacheline = 1; 381 while (cp->mnp) { 382 if (strcmp(cp->mnp->path, mp->msgfile) == 0) { 383 #ifdef GETTEXT_DEBUG 384 (void) printf("************* exiting check_cache\n"); 385 (void) printf("cache found\n"); 386 printmnp(cp->mnp, 0); 387 #endif 388 return (1); 389 } 390 cp->mnp = cp->mnp->next; 391 } 392 #ifdef GETTEXT_DEBUG 393 (void) printf("************* exiting check_cache\n"); 394 (void) printf("cache not found\n"); 395 #endif 396 return (0); 397 } 398 /* search the cache list */ 399 cp->cnp = gt->c_node; 400 cp->mnp = NULL; 401 while (cp->cnp) { 402 if (cp->cnp->hashid == mp->hash_locale) { 403 cp->node_hash = cp->cnp; 404 cp->mnp = cp->cnp->m_node; 405 cp->cacheline = 1; 406 while (cp->mnp) { 407 if (strcmp(cp->mnp->path, mp->msgfile) == 0) { 408 /* 409 * msgfile found in the cache 410 */ 411 #ifdef GETTEXT_DEBUG 412 (void) printf("************* exiting check_cache\n"); 413 (void) printf("cache found\n"); 414 printmnp(cp->mnp, 0); 415 #endif 416 return (1); 417 } 418 cp->mnp = cp->mnp->next; 419 } 420 #ifdef GETTEXT_DEBUG 421 (void) printf("************* exiting check_cache\n"); 422 (void) printf("cache not found\n"); 423 #endif 424 return (0); 425 } else { 426 cp->cnp = cp->cnp->next; 427 } 428 } 429 cp->cacheline = 0; 430 #ifdef GETTEXT_DEBUG 431 (void) printf("************* exiting check_cache\n"); 432 (void) printf("cache not found\n"); 433 #endif 434 return (0); 435 } 436 437 char * 438 get_codeset(const char *domain) 439 { 440 char *codeset; 441 442 #ifdef GETTEXT_DEBUG 443 (void) printf("*************** get_codeset(\"%s\")\n", 444 domain ? domain : "(null)"); 445 #endif 446 447 codeset = _real_bindtextdomain_u(domain, NULL, TP_CODESET); 448 if (!codeset) { 449 /* no codeset is bound to this domain */ 450 codeset = nl_langinfo(CODESET); 451 } 452 #ifdef GETTEXT_DEBUG 453 (void) printf("*************** existing get_codeset(\"%s\")\n", 454 domain ? domain : "(null)"); 455 (void) printf(" = \"%s\"\n", codeset); 456 #endif 457 458 return (codeset); 459 } 460 461 void 462 connect_entry(struct cache_pack *cp) 463 { 464 Gettext_t *gt = global_gt; 465 466 #ifdef GETTEXT_DEBUG 467 (void) printf("*************** connect_entry(0x%p)\n", 468 (void *)cp); 469 printcp(cp, 0); 470 #endif 471 472 if (cp->cacheline) { 473 if (cp->cnp->m_last) 474 cp->cnp->m_last->next = cp->mnp; 475 else 476 cp->cnp->m_node = cp->mnp; 477 cp->cnp->m_last = cp->mnp; 478 } else { 479 if (gt->c_last) 480 gt->c_last->next = cp->cnp; 481 else 482 gt->c_node = cp->cnp; 483 gt->c_last = cp->cnp; 484 } 485 gt->c_m_node = cp->mnp; 486 } 487 488 int 489 connect_invalid_entry(struct cache_pack *cp, struct msg_pack *mp) 490 { 491 #ifdef GETTEXT_DEBUG 492 (void) printf("*************** connect_invalid_entry(0x%p, 0x%p)\n", 493 (void *)cp, (void *)mp); 494 printcp(cp, 0); 495 printmp(mp, 0); 496 #endif 497 498 cp->mnp = create_mnp(mp); 499 if (!cp->mnp) { 500 return (-1); 501 } 502 503 if (!cp->cacheline) { 504 cp->cnp = create_cnp(cp->mnp, mp); 505 if (!cp->cnp) { 506 free_mnp_mp(cp->mnp, mp); 507 return (-1); 508 } 509 } 510 cp->mnp->type = T_ILL_MO; 511 connect_entry(cp); 512 513 return (0); 514 } 515 516 Msg_node * 517 create_mnp(struct msg_pack *mp) 518 { 519 Msg_node *mnp; 520 char *s; 521 size_t msglen; 522 523 #ifdef GETTEXT_DEBUG 524 (void) printf("*************** create_mnp(0x%p)\n", (void *)mp); 525 printmp(mp, 0); 526 #endif 527 528 mnp = (Msg_node *)calloc(1, sizeof (Msg_node)); 529 if (!mnp) { 530 return (NULL); 531 } 532 msglen = mp->msgfile_len; 533 s = (char *)malloc(msglen + 1); 534 if (!s) { 535 free(mnp); 536 return (NULL); 537 } 538 (void) memcpy(s, mp->msgfile, msglen + 1); 539 mnp->path = s; 540 return (mnp); 541 } 542 543 Cache_node * 544 create_cnp(Msg_node *mnp, struct msg_pack *mp) 545 { 546 Cache_node *cnp; 547 548 #ifdef GETTEXT_DEBUG 549 (void) printf("*************** create_cnp(0x%p, 0x%p)\n", 550 (void *)mnp, (void *)mp); 551 printmnp(mnp, 0); 552 printmp(mp, 0); 553 #endif 554 555 cnp = (Cache_node *)calloc(1, sizeof (Cache_node)); 556 if (!cnp) { 557 return (NULL); 558 } 559 cnp->hashid = mp->hash_locale; 560 cnp->m_node = mnp; 561 cnp->m_last = mnp; 562 563 return (cnp); 564 } 565 566 void 567 free_mnp_mp(Msg_node *mnp, struct msg_pack *mp) 568 { 569 #ifdef GETTEXT_DEBUG 570 (void) printf("*************** free_mnp_mp(0x%p, 0x%p)\n", 571 (void *)mnp, (void *)mp); 572 printmnp(mnp, 0); 573 printmp(mp, 0); 574 #endif 575 576 if (mnp) { 577 if (mnp->path) 578 free(mnp->path); 579 switch (mnp->type) { 580 case T_SUN_MO: 581 free(mnp->msg.sunmsg); 582 break; 583 case T_GNU_MO: 584 free(mnp->msg.gnumsg); 585 break; 586 } 587 free(mnp); 588 } 589 if (mp->addr != (caddr_t)-1) { 590 (void) munmap(mp->addr, mp->fsz); 591 } 592 } 593 594 /* 595 * get_hashid 596 * 597 * Calculates the hash value from the specified string. 598 * Actual hashid will be mod(hash value, PRIME_NUMBER). 599 * 600 * hashpjw 601 * Ref: Compilers - Principles, Techniques, and Tools 602 * Aho, Sethi, and Ullman 603 */ 604 unsigned int 605 get_hashid(const char *str, size_t *len) 606 { 607 const char *p; 608 unsigned int h = 0, g; 609 610 for (p = str; *p; p++) { 611 h = (h << 4) + *p; 612 g = h & 0xf0000000; 613 if (g) { 614 h = h ^ (g >> 24); 615 h = h ^ g; 616 } 617 } 618 if (len) 619 *len = (size_t)(p - str); 620 return (h); 621 } 622 623 unsigned int 624 doswap32(unsigned int n) 625 { 626 unsigned int r; 627 628 r = (n << 24) | ((n & 0xff00) << 8) | 629 ((n >> 8) & 0xff00) | (n >> 24); 630 return (r); 631 } 632 633 #ifdef GETTEXT_DEBUG 634 void 635 gprintf(int level, const char *format, ...) 636 { 637 va_list ap; 638 639 va_start(ap, format); 640 641 while (level-- >= 0) { 642 (void) fputs(" ", stdout); 643 } 644 (void) vprintf(format, ap); 645 va_end(ap); 646 } 647 648 void 649 printlist(void) 650 { 651 struct domain_binding *ppp; 652 Gettext_t *gt = global_gt; 653 654 (void) printf("=== Printing default list and regural list\n"); 655 (void) printf(" Default domain=<%s>, binding=<%s>\n", 656 DEFAULT_DOMAIN, defaultbind); 657 658 ppp = FIRSTBIND(gt); 659 while (ppp) { 660 (void) printf( 661 " domain=<%s>, binding=<%s>, codeset=<%s>\n", 662 ppp->domain ? ppp->domain : "(null)", 663 ppp->binding ? ppp->binding : "(null)", 664 ppp->codeset ? ppp->codeset : "(null)"); 665 ppp = ppp->next; 666 } 667 } 668 669 void 670 printmp(struct msg_pack *mp, int level) 671 { 672 gprintf(level, "=== mp ===\n"); 673 gprintf(level, " msgid1: \"%s\"\n", 674 mp->msgid1 ? mp->msgid1 : "(null)"); 675 gprintf(level, " msgid2: \"%s\"\n", 676 mp->msgid2 ? mp->msgid2 : "(null)"); 677 gprintf(level, " n: %d\n", mp->n); 678 gprintf(level, " plural: %d\n", mp->plural); 679 gprintf(level, " category: \"%s\"\n", 680 category_name[mp->category]); 681 gprintf(level, " domain: \"%s\"\n", 682 mp->domain ? mp->domain : "(null)"); 683 gprintf(level, " binding: \"%s\"\n", 684 mp->binding ? mp->binding : "(null)"); 685 gprintf(level, " msgfile: \"%s\"\n", 686 mp->msgfile ? mp->msgfile : "(null)"); 687 gprintf(level, " locale: \"%s\"\n", 688 mp->locale ? mp->locale : "(null)"); 689 gprintf(level, " language: \"%s\"\n", 690 mp->language ? mp->language : "(null)"); 691 gprintf(level, " hash_locale: %d\n", mp->hash_locale); 692 gprintf(level, " addr: 0x%p\n", mp->addr); 693 gprintf(level, " fsz: %d\n", mp->fsz); 694 gprintf(level, " trusted: %d\n", mp->trusted); 695 } 696 697 void 698 printsunmsg(Msg_s_node *smnp, int level) 699 { 700 gprintf(level, "=== sunmsg ===\n"); 701 gprintf(level, " msg_file_info: 0x%p\n", 702 (void *)smnp->msg_file_info); 703 gprintf(level, " msg_mid: %d\n", 704 smnp->msg_file_info->msg_mid); 705 gprintf(level, " msg_count: %d\n", 706 smnp->msg_file_info->msg_count); 707 gprintf(level, " str_count_msgid: %d\n", 708 smnp->msg_file_info->str_count_msgid); 709 gprintf(level, " str_count_msgstr: %d\n", 710 smnp->msg_file_info->str_count_msgstr); 711 gprintf(level, " msg_struct_size: %d\n", 712 smnp->msg_file_info->msg_struct_size); 713 gprintf(level, " msg_list: 0x%p\n", 714 (void *)smnp->msg_list); 715 gprintf(level, " msg_ids: 0x%p\n", 716 (void *)smnp->msg_ids); 717 gprintf(level, " msg_strs: 0x%p\n", 718 (void *)smnp->msg_strs); 719 } 720 721 void 722 printgnumsg(Msg_g_node *gmnp, int level) 723 { 724 gprintf(level, "=== gnumsg ===\n"); 725 gprintf(level, " msg_file_info: 0x%p\n", 726 (void *)gmnp->msg_file_info); 727 gprintf(level, " magic: 0x%x\n", 728 gmnp->msg_file_info->magic); 729 gprintf(level, " revision: %d\n", 730 SWAP(gmnp, gmnp->msg_file_info->revision)); 731 gprintf(level, " num_of_str: %d\n", 732 SWAP(gmnp, gmnp->msg_file_info->num_of_str)); 733 gprintf(level, " off_msgid_tbl: %d\n", 734 SWAP(gmnp, gmnp->msg_file_info->off_msgid_tbl)); 735 gprintf(level, " off_msgstr_tbl: %d\n", 736 SWAP(gmnp, gmnp->msg_file_info->off_msgstr_tbl)); 737 gprintf(level, " sz_hashtbl: %d\n", 738 SWAP(gmnp, gmnp->msg_file_info->sz_hashtbl)); 739 gprintf(level, " off_hashtbl: %d\n", 740 SWAP(gmnp, gmnp->msg_file_info->off_hashtbl)); 741 gprintf(level, " hash_table: 0x%p\n", 742 (void *)gmnp->hash_table); 743 gprintf(level, " header_flag: %08x\n", 744 gmnp->header_flag); 745 gprintf(level, " src_encoding: \"%s\"\n", 746 gmnp->src_encoding ? gmnp->src_encoding : "(null)"); 747 gprintf(level, " dst_encoding: \"%s\"\n", 748 gmnp->dst_encoding ? gmnp->dst_encoding : "(null)"); 749 gprintf(level, " nplurals: %d\n", 750 gmnp->nplurals); 751 gprintf(level, " plural: 0x%p\n", 752 (void *)gmnp->plural); 753 if (gmnp->plural) 754 printexpr(gmnp->plural, level+1); 755 gprintf(level, " fd: 0x%p\n", (void *)gmnp->fd); 756 gprintf(level, " conv_msgstr: 0x%p\n", 757 (void *)gmnp->conv_msgstr); 758 } 759 760 void 761 printexpr(struct expr *e, int level) 762 { 763 static const char *op_name[] = { 764 "NULL", "INIT", "EXP", 765 "NUM", "VAR", "?", ":", "||", 766 "&&", "==", "!=", ">", "<", 767 ">=", "<=", "+", "-", "*", "/", 768 "%", "!", "(", ")", "ERR" 769 }; 770 switch (GETOPNUM(e->op)) { 771 case 0: 772 switch (GETTYPE(e->op)) { 773 case T_NUM: 774 gprintf(level, "NUM(%d)\n", e->num); 775 break; 776 case T_VAR: 777 gprintf(level, "VAR(n)\n"); 778 break; 779 } 780 break; 781 case 1: 782 gprintf(level, "OP: !\n"); 783 printexpr(e->nodes[0], level+1); 784 break; 785 case 2: 786 gprintf(level, "OP: %s\n", op_name[GETTYPE(e->op)]); 787 printexpr(e->nodes[0], level+1); 788 printexpr(e->nodes[1], level+1); 789 break; 790 case 3: 791 gprintf(level, "OP: ?\n"); 792 793 printexpr(e->nodes[0], level+1); 794 printexpr(e->nodes[1], level+1); 795 printexpr(e->nodes[2], level+1); 796 break; 797 } 798 } 799 800 801 void 802 printmnp(Msg_node *mnp, int level) 803 { 804 gprintf(level, "=== mnp ===\n"); 805 806 gprintf(level, " type: \"%s\"\n", 807 mnp->type == T_ILL_MO ? "T_ILL_MO" : 808 mnp->type == T_SUN_MO ? "T_SUN_MO" : 809 mnp->type == T_GNU_MO ? "T_GNU_MO" : 810 "UNKNOWN TYPE"); 811 gprintf(level, " path: \"%s\"\n", 812 mnp->path ? mnp->path : "(null)"); 813 gprintf(level, " msg_file_trusted: %d\n", 814 mnp->trusted); 815 if (mnp->type == T_SUN_MO) 816 printsunmsg(mnp->msg.sunmsg, level+1); 817 else if (mnp->type == T_GNU_MO) 818 printgnumsg(mnp->msg.gnumsg, level+1); 819 gprintf(level, " next: 0x%p\n", (void *)mnp->next); 820 } 821 822 void 823 printcnp(Cache_node *cnp, int level) 824 { 825 gprintf(level, "=== cnp ===\n"); 826 827 gprintf(level, " hashid: %d\n", cnp->hashid); 828 gprintf(level, " m_node: 0x%p\n", (void *)cnp->m_node); 829 if (cnp->m_node) 830 printmnp(cnp->m_node, level+1); 831 gprintf(level, " m_last: 0x%p\n", (void *)cnp->m_last); 832 if (cnp->m_last) 833 printmnp(cnp->m_last, level+1); 834 gprintf(level, " n_node: 0x%p\n", (void *)cnp->n_node); 835 gprintf(level, " next: 0x%p\n", (void *)cnp->next); 836 } 837 838 void 839 printcp(struct cache_pack *cp, int level) 840 { 841 gprintf(level, "=== cp ===\n"); 842 gprintf(level, " cacheline: %d\n", cp->cacheline); 843 gprintf(level, " mnp: 0x%p\n", (void *)cp->mnp); 844 if (cp->mnp) 845 printmnp(cp->mnp, level+1); 846 gprintf(level, " cnp: 0x%p\n", (void *)cp->cnp); 847 if (cp->cnp) 848 printcnp(cp->cnp, level+1); 849 gprintf(level, " node_hash: 0x%p\n", (void *)cp->node_hash); 850 if (cp->node_hash) 851 printcnp(cp->node_hash, level+1); 852 } 853 #endif 854