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 }