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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * misc.cc 29 * 30 * This file contains various unclassified routines. Some main groups: 31 * getname 32 * Memory allocation 33 * String handling 34 * Property handling 35 * Error message handling 36 * Make internal state dumping 37 * main routine support 38 */ 39 40 /* 41 * Included files 42 */ 43 #include <bsd/bsd.h> /* bsd_signal() */ 44 #include <mksh/i18n.h> /* get_char_semantics_value() */ 45 #include <mksh/misc.h> 46 #include <mksdmsi18n/mksdmsi18n.h> 47 #include <stdarg.h> /* va_list, va_start(), va_end() */ 48 #include <stdlib.h> /* mbstowcs() */ 49 #include <sys/signal.h> /* SIG_DFL */ 50 #include <sys/wait.h> /* wait() */ 51 52 #include <string.h> /* strerror() */ 53 54 55 /* 56 * Defined macros 57 */ 58 59 /* 60 * typedefs & structs 61 */ 62 63 /* 64 * Static variables 65 */ 66 extern "C" { 67 void (*sigivalue)(int) = SIG_DFL; 68 void (*sigqvalue)(int) = SIG_DFL; 69 void (*sigtvalue)(int) = SIG_DFL; 70 void (*sighvalue)(int) = SIG_DFL; 71 } 72 73 long getname_bytes_count = 0; 74 long getname_names_count = 0; 75 long getname_struct_count = 0; 76 77 long freename_bytes_count = 0; 78 long freename_names_count = 0; 79 long freename_struct_count = 0; 80 81 long expandstring_count = 0; 82 long getwstring_count = 0; 83 84 /* 85 * File table of contents 86 */ 87 static void expand_string(register String string, register int length); 88 89 #define FATAL_ERROR_MSG_SIZE 200 90 91 /* 92 * getmem(size) 93 * 94 * malloc() version that checks the returned value. 95 * 96 * Return value: 97 * The memory chunk we allocated 98 * 99 * Parameters: 100 * size The size of the chunk we need 101 * 102 * Global variables used: 103 */ 104 char * 105 getmem(register int size) 106 { 107 register char *result = (char *) malloc((unsigned) size); 108 if (result == NULL) { 109 char buf[FATAL_ERROR_MSG_SIZE]; 110 sprintf(buf, NOCATGETS("*** Error: malloc(%d) failed: %s\n"), size, strerror(errno)); 111 strcat(buf, catgets(libmksdmsi18n_catd, 1, 126, "mksh: Fatal error: Out of memory\n")); 112 fputs(buf, stderr); 113 exit_status = 1; 114 exit(1); 115 } 116 return result; 117 } 118 119 /* 120 * retmem(p) 121 * 122 * Cover funtion for free() to make it possible to insert advises. 123 * 124 * Parameters: 125 * p The memory block to free 126 * 127 * Global variables used: 128 */ 129 void 130 retmem(wchar_t *p) 131 { 132 (void) free((char *) p); 133 } 134 135 void 136 retmem_mb(caddr_t p) 137 { 138 (void) free(p); 139 } 140 141 /* 142 * getname_fn(name, len, dont_enter) 143 * 144 * Hash a name string to the corresponding nameblock. 145 * 146 * Return value: 147 * The Name block for the string 148 * 149 * Parameters: 150 * name The string we want to internalize 151 * len The length of that string 152 * dont_enter Don't enter the name if it does not exist 153 * 154 * Global variables used: 155 * funny The vector of semantic tags for characters 156 * hashtab The hashtable used for the nametable 157 */ 158 Name 159 getname_fn(wchar_t *name, register int len, register Boolean dont_enter, register Boolean * foundp) 160 { 161 register int length; 162 register wchar_t *cap = name; 163 register Name np; 164 static Name_rec empty_Name; 165 char *tmp_mbs_buffer = NULL; 166 char *mbs_name = mbs_buffer; 167 168 /* 169 * First figure out how long the string is. 170 * If the len argument is -1 we count the chars here. 171 */ 172 if (len == FIND_LENGTH) { 173 length = wslen(name); 174 } else { 175 length = len; 176 } 177 178 Wstring ws; 179 ws.init(name, length); 180 if (length >= MAXPATHLEN) { 181 mbs_name = tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1); 182 } 183 (void) wcstombs(mbs_name, ws.get_string(), (length * MB_LEN_MAX) + 1); 184 185 /* Look for the string */ 186 if (dont_enter || (foundp != 0)) { 187 np = hashtab.lookup(mbs_name); 188 if (foundp != 0) { 189 *foundp = (np != 0) ? true : false; 190 } 191 if ((np != 0) || dont_enter) { 192 if(tmp_mbs_buffer != NULL) { 193 retmem_mb(tmp_mbs_buffer); 194 } 195 return np; 196 } else { 197 np = ALLOC(Name); 198 } 199 } else { 200 Boolean found; 201 np = hashtab.insert(mbs_name, found); 202 if (found) { 203 if(tmp_mbs_buffer != NULL) { 204 retmem_mb(tmp_mbs_buffer); 205 } 206 return np; 207 } 208 } 209 getname_struct_count += sizeof(struct _Name); 210 *np = empty_Name; 211 212 np->string_mb = strdup(mbs_name); 213 if(tmp_mbs_buffer != NULL) { 214 retmem_mb(tmp_mbs_buffer); 215 mbs_name = tmp_mbs_buffer = NULL; 216 } 217 getname_bytes_count += strlen(np->string_mb) + 1; 218 /* Fill in the new Name */ 219 np->stat.time = file_no_time; 220 np->hash.length = length; 221 /* Scan the namestring to classify it */ 222 for (cap = name, len = 0; --length >= 0;) { 223 len |= get_char_semantics_value(*cap++); 224 } 225 np->dollar = BOOLEAN((len & (int) dollar_sem) != 0); 226 np->meta = BOOLEAN((len & (int) meta_sem) != 0); 227 np->percent = BOOLEAN((len & (int) percent_sem) != 0); 228 np->wildcard = BOOLEAN((len & (int) wildcard_sem) != 0); 229 np->colon = BOOLEAN((len & (int) colon_sem) != 0); 230 np->parenleft = BOOLEAN((len & (int) parenleft_sem) != 0); 231 getname_names_count++; 232 return np; 233 } 234 235 void 236 store_name(Name name) 237 { 238 hashtab.insert(name); 239 } 240 241 void 242 free_name(Name name) 243 { 244 freename_names_count++; 245 freename_struct_count += sizeof(struct _Name); 246 freename_bytes_count += strlen(name->string_mb) + 1; 247 retmem_mb(name->string_mb); 248 for (Property next, p = name->prop; p != NULL; p = next) { 249 next = p->next; 250 free(p); 251 } 252 free(name); 253 } 254 255 /* 256 * enable_interrupt(handler) 257 * 258 * This routine sets a new interrupt handler for the signals make 259 * wants to deal with. 260 * 261 * Parameters: 262 * handler The function installed as interrupt handler 263 * 264 * Static variables used: 265 * sigivalue The original signal handler 266 * sigqvalue The original signal handler 267 * sigtvalue The original signal handler 268 * sighvalue The original signal handler 269 */ 270 void 271 enable_interrupt(register void (*handler) (int)) 272 { 273 if (sigivalue != SIG_IGN) { 274 (void) bsd_signal(SIGINT, (SIG_PF) handler); 275 } 276 if (sigqvalue != SIG_IGN) { 277 (void) bsd_signal(SIGQUIT, (SIG_PF) handler); 278 } 279 if (sigtvalue != SIG_IGN) { 280 (void) bsd_signal(SIGTERM, (SIG_PF) handler); 281 } 282 if (sighvalue != SIG_IGN) { 283 (void) bsd_signal(SIGHUP, (SIG_PF) handler); 284 } 285 } 286 287 /* 288 * setup_char_semantics() 289 * 290 * Load the vector char_semantics[] with lexical markers 291 * 292 * Parameters: 293 * 294 * Global variables used: 295 * char_semantics The vector of character semantics that we set 296 */ 297 void 298 setup_char_semantics(void) 299 { 300 const char *s; 301 wchar_t wc_buffer[1]; 302 int entry; 303 304 if (svr4) { 305 s = "@-"; 306 } else { 307 s = "=@-?!+"; 308 } 309 for (s; MBTOWC(wc_buffer, s); s++) { 310 entry = get_char_semantics_entry(*wc_buffer); 311 char_semantics[entry] |= (int) command_prefix_sem; 312 } 313 char_semantics[dollar_char_entry] |= (int) dollar_sem; 314 for (s = "#|=^();&<>*?[]:$`'\"\\\n"; MBTOWC(wc_buffer, s); s++) { 315 entry = get_char_semantics_entry(*wc_buffer); 316 char_semantics[entry] |= (int) meta_sem; 317 } 318 char_semantics[percent_char_entry] |= (int) percent_sem; 319 for (s = "@*<%?^"; MBTOWC(wc_buffer, s); s++) { 320 entry = get_char_semantics_entry(*wc_buffer); 321 char_semantics[entry] |= (int) special_macro_sem; 322 } 323 for (s = "?[*"; MBTOWC(wc_buffer, s); s++) { 324 entry = get_char_semantics_entry(*wc_buffer); 325 char_semantics[entry] |= (int) wildcard_sem; 326 } 327 char_semantics[colon_char_entry] |= (int) colon_sem; 328 char_semantics[parenleft_char_entry] |= (int) parenleft_sem; 329 } 330 331 /* 332 * errmsg(errnum) 333 * 334 * Return the error message for a system call error 335 * 336 * Return value: 337 * An error message string 338 * 339 * Parameters: 340 * errnum The number of the error we want to describe 341 * 342 * Global variables used: 343 * sys_errlist A vector of error messages 344 * sys_nerr The size of sys_errlist 345 */ 346 char * 347 errmsg(int errnum) 348 { 349 350 extern int sys_nerr; 351 char *errbuf; 352 353 if ((errnum < 0) || (errnum > sys_nerr)) { 354 errbuf = getmem(6+1+11+1); 355 (void) sprintf(errbuf, catgets(libmksdmsi18n_catd, 1, 127, "Error %d"), errnum); 356 return errbuf; 357 } else { 358 return strerror(errnum); 359 360 } 361 } 362 363 static char static_buf[MAXPATHLEN*3]; 364 365 /* 366 * fatal_mksh(format, args...) 367 * 368 * Print a message and die 369 * 370 * Parameters: 371 * format printf type format string 372 * args Arguments to match the format 373 */ 374 /*VARARGS*/ 375 void 376 fatal_mksh(const char *message, ...) 377 { 378 va_list args; 379 char *buf = static_buf; 380 char *mksh_fat_err = catgets(libmksdmsi18n_catd, 1, 128, "mksh: Fatal error: "); 381 char *cur_wrk_dir = catgets(libmksdmsi18n_catd, 1, 129, "Current working directory: "); 382 int mksh_fat_err_len = strlen(mksh_fat_err); 383 384 va_start(args, message); 385 (void) fflush(stdout); 386 (void) strcpy(buf, mksh_fat_err); 387 size_t buf_len = vsnprintf(static_buf + mksh_fat_err_len, 388 sizeof(static_buf) - mksh_fat_err_len, 389 message, args) 390 + mksh_fat_err_len 391 + strlen(cur_wrk_dir) 392 + strlen(get_current_path_mksh()) 393 + 3; // "\n\n" 394 va_end(args); 395 if (buf_len >= sizeof(static_buf)) { 396 buf = getmem(buf_len); 397 (void) strcpy(buf, mksh_fat_err); 398 va_start(args, message); 399 (void) vsprintf(buf + mksh_fat_err_len, message, args); 400 va_end(args); 401 } 402 (void) strcat(buf, "\n"); 403 /* 404 if (report_pwd) { 405 */ 406 if (1) { 407 (void) strcat(buf, cur_wrk_dir); 408 (void) strcat(buf, get_current_path_mksh()); 409 (void) strcat(buf, "\n"); 410 } 411 (void) fputs(buf, stderr); 412 (void) fflush(stderr); 413 if (buf != static_buf) { 414 retmem_mb(buf); 415 } 416 exit_status = 1; 417 exit(1); 418 } 419 420 /* 421 * fatal_reader_mksh(format, args...) 422 * 423 * Parameters: 424 * format printf style format string 425 * args arguments to match the format 426 */ 427 /*VARARGS*/ 428 void 429 fatal_reader_mksh(const char * pattern, ...) 430 { 431 va_list args; 432 char message[1000]; 433 434 va_start(args, pattern); 435 /* 436 if (file_being_read != NULL) { 437 WCSTOMBS(mbs_buffer, file_being_read); 438 if (line_number != 0) { 439 (void) sprintf(message, 440 catgets(libmksdmsi18n_catd, 1, 130, "%s, line %d: %s"), 441 mbs_buffer, 442 line_number, 443 pattern); 444 } else { 445 (void) sprintf(message, 446 "%s: %s", 447 mbs_buffer, 448 pattern); 449 } 450 pattern = message; 451 } 452 */ 453 454 (void) fflush(stdout); 455 (void) fprintf(stderr, catgets(libmksdmsi18n_catd, 1, 131, "mksh: Fatal error in reader: ")); 456 (void) vfprintf(stderr, pattern, args); 457 (void) fprintf(stderr, "\n"); 458 va_end(args); 459 460 /* 461 if (temp_file_name != NULL) { 462 (void) fprintf(stderr, 463 catgets(libmksdmsi18n_catd, 1, 132, "mksh: Temp-file %s not removed\n"), 464 temp_file_name->string_mb); 465 temp_file_name = NULL; 466 } 467 */ 468 469 /* 470 if (report_pwd) { 471 */ 472 if (1) { 473 (void) fprintf(stderr, 474 catgets(libmksdmsi18n_catd, 1, 133, "Current working directory %s\n"), 475 get_current_path_mksh()); 476 } 477 (void) fflush(stderr); 478 exit_status = 1; 479 exit(1); 480 } 481 482 /* 483 * warning_mksh(format, args...) 484 * 485 * Print a message and continue. 486 * 487 * Parameters: 488 * format printf type format string 489 * args Arguments to match the format 490 */ 491 /*VARARGS*/ 492 void 493 warning_mksh(char * message, ...) 494 { 495 va_list args; 496 497 va_start(args, message); 498 (void) fflush(stdout); 499 (void) fprintf(stderr, catgets(libmksdmsi18n_catd, 1, 134, "mksh: Warning: ")); 500 (void) vfprintf(stderr, message, args); 501 (void) fprintf(stderr, "\n"); 502 va_end(args); 503 /* 504 if (report_pwd) { 505 */ 506 if (1) { 507 (void) fprintf(stderr, 508 catgets(libmksdmsi18n_catd, 1, 135, "Current working directory %s\n"), 509 get_current_path_mksh()); 510 } 511 (void) fflush(stderr); 512 } 513 514 /* 515 * get_current_path_mksh() 516 * 517 * Stuff current_path with the current path if it isnt there already. 518 * 519 * Parameters: 520 * 521 * Global variables used: 522 */ 523 char * 524 get_current_path_mksh(void) 525 { 526 char pwd[(MAXPATHLEN * MB_LEN_MAX)]; 527 static char *current_path; 528 529 if (current_path == NULL) { 530 getcwd(pwd, sizeof(pwd)); 531 if (pwd[0] == (int) nul_char) { 532 pwd[0] = (int) slash_char; 533 pwd[1] = (int) nul_char; 534 } 535 current_path = strdup(pwd); 536 } 537 return current_path; 538 } 539 540 /* 541 * append_prop(target, type) 542 * 543 * Create a new property and append it to the property list of a Name. 544 * 545 * Return value: 546 * A new property block for the target 547 * 548 * Parameters: 549 * target The target that wants a new property 550 * type The type of property being requested 551 * 552 * Global variables used: 553 */ 554 Property 555 append_prop(register Name target, register Property_id type) 556 { 557 register Property *insert = &target->prop; 558 register Property prop = *insert; 559 register int size; 560 561 switch (type) { 562 case conditional_prop: 563 size = sizeof (struct Conditional); 564 break; 565 case line_prop: 566 size = sizeof (struct Line); 567 break; 568 case macro_prop: 569 size = sizeof (struct _Macro); 570 break; 571 case makefile_prop: 572 size = sizeof (struct Makefile); 573 break; 574 case member_prop: 575 size = sizeof (struct Member); 576 break; 577 case recursive_prop: 578 size = sizeof (struct Recursive); 579 break; 580 case sccs_prop: 581 size = sizeof (struct Sccs); 582 break; 583 case suffix_prop: 584 size = sizeof (struct Suffix); 585 break; 586 case target_prop: 587 size = sizeof (struct Target); 588 break; 589 case time_prop: 590 size = sizeof (struct STime); 591 break; 592 case vpath_alias_prop: 593 size = sizeof (struct Vpath_alias); 594 break; 595 case long_member_name_prop: 596 size = sizeof (struct Long_member_name); 597 break; 598 case macro_append_prop: 599 size = sizeof (struct _Macro_appendix); 600 break; 601 case env_mem_prop: 602 size = sizeof (struct _Env_mem); 603 break; 604 default: 605 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 136, "Internal error. Unknown prop type %d"), type); 606 } 607 for (; prop != NULL; insert = &prop->next, prop = *insert); 608 size += PROPERTY_HEAD_SIZE; 609 *insert = prop = (Property) getmem(size); 610 memset((char *) prop, 0, size); 611 prop->type = type; 612 prop->next = NULL; 613 return prop; 614 } 615 616 /* 617 * maybe_append_prop(target, type) 618 * 619 * Append a property to the Name if none of this type exists 620 * else return the one already there 621 * 622 * Return value: 623 * A property of the requested type for the target 624 * 625 * Parameters: 626 * target The target that wants a new property 627 * type The type of property being requested 628 * 629 * Global variables used: 630 */ 631 Property 632 maybe_append_prop(register Name target, register Property_id type) 633 { 634 register Property prop; 635 636 if ((prop = get_prop(target->prop, type)) != NULL) { 637 return prop; 638 } 639 return append_prop(target, type); 640 } 641 642 /* 643 * get_prop(start, type) 644 * 645 * Scan the property list of a Name to find the next property 646 * of a given type. 647 * 648 * Return value: 649 * The first property of the type, if any left 650 * 651 * Parameters: 652 * start The first property block to check for type 653 * type The type of property block we need 654 * 655 * Global variables used: 656 */ 657 Property 658 get_prop(register Property start, register Property_id type) 659 { 660 for (; start != NULL; start = start->next) { 661 if (start->type == type) { 662 return start; 663 } 664 } 665 return NULL; 666 } 667 668 /* 669 * append_string(from, to, length) 670 * 671 * Append a C string to a make string expanding it if nessecary 672 * 673 * Parameters: 674 * from The source (C style) string 675 * to The destination (make style) string 676 * length The length of the from string 677 * 678 * Global variables used: 679 */ 680 void 681 append_string(register wchar_t *from, register String to, register int length) 682 { 683 if (length == FIND_LENGTH) { 684 length = wslen(from); 685 } 686 if (to->buffer.start == NULL) { 687 expand_string(to, 32 + length); 688 } 689 if (to->buffer.end - to->text.p <= length) { 690 expand_string(to, 691 (to->buffer.end - to->buffer.start) * 2 + 692 length); 693 } 694 if (length > 0) { 695 (void) wsncpy(to->text.p, from, length); 696 to->text.p += length; 697 } 698 *(to->text.p) = (int) nul_char; 699 } 700 701 wchar_t * get_wstring(char *from) { 702 if(from == NULL) { 703 return NULL; 704 } 705 getwstring_count++; 706 wchar_t * wcbuf = ALLOC_WC(strlen(from) + 1); 707 mbstowcs(wcbuf, from, strlen(from)+1); 708 return wcbuf; 709 } 710 711 void 712 append_string(register char *from, register String to, register int length) 713 { 714 if (length == FIND_LENGTH) { 715 length = strlen(from); 716 } 717 if (to->buffer.start == NULL) { 718 expand_string(to, 32 + length); 719 } 720 if (to->buffer.end - to->text.p <= length) { 721 expand_string(to, 722 (to->buffer.end - to->buffer.start) * 2 + 723 length); 724 } 725 if (length > 0) { 726 (void) mbstowcs(to->text.p, from, length); 727 to->text.p += length; 728 } 729 *(to->text.p) = (int) nul_char; 730 } 731 732 /* 733 * expand_string(string, length) 734 * 735 * Allocate more memory for strings that run out of space. 736 * 737 * Parameters: 738 * string The make style string we want to expand 739 * length The new length we need 740 * 741 * Global variables used: 742 */ 743 static void 744 expand_string(register String string, register int length) 745 { 746 register wchar_t *p; 747 748 if (string->buffer.start == NULL) { 749 /* For strings that have no memory allocated */ 750 string->buffer.start = 751 string->text.p = 752 string->text.end = 753 ALLOC_WC(length); 754 string->buffer.end = string->buffer.start + length; 755 string->text.p[0] = (int) nul_char; 756 string->free_after_use = true; 757 expandstring_count++; 758 return; 759 } 760 if (string->buffer.end - string->buffer.start >= length) { 761 /* If we really don't need more memory. */ 762 return; 763 } 764 /* 765 * Get more memory, copy the string and free the old buffer if 766 * it is was malloc()'ed. 767 */ 768 expandstring_count++; 769 p = ALLOC_WC(length); 770 (void) wscpy(p, string->buffer.start); 771 string->text.p = p + (string->text.p - string->buffer.start); 772 string->text.end = p + (string->text.end - string->buffer.start); 773 string->buffer.end = p + length; 774 if (string->free_after_use) { 775 retmem(string->buffer.start); 776 } 777 string->buffer.start = p; 778 string->free_after_use = true; 779 } 780 781 /* 782 * append_char(from, to) 783 * 784 * Append one char to a make string expanding it if nessecary 785 * 786 * Parameters: 787 * from Single character to append to string 788 * to The destination (make style) string 789 * 790 * Global variables used: 791 */ 792 void 793 append_char(wchar_t from, register String to) 794 { 795 if (to->buffer.start == NULL) { 796 expand_string(to, 32); 797 } 798 if (to->buffer.end - to->text.p <= 2) { 799 expand_string(to, to->buffer.end - to->buffer.start + 32); 800 } 801 *(to->text.p)++ = from; 802 *(to->text.p) = (int) nul_char; 803 } 804 805 /* 806 * handle_interrupt_mksh() 807 * 808 * This is where C-C traps are caught. 809 */ 810 void 811 handle_interrupt_mksh(int) 812 { 813 (void) fflush(stdout); 814 /* Make sure the processes running under us terminate first. */ 815 if (childPid > 0) { 816 kill(childPid, SIGTERM); 817 childPid = -1; 818 } 819 while (wait((int *) NULL) != -1); 820 exit_status = 2; 821 exit(2); 822 } 823 824 /* 825 * setup_interrupt() 826 * 827 * This routine saves the original interrupt handler pointers 828 * 829 * Parameters: 830 * 831 * Static variables used: 832 * sigivalue The original signal handler 833 * sigqvalue The original signal handler 834 * sigtvalue The original signal handler 835 * sighvalue The original signal handler 836 */ 837 void 838 setup_interrupt(register void (*handler) (int)) 839 { 840 sigivalue = bsd_signal(SIGINT, SIG_IGN); 841 sigqvalue = bsd_signal(SIGQUIT, SIG_IGN); 842 sigtvalue = bsd_signal(SIGTERM, SIG_IGN); 843 sighvalue = bsd_signal(SIGHUP, SIG_IGN); 844 enable_interrupt(handler); 845 } 846 847 848 void 849 mbstowcs_with_check(wchar_t *pwcs, const char *s, size_t n) 850 { 851 if(mbstowcs(pwcs, s, n) == -1) { 852 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 143, "The string `%s' is not valid in current locale"), s); 853 } 854 } 855 856 857 858 Wstring::Wstring() 859 { 860 INIT_STRING_FROM_STACK(string, string_buf); 861 } 862 863 Wstring::Wstring(struct _Name * name) 864 { 865 INIT_STRING_FROM_STACK(string, string_buf); 866 append_string(name->string_mb, &string, name->hash.length); 867 } 868 869 Wstring::~Wstring() 870 { 871 if(string.free_after_use) { 872 retmem(string.buffer.start); 873 } 874 } 875 876 void 877 Wstring::init(struct _Name * name) 878 { 879 if(string.free_after_use) { 880 retmem(string.buffer.start); 881 } 882 INIT_STRING_FROM_STACK(string, string_buf); 883 append_string(name->string_mb, &string, name->hash.length); 884 } 885 886 void 887 Wstring::init(wchar_t * name, unsigned length) 888 { 889 INIT_STRING_FROM_STACK(string, string_buf); 890 append_string(name, &string, length); 891 string.buffer.start[length] = 0; 892 } 893 894 Boolean 895 Wstring::equaln(wchar_t * str, unsigned length) 896 { 897 return (Boolean)IS_WEQUALN(string.buffer.start, str, length); 898 } 899 900 Boolean 901 Wstring::equaln(Wstring * str, unsigned length) 902 { 903 return (Boolean)IS_WEQUALN(string.buffer.start, str->string.buffer.start, length); 904 } 905 906 Boolean 907 Wstring::equal(wchar_t * str, unsigned off, unsigned length) 908 { 909 return (Boolean)IS_WEQUALN(string.buffer.start + off, str, length); 910 } 911 912 Boolean 913 Wstring::equal(wchar_t * str, unsigned off) 914 { 915 return (Boolean)IS_WEQUAL(string.buffer.start + off, str); 916 } 917 918 Boolean 919 Wstring::equal(wchar_t * str) 920 { 921 return equal(str, 0); 922 } 923 924 Boolean 925 Wstring::equal(Wstring * str, unsigned off, unsigned length) 926 { 927 return (Boolean)IS_WEQUALN(string.buffer.start + off, str->string.buffer.start, length); 928 } 929 930 Boolean 931 Wstring::equal(Wstring * str) 932 { 933 return equal(str, 0); 934 } 935 936 Boolean 937 Wstring::equal(Wstring * str, unsigned off) 938 { 939 return (Boolean)IS_WEQUAL(string.buffer.start + off, str->string.buffer.start); 940 } 941 942 void 943 Wstring::append_to_str(struct _String * str, unsigned off, unsigned length) 944 { 945 append_string(string.buffer.start + off, str, length); 946 } 947 948 Name 949 Name_set::lookup(const char *key) 950 { 951 for (entry *node = root; node != 0;) { 952 int res = strcmp(key, node->name->string_mb); 953 if (res < 0) { 954 node = node->left; 955 } else if (res > 0) { 956 node = node->right; 957 } else { 958 return node->name; 959 } 960 } 961 return 0; 962 } 963 964 Name 965 Name_set::insert(const char *key, Boolean &found) 966 { 967 Name name = 0; 968 969 if (root != 0) { 970 for (entry *node = root; name == 0;) { 971 int res = strcmp(key, node->name->string_mb); 972 if (res < 0) { 973 if (node->left != 0) { 974 node = node->left; 975 } else { 976 found = false; 977 name = ALLOC(Name); 978 979 node->left = new entry(name, node); 980 rebalance(node); 981 } 982 } else if (res > 0) { 983 if (node->right != 0) { 984 node = node->right; 985 } else { 986 found = false; 987 name = ALLOC(Name); 988 989 node->right = new entry(name, node); 990 rebalance(node); 991 } 992 } else { 993 found = true; 994 name = node->name; 995 } 996 } 997 } else { 998 found = false; 999 name = ALLOC(Name); 1000 1001 root = new entry(name, 0); 1002 } 1003 return name; 1004 } 1005 1006 void 1007 Name_set::insert(Name name) { 1008 if (root != 0) { 1009 for (entry *node = root;;) { 1010 int res = strcmp(name->string_mb, node->name->string_mb); 1011 if (res < 0) { 1012 if (node->left != 0) { 1013 node = node->left; 1014 } else { 1015 node->left = new entry(name, node); 1016 rebalance(node); 1017 break; 1018 } 1019 } else if (res > 0) { 1020 if (node->right != 0) { 1021 node = node->right; 1022 } else { 1023 node->right = new entry(name, node); 1024 rebalance(node); 1025 break; 1026 } 1027 } else { 1028 // should be an error: inserting already existing name 1029 break; 1030 } 1031 } 1032 } else { 1033 root = new entry(name, 0); 1034 } 1035 } 1036 1037 void 1038 Name_set::rebalance(Name_set::entry *node) { 1039 for (; node != 0; node = node->parent) { 1040 entry *right = node->right; 1041 entry *left = node->left; 1042 1043 unsigned rdepth = (right != 0) ? right->depth : 0; 1044 unsigned ldepth = (left != 0) ? left->depth : 0; 1045 1046 if (ldepth > rdepth + 1) { 1047 if ((node->left = left->right) != 0) { 1048 left->right->parent = node; 1049 } 1050 if ((left->parent = node->parent) != 0) { 1051 if (node == node->parent->right) { 1052 node->parent->right = left; 1053 } else { 1054 node->parent->left = left; 1055 } 1056 } else { 1057 root = left; 1058 } 1059 left->right = node; 1060 node->parent = left; 1061 1062 node->setup_depth(); 1063 node = left; 1064 } else if (rdepth > ldepth + 1) { 1065 if ((node->right = right->left) != 0) { 1066 right->left->parent = node; 1067 } 1068 if ((right->parent = node->parent) != 0) { 1069 if (node == node->parent->right) { 1070 node->parent->right = right; 1071 } else { 1072 node->parent->left = right; 1073 } 1074 } else { 1075 root = right; 1076 } 1077 right->left = node; 1078 node->parent = right; 1079 1080 node->setup_depth(); 1081 node = right; 1082 } 1083 node->setup_depth(); 1084 } 1085 } 1086 1087 Name_set::iterator 1088 Name_set::begin() const { 1089 for (entry *node = root; node != 0; node = node->left) { 1090 if (node->left == 0) { 1091 return iterator(node); 1092 } 1093 } 1094 return iterator(); 1095 } 1096 1097 Name_set::iterator& 1098 Name_set::iterator::operator++() { 1099 if (node != 0) { 1100 if (node->right != 0) { 1101 node = node->right; 1102 while (node->left != 0) { 1103 node = node->left; 1104 } 1105 } else { 1106 while ((node->parent != 0) && (node->parent->right == node)) { 1107 node = node->parent; 1108 } 1109 node = node->parent; 1110 } 1111 } 1112 return *this; 1113 }