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