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