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