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 2006 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 /*
  28  *      macro.cc
  29  *
  30  *      Handle expansion of make macros
  31  */
  32 
  33 /*
  34  * Included files
  35  */
  36 #include <mksh/dosys.h>           /* sh_command2string() */
  37 #include <mksh/i18n.h>            /* get_char_semantics_value() */
  38 #include <mksh/macro.h>
  39 #include <mksh/misc.h>            /* retmem() */
  40 #include <mksh/read.h>            /* get_next_block_fn() */
  41 #include <mksdmsi18n/mksdmsi18n.h>        /* libmksdmsi18n_init() */
  42 
  43 #include <widec.h>
  44 
  45 /*
  46  * File table of contents
  47  */
  48 static void     add_macro_to_global_list(Name macro_to_add);
  49 #ifdef NSE
  50 static void     expand_value_with_daemon(Name name, register Property macro, register String destination, Boolean cmd);
  51 #else
  52 static void     expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd);
  53 #endif
  54 
  55 static void     init_arch_macros(void);
  56 static void     init_mach_macros(void);
  57 static Boolean  init_arch_done = false;
  58 static Boolean  init_mach_done = false;
  59 
  60 
  61 long env_alloc_num = 0;
  62 long env_alloc_bytes = 0;
  63 
  64 /*
  65  *      getvar(name)
  66  *
  67  *      Return expanded value of macro.
  68  *
  69  *      Return value:
  70  *                              The expanded value of the macro
  71  *
  72  *      Parameters:
  73  *              name            The name of the macro we want the value for
  74  *
  75  *      Global variables used:
  76  */
  77 Name
  78 getvar(register Name name)
  79 {
  80         String_rec              destination;
  81         wchar_t                 buffer[STRING_BUFFER_LENGTH];
  82         register Name           result;
  83 
  84         if ((name == host_arch) || (name == target_arch)) {
  85                 if (!init_arch_done) {
  86                         init_arch_done = true;
  87                         init_arch_macros();
  88                 }
  89         }
  90         if ((name == host_mach) || (name == target_mach)) {
  91                 if (!init_mach_done) {
  92                         init_mach_done = true;
  93                         init_mach_macros();
  94                 }
  95         }
  96 
  97         INIT_STRING_FROM_STACK(destination, buffer);
  98         expand_value(maybe_append_prop(name, macro_prop)->body.macro.value,
  99                      &destination,
 100                      false);
 101         result = GETNAME(destination.buffer.start, FIND_LENGTH);
 102         if (destination.free_after_use) {
 103                 retmem(destination.buffer.start);
 104         }
 105         return result;
 106 }
 107 
 108 /*
 109  *      expand_value(value, destination, cmd)
 110  *
 111  *      Recursively expands all macros in the string value.
 112  *      destination is where the expanded value should be appended.
 113  *
 114  *      Parameters:
 115  *              value           The value we are expanding
 116  *              destination     Where to deposit the expansion
 117  *              cmd             If we are evaluating a command line we
 118  *                              turn \ quoting off
 119  *
 120  *      Global variables used:
 121  */
 122 void
 123 expand_value(Name value, register String destination, Boolean cmd)
 124 {
 125         Source_rec              sourceb;
 126         register Source         source = &sourceb;
 127         register wchar_t        *source_p = NULL;
 128         register wchar_t        *source_end = NULL;
 129         wchar_t                 *block_start = NULL;
 130         int                     quote_seen = 0;
 131 
 132         if (value == NULL) {
 133                 /*
 134                  * Make sure to get a string allocated even if it
 135                  * will be empty.
 136                  */
 137                 MBSTOWCS(wcs_buffer, "");
 138                 append_string(wcs_buffer, destination, FIND_LENGTH);
 139                 destination->text.end = destination->text.p;
 140                 return;
 141         }
 142         if (!value->dollar) {
 143                 /*
 144                  * If the value we are expanding does not contain
 145                  * any $, we don't have to parse it.
 146                  */
 147                 APPEND_NAME(value,
 148                         destination,
 149                         (int) value->hash.length
 150                 );
 151                 destination->text.end = destination->text.p;
 152                 return;
 153         }
 154 
 155         if (value->being_expanded) {
 156                 fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 113, "Loop detected when expanding macro value `%s'"),
 157                              value->string_mb);
 158         }
 159         value->being_expanded = true;
 160         /* Setup the structure we read from */
 161         Wstring vals(value);
 162         sourceb.string.text.p = sourceb.string.buffer.start = wsdup(vals.get_string());
 163         sourceb.string.free_after_use = true;
 164         sourceb.string.text.end =
 165           sourceb.string.buffer.end =
 166             sourceb.string.text.p + value->hash.length;
 167         sourceb.previous = NULL;
 168         sourceb.fd = -1;
 169         sourceb.inp_buf =
 170           sourceb.inp_buf_ptr =
 171             sourceb.inp_buf_end = NULL;
 172         sourceb.error_converting = false;
 173         /* Lift some pointers from the struct to local register variables */
 174         CACHE_SOURCE(0);
 175 /* We parse the string in segments */
 176 /* We read chars until we find a $, then we append what we have read so far */
 177 /* (since last $ processing) to the destination. When we find a $ we call */
 178 /* expand_macro() and let it expand that particular $ reference into dest */
 179         block_start = source_p;
 180         quote_seen = 0;
 181         for (; 1; source_p++) {
 182                 switch (GET_CHAR()) {
 183                 case backslash_char:
 184                         /* Quote $ in macro value */
 185                         if (!cmd) {
 186                                 quote_seen = ~quote_seen;
 187                         }
 188                         continue;
 189                 case dollar_char:
 190                         /* Save the plain string we found since */
 191                         /* start of string or previous $ */
 192                         if (quote_seen) {
 193                                 append_string(block_start,
 194                                               destination,
 195                                               source_p - block_start - 1);
 196                                 block_start = source_p;
 197                                 break;
 198                         }
 199                         append_string(block_start,
 200                                       destination,
 201                                       source_p - block_start);
 202                         source->string.text.p = ++source_p;
 203                         UNCACHE_SOURCE();
 204                         /* Go expand the macro reference */
 205                         expand_macro(source, destination, sourceb.string.buffer.start, cmd);
 206                         CACHE_SOURCE(1);
 207                         block_start = source_p + 1;
 208                         break;
 209                 case nul_char:
 210                         /* The string ran out. Get some more */
 211                         append_string(block_start,
 212                                       destination,
 213                                       source_p - block_start);
 214                         GET_NEXT_BLOCK_NOCHK(source);
 215                         if (source == NULL) {
 216                                 destination->text.end = destination->text.p;
 217                                 value->being_expanded = false;
 218                                 return;
 219                         }
 220                         if (source->error_converting) {
 221                                 fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_value()"));
 222                         }
 223                         block_start = source_p;
 224                         source_p--;
 225                         continue;
 226                 }
 227                 quote_seen = 0;
 228         }
 229         retmem(sourceb.string.buffer.start);
 230 }
 231 
 232 /*
 233  *      expand_macro(source, destination, current_string, cmd)
 234  *
 235  *      Should be called with source->string.text.p pointing to
 236  *      the first char after the $ that starts a macro reference.
 237  *      source->string.text.p is returned pointing to the first char after
 238  *      the macro name.
 239  *      It will read the macro name, expanding any macros in it,
 240  *      and get the value. The value is then expanded.
 241  *      destination is a String that is filled in with the expanded macro.
 242  *      It may be passed in referencing a buffer to expand the macro into.
 243  *      Note that most expansions are done on demand, e.g. right 
 244  *      before the command is executed and not while the file is
 245  *      being parsed.
 246  *
 247  *      Parameters:
 248  *              source          The source block that references the string
 249  *                              to expand
 250  *              destination     Where to put the result
 251  *              current_string  The string we are expanding, for error msg
 252  *              cmd             If we are evaluating a command line we
 253  *                              turn \ quoting off
 254  *
 255  *      Global variables used:
 256  *              funny           Vector of semantic tags for characters
 257  *              is_conditional  Set if a conditional macro is refd
 258  *              make_word_mentioned Set if the word "MAKE" is mentioned
 259  *              makefile_type   We deliver extra msg when reading makefiles
 260  *              query           The Name "?", compared against
 261  *              query_mentioned Set if the word "?" is mentioned
 262  */
 263 void
 264 expand_macro(register Source source, register String destination, wchar_t *current_string, Boolean cmd)
 265 {
 266         static Name             make = (Name)NULL;
 267         static wchar_t          colon_sh[4];
 268         static wchar_t          colon_shell[7];
 269         String_rec              string;
 270         wchar_t                 buffer[STRING_BUFFER_LENGTH];
 271         register wchar_t        *source_p = source->string.text.p;
 272         register wchar_t        *source_end = source->string.text.end;
 273         register int            closer = 0;
 274         wchar_t                 *block_start = (wchar_t *)NULL;
 275         int                     quote_seen = 0;
 276         register int            closer_level = 1;
 277         Name                    name = (Name)NULL;
 278         wchar_t                 *colon = (wchar_t *)NULL;
 279         wchar_t                 *percent = (wchar_t *)NULL;
 280         wchar_t                 *eq = (wchar_t *) NULL;
 281         Property                macro = NULL;
 282         wchar_t                 *p = (wchar_t*)NULL;
 283         String_rec              extracted;
 284         wchar_t                 extracted_string[MAXPATHLEN];
 285         wchar_t                 *left_head = NULL;
 286         wchar_t                 *left_tail = NULL;
 287         wchar_t                 *right_tail = NULL;
 288         int                     left_head_len = 0;
 289         int                     left_tail_len = 0;
 290         int                     tmp_len = 0;
 291         wchar_t                 *right_hand[128];
 292         int                     i = 0;
 293         enum {
 294                 no_extract,
 295                 dir_extract,
 296                 file_extract
 297         }                       extraction = no_extract;
 298         enum {
 299                 no_replace,
 300                 suffix_replace,
 301                 pattern_replace,
 302                 sh_replace
 303         }                       replacement = no_replace;
 304 
 305         if (make == NULL) {
 306                 MBSTOWCS(wcs_buffer, NOCATGETS("MAKE"));
 307                 make = GETNAME(wcs_buffer, FIND_LENGTH);
 308 
 309                 MBSTOWCS(colon_sh, NOCATGETS(":sh"));
 310                 MBSTOWCS(colon_shell, NOCATGETS(":shell"));
 311         }
 312 
 313         right_hand[0] = NULL;
 314 
 315         /* First copy the (macro-expanded) macro name into string. */
 316         INIT_STRING_FROM_STACK(string, buffer);
 317 recheck_first_char:
 318         /* Check the first char of the macro name to figure out what to do. */
 319         switch (GET_CHAR()) {
 320         case nul_char:
 321                 GET_NEXT_BLOCK_NOCHK(source);
 322                 if (source == NULL) {
 323                         WCSTOMBS(mbs_buffer, current_string);
 324                         fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 114, "'$' at end of string `%s'"),
 325                                      mbs_buffer);
 326                 }
 327                 if (source->error_converting) {
 328                         fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_macro()"));
 329                 }
 330                 goto recheck_first_char;
 331         case parenleft_char:
 332                 /* Multi char name. */
 333                 closer = (int) parenright_char;
 334                 break;
 335         case braceleft_char:
 336                 /* Multi char name. */
 337                 closer = (int) braceright_char;
 338                 break;
 339         case newline_char:
 340                 fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 115, "'$' at end of line"));
 341         default:
 342                 /* Single char macro name. Just suck it up */
 343                 append_char(*source_p, &string);
 344                 source->string.text.p = source_p + 1;
 345                 goto get_macro_value;
 346         }
 347 
 348         /* Handle multi-char macro names */
 349         block_start = ++source_p;
 350         quote_seen = 0;
 351         for (; 1; source_p++) {
 352                 switch (GET_CHAR()) {
 353                 case nul_char:
 354                         append_string(block_start,
 355                                       &string,
 356                                       source_p - block_start);
 357                         GET_NEXT_BLOCK_NOCHK(source);
 358                         if (source == NULL) {
 359                                 if (current_string != NULL) {
 360                                         WCSTOMBS(mbs_buffer, current_string);
 361                                         fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 116, "Unmatched `%c' in string `%s'"),
 362                                                      closer ==
 363                                                      (int) braceright_char ?
 364                                                      (int) braceleft_char :
 365                                                      (int) parenleft_char,
 366                                                      mbs_buffer);
 367                                 } else {
 368                                         fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 117, "Premature EOF"));
 369                                 }
 370                         }
 371                         if (source->error_converting) {
 372                                 fatal_reader_mksh(NOCATGETS("Internal error: Invalid byte sequence in expand_macro()"));
 373                         }
 374                         block_start = source_p;
 375                         source_p--;
 376                         continue;
 377                 case newline_char:
 378                         fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 118, "Unmatched `%c' on line"),
 379                                      closer == (int) braceright_char ?
 380                                      (int) braceleft_char :
 381                                      (int) parenleft_char);
 382                 case backslash_char:
 383                         /* Quote dollar in macro value. */
 384                         if (!cmd) {
 385                                 quote_seen = ~quote_seen;
 386                         }
 387                         continue;
 388                 case dollar_char:
 389                         /*
 390                          * Macro names may reference macros.
 391                          * This expands the value of such macros into the
 392                          * macro name string.
 393                          */
 394                         if (quote_seen) {
 395                                 append_string(block_start,
 396                                               &string,
 397                                               source_p - block_start - 1);
 398                                 block_start = source_p;
 399                                 break;
 400                         }
 401                         append_string(block_start,
 402                                       &string,
 403                                       source_p - block_start);
 404                         source->string.text.p = ++source_p;
 405                         UNCACHE_SOURCE();
 406                         expand_macro(source, &string, current_string, cmd);
 407                         CACHE_SOURCE(0);
 408                         block_start = source_p;
 409                         source_p--;
 410                         break;
 411                 case parenleft_char:
 412                         /* Allow nested pairs of () in the macro name. */
 413                         if (closer == (int) parenright_char) {
 414                                 closer_level++;
 415                         }
 416                         break;
 417                 case braceleft_char:
 418                         /* Allow nested pairs of {} in the macro name. */
 419                         if (closer == (int) braceright_char) {
 420                                 closer_level++;
 421                         }
 422                         break;
 423                 case parenright_char:
 424                 case braceright_char:
 425                         /*
 426                          * End of the name. Save the string in the macro
 427                          * name string.
 428                          */
 429                         if ((*source_p == closer) && (--closer_level <= 0)) {
 430                                 source->string.text.p = source_p + 1;
 431                                 append_string(block_start,
 432                                               &string,
 433                                               source_p - block_start);
 434                                 goto get_macro_value;
 435                         }
 436                         break;
 437                 }
 438                 quote_seen = 0;
 439         }
 440         /*
 441          * We got the macro name. We now inspect it to see if it
 442          * specifies any translations of the value.
 443          */
 444 get_macro_value:
 445         name = NULL;
 446         /* First check if we have a $(@D) type translation. */
 447         if ((get_char_semantics_value(string.buffer.start[0]) &
 448              (int) special_macro_sem) &&
 449             (string.text.p - string.buffer.start >= 2) &&
 450             ((string.buffer.start[1] == 'D') ||
 451              (string.buffer.start[1] == 'F'))) {
 452                 switch (string.buffer.start[1]) {
 453                 case 'D':
 454                         extraction = dir_extract;
 455                         break;
 456                 case 'F':
 457                         extraction = file_extract;
 458                         break;
 459                 default:
 460                         WCSTOMBS(mbs_buffer, string.buffer.start);
 461                         fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 119, "Illegal macro reference `%s'"),
 462                                      mbs_buffer);
 463                 }
 464                 /* Internalize the macro name using the first char only. */
 465                 name = GETNAME(string.buffer.start, 1);
 466                 (void) wscpy(string.buffer.start, string.buffer.start + 2);
 467         }
 468         /* Check for other kinds of translations. */
 469         if ((colon = (wchar_t *) wschr(string.buffer.start,
 470                                        (int) colon_char)) != NULL) {
 471                 /*
 472                  * We have a $(FOO:.c=.o) type translation.
 473                  * Get the name of the macro proper.
 474                  */
 475                 if (name == NULL) {
 476                         name = GETNAME(string.buffer.start,
 477                                        colon - string.buffer.start);
 478                 }
 479                 /* Pickup all the translations. */
 480                 if (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell)) {
 481                         replacement = sh_replace;
 482                 } else if ((svr4) ||
 483                            ((percent = (wchar_t *) wschr(colon + 1,
 484                                                          (int) percent_char)) == NULL)) {
 485                         while (colon != NULL) {
 486                                 if ((eq = (wchar_t *) wschr(colon + 1,
 487                                                             (int) equal_char)) == NULL) {
 488                                         fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 120, "= missing from replacement macro reference"));
 489                                 }
 490                                 left_tail_len = eq - colon - 1;
 491                                 if(left_tail) {
 492                                         retmem(left_tail);
 493                                 }
 494                                 left_tail = ALLOC_WC(left_tail_len + 1);
 495                                 (void) wsncpy(left_tail,
 496                                               colon + 1,
 497                                               eq - colon - 1);
 498                                 left_tail[eq - colon - 1] = (int) nul_char;
 499                                 replacement = suffix_replace;
 500                                 if ((colon = (wchar_t *) wschr(eq + 1,
 501                                                                (int) colon_char)) != NULL) {
 502                                         tmp_len = colon - eq;
 503                                         if(right_tail) {
 504                                                 retmem(right_tail);
 505                                         }
 506                                         right_tail = ALLOC_WC(tmp_len);
 507                                         (void) wsncpy(right_tail,
 508                                                       eq + 1,
 509                                                       colon - eq - 1);
 510                                         right_tail[colon - eq - 1] =
 511                                           (int) nul_char;
 512                                 } else {
 513                                         if(right_tail) {
 514                                                 retmem(right_tail);
 515                                         }
 516                                         right_tail = ALLOC_WC(wslen(eq) + 1);
 517                                         (void) wscpy(right_tail, eq + 1);
 518                                 }
 519                         }
 520                 } else {
 521                         if ((eq = (wchar_t *) wschr(colon + 1,
 522                                                     (int) equal_char)) == NULL) {
 523                                 fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 121, "= missing from replacement macro reference"));
 524                         }
 525                         if ((percent = (wchar_t *) wschr(colon + 1,
 526                                                          (int) percent_char)) == NULL) {
 527                                 fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 122, "%% missing from replacement macro reference"));
 528                         }
 529                         if (eq < percent) {
 530                                 fatal_reader_mksh(catgets(libmksdmsi18n_catd, 1, 123, "%% missing from replacement macro reference"));
 531                         }
 532 
 533                         if (percent > (colon + 1)) {
 534                                 tmp_len = percent - colon;
 535                                 if(left_head) {
 536                                         retmem(left_head);
 537                                 }
 538                                 left_head = ALLOC_WC(tmp_len);
 539                                 (void) wsncpy(left_head,
 540                                               colon + 1,
 541                                               percent - colon - 1);
 542                                 left_head[percent-colon-1] = (int) nul_char;
 543                                 left_head_len = percent-colon-1;
 544                         } else {
 545                                 left_head = NULL;
 546                                 left_head_len = 0;
 547                         }
 548 
 549                         if (eq > percent+1) {
 550                                 tmp_len = eq - percent;
 551                                 if(left_tail) {
 552                                         retmem(left_tail);
 553                                 }
 554                                 left_tail = ALLOC_WC(tmp_len);
 555                                 (void) wsncpy(left_tail,
 556                                               percent + 1,
 557                                               eq - percent - 1);
 558                                 left_tail[eq-percent-1] = (int) nul_char;
 559                                 left_tail_len = eq-percent-1;
 560                         } else {
 561                                 left_tail = NULL;
 562                                 left_tail_len = 0;
 563                         }
 564 
 565                         if ((percent = (wchar_t *) wschr(++eq,
 566                                                          (int) percent_char)) == NULL) {
 567 
 568                                 right_hand[0] = ALLOC_WC(wslen(eq) + 1);
 569                                 right_hand[1] = NULL;
 570                                 (void) wscpy(right_hand[0], eq);
 571                         } else {
 572                                 i = 0;
 573                                 do {
 574                                         right_hand[i] = ALLOC_WC(percent-eq+1);
 575                                         (void) wsncpy(right_hand[i],
 576                                                       eq,
 577                                                       percent - eq);
 578                                         right_hand[i][percent-eq] =
 579                                           (int) nul_char;
 580                                         if (i++ >= VSIZEOF(right_hand)) {
 581                                                 fatal_mksh(catgets(libmksdmsi18n_catd, 1, 124, "Too many %% in pattern"));
 582                                         }
 583                                         eq = percent + 1;
 584                                         if (eq[0] == (int) nul_char) {
 585                                                 MBSTOWCS(wcs_buffer, "");
 586                                                 right_hand[i] = (wchar_t *) wsdup(wcs_buffer);
 587                                                 i++;
 588                                                 break;
 589                                         }
 590                                 } while ((percent = (wchar_t *) wschr(eq, (int) percent_char)) != NULL);
 591                                 if (eq[0] != (int) nul_char) {
 592                                         right_hand[i] = ALLOC_WC(wslen(eq) + 1);
 593                                         (void) wscpy(right_hand[i], eq);
 594                                         i++;
 595                                 }
 596                                 right_hand[i] = NULL;
 597                         }
 598                         replacement = pattern_replace;
 599                 }
 600         }
 601         if (name == NULL) {
 602                 /*
 603                  * No translations found.
 604                  * Use the whole string as the macro name.
 605                  */
 606                 name = GETNAME(string.buffer.start,
 607                                string.text.p - string.buffer.start);
 608         }
 609         if (string.free_after_use) {
 610                 retmem(string.buffer.start);
 611         }
 612         if (name == make) {
 613                 make_word_mentioned = true;
 614         }
 615         if (name == query) {
 616                 query_mentioned = true;
 617         }
 618         if ((name == host_arch) || (name == target_arch)) {
 619                 if (!init_arch_done) {
 620                         init_arch_done = true;
 621                         init_arch_macros();
 622                 }
 623         }
 624         if ((name == host_mach) || (name == target_mach)) {
 625                 if (!init_mach_done) {
 626                         init_mach_done = true;
 627                         init_mach_macros();
 628                 }
 629         }
 630         /* Get the macro value. */
 631         macro = get_prop(name->prop, macro_prop);
 632 #ifdef NSE
 633         if (nse_watch_vars && nse && macro != NULL) {
 634                 if (macro->body.macro.imported) {
 635                         nse_shell_var_used= name;
 636                 }
 637                 if (macro->body.macro.value != NULL){
 638                       if (nse_backquotes(macro->body.macro.value->string)) {
 639                                nse_backquote_seen= name;
 640                       }
 641                }
 642         }
 643 #endif
 644         if ((macro != NULL) && macro->body.macro.is_conditional) {
 645                 conditional_macro_used = true;
 646                 /*
 647                  * Add this conditional macro to the beginning of the
 648                  * global list.
 649                  */
 650                 add_macro_to_global_list(name);
 651                 if (makefile_type == reading_makefile) {
 652                         warning_mksh(catgets(libmksdmsi18n_catd, 1, 164, "Conditional macro `%s' referenced in file `%ws', line %d"),
 653                                         name->string_mb, file_being_read, line_number);
 654                 }
 655         }
 656         /* Macro name read and parsed. Expand the value. */
 657         if ((macro == NULL) || (macro->body.macro.value == NULL)) {
 658                 /* If the value is empty, we just get out of here. */
 659                 goto exit;
 660         }
 661         if (replacement == sh_replace) {
 662                 /* If we should do a :sh transform, we expand the command
 663                  * and process it.
 664                  */
 665                 INIT_STRING_FROM_STACK(string, buffer);
 666                 /* Expand the value into a local string buffer and run cmd. */
 667                 expand_value_with_daemon(name, macro, &string, cmd);
 668                 sh_command2string(&string, destination);
 669         } else if ((replacement != no_replace) || (extraction != no_extract)) {
 670                 /*
 671                  * If there were any transforms specified in the macro
 672                  * name, we deal with them here.
 673                  */
 674                 INIT_STRING_FROM_STACK(string, buffer);
 675                 /* Expand the value into a local string buffer. */
 676                 expand_value_with_daemon(name, macro, &string, cmd);
 677                 /* Scan the expanded string. */
 678                 p = string.buffer.start;
 679                 while (*p != (int) nul_char) {
 680                         wchar_t         chr;
 681 
 682                         /*
 683                          * First skip over any white space and append
 684                          * that to the destination string.
 685                          */
 686                         block_start = p;
 687                         while ((*p != (int) nul_char) && iswspace(*p)) {
 688                                 p++;
 689                         }
 690                         append_string(block_start,
 691                                       destination,
 692                                       p - block_start);
 693                         /* Then find the end of the next word. */
 694                         block_start = p;
 695                         while ((*p != (int) nul_char) && !iswspace(*p)) {
 696                                 p++;
 697                         }
 698                         /* If we cant find another word we are done */
 699                         if (block_start == p) {
 700                                 break;
 701                         }
 702                         /* Then apply the transforms to the word */
 703                         INIT_STRING_FROM_STACK(extracted, extracted_string);
 704                         switch (extraction) {
 705                         case dir_extract:
 706                                 /*
 707                                  * $(@D) type transform. Extract the
 708                                  * path from the word. Deliver "." if
 709                                  * none is found.
 710                                  */
 711                                 if (p != NULL) {
 712                                         chr = *p;
 713                                         *p = (int) nul_char;
 714                                 }
 715                                 eq = (wchar_t *) wsrchr(block_start, (int) slash_char);
 716                                 if (p != NULL) {
 717                                         *p = chr;
 718                                 }
 719                                 if ((eq == NULL) || (eq > p)) {
 720                                         MBSTOWCS(wcs_buffer, ".");
 721                                         append_string(wcs_buffer, &extracted, 1);
 722                                 } else {
 723                                         append_string(block_start,
 724                                                       &extracted,
 725                                                       eq - block_start);
 726                                 }
 727                                 break;
 728                         case file_extract:
 729                                 /*
 730                                  * $(@F) type transform. Remove the path
 731                                  * from the word if any.
 732                                  */
 733                                 if (p != NULL) {
 734                                         chr = *p;
 735                                         *p = (int) nul_char;
 736                                 }
 737                                 eq = (wchar_t *) wsrchr(block_start, (int) slash_char);
 738                                 if (p != NULL) {
 739                                         *p = chr;
 740                                 }
 741                                 if ((eq == NULL) || (eq > p)) {
 742                                         append_string(block_start,
 743                                                       &extracted,
 744                                                       p - block_start);
 745                                 } else {
 746                                         append_string(eq + 1,
 747                                                       &extracted,
 748                                                       p - eq - 1);
 749                                 }
 750                                 break;
 751                         case no_extract:
 752                                 append_string(block_start,
 753                                               &extracted,
 754                                               p - block_start);
 755                                 break;
 756                         }
 757                         switch (replacement) {
 758                         case suffix_replace:
 759                                 /*
 760                                  * $(FOO:.o=.c) type transform.
 761                                  * Maybe replace the tail of the word.
 762                                  */
 763                                 if (((extracted.text.p -
 764                                       extracted.buffer.start) >=
 765                                      left_tail_len) &&
 766                                     IS_WEQUALN(extracted.text.p - left_tail_len,
 767                                               left_tail,
 768                                               left_tail_len)) {
 769                                         append_string(extracted.buffer.start,
 770                                                       destination,
 771                                                       (extracted.text.p -
 772                                                        extracted.buffer.start)
 773                                                       - left_tail_len);
 774                                         append_string(right_tail,
 775                                                       destination,
 776                                                       FIND_LENGTH);
 777                                 } else {
 778                                         append_string(extracted.buffer.start,
 779                                                       destination,
 780                                                       FIND_LENGTH);
 781                                 }
 782                                 break;
 783                         case pattern_replace:
 784                                 /* $(X:a%b=c%d) type transform. */
 785                                 if (((extracted.text.p -
 786                                       extracted.buffer.start) >=
 787                                      left_head_len+left_tail_len) &&
 788                                     IS_WEQUALN(left_head,
 789                                               extracted.buffer.start,
 790                                               left_head_len) &&
 791                                     IS_WEQUALN(left_tail,
 792                                               extracted.text.p - left_tail_len,
 793                                               left_tail_len)) {
 794                                         i = 0;
 795                                         while (right_hand[i] != NULL) {
 796                                                 append_string(right_hand[i],
 797                                                               destination,
 798                                                               FIND_LENGTH);
 799                                                 i++;
 800                                                 if (right_hand[i] != NULL) {
 801                                                         append_string(extracted.buffer.
 802                                                                       start +
 803                                                                       left_head_len,
 804                                                                       destination,
 805                                                                       (extracted.text.p - extracted.buffer.start)-left_head_len-left_tail_len);
 806                                                 }
 807                                         }
 808                                 } else {
 809                                         append_string(extracted.buffer.start,
 810                                                       destination,
 811                                                       FIND_LENGTH);
 812                                 }
 813                                 break;
 814                         case no_replace:
 815                                 append_string(extracted.buffer.start,
 816                                               destination,
 817                                               FIND_LENGTH);
 818                                 break;
 819                         case sh_replace:
 820                                 break;
 821                             }
 822                 }
 823                 if (string.free_after_use) {
 824                         retmem(string.buffer.start);
 825                 }
 826         } else {
 827                 /*
 828                  * This is for the case when the macro name did not
 829                  * specify transforms.
 830                  */
 831                 if (!strncmp(name->string_mb, NOCATGETS("GET"), 3)) {
 832                         dollarget_seen = true;
 833                 }
 834                 dollarless_flag = false;
 835                 if (!strncmp(name->string_mb, "<", 1) &&
 836                     dollarget_seen) {
 837                         dollarless_flag = true;
 838                         dollarget_seen = false;
 839                 }
 840                 expand_value_with_daemon(name, macro, destination, cmd);
 841         }
 842 exit:
 843         if(left_tail) {
 844                 retmem(left_tail);
 845         }
 846         if(right_tail) {
 847                 retmem(right_tail);
 848         }
 849         if(left_head) {
 850                 retmem(left_head);
 851         }
 852         i = 0;
 853         while (right_hand[i] != NULL) {
 854                 retmem(right_hand[i]);
 855                 i++;
 856         }
 857         *destination->text.p = (int) nul_char;
 858         destination->text.end = destination->text.p;
 859 }
 860 
 861 static void
 862 add_macro_to_global_list(Name macro_to_add)
 863 {
 864         Macro_list      new_macro;
 865         Macro_list      macro_on_list;
 866         char            *name_on_list = (char*)NULL;
 867         char            *name_to_add = macro_to_add->string_mb;
 868         char            *value_on_list = (char*)NULL;
 869         const char      *value_to_add = (char*)NULL;
 870 
 871         if (macro_to_add->prop->body.macro.value != NULL) {
 872                 value_to_add = macro_to_add->prop->body.macro.value->string_mb;
 873         } else {
 874                 value_to_add = "";
 875         }
 876 
 877         /* 
 878          * Check if this macro is already on list, if so, do nothing
 879          */
 880         for (macro_on_list = cond_macro_list;
 881              macro_on_list != NULL;
 882              macro_on_list = macro_on_list->next) {
 883 
 884                 name_on_list = macro_on_list->macro_name;
 885                 value_on_list = macro_on_list->value;
 886 
 887                 if (IS_EQUAL(name_on_list, name_to_add)) {
 888                         if (IS_EQUAL(value_on_list, value_to_add)) {
 889                                 return;
 890                         }
 891                 }
 892         }
 893         new_macro = (Macro_list) malloc(sizeof(Macro_list_rec));
 894         new_macro->macro_name = strdup(name_to_add);
 895         new_macro->value = strdup(value_to_add);
 896         new_macro->next = cond_macro_list;
 897         cond_macro_list = new_macro;
 898 }
 899 
 900 /*
 901  *      init_arch_macros(void)
 902  *
 903  *      Set the magic macros TARGET_ARCH, HOST_ARCH,
 904  *
 905  *      Parameters: 
 906  *
 907  *      Global variables used:
 908  *                              host_arch   Property for magic macro HOST_ARCH
 909  *                              target_arch Property for magic macro TARGET_ARCH
 910  *
 911  *      Return value:
 912  *                              The function does not return a value, but can
 913  *                              call fatal() in case of error.
 914  */
 915 static void
 916 init_arch_macros(void)
 917 {
 918         String_rec      result_string;
 919         wchar_t         wc_buf[STRING_BUFFER_LENGTH];
 920         char            mb_buf[STRING_BUFFER_LENGTH];
 921         FILE            *pipe;
 922         Name            value;
 923         int             set_host, set_target;
 924 #ifdef NSE
 925         Property        macro;
 926 #endif
 927 #if defined(linux)
 928         const char      *mach_command = NOCATGETS("/bin/uname -p");
 929 #else
 930         const char      *mach_command = NOCATGETS("/bin/mach");
 931 #endif
 932 
 933         set_host = (get_prop(host_arch->prop, macro_prop) == NULL);
 934         set_target = (get_prop(target_arch->prop, macro_prop) == NULL);
 935 
 936         if (set_host || set_target) {
 937                 INIT_STRING_FROM_STACK(result_string, wc_buf);
 938                 append_char((int) hyphen_char, &result_string);
 939 
 940                 if ((pipe = popen(mach_command, "r")) == NULL) {
 941                         fatal_mksh(catgets(libmksdmsi18n_catd, 1, 185, "Execute of %s failed"), mach_command);
 942                 }
 943                 while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
 944                         MBSTOWCS(wcs_buffer, mb_buf);
 945                         append_string(wcs_buffer, &result_string, wslen(wcs_buffer));
 946                 }
 947                 if (pclose(pipe) != 0) {
 948                         fatal_mksh(catgets(libmksdmsi18n_catd, 1, 186, "Execute of %s failed"), mach_command);
 949                 }
 950 
 951                 value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start));
 952 
 953 #ifdef NSE
 954                 macro = setvar_daemon(host_arch, value, false, no_daemon, true, 0);
 955                 macro->body.macro.imported= true;
 956                 macro = setvar_daemon(target_arch, value, false, no_daemon, true, 0);
 957                 macro->body.macro.imported= true;
 958 #else
 959                 if (set_host) {
 960                         (void) setvar_daemon(host_arch, value, false, no_daemon, true, 0);
 961                 }
 962                 if (set_target) {
 963                         (void) setvar_daemon(target_arch, value, false, no_daemon, true, 0);
 964                 }
 965 #endif
 966         }
 967 }
 968 
 969 /*
 970  *      init_mach_macros(void)
 971  *
 972  *      Set the magic macros TARGET_MACH, HOST_MACH,
 973  *
 974  *      Parameters: 
 975  *
 976  *      Global variables used:
 977  *                              host_mach   Property for magic macro HOST_MACH
 978  *                              target_mach Property for magic macro TARGET_MACH
 979  *
 980  *      Return value:
 981  *                              The function does not return a value, but can
 982  *                              call fatal() in case of error.
 983  */
 984 static void
 985 init_mach_macros(void)
 986 {
 987         String_rec      result_string;
 988         wchar_t         wc_buf[STRING_BUFFER_LENGTH];
 989         char            mb_buf[STRING_BUFFER_LENGTH];
 990         FILE            *pipe;
 991         Name            value;
 992         int             set_host, set_target;
 993         const char      *arch_command = NOCATGETS("/bin/arch");
 994 
 995         set_host = (get_prop(host_mach->prop, macro_prop) == NULL);
 996         set_target = (get_prop(target_mach->prop, macro_prop) == NULL);
 997 
 998         if (set_host || set_target) {
 999                 INIT_STRING_FROM_STACK(result_string, wc_buf);
1000                 append_char((int) hyphen_char, &result_string);
1001 
1002                 if ((pipe = popen(arch_command, "r")) == NULL) {
1003                         fatal_mksh(catgets(libmksdmsi18n_catd, 1, 183, "Execute of %s failed"), arch_command);
1004                 }
1005                 while (fgets(mb_buf, sizeof(mb_buf), pipe) != NULL) {
1006                         MBSTOWCS(wcs_buffer, mb_buf);
1007                         append_string(wcs_buffer, &result_string, wslen(wcs_buffer));
1008                 }
1009                 if (pclose(pipe) != 0) {
1010                         fatal_mksh(catgets(libmksdmsi18n_catd, 1, 184, "Execute of %s failed"), arch_command);
1011                 }
1012 
1013                 value = GETNAME(result_string.buffer.start, wslen(result_string.buffer.start));
1014 
1015                 if (set_host) {
1016                         (void) setvar_daemon(host_mach, value, false, no_daemon, true, 0);
1017                 }
1018                 if (set_target) {
1019                         (void) setvar_daemon(target_mach, value, false, no_daemon, true, 0);
1020                 }
1021         }
1022 }
1023 
1024 /*
1025  *      expand_value_with_daemon(name, macro, destination, cmd)
1026  *
1027  *      Checks for daemons and then maybe calls expand_value().
1028  *
1029  *      Parameters:
1030  *              name            Name of the macro  (Added by the NSE)
1031  *              macro           The property block with the value to expand
1032  *              destination     Where the result should be deposited
1033  *              cmd             If we are evaluating a command line we
1034  *                              turn \ quoting off
1035  *
1036  *      Global variables used:
1037  */
1038 static void
1039 #ifdef NSE
1040 expand_value_with_daemon(Name name, register Property macro, register String destination, Boolean cmd)
1041 #else
1042 expand_value_with_daemon(Name, register Property macro, register String destination, Boolean cmd)
1043 #endif
1044 {
1045         register Chain          chain;
1046 
1047 #ifdef NSE
1048         if (reading_dependencies) {
1049                 /*
1050                  * Processing the dependencies themselves
1051                  */
1052                 depvar_dep_macro_used(name);
1053         } else {
1054                 /*
1055                  * Processing the rules for the targets
1056                  * the nse_watch_vars flags chokes off most
1057                  * checks.  it is true only when processing
1058                  * the output from a recursive make run
1059                  * which is all we are interested in here.
1060                  */
1061                  if (nse_watch_vars) {
1062                         depvar_rule_macro_used(name);
1063                 }
1064          }
1065 #endif
1066 
1067         switch (macro->body.macro.daemon) {
1068         case no_daemon:
1069                 if (!svr4 && !posix) {
1070                         expand_value(macro->body.macro.value, destination, cmd);
1071                 } else {
1072                         if (dollarless_flag && tilde_rule) {
1073                                 expand_value(dollarless_value, destination, cmd);
1074                                 dollarless_flag = false;
1075                                 tilde_rule = false;
1076                         } else {
1077                                 expand_value(macro->body.macro.value, destination, cmd);
1078                         }
1079                 }
1080                 return;
1081         case chain_daemon:
1082                 /* If this is a $? value we call the daemon to translate the */
1083                 /* list of names to a string */
1084                 for (chain = (Chain) macro->body.macro.value;
1085                      chain != NULL;
1086                      chain = chain->next) {
1087                         APPEND_NAME(chain->name,
1088                                       destination,
1089                                       (int) chain->name->hash.length);
1090                         if (chain->next != NULL) {
1091                                 append_char((int) space_char, destination);
1092                         }
1093                 }
1094                 return;
1095         }
1096 }
1097 
1098 /*
1099  * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
1100  */
1101 char    *sunpro_dependencies_buf = NULL;
1102 char    *sunpro_dependencies_oldbuf = NULL;
1103 int     sunpro_dependencies_buf_size = 0;
1104 
1105 /*
1106  *      setvar_daemon(name, value, append, daemon, strip_trailing_spaces)
1107  *
1108  *      Set a macro value, possibly supplying a daemon to be used
1109  *      when referencing the value.
1110  *
1111  *      Return value:
1112  *                              The property block with the new value
1113  *
1114  *      Parameters:
1115  *              name            Name of the macro to set
1116  *              value           The value to set
1117  *              append          Should we reset or append to the current value?
1118  *              daemon          Special treatment when reading the value
1119  *              strip_trailing_spaces from the end of value->string
1120  *              debug_level     Indicates how much tracing we should do
1121  *
1122  *      Global variables used:
1123  *              makefile_type   Used to check if we should enforce read only
1124  *              path_name       The Name "PATH", compared against
1125  *              virtual_root    The Name "VIRTUAL_ROOT", compared against
1126  *              vpath_defined   Set if the macro VPATH is set
1127  *              vpath_name      The Name "VPATH", compared against
1128  *              envvar          A list of environment vars with $ in value
1129  */
1130 Property
1131 setvar_daemon(register Name name, register Name value, Boolean append, Daemon daemon, Boolean strip_trailing_spaces, short debug_level)
1132 {
1133         register Property       macro = maybe_append_prop(name, macro_prop);
1134         register Property       macro_apx = get_prop(name->prop, macro_append_prop);
1135         int                     length = 0;
1136         String_rec              destination;
1137         wchar_t                 buffer[STRING_BUFFER_LENGTH];
1138         register Chain          chain;
1139         Name                    val;
1140         wchar_t                 *val_string = (wchar_t*)NULL;
1141         Wstring                 wcb;
1142 
1143 #ifdef NSE
1144         macro->body.macro.imported = false;
1145 #endif
1146 
1147         if ((makefile_type != reading_nothing) &&
1148             macro->body.macro.read_only) {
1149                 return macro;
1150         }
1151         /* Strip spaces from the end of the value */
1152         if (daemon == no_daemon) {
1153                 if(value != NULL) {
1154                         wcb.init(value);
1155                         length = wcb.length();
1156                         val_string = wcb.get_string();
1157                 }
1158                 if ((length > 0) && iswspace(val_string[length-1])) {
1159                         INIT_STRING_FROM_STACK(destination, buffer);
1160                         buffer[0] = 0;
1161                         append_string(val_string, &destination, length);
1162                         if (strip_trailing_spaces) {
1163                                 while ((length > 0) &&
1164                                        iswspace(destination.buffer.start[length-1])) {
1165                                         destination.buffer.start[--length] = 0;
1166                                 }
1167                         }
1168                         value = GETNAME(destination.buffer.start, FIND_LENGTH);
1169                 }
1170         }
1171                 
1172         if(macro_apx != NULL) {
1173                 val = macro_apx->body.macro_appendix.value;
1174         } else {
1175                 val = macro->body.macro.value;
1176         }
1177 
1178         if (append) {
1179                 /*
1180                  * If we are appending, we just tack the new value after
1181                  * the old one with a space in between.
1182                  */
1183                 INIT_STRING_FROM_STACK(destination, buffer);
1184                 buffer[0] = 0;
1185                 if ((macro != NULL) && (val != NULL)) {
1186                         APPEND_NAME(val,
1187                                       &destination,
1188                                       (int) val->hash.length);
1189                         if (value != NULL) {
1190                                 wcb.init(value);
1191                                 if(wcb.length() > 0) {
1192                                         MBTOWC(wcs_buffer, " ");
1193                                         append_char(wcs_buffer[0], &destination);
1194                                 }
1195                         }
1196                 }
1197                 if (value != NULL) {
1198                         APPEND_NAME(value,
1199                                       &destination,
1200                                       (int) value->hash.length);
1201                 }
1202                 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1203                 wcb.init(value);
1204                 if (destination.free_after_use) {
1205                         retmem(destination.buffer.start);
1206                 }
1207         }
1208 
1209         /* Debugging trace */
1210         if (debug_level > 1) {
1211                 if (value != NULL) {
1212                         switch (daemon) {
1213                         case chain_daemon:
1214                                 (void) printf("%s =", name->string_mb);
1215                                 for (chain = (Chain) value;
1216                                      chain != NULL;
1217                                      chain = chain->next) {
1218                                         (void) printf(" %s", chain->name->string_mb);
1219                                 }
1220                                 (void) printf("\n");
1221                                 break;
1222                         case no_daemon:
1223                                 (void) printf("%s= %s\n",
1224                                               name->string_mb,
1225                                               value->string_mb);
1226                                 break;
1227                         }
1228                 } else {
1229                         (void) printf("%s =\n", name->string_mb);
1230                 }
1231         }
1232         /* Set the new values in the macro property block */
1233 /**/
1234         if(macro_apx != NULL) {
1235                 macro_apx->body.macro_appendix.value = value;
1236                 INIT_STRING_FROM_STACK(destination, buffer);
1237                 buffer[0] = 0;
1238                 if (value != NULL) {
1239                         APPEND_NAME(value,
1240                                       &destination,
1241                                       (int) value->hash.length);
1242                         if (macro_apx->body.macro_appendix.value_to_append != NULL) {
1243                                 MBTOWC(wcs_buffer, " ");
1244                                 append_char(wcs_buffer[0], &destination);
1245                         }
1246                 }
1247                 if (macro_apx->body.macro_appendix.value_to_append != NULL) {
1248                         APPEND_NAME(macro_apx->body.macro_appendix.value_to_append,
1249                                       &destination,
1250                                       (int) macro_apx->body.macro_appendix.value_to_append->hash.length);
1251                 }
1252                 value = GETNAME(destination.buffer.start, FIND_LENGTH);
1253                 if (destination.free_after_use) {
1254                         retmem(destination.buffer.start);
1255                 }
1256         }
1257 /**/
1258         macro->body.macro.value = value;
1259         macro->body.macro.daemon = daemon;
1260         /*
1261          * If the user changes the VIRTUAL_ROOT, we need to flush
1262          * the vroot package cache.
1263          */
1264         if (name == path_name) {
1265                 flush_path_cache();
1266         }
1267         if (name == virtual_root) {
1268                 flush_vroot_cache();
1269         }
1270         /* If this sets the VPATH we remember that */
1271         if ((name == vpath_name) &&
1272             (value != NULL) &&
1273             (value->hash.length > 0)) {
1274                 vpath_defined = true;
1275         }
1276         /*
1277          * For environment variables we also set the
1278          * environment value each time.
1279          */
1280         if (macro->body.macro.exported) {
1281                 static char     *env;
1282 
1283 #ifdef DISTRIBUTED
1284                 if (!reading_environment && (value != NULL)) {
1285 #else
1286                 if (!reading_environment && (value != NULL) && value->dollar) {
1287 #endif
1288                         Envvar  p;
1289 
1290                         for (p = envvar; p != NULL; p = p->next) {
1291                                 if (p->name == name) {
1292                                         p->value = value;
1293                                         p->already_put = false;
1294                                         goto found_it;
1295                                 }
1296                         }
1297                         p = ALLOC(Envvar);
1298                         p->name = name;
1299                         p->value = value;
1300                         p->next = envvar;
1301                         p->env_string = NULL;
1302                         p->already_put = false;
1303                         envvar = p;
1304 found_it:;
1305 #ifdef DISTRIBUTED
1306                 }
1307                 if (reading_environment || (value == NULL) || !value->dollar) {
1308 #else
1309                 } else {
1310 #endif
1311                         length = 2 + strlen(name->string_mb);
1312                         if (value != NULL) {
1313                                 length += strlen(value->string_mb);
1314                         }
1315                         Property env_prop = maybe_append_prop(name, env_mem_prop);
1316                         /*
1317                          * We use a permanent buffer to reset SUNPRO_DEPENDENCIES value.
1318                          */
1319                         if (!strncmp(name->string_mb, NOCATGETS("SUNPRO_DEPENDENCIES"), 19)) {
1320                                 if (length >= sunpro_dependencies_buf_size) {
1321                                         sunpro_dependencies_buf_size=length*2;
1322                                         if (sunpro_dependencies_buf_size < 4096)
1323                                                 sunpro_dependencies_buf_size = 4096; // Default minimum size
1324                                         if (sunpro_dependencies_buf)
1325                                                 sunpro_dependencies_oldbuf = sunpro_dependencies_buf;
1326                                         sunpro_dependencies_buf=getmem(sunpro_dependencies_buf_size);
1327                                 }
1328                                 env = sunpro_dependencies_buf;
1329                         } else {
1330                                 env = getmem(length);
1331                         }
1332                         env_alloc_num++;
1333                         env_alloc_bytes += length;
1334                         (void) sprintf(env,
1335                                        "%s=%s",
1336                                        name->string_mb,
1337                                        value == NULL ?
1338                                          "" : value->string_mb);
1339                         (void) putenv(env);
1340                         env_prop->body.env_mem.value = env;
1341                         if (sunpro_dependencies_oldbuf) {
1342                                 /* Return old buffer */
1343                                 retmem_mb(sunpro_dependencies_oldbuf);
1344                                 sunpro_dependencies_oldbuf = NULL;
1345                         }
1346                 }
1347         }
1348         if (name == target_arch) {
1349                 Name            ha = getvar(host_arch);
1350                 Name            ta = getvar(target_arch);
1351                 Name            vr = getvar(virtual_root);
1352                 int             length;
1353                 wchar_t         *new_value;
1354                 wchar_t         *old_vr;
1355                 Boolean         new_value_allocated = false;
1356 
1357                 Wstring         ha_str(ha);
1358                 Wstring         ta_str(ta);
1359                 Wstring         vr_str(vr);
1360 
1361                 wchar_t * wcb_ha = ha_str.get_string();
1362                 wchar_t * wcb_ta = ta_str.get_string();
1363                 wchar_t * wcb_vr = vr_str.get_string();
1364 
1365                 length = 32 +
1366                   wslen(wcb_ha) +
1367                     wslen(wcb_ta) +
1368                       wslen(wcb_vr);
1369                 old_vr = wcb_vr;
1370                 MBSTOWCS(wcs_buffer, NOCATGETS("/usr/arch/"));
1371                 if (IS_WEQUALN(old_vr,
1372                                wcs_buffer,
1373                                wslen(wcs_buffer))) {
1374                         old_vr = (wchar_t *) wschr(old_vr, (int) colon_char) + 1;
1375                 }
1376                 if ( (ha == ta) || (wslen(wcb_ta) == 0) ) {
1377                         new_value = old_vr;
1378                 } else {
1379                         new_value = ALLOC_WC(length);
1380                         new_value_allocated = true;
1381                         WCSTOMBS(mbs_buffer, old_vr);
1382 #if !defined(linux)
1383                         (void) wsprintf(new_value,
1384                                         NOCATGETS("/usr/arch/%s/%s:%s"),
1385                                         ha->string_mb + 1,
1386                                         ta->string_mb + 1,
1387                                         mbs_buffer);
1388 #else
1389                         char * mbs_new_value = (char *)getmem(length);
1390                         (void) sprintf(mbs_new_value,
1391                                         NOCATGETS("/usr/arch/%s/%s:%s"),
1392                                         ha->string_mb + 1,
1393                                         ta->string_mb + 1,
1394                                         mbs_buffer);
1395                         MBSTOWCS(new_value, mbs_new_value);
1396                         retmem_mb(mbs_new_value);
1397 #endif
1398                 }
1399                 if (new_value[0] != 0) {
1400                         (void) setvar_daemon(virtual_root,
1401                                              GETNAME(new_value, FIND_LENGTH),
1402                                              false,
1403                                              no_daemon,
1404                                              true,
1405                                              debug_level);
1406                 }
1407                 if (new_value_allocated) {
1408                         retmem(new_value);
1409                 }
1410         }
1411         return macro;
1412 }