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