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 }