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