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 }