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