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