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 2005 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      read.c
  28  *
  29  *      This file contains the makefile reader.
  30  */
  31 
  32 /*
  33  * Included files
  34  */
  35 #include <mk/defs.h>
  36 #include <mksh/dosys.h>           /* sh_command2string() */
  37 #include <mksh/macro.h>           /* expand_value() */
  38 #include <mksh/misc.h>            /* retmem() */
  39 #include <stdarg.h>               /* va_list, va_start(), va_end() */
  40 
  41 /*
  42  * Defined macros
  43  */
  44 
  45 /*
  46  * typedefs & structs
  47  */
  48 
  49 /*
  50  * Static variables
  51  */
  52 static  Boolean         built_last_make_run_seen;
  53 
  54 /*
  55  * File table of contents
  56  */
  57 static  Name_vector     enter_member_name(register wchar_t *lib_start, register wchar_t *member_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names);
  58 extern  Name            normalize_name(register wchar_t *name_string, register int length);
  59 static  void            read_suffixes_list(register Name_vector depes);
  60 static  void            make_relative(wchar_t *to, wchar_t *result);
  61 static  void            print_rule(register Cmd_line command);
  62 static  void            sh_transform(Name *name, Name *value);
  63 
  64 
  65 /*
  66  *      enter_name(string, tail_present, string_start, string_end,
  67  *            current_names, extra_names, target_group_seen)
  68  *
  69  *      Take one string and enter it as a name. The string is passed in
  70  *      two parts. A make string and possibly a C string to append to it.
  71  *      The result is stuffed in the vector current_names.
  72  *      extra_names points to a vector that is used if current_names overflows.
  73  *      This is allocad in the calling routine.
  74  *      Here we handle the "lib.a[members]" notation.
  75  *
  76  *      Return value:
  77  *                              The name vector that was used
  78  *
  79  *      Parameters:
  80  *              tail_present    Indicates if both C and make string was passed
  81  *              string_start    C string
  82  *              string_end      Pointer to char after last in C string
  83  *              string          make style string with head of name
  84  *              current_names   Vector to deposit the name in
  85  *              extra_names     Where to get next name vector if we run out
  86  *              target_group_seen Pointer to boolean that is set if "+" is seen
  87  *
  88  *      Global variables used:
  89  *              makefile_type   When we read a report file we normalize paths
  90  *              plus            Points to the Name "+"
  91  */
  92 
  93 Name_vector
  94 enter_name(String string, Boolean tail_present, register wchar_t *string_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names, Boolean *target_group_seen)
  95 {
  96         Name                    name;
  97         register wchar_t        *cp;
  98         wchar_t                 ch;
  99 
 100         /* If we were passed a separate tail of the name we append it to the */
 101         /* make string with the rest of it */
 102         if (tail_present) {
 103                 append_string(string_start, string, string_end - string_start);
 104                 string_start = string->buffer.start;
 105                 string_end = string->text.p;
 106         }
 107         ch = *string_end;
 108         *string_end = (int) nul_char;
 109         /*
 110          * Check if there are any ( or [ that are not prefixed with $.
 111          * If there are, we have to deal with the lib.a(members) format.
 112          */
 113         for (cp = (wchar_t *) wschr(string_start, (int) parenleft_char);
 114              cp != NULL;
 115              cp = (wchar_t *) wschr(cp + 1, (int) parenleft_char)) {
 116                 if (*(cp - 1) != (int) dollar_char) {
 117                         *string_end = ch;
 118                         return enter_member_name(string_start,
 119                                                  cp,
 120                                                  string_end,
 121                                                  current_names,
 122                                                  extra_names);
 123                 }
 124         }
 125         *string_end = ch;
 126 
 127         if (makefile_type == reading_cpp_file) {
 128                 /* Remove extra ../ constructs if we are reading from a report file */
 129                 name = normalize_name(string_start, string_end - string_start);
 130         } else {
 131                 /*
 132                  * /tolik, fix bug 1197477/
 133                  * Normalize every target name before entering.
 134                  * ..//obj/a.o and ../obj//a.o are not two different targets.
 135                  * There is only one target ../obj/a.o
 136                  */
 137                 /*name = GETNAME(string_start, string_end - string_start);*/
 138                 name = normalize_name(string_start, string_end - string_start);
 139         }
 140 
 141         /* Internalize the name. Detect the name "+" (target group here) */
 142 if(current_names->used != 0 && current_names->names[current_names->used-1] == plus) {
 143         if(name == plus) {
 144                 return current_names;
 145         }
 146 }
 147         /* If the current_names vector is full we patch in the one from */
 148         /* extra_names */
 149         if (current_names->used == VSIZEOF(current_names->names)) {
 150                 if (current_names->next != NULL) {
 151                         current_names = current_names->next;
 152                 } else {
 153                         current_names->next = *extra_names;
 154                         *extra_names = NULL;
 155                         current_names = current_names->next;
 156                         current_names->used = 0;
 157                         current_names->next = NULL;
 158                 }
 159         }
 160         current_names->target_group[current_names->used] = NULL;
 161         current_names->names[current_names->used++] = name;
 162         if (name == plus) {
 163                 *target_group_seen = true;
 164         }
 165         if (tail_present && string->free_after_use) {
 166                 retmem(string->buffer.start);
 167         }
 168         return current_names;
 169 }
 170 
 171 /*
 172  *      enter_member_name(lib_start, member_start, string_end,
 173  *                current_names, extra_names)
 174  *
 175  *      A string has been found to contain member names.
 176  *      (The "lib.a[members]" and "lib.a(members)" notation)
 177  *      Handle it pretty much as enter_name() does for simple names.
 178  *
 179  *      Return value:
 180  *                              The name vector that was used
 181  *
 182  *      Parameters:
 183  *              lib_start       Points to the of start of "lib.a(member.o)"
 184  *              member_start    Points to "member.o" from above string.
 185  *              string_end      Points to char after last of above string.
 186  *              current_names   Vector to deposit the name in
 187  *              extra_names     Where to get next name vector if we run out
 188  *
 189  *      Global variables used:
 190  */
 191 static Name_vector
 192 enter_member_name(register wchar_t *lib_start, register wchar_t *member_start, register wchar_t *string_end, Name_vector current_names, Name_vector *extra_names)
 193 {
 194         register Boolean        entry = false;
 195         wchar_t                 buffer[STRING_BUFFER_LENGTH];
 196         Name                    lib;
 197         Name                    member;
 198         Name                    name;
 199         Property                prop;
 200         wchar_t                 *memberp;
 201         wchar_t                 *q;
 202         register int            paren_count;
 203         register Boolean        has_dollar;
 204         register wchar_t        *cq;
 205         Name                    long_member_name = NULL;
 206 
 207         /* Internalize the name of the library */
 208         lib = GETNAME(lib_start, member_start - lib_start);
 209         lib->is_member = true;
 210         member_start++;
 211         if (*member_start == (int) parenleft_char) {
 212                 /* This is really the "lib.a((entries))" format */
 213                 entry = true;
 214                 member_start++;
 215         }
 216         /* Move the library name to the buffer where we intend to build the */
 217         /* "lib.a(member)" for each member */
 218         (void) wsncpy(buffer, lib_start, member_start - lib_start);
 219         memberp = buffer + (member_start-lib_start);
 220         while (1) {
 221                 long_member_name = NULL;
 222                 /* Skip leading spaces */
 223                 for (;
 224                      (member_start < string_end) && iswspace(*member_start);
 225                      member_start++);
 226                 /* Find the end of the member name. Allow nested (). Detect $*/
 227                 for (cq = memberp, has_dollar = false, paren_count = 0;
 228                      (member_start < string_end) &&
 229                      ((*member_start != (int) parenright_char) ||
 230                       (paren_count > 0)) &&
 231                      !iswspace(*member_start);
 232                      *cq++ = *member_start++) {
 233                         switch (*member_start) {
 234                         case parenleft_char:
 235                                 paren_count++;
 236                                 break;
 237                         case parenright_char:
 238                                 paren_count--;
 239                                 break;
 240                         case dollar_char:
 241                                 has_dollar = true;
 242                         }
 243                 }
 244                 /* Internalize the member name */
 245                 member = GETNAME(memberp, cq - memberp);
 246                 *cq = 0;
 247                 if ((q = (wchar_t *) wsrchr(memberp, (int) slash_char)) == NULL) {
 248                         q = memberp;
 249                 }
 250                 if ((cq - q > (int) ar_member_name_len) &&
 251                     !has_dollar) {
 252                         *cq++ = (int) parenright_char;
 253                         if (entry) {
 254                                 *cq++ = (int) parenright_char;
 255                         }
 256                         long_member_name = GETNAME(buffer, cq - buffer);
 257                         cq = q + (int) ar_member_name_len;
 258                 }
 259                 *cq++ = (int) parenright_char;
 260                 if (entry) {
 261                         *cq++ = (int) parenright_char;
 262                 }
 263                 /* Internalize the "lib.a(member)" notation for this member */
 264                 name = GETNAME(buffer, cq - buffer);
 265                 name->is_member = lib->is_member;
 266                 if (long_member_name != NULL) {
 267                         prop = append_prop(name, long_member_name_prop);
 268                         name->has_long_member_name = true;
 269                         prop->body.long_member_name.member_name =
 270                           long_member_name;
 271                 }
 272                 /* And add the member prop */
 273                 prop = append_prop(name, member_prop);
 274                 prop->body.member.library = lib;
 275                 if (entry) {
 276                         /* "lib.a((entry))" notation */
 277                         prop->body.member.entry = member;
 278                         prop->body.member.member = NULL;
 279                 } else {
 280                         /* "lib.a(member)" Notation */
 281                         prop->body.member.entry = NULL;
 282                         prop->body.member.member = member;
 283                 }
 284                 /* Handle overflow of current_names */
 285                 if (current_names->used == VSIZEOF(current_names->names)) {
 286                         if (current_names->next != NULL) {
 287                                 current_names = current_names->next;
 288                         } else {
 289                                 if (*extra_names == NULL) {
 290                                         current_names =
 291                                           current_names->next =
 292                                             ALLOC(Name_vector);
 293                                 } else {
 294                                         current_names =
 295                                           current_names->next =
 296                                             *extra_names;
 297                                         *extra_names = NULL;
 298                                 }
 299                                 current_names->used = 0;
 300                                 current_names->next = NULL;
 301                         }
 302                 }
 303                 current_names->target_group[current_names->used] = NULL;
 304                 current_names->names[current_names->used++] = name;
 305                 while (iswspace(*member_start)) {
 306                         member_start++;
 307                 }
 308                 /* Check if there are more members */
 309                 if ((*member_start == (int) parenright_char) ||
 310                     (member_start >= string_end)) {
 311                         return current_names;
 312                 }
 313         }
 314         /* NOTREACHED */
 315 }
 316 
 317 /*
 318  *      normalize_name(name_string, length)
 319  *
 320  *      Take a namestring and remove redundant ../, // and ./ constructs
 321  *
 322  *      Return value:
 323  *                              The normalized name
 324  *
 325  *      Parameters:
 326  *              name_string     Path string to normalize
 327  *              length          Length of that string
 328  *
 329  *      Global variables used:
 330  *              dot             The Name ".", compared against
 331  *              dotdot          The Name "..", compared against
 332  */
 333 Name
 334 normalize_name(register wchar_t *name_string, register int length)
 335 {
 336         static Name             dotdot;
 337         register wchar_t        *string = ALLOC_WC(length + 1);
 338         register wchar_t        *string2;
 339         register wchar_t        *cdp;
 340         wchar_t                 *current_component;
 341         Name                    name;
 342         register int            count;
 343 
 344         if (dotdot == NULL) {
 345                 MBSTOWCS(wcs_buffer, "..");
 346                 dotdot = GETNAME(wcs_buffer, FIND_LENGTH);
 347         }
 348 
 349         /*
 350          * Copy string removing ./ and //.
 351          * First strip leading ./
 352          */
 353         while ((length > 1) &&
 354                (name_string[0] == (int) period_char) &&
 355                (name_string[1] == (int) slash_char)) {
 356                 name_string += 2;
 357                 length -= 2;
 358                 while ((length > 0) && (name_string[0] == (int) slash_char)) {
 359                         name_string++;
 360                         length--;
 361                 }
 362         }
 363         /* Then copy the rest of the string removing /./ & // */
 364         cdp = string;
 365         while (length > 0) {
 366                 if (((length > 2) &&
 367                      (name_string[0] == (int) slash_char) &&
 368                      (name_string[1] == (int) period_char) &&
 369                      (name_string[2] == (int) slash_char)) ||
 370                     ((length == 2) &&
 371                      (name_string[0] == (int) slash_char) &&
 372                      (name_string[1] == (int) period_char))) {
 373                         name_string += 2;
 374                         length -= 2;
 375                         continue;
 376                 }
 377                 if ((length > 1) &&
 378                     (name_string[0] == (int) slash_char) &&
 379                     (name_string[1] == (int) slash_char)) {
 380                         name_string++;
 381                         length--;
 382                         continue;
 383                 }
 384                 *cdp++ = *name_string++;
 385                 length--;
 386         }
 387         *cdp = (int) nul_char;
 388         /*
 389          * Now scan for <name>/../ and remove such combinations iff <name>
 390          * is not another ..
 391          * Each time something is removed, the whole process is restarted.
 392          */
 393 removed_one:
 394         name_string = string;
 395         string2 = name_string;          /*save for free*/
 396         current_component =
 397           cdp =
 398             string =
 399               ALLOC_WC((length = wslen(name_string)) + 1);
 400         while (length > 0) {
 401                 if (((length > 3) &&
 402                      (name_string[0] == (int) slash_char) &&
 403                      (name_string[1] == (int) period_char) &&
 404                      (name_string[2] == (int) period_char) &&
 405                      (name_string[3] == (int) slash_char)) ||
 406                     ((length == 3) &&
 407                      (name_string[0] == (int) slash_char) &&
 408                      (name_string[1] == (int) period_char) &&
 409                      (name_string[2] == (int) period_char))) {
 410                         /* Positioned on the / that starts a /.. sequence */
 411                         if (((count = cdp - current_component) != 0) &&
 412                             (exists(name = GETNAME(string, cdp - string)) > file_doesnt_exist) &&
 413                             (!name->stat.is_sym_link)) {
 414                                 name = GETNAME(current_component, count);
 415                                 if(name != dotdot) {
 416                                         cdp = current_component;
 417                                         name_string += 3;
 418                                         length -= 3;
 419                                         if (length > 0) {
 420                                                 name_string++;  /* skip slash */
 421                                                 length--;
 422                                                 while (length > 0) {
 423                                                         *cdp++ = *name_string++;
 424                                                         length--;
 425                                                 }
 426                                         }
 427                                         *cdp = (int) nul_char;
 428                                         retmem(string2);
 429                                         goto removed_one;
 430                                 }
 431                         }
 432                 }
 433                 if ((*cdp++ = *name_string++) == (int) slash_char) {
 434                         current_component = cdp;
 435                 }
 436                 length--;
 437         }
 438         *cdp = (int) nul_char;
 439         if (string[0] == (int) nul_char) {
 440                 name = dot;
 441         } else {
 442                 name = GETNAME(string, FIND_LENGTH);
 443         }
 444         retmem(string);
 445         retmem(string2);
 446         return name;
 447 }
 448 
 449 /*
 450  *      find_target_groups(target_list)
 451  *
 452  *      If a "+" was seen when the target list was scanned we need to extract
 453  *      the groups. Each target in the name vector that is a member of a
 454  *      group gets a pointer to a chain of all the members stuffed in its
 455  *      target_group vector slot
 456  *
 457  *      Parameters:
 458  *              target_list     The list of targets that contains "+"
 459  *
 460  *      Global variables used:
 461  *              plus            The Name "+", compared against
 462  */
 463 Chain
 464 find_target_groups(register Name_vector target_list, register int i, Boolean reset)
 465 {
 466         static Chain            target_group = NULL;
 467         static Chain            tail_target_group = NULL;
 468         static Name             *next;
 469         static Boolean  clear_target_group = false;
 470 
 471         if (reset) {
 472                 target_group = NULL;
 473                 tail_target_group = NULL;
 474                 clear_target_group = false;
 475         }
 476 
 477         /* Scan the list of targets */
 478         /* If the previous target terminated a group */
 479         /* we flush the pointer to that member chain */
 480         if (clear_target_group) {
 481                 clear_target_group = false;
 482                 target_group = NULL;
 483         }
 484         /* Pick up a pointer to the cell with */
 485         /* the next target */
 486         if (i + 1 != target_list->used) {
 487                 next = &target_list->names[i + 1];
 488         } else {
 489                 next = (target_list->next != NULL) ?
 490                   &target_list->next->names[0] : NULL;
 491         }
 492         /* We have four states here :
 493          *      0:      No target group started and next element is not "+" 
 494          *              This is not interesting.
 495          *      1:      A target group is being built and the next element 
 496          *              is not "+". This terminates the group.
 497          *      2:      No target group started and the next member is "+" 
 498          *              This is the first target in a group.
 499          *      3:      A target group started and the next member is a "+" 
 500          *              The group continues.
 501          */
 502         switch ((target_group ? 1 : 0) +
 503                 (next && (*next == plus) ?
 504                  2 : 0)) {
 505               case 0:   /* Not target_group */
 506                 break;
 507               case 1:   /* Last group member */
 508                 /* We need to keep this pointer so */
 509                 /* we can stuff it for last member */
 510                 clear_target_group = true;
 511                 /* fall into */
 512               case 3:   /* Middle group member */
 513                 /* Add this target to the */
 514                 /* current chain */
 515                 tail_target_group->next = ALLOC(Chain);
 516                 tail_target_group = tail_target_group->next;
 517                 tail_target_group->next = NULL;
 518                 tail_target_group->name = target_list->names[i];
 519                 break;
 520               case 2:   /* First group member */
 521                 /* Start a new chain */
 522                 target_group = tail_target_group = ALLOC(Chain);
 523                 target_group->next = NULL;
 524                 target_group->name = target_list->names[i];
 525                 break;
 526         }
 527         /* Stuff the current chain, if any, in the */
 528         /* targets group slot */
 529         target_list->target_group[i] = target_group;
 530         if ((next != NULL) &&
 531             (*next == plus)) {
 532                 *next = NULL;
 533         }
 534         return (tail_target_group);
 535 }
 536 
 537 /*
 538  *      enter_dependencies(target, target_group, depes, command, separator)
 539  *
 540  *      Take one target and a list of dependencies and process the whole thing.
 541  *      The target might be special in some sense in which case that is handled
 542  *
 543  *      Parameters:
 544  *              target          The target we want to enter
 545  *              target_group    Non-NULL if target is part of a group this time
 546  *              depes           A list of dependencies for the target
 547  *              command         The command the target should be entered with
 548  *              separator       Indicates if this is a ":" or a "::" rule
 549  *
 550  *      Static variables used:
 551  *              built_last_make_run_seen If the previous target was
 552  *                                      .BUILT_LAST_MAKE_RUN we say to rewrite
 553  *                                      the state file later on
 554  *
 555  *      Global variables used:
 556  *              command_changed Set to indicate if .make.state needs rewriting
 557  *              default_target_to_build Set to the target if reading makefile
 558  *                                      and this is the first regular target
 559  *              force           The Name " FORCE", used with "::" targets
 560  *              makefile_type   We do different things for makefile vs. report
 561  *              not_auto        The Name ".NOT_AUTO", compared against
 562  *              recursive_name  The Name ".RECURSIVE", compared against
 563  *              temp_file_number Used to figure out when to clear stale
 564  *                                      automatic dependencies
 565  *              trace_reader    Indicates that we should echo stuff we read
 566  */
 567 void
 568 enter_dependencies(register Name target, Chain target_group, register Name_vector depes, register Cmd_line command, register Separator separator)
 569 {
 570         register int            i;
 571         register Property       line;
 572         Name                    name;
 573         Name                    directory;
 574         wchar_t                 *namep;
 575         char                    *mb_namep;
 576         Dependency              dp;
 577         Dependency              *dpp;
 578         Property                line2;
 579         wchar_t                 relative[MAXPATHLEN];
 580         register int            recursive_state;
 581         Boolean                 register_as_auto;
 582         Boolean                 not_auto_found;
 583         char                    *slash;
 584         Wstring                 depstr;
 585 
 586         /* Check if this is a .RECURSIVE line */
 587         if ((depes->used >= 3) &&
 588             (depes->names[0] == recursive_name)) {
 589 #ifdef NSE
 590                 nse_did_recursion= true;
 591 #endif
 592                 target->has_recursive_dependency = true;
 593                 depes->names[0] = NULL;
 594                 recursive_state = 0;
 595                 dp = NULL;
 596                 dpp = &dp;
 597                 /* Read the dependencies. They are "<directory> <target-made>*/
 598                 /* <makefile>*" */
 599                 for (; depes != NULL; depes = depes->next) {
 600                         for (i = 0; i < depes->used; i++) {
 601                                 if (depes->names[i] != NULL) {
 602                                         switch (recursive_state++) {
 603                                         case 0: /* Directory */
 604                                         {
 605                                                 depstr.init(depes->names[i]);
 606                                                 make_relative(depstr.get_string(),
 607                                                               relative);
 608                                                 directory =
 609                                                   GETNAME(relative,
 610                                                           FIND_LENGTH);
 611                                         }
 612                                                 break;
 613                                         case 1: /* Target */
 614                                                 name = depes->names[i];
 615                                                 break;
 616                                         default:        /* Makefiles */
 617                                                 *dpp = ALLOC(Dependency);
 618                                                 (*dpp)->next = NULL;
 619                                                 (*dpp)->name = depes->names[i];
 620                                                 (*dpp)->automatic = false;
 621                                                 (*dpp)->stale = false;
 622                                                 (*dpp)->built = false;
 623                                                 dpp = &((*dpp)->next);
 624                                                 break;
 625                                         }
 626                                 }
 627                         }
 628                 }
 629                 /* Check if this recursion already has been reported else */
 630                 /* enter the recursive prop for the target */
 631                 /* The has_built flag is used to tell if this .RECURSIVE */
 632                 /* was discovered from this run (read from a tmp file) */
 633                 /* or was from discovered from the original .make.state */
 634                 /* file */
 635                 for (line = get_prop(target->prop, recursive_prop);
 636                      line != NULL;
 637                      line = get_prop(line->next, recursive_prop)) {
 638                         if ((line->body.recursive.directory == directory) &&
 639                             (line->body.recursive.target == name)) {
 640                                 line->body.recursive.makefiles = dp;
 641                                 line->body.recursive.has_built = 
 642                                   (Boolean)
 643                                     (makefile_type == reading_cpp_file);
 644                                 return;
 645                         }
 646                 }
 647                 line2 = append_prop(target, recursive_prop);
 648                 line2->body.recursive.directory = directory;
 649                 line2->body.recursive.target = name;
 650                 line2->body.recursive.makefiles = dp;
 651                 line2->body.recursive.has_built = 
 652                     (Boolean) (makefile_type == reading_cpp_file);
 653                 line2->body.recursive.in_depinfo = false;
 654                 return;
 655         }
 656         /* If this is the first target that doesnt start with a "." in the */
 657         /* makefile we remember that */
 658         Wstring tstr(target);
 659         wchar_t * wcb = tstr.get_string();
 660         if ((makefile_type == reading_makefile) &&
 661             (default_target_to_build == NULL) &&
 662             ((wcb[0] != (int) period_char) ||
 663              wschr(wcb, (int) slash_char))) {
 664 
 665 /* BID 1181577: $(EMPTY_MACRO) + $(EMPTY_MACRO):
 666 ** The target with empty name cannot be default_target_to_build
 667 */
 668                 if (target->hash.length != 0)
 669                         default_target_to_build = target;
 670         }
 671         /* Check if the line is ":" or "::" */
 672         if (makefile_type == reading_makefile) {
 673                 if (target->colons == no_colon) {
 674                         target->colons = separator;
 675                 } else {
 676                         if (target->colons != separator) {
 677                                 fatal_reader(catgets(catd, 1, 92, ":/:: conflict for target `%s'"),
 678                                              target->string_mb);
 679                         }
 680                 }
 681                 if (target->colons == two_colon) {
 682                         if (depes->used == 0) {
 683                                 /* If this is a "::" type line with no */
 684                                 /* dependencies we add one "FRC" type */
 685                                 /* dependency for free */
 686                                 depes->used = 1; /* Force :: targets with no
 687                                                   * depes to always run */
 688                                 depes->names[0] = force;
 689                         }
 690                         /* Do not delete "::" type targets when interrupted */
 691                         target->stat.is_precious = true;
 692                         /*
 693                          * Build a synthetic target "<number>%target"
 694                          * for "target".
 695                          */
 696                         mb_namep = getmem((int) (strlen(target->string_mb) + 10));
 697                         namep = ALLOC_WC((int) (target->hash.length + 10));
 698                         slash = strrchr(target->string_mb, (int) slash_char);
 699                         if (slash == NULL) {
 700                                 (void) sprintf(mb_namep,
 701                                                 "%d@%s",
 702                                                 target->colon_splits++,
 703                                                 target->string_mb);
 704                         } else {
 705                                 *slash = 0;
 706                                 (void) sprintf(mb_namep,
 707                                                 "%s/%d@%s",
 708                                                 target->string_mb,
 709                                                 target->colon_splits++,
 710                                                 slash + 1);
 711                                 *slash = (int) slash_char;
 712                         }
 713                         MBSTOWCS(namep, mb_namep);
 714                         retmem_mb(mb_namep);
 715                         name = GETNAME(namep, FIND_LENGTH);
 716                         retmem(namep);
 717                         if (trace_reader) {
 718                                 (void) printf("%s:\t", target->string_mb);
 719                         }
 720                         /* Make "target" depend on "<number>%target */
 721                         line2 = maybe_append_prop(target, line_prop);
 722                         enter_dependency(line2, name, true);
 723                         line2->body.line.target = target;
 724                         /* Put a prop on "<number>%target that makes */
 725                         /* appear as "target" */
 726                         /* when it is processed */
 727                         maybe_append_prop(name, target_prop)->
 728                           body.target.target = target;
 729                         target->is_double_colon_parent = true;
 730                         name->is_double_colon = true;
 731                         name->has_target_prop = true;
 732                         if (trace_reader) {
 733                                 (void) printf("\n");
 734                         }
 735                         (target = name)->stat.is_file = true;
 736                 }
 737         }
 738         /* This really is a regular dependency line. Just enter it */
 739         line = maybe_append_prop(target, line_prop);
 740         line->body.line.target = target;
 741         /* Depending on what kind of makefile we are reading we have to */
 742         /* treat things differently */
 743         switch (makefile_type) {
 744         case reading_makefile:
 745                 /* Reading regular makefile. Just notice whether this */
 746                 /* redefines the rule for the  target */
 747                 if (command != NULL) {
 748                         if (line->body.line.command_template != NULL) {
 749                                 line->body.line.command_template_redefined =
 750                                   true;
 751                                 if ((wcb[0] == (int) period_char) &&
 752                                     !wschr(wcb, (int) slash_char)) {
 753                                         line->body.line.command_template =
 754                                           command;
 755                                 }
 756                         } else {
 757                                 line->body.line.command_template = command;
 758                         }
 759                 } else {
 760                         if ((wcb[0] == (int) period_char) &&
 761                             !wschr(wcb, (int) slash_char)) {
 762                                 line->body.line.command_template = command;
 763                         }
 764                 }
 765                 break;
 766         case rereading_statefile:
 767                 /* Rereading the statefile. We only enter thing that changed */
 768                 /* since the previous time we read it */
 769                 if (!built_last_make_run_seen) {
 770                         for (Cmd_line next, cmd = command; cmd != NULL; cmd = next) {
 771                                 next = cmd->next;
 772                                 free(cmd);
 773                         }
 774                         return;
 775                 }
 776                 built_last_make_run_seen = false;
 777                 command_changed = true;
 778                 target->ran_command = true;
 779         case reading_statefile:
 780                 /* Reading the statefile for the first time. Enter the rules */
 781                 /* as "Commands used" not "templates to use" */
 782                 if (command != NULL) {
 783                         for (Cmd_line next, cmd = line->body.line.command_used;
 784                              cmd != NULL; cmd = next) {
 785                                 next = cmd->next;
 786                                 free(cmd);
 787                         }
 788                         line->body.line.command_used = command;
 789                 }
 790         case reading_cpp_file:
 791                 /* Reading report file from programs that reports */
 792                 /* dependencies. If this is the first time the target is */
 793                 /* read from this reportfile we clear all old */
 794                 /* automatic depes */
 795                 if (target->temp_file_number == temp_file_number) {
 796                         break;
 797                 }
 798                 target->temp_file_number = temp_file_number;
 799                 command_changed = true;
 800                 if (line != NULL) {
 801                         for (dp = line->body.line.dependencies;
 802                              dp != NULL;
 803                              dp = dp->next) {
 804                                 if (dp->automatic) {
 805                                         dp->stale = true;
 806                                 }
 807                         }
 808                 }
 809                 break;
 810         default:
 811                 fatal_reader(catgets(catd, 1, 93, "Internal error. Unknown makefile type %d"),
 812                              makefile_type);
 813         }
 814         /* A target may only be involved in one target group */
 815         if (line->body.line.target_group != NULL) {
 816                 if (target_group != NULL) {
 817                         fatal_reader(catgets(catd, 1, 94, "Too many target groups for target `%s'"),
 818                                      target->string_mb);
 819                 }
 820         } else {
 821                 line->body.line.target_group = target_group;
 822         }
 823 
 824         if (trace_reader) {
 825                 (void) printf("%s:\t", target->string_mb);
 826         }
 827         /* Enter the dependencies */
 828         register_as_auto = BOOLEAN(makefile_type != reading_makefile);
 829         not_auto_found = false;
 830         for (;
 831              (depes != NULL) && !not_auto_found;
 832              depes = depes->next) {
 833                 for (i = 0; i < depes->used; i++) {
 834                         /* the dependency .NOT_AUTO signals beginning of
 835                          * explicit dependancies which were put at end of
 836                          * list in .make.state file - we stop entering
 837                          * dependencies at this point
 838                          */
 839                         if (depes->names[i] == not_auto) {
 840                                 not_auto_found = true;
 841                                 break;
 842                         }
 843                         enter_dependency(line,
 844                                          depes->names[i],
 845                                          register_as_auto);
 846                 }
 847         }
 848         if (trace_reader) {
 849                 (void) printf("\n");
 850                 print_rule(command);
 851         }
 852 }
 853 
 854 /*
 855  *      enter_dependency(line, depe, automatic)
 856  *
 857  *      Enter one dependency. Do not enter duplicates.
 858  *
 859  *      Parameters:
 860  *              line            The line block that the dependeny is
 861  *                              entered for
 862  *              depe            The dependency to enter
 863  *              automatic       Used to set the field "automatic"
 864  *
 865  *      Global variables used:
 866  *              makefile_type   We do different things for makefile vs. report
 867  *              trace_reader    Indicates that we should echo stuff we read
 868  *              wait_name       The Name ".WAIT", compared against
 869  */
 870 void
 871 enter_dependency(Property line, register Name depe, Boolean automatic)
 872 {
 873         register Dependency     dp;
 874         register Dependency     *insert;
 875 
 876         if (trace_reader) {
 877                 (void) printf("%s ", depe->string_mb);
 878         }
 879         /* Find the end of the list and check for duplicates */
 880         for (insert = &line->body.line.dependencies, dp = *insert;
 881              dp != NULL;
 882              insert = &dp->next, dp = *insert) {
 883                 if ((dp->name == depe) && (depe != wait_name)) {
 884                         if (dp->automatic) {
 885                                 dp->automatic = automatic;
 886                                 if (automatic) {
 887                                         dp->built = false;
 888                                         depe->stat.is_file = true;
 889 #ifdef NSE
 890                                         depe->has_parent= true;
 891                                         depe->is_target= true;
 892 #endif
 893                                 }
 894                         }
 895                         dp->stale = false;
 896                         return;
 897                 }
 898         }
 899         /* Insert the new dependency since we couldnt find it */
 900         dp = *insert = ALLOC(Dependency);
 901         dp->name = depe;
 902         dp->next = NULL;
 903         dp->automatic = automatic;
 904         dp->stale = false;
 905         dp->built = false;
 906         depe->stat.is_file = true;
 907 #ifdef NSE
 908         depe->has_parent= true;
 909         depe->is_target= true;
 910 #endif
 911 
 912         if ((makefile_type == reading_makefile) &&
 913             (line != NULL) &&
 914             (line->body.line.target != NULL)) {
 915                 line->body.line.target->has_regular_dependency = true;
 916 #ifdef NSE
 917                 line->body.line.target->is_target= true;
 918 #endif
 919         }
 920 }
 921 
 922 /*
 923  *      enter_percent(target, depes, command)
 924  *
 925  *      Enter "x%y : a%b" type lines
 926  *      % patterns are stored in four parts head and tail for target and source
 927  *
 928  *      Parameters:
 929  *              target          Left hand side of pattern
 930  *              depes           The dependency list with the rh pattern
 931  *              command         The command for the pattern
 932  *
 933  *      Global variables used:
 934  *              empty_name      The Name "", compared against
 935  *              percent_list    The list of all percent rules, added to
 936  *              trace_reader    Indicates that we should echo stuff we read
 937  */
 938 Percent
 939 enter_percent(register Name target, Chain target_group, register Name_vector depes, Cmd_line command)
 940 {
 941         register Percent        result = ALLOC(Percent);
 942         register Percent        depe;
 943         register Percent        *depe_tail = &result->dependencies;
 944         register Percent        *insert;
 945         register wchar_t        *cp, *cp1;
 946         Name_vector             nvp;
 947         int                     i;
 948         int                     pattern;
 949 
 950         result->next = NULL;
 951         result->patterns = NULL;
 952         result->patterns_total = 0;
 953         result->command_template = command;
 954         result->being_expanded = false;
 955         result->name = target;
 956         result->dependencies = NULL;
 957         result->target_group = target_group;
 958 
 959         /* get patterns count */
 960         Wstring wcb(target);
 961         cp = wcb.get_string();
 962         while (true) {
 963                 cp = (wchar_t *) wschr(cp, (int) percent_char);
 964                 if (cp != NULL) {
 965                         result->patterns_total++;
 966                         cp++;
 967                 } else {
 968                         break;
 969                 }
 970         }
 971         result->patterns_total++;
 972 
 973         /* allocate storage for patterns */
 974         result->patterns = (Name *) getmem(sizeof(Name) * result->patterns_total);
 975 
 976         /* then create patterns */
 977         cp = wcb.get_string();
 978         pattern = 0;
 979         while (true) {
 980                 cp1 = (wchar_t *) wschr(cp, (int) percent_char);
 981                 if (cp1 != NULL) {
 982                         result->patterns[pattern] = GETNAME(cp, cp1 - cp);
 983                         cp = cp1 + 1;
 984                         pattern++;
 985                 } else {
 986                         result->patterns[pattern] = GETNAME(cp, (int) target->hash.length - (cp - wcb.get_string()));
 987                         break;
 988                 }
 989         }
 990 
 991         Wstring wcb1;
 992 
 993         /* build dependencies list */
 994         for (nvp = depes; nvp != NULL; nvp = nvp->next) {
 995                 for (i = 0; i < nvp->used; i++) {
 996                         depe = ALLOC(Percent);
 997                         depe->next = NULL;
 998                         depe->patterns = NULL;
 999                         depe->patterns_total = 0;
1000                         depe->name = nvp->names[i];
1001                         depe->dependencies = NULL;
1002                         depe->command_template = NULL;
1003                         depe->being_expanded = false;
1004                         depe->target_group = NULL;
1005 
1006                         *depe_tail = depe;
1007                         depe_tail = &depe->next;
1008 
1009                         if (depe->name->percent) {
1010                                 /* get patterns count */
1011                                 wcb1.init(depe->name);
1012                                 cp = wcb1.get_string();
1013                                 while (true) {
1014                                         cp = (wchar_t *) wschr(cp, (int) percent_char);
1015                                         if (cp != NULL) {
1016                                                 depe->patterns_total++;
1017                                                 cp++;
1018                                         } else {
1019                                                 break;
1020                                         }
1021                                 }
1022                                 depe->patterns_total++;
1023 
1024                                 /* allocate storage for patterns */
1025                                 depe->patterns = (Name *) getmem(sizeof(Name) * depe->patterns_total);
1026 
1027                                 /* then create patterns */
1028                                 cp = wcb1.get_string();
1029                                 pattern = 0;
1030                                 while (true) {
1031                                         cp1 = (wchar_t *) wschr(cp, (int) percent_char);
1032                                         if (cp1 != NULL) {
1033                                                 depe->patterns[pattern] = GETNAME(cp, cp1 - cp);
1034                                                 cp = cp1 + 1;
1035                                                 pattern++;
1036                                         } else {
1037                                                 depe->patterns[pattern] = GETNAME(cp, (int) depe->name->hash.length - (cp - wcb1.get_string()));
1038                                                 break;
1039                                         }
1040                                 }
1041                         }
1042                 }
1043         }
1044 
1045         /* Find the end of the percent list and append the new pattern */
1046         for (insert = &percent_list; (*insert) != NULL; insert = &(*insert)->next);
1047         *insert = result;
1048 
1049         if (trace_reader) {
1050                 (void) printf("%s:", result->name->string_mb);
1051 
1052                 for (depe = result->dependencies; depe != NULL; depe = depe->next) {
1053                         (void) printf(" %s", depe->name->string_mb);
1054                 }
1055 
1056                 (void) printf("\n");
1057 
1058                 print_rule(command);
1059         }
1060 
1061         return result;
1062 }
1063 
1064 /*
1065  *      enter_dyntarget(target)
1066  *
1067  *      Enter "$$(MACRO) : b" type lines
1068  *
1069  *      Parameters:
1070  *              target          Left hand side of pattern
1071  *
1072  *      Global variables used:
1073  *              dyntarget_list  The list of all percent rules, added to
1074  *              trace_reader    Indicates that we should echo stuff we read
1075  */
1076 Dyntarget
1077 enter_dyntarget(register Name target)
1078 {
1079         register Dyntarget      result = ALLOC(Dyntarget);
1080         Dyntarget               p;
1081         Dyntarget               *insert;
1082         int                             i;
1083 
1084         result->next = NULL;
1085         result->name = target;
1086 
1087 
1088         /* Find the end of the dyntarget list and append the new pattern */
1089         for (insert = &dyntarget_list, p = *insert;
1090              p != NULL;
1091              insert = &p->next, p = *insert);
1092         *insert = result;
1093 
1094         if (trace_reader) {
1095                 (void) printf(NOCATGETS("Dynamic target %s:\n"), result->name->string_mb);
1096         }
1097         return( result);
1098 }
1099 
1100 
1101 /*
1102  *      special_reader(target, depes, command)
1103  *
1104  *      Read the pseudo targets make knows about
1105  *      This handles the special targets that should not be entered as regular
1106  *      target/dependency sets.
1107  *
1108  *      Parameters:
1109  *              target          The special target
1110  *              depes           The list of dependencies it was entered with
1111  *              command         The command it was entered with
1112  *
1113  *      Static variables used:
1114  *              built_last_make_run_seen Set to indicate .BUILT_LAST... seen
1115  *
1116  *      Global variables used:
1117  *              all_parallel    Set to indicate that everything runs parallel
1118  *              svr4            Set when ".SVR4" target is read
1119  *              svr4_name       The Name ".SVR4"
1120  *              posix           Set when ".POSIX" target is read
1121  *              posix_name      The Name ".POSIX"
1122  *              current_make_version The Name "<current version number>"
1123  *              default_rule    Set when ".DEFAULT" target is read
1124  *              default_rule_name The Name ".DEFAULT", used for tracing
1125  *              dot_keep_state  The Name ".KEEP_STATE", used for tracing
1126  *              ignore_errors   Set if ".IGNORE" target is read
1127  *              ignore_name     The Name ".IGNORE", used for tracing
1128  *              keep_state      Set if ".KEEP_STATE" target is read
1129  *              no_parallel_name The Name ".NO_PARALLEL", used for tracing
1130  *              only_parallel   Set to indicate only some targets runs parallel
1131  *              parallel_name   The Name ".PARALLEL", used for tracing
1132  *              precious        The Name ".PRECIOUS", used for tracing
1133  *              sccs_get_name   The Name ".SCCS_GET", used for tracing
1134  *              sccs_get_posix_name The Name ".SCCS_GET_POSIX", used for tracing
1135  *              get_name        The Name ".GET", used for tracing
1136  *              sccs_get_rule   Set when ".SCCS_GET" target is read
1137  *              silent          Set when ".SILENT" target is read
1138  *              silent_name     The Name ".SILENT", used for tracing
1139  *              trace_reader    Indicates that we should echo stuff we read
1140  */
1141 void
1142 special_reader(Name target, register Name_vector depes, Cmd_line command)
1143 {
1144         register int            n;
1145 
1146         switch (target->special_reader) {
1147 
1148         case svr4_special:
1149                 if (depes->used != 0) {
1150                         fatal_reader(catgets(catd, 1, 98, "Illegal dependencies for target `%s'"),
1151                                      target->string_mb);
1152                 }
1153                 svr4  = true;
1154                 posix  = false;
1155                 keep_state = false;
1156                 all_parallel = false;
1157                 only_parallel = false;
1158                 if (trace_reader) {
1159                         (void) printf("%s:\n", svr4_name->string_mb);
1160                 }
1161                 break;
1162 
1163         case posix_special:
1164                 if(svr4)
1165                   break;
1166                 if (depes->used != 0) {
1167                         fatal_reader(catgets(catd, 1, 99, "Illegal dependencies for target `%s'"),
1168                                      target->string_mb);
1169                 }
1170                 posix  = true;
1171                         /* with posix on, use the posix get rule */
1172                 sccs_get_rule = sccs_get_posix_rule;
1173                         /* turn keep state off being SunPro make specific */
1174                 keep_state = false;
1175                 #if defined(SUN5_0)
1176                 /* Use /usr/xpg4/bin/sh on Solaris */
1177                 MBSTOWCS(wcs_buffer, NOCATGETS("/usr/xpg4/bin/sh"));
1178                 (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
1179                 #endif
1180                 if (trace_reader) {
1181                         (void) printf("%s:\n", posix_name->string_mb);
1182                 }
1183                 break;
1184 
1185         case built_last_make_run_special:
1186                 built_last_make_run_seen = true;
1187                 break;
1188 
1189         case default_special:
1190                 if (depes->used != 0) {
1191                         warning(catgets(catd, 1, 100, "Illegal dependency list for target `%s'"),
1192                                 target->string_mb);
1193                 }
1194                 default_rule = command;
1195                 if (trace_reader) {
1196                         (void) printf("%s:\n",
1197                                       default_rule_name->string_mb);
1198                         print_rule(command);
1199                 }
1200                 break;
1201 
1202 #ifdef NSE
1203         case derived_src_special:
1204                 for (; depes != NULL; depes= depes->next)
1205                         for (n= 0; n < depes->used; n++) {
1206                                 if (trace_reader)
1207                                         (void)printf("%s:\t%s\n",
1208                                         precious->string_mb,
1209                                         depes->names[n]->string_mb);
1210                                 depes->names[n]->stat.is_derived_src= true;
1211                         };
1212                 break;
1213 #endif
1214 
1215         case ignore_special:
1216                 if ((depes->used != 0) &&(!posix)){
1217                         fatal_reader(catgets(catd, 1, 101, "Illegal dependencies for target `%s'"),
1218                                      target->string_mb);
1219                 }
1220                 if (depes->used == 0)
1221                 {
1222                    ignore_errors_all = true;
1223                 }
1224                 if(svr4) {
1225                   ignore_errors_all = true;
1226                   break;
1227                 }
1228                 for (; depes != NULL; depes = depes->next) {
1229                         for (n = 0; n < depes->used; n++) {
1230                                 depes->names[n]->ignore_error_mode = true;
1231                         }
1232                 }
1233                 if (trace_reader) {
1234                         (void) printf("%s:\n", ignore_name->string_mb);
1235                 }
1236                 break;
1237 
1238         case keep_state_special:
1239                 if(svr4)
1240                   break;
1241                         /* ignore keep state, being SunPro make specific */
1242                 if(posix)
1243                   break;
1244                 if (depes->used != 0) {
1245                         fatal_reader(catgets(catd, 1, 102, "Illegal dependencies for target `%s'"),
1246                                      target->string_mb);
1247                 }
1248                 keep_state = true;
1249                 if (trace_reader) {
1250                         (void) printf("%s:\n",
1251                                       dot_keep_state->string_mb);
1252                 }
1253                 break;
1254 
1255         case keep_state_file_special:
1256                 if(svr4)
1257                   break;
1258                 if(posix)
1259                   break;
1260                         /* it's not necessary to specify KEEP_STATE, if this 
1261                         ** is given, so set the keep_state.
1262                         */
1263                 keep_state = true;
1264                 if (depes->used != 0) {
1265                    if((!make_state) ||(!strcmp(make_state->string_mb,NOCATGETS(".make.state")))) {
1266                      make_state = depes->names[0];
1267                    }
1268                 }
1269                 break;
1270         case make_version_special:
1271                 if(svr4)
1272                   break;
1273                 if (depes->used != 1) {
1274                         fatal_reader(catgets(catd, 1, 103, "Illegal dependency list for target `%s'"),
1275                                      target->string_mb);
1276                 }
1277                 if (depes->names[0] != current_make_version) {
1278                         /*
1279                          * Special case the fact that version 1.0 and 1.1
1280                          * are identical.
1281                          */
1282                         if (!IS_EQUAL(depes->names[0]->string_mb,
1283                                       NOCATGETS("VERSION-1.1")) ||
1284                             !IS_EQUAL(current_make_version->string_mb,
1285                                       NOCATGETS("VERSION-1.0"))) {
1286                                 /*
1287                                  * Version mismatches should cause the
1288                                  * .make.state file to be skipped.
1289                                  * This is currently not true - it is read
1290                                  * anyway.
1291                                  */
1292                                 warning(catgets(catd, 1, 104, "Version mismatch between current version `%s' and `%s'"),
1293                                         current_make_version->string_mb,
1294                                         depes->names[0]->string_mb);
1295                         }
1296                 }
1297                 break;
1298 
1299         case no_parallel_special:
1300                 if(svr4)
1301                   break;
1302                 /* Set the no_parallel bit for all the targets on */
1303                 /* the dependency list */
1304                 if (depes->used == 0) {
1305                         /* only those explicitly made parallel */
1306                         only_parallel = true;
1307                         all_parallel = false;
1308                 }
1309                 for (; depes != NULL; depes = depes->next) {
1310                         for (n = 0; n < depes->used; n++) {
1311                                 if (trace_reader) {
1312                                         (void) printf("%s:\t%s\n",
1313                                                       no_parallel_name->string_mb,
1314                                                       depes->names[n]->string_mb);
1315                                 }
1316                                 depes->names[n]->no_parallel = true;
1317                                 depes->names[n]->parallel = false;
1318                         }
1319                 }
1320                 break;
1321 
1322         case parallel_special:
1323                 if(svr4)
1324                   break;
1325                 if (depes->used == 0) {
1326                         /* everything runs in parallel */
1327                         all_parallel = true;
1328                         only_parallel = false;
1329                 }
1330                 /* Set the parallel bit for all the targets on */
1331                 /* the dependency list */
1332                 for (; depes != NULL; depes = depes->next) {
1333                         for (n = 0; n < depes->used; n++) {
1334                                 if (trace_reader) {
1335                                         (void) printf("%s:\t%s\n",
1336                                                       parallel_name->string_mb,
1337                                                       depes->names[n]->string_mb);
1338                                 }
1339                                 depes->names[n]->parallel = true;
1340                                 depes->names[n]->no_parallel = false;
1341                         }
1342                 }
1343                 break;
1344 
1345         case localhost_special:
1346                 if(svr4)
1347                   break;
1348                 /* Set the no_parallel bit for all the targets on */
1349                 /* the dependency list */
1350                 if (depes->used == 0) {
1351                         /* only those explicitly made parallel */
1352                         only_parallel = true;
1353                         all_parallel = false;
1354                 }
1355                 for (; depes != NULL; depes = depes->next) {
1356                         for (n = 0; n < depes->used; n++) {
1357                                 if (trace_reader) {
1358                                         (void) printf("%s:\t%s\n",
1359                                                       localhost_name->string_mb,
1360                                                       depes->names[n]->string_mb);
1361                                 }
1362                                 depes->names[n]->no_parallel = true;
1363                                 depes->names[n]->parallel = false;
1364                                 depes->names[n]->localhost = true;
1365                         }
1366                 }
1367                 break;
1368 
1369         case precious_special:
1370                 if (depes->used == 0) {
1371                         /* everything is precious      */
1372                         all_precious = true;
1373                 } else {
1374                         all_precious = false;
1375                 }
1376                 if(svr4) {
1377                   all_precious = true;
1378                   break;
1379                 }
1380                 /* Set the precious bit for all the targets on */
1381                 /* the dependency list */
1382                 for (; depes != NULL; depes = depes->next) {
1383                         for (n = 0; n < depes->used; n++) {
1384                                 if (trace_reader) {
1385                                         (void) printf("%s:\t%s\n",
1386                                                       precious->string_mb,
1387                                                       depes->names[n]->string_mb);
1388                                 }
1389                                 depes->names[n]->stat.is_precious = true;
1390                         }
1391                 }
1392                 break;
1393 
1394         case sccs_get_special:
1395                 if (depes->used != 0) {
1396                         fatal_reader(catgets(catd, 1, 105, "Illegal dependencies for target `%s'"),
1397                                      target->string_mb);
1398                 }
1399                 sccs_get_rule = command;
1400                 sccs_get_org_rule = command;
1401                 if (trace_reader) {
1402                         (void) printf("%s:\n", sccs_get_name->string_mb);
1403                         print_rule(command);
1404                 }
1405                 break;
1406 
1407         case sccs_get_posix_special:
1408                 if (depes->used != 0) {
1409                         fatal_reader(catgets(catd, 1, 106, "Illegal dependencies for target `%s'"),
1410                                      target->string_mb);
1411                 }
1412                 sccs_get_posix_rule = command;
1413                 if (trace_reader) {
1414                         (void) printf("%s:\n", sccs_get_posix_name->string_mb);
1415                         print_rule(command);
1416                 }
1417                 break;
1418 
1419         case get_posix_special:
1420                 if (depes->used != 0) {
1421                         fatal_reader(catgets(catd, 1, 107, "Illegal dependencies for target `%s'"),
1422                                      target->string_mb);
1423                 }
1424                 get_posix_rule = command;
1425                 if (trace_reader) {
1426                         (void) printf("%s:\n", get_posix_name->string_mb);
1427                         print_rule(command);
1428                 }
1429                 break;
1430 
1431         case get_special:
1432                 if(!svr4) {
1433                   break;
1434                 }
1435                 if (depes->used != 0) {
1436                         fatal_reader(catgets(catd, 1, 108, "Illegal dependencies for target `%s'"),
1437                                      target->string_mb);
1438                 }
1439                 get_rule = command;
1440                 sccs_get_rule = command;
1441                 if (trace_reader) {
1442                         (void) printf("%s:\n", get_name->string_mb);
1443                         print_rule(command);
1444                 }
1445                 break;
1446 
1447         case silent_special:
1448                 if ((depes->used != 0) && (!posix)){
1449                         fatal_reader(catgets(catd, 1, 109, "Illegal dependencies for target `%s'"),
1450                                      target->string_mb);
1451                 }
1452                 if (depes->used == 0)
1453                 {
1454                    silent_all = true;
1455                 }
1456                 if(svr4) {
1457                   silent_all = true;
1458                   break;
1459                 }
1460                 for (; depes != NULL; depes = depes->next) {
1461                         for (n = 0; n < depes->used; n++) {
1462                                 depes->names[n]->silent_mode = true;
1463                         }
1464                 }
1465                 if (trace_reader) {
1466                         (void) printf("%s:\n", silent_name->string_mb);
1467                 }
1468                 break;
1469 
1470         case suffixes_special:
1471                 read_suffixes_list(depes);
1472                 break;
1473 
1474         default:
1475 
1476                 fatal_reader(catgets(catd, 1, 110, "Internal error: Unknown special reader"));
1477         }
1478 }
1479 
1480 /*
1481  *      read_suffixes_list(depes)
1482  *
1483  *      Read the special list .SUFFIXES. If it is empty the old list is
1484  *      cleared. Else the new one is appended. Suffixes with ~ are extracted
1485  *      and marked.
1486  *
1487  *      Parameters:
1488  *              depes           The list of suffixes
1489  *
1490  *      Global variables used:
1491  *              hashtab         The central hashtable for Names.
1492  *              suffixes        The list of suffixes, set or appended to
1493  *              suffixes_name   The Name ".SUFFIXES", used for tracing
1494  *              trace_reader    Indicates that we should echo stuff we read
1495  */
1496 static void
1497 read_suffixes_list(register Name_vector depes)
1498 {
1499         register int            n;
1500         register Dependency     dp;
1501         register Dependency     *insert_dep;
1502         register Name           np;
1503         Name                    np2;
1504         register Boolean        first = true;
1505 
1506         if (depes->used == 0) {
1507                 /* .SUFFIXES with no dependency list clears the */
1508                 /* suffixes list */
1509                 for (Name_set::iterator np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
1510                                 np->with_squiggle =
1511                                   np->without_squiggle =
1512                                     false;
1513                 }
1514                 suffixes = NULL;
1515                 if (trace_reader) {
1516                         (void) printf("%s:\n", suffixes_name->string_mb);
1517                 }
1518                 return;
1519         }
1520         Wstring str;
1521         /* Otherwise we append to the list */
1522         for (; depes != NULL; depes = depes->next) {
1523                 for (n = 0; n < depes->used; n++) {
1524                         np = depes->names[n];
1525                         /* Find the end of the list and check if the */
1526                         /* suffix already has been entered */
1527                         for (insert_dep = &suffixes, dp = *insert_dep;
1528                              dp != NULL;
1529                              insert_dep = &dp->next, dp = *insert_dep) {
1530                                 if (dp->name == np) {
1531                                         goto duplicate_suffix;
1532                                 }
1533                         }
1534                         if (trace_reader) {
1535                                 if (first) {
1536                                         (void) printf("%s:\t",
1537                                                       suffixes_name->string_mb);
1538                                         first = false;
1539                                 }
1540                                 (void) printf("%s ", depes->names[n]->string_mb);
1541                         }
1542                 if(!(posix|svr4)) {
1543                         /* If the suffix is suffixed with "~" we */
1544                         /* strip that and mark the suffix nameblock */
1545                         str.init(np);
1546                         wchar_t * wcb = str.get_string();
1547                         if (wcb[np->hash.length - 1] ==
1548                             (int) tilde_char) {
1549                                 np2 = GETNAME(wcb,
1550                                               (int)(np->hash.length - 1));
1551                                 np2->with_squiggle = true;
1552                                 if (np2->without_squiggle) {
1553                                         continue;
1554                                 }
1555                                 np = np2;
1556                         }
1557                 }
1558                         np->without_squiggle = true;
1559                         /* Add the suffix to the list */
1560                         dp = *insert_dep = ALLOC(Dependency);
1561                         insert_dep = &dp->next;
1562                         dp->next = NULL;
1563                         dp->name = np;
1564                         dp->built = false;
1565                 duplicate_suffix:;
1566                 }
1567         }
1568         if (trace_reader) {
1569                 (void) printf("\n");
1570         }
1571 }
1572 
1573 /*
1574  *      make_relative(to, result)
1575  *
1576  *      Given a file name compose a relative path name from it to the
1577  *      current directory.
1578  *
1579  *      Parameters:
1580  *              to              The path we want to make relative
1581  *              result          Where to put the resulting relative path
1582  *
1583  *      Global variables used:
1584  */
1585 static void
1586 make_relative(wchar_t *to, wchar_t *result)
1587 {
1588         wchar_t                 *from;
1589         wchar_t                 *allocated;
1590         wchar_t                 *cp;
1591         wchar_t                 *tocomp;
1592         int                     ncomps;
1593         int                     i;
1594         int                     len;
1595 
1596         /* Check if the path is already relative. */
1597         if (to[0] != (int) slash_char) {
1598                 (void) wscpy(result, to);
1599                 return;
1600         }
1601 
1602         MBSTOWCS(wcs_buffer, get_current_path());
1603         from = allocated = (wchar_t *) wsdup(wcs_buffer);
1604 
1605         /*
1606          * Find the number of components in the from name.
1607          * ncomp = number of slashes + 1.
1608          */
1609         ncomps = 1;
1610         for (cp = from; *cp != (int) nul_char; cp++) {
1611                 if (*cp == (int) slash_char) {
1612                         ncomps++;
1613                 }
1614         }
1615 
1616         /*
1617          * See how many components match to determine how many "..",
1618          * if any, will be needed.
1619          */
1620         result[0] = (int) nul_char;
1621         tocomp = to;
1622         while ((*from != (int) nul_char) && (*from == *to)) {
1623                 if (*from == (int) slash_char) {
1624                         ncomps--;
1625                         tocomp = &to[1];
1626                 }
1627                 from++;
1628                 to++;
1629         }
1630 
1631         /*
1632          * Now for some special cases. Check for exact matches and
1633          * for either name terminating exactly.
1634          */
1635         if (*from == (int) nul_char) {
1636                 if (*to == (int) nul_char) {
1637                         MBSTOWCS(wcs_buffer, ".");
1638                         (void) wscpy(result, wcs_buffer);
1639                         retmem(allocated);
1640                         return;
1641                 }
1642                 if (*to == (int) slash_char) {
1643                         ncomps--;
1644                         tocomp = &to[1];
1645                 }
1646         } else if ((*from == (int) slash_char) && (*to == (int) nul_char)) {
1647                 ncomps--;
1648                 tocomp = to;
1649         }
1650         /* Add on the ".."s. */
1651         for (i = 0; i < ncomps; i++) {
1652                 MBSTOWCS(wcs_buffer, "../");
1653                 (void) wscat(result, wcs_buffer);
1654         }
1655 
1656         /* Add on the remainder of the to name, if any. */
1657         if (*tocomp == (int) nul_char) {
1658                 len = wslen(result);
1659                 result[len - 1] = (int) nul_char;
1660         } else {
1661                 (void) wscat(result, tocomp);
1662         }
1663         retmem(allocated);
1664         return;
1665 }
1666 
1667 /*
1668  *      print_rule(command)
1669  *
1670  *      Used when tracing the reading of rules
1671  *
1672  *      Parameters:
1673  *              command         Command to print
1674  *
1675  *      Global variables used:
1676  */
1677 static void
1678 print_rule(register Cmd_line command)
1679 {
1680         for (; command != NULL; command = command->next) {
1681                 (void) printf("\t%s\n", command->command_line->string_mb);
1682         }
1683 }
1684 
1685 /*
1686  *      enter_conditional(target, name, value, append)
1687  *
1688  *      Enter "target := MACRO= value" constructs
1689  *
1690  *      Parameters:
1691  *              target          The target the macro is for
1692  *              name            The name of the macro
1693  *              value           The value for the macro
1694  *              append          Indicates if the assignment is appending or not
1695  *
1696  *      Global variables used:
1697  *              conditionals    A special Name that stores all conditionals
1698  *                              where the target is a % pattern
1699  *              trace_reader    Indicates that we should echo stuff we read
1700  */
1701 void
1702 enter_conditional(register Name target, Name name, Name value, register Boolean append)
1703 {
1704         register Property       conditional;
1705         static int              sequence;
1706         Name                    orig_target = target;
1707 
1708         if (name == target_arch) {
1709                 enter_conditional(target, virtual_root, virtual_root, false);
1710         }
1711 
1712         if (target->percent) {
1713                 target = conditionals;
1714         }
1715         
1716         if (name->colon) {
1717                 sh_transform(&name, &value);
1718         }
1719 
1720         /* Count how many conditionals we must activate before building the */
1721         /* target */
1722         if (target->percent) {
1723                 target = conditionals;
1724         }
1725 
1726         target->conditional_cnt++;
1727         maybe_append_prop(name, macro_prop)->body.macro.is_conditional = true;
1728         /* Add the property for the target */
1729         conditional = append_prop(target, conditional_prop);
1730         conditional->body.conditional.target = orig_target;
1731         conditional->body.conditional.name = name;
1732         conditional->body.conditional.value = value;
1733         conditional->body.conditional.sequence = sequence++;
1734         conditional->body.conditional.append = append;
1735         if (trace_reader) {
1736                 if (value == NULL) {
1737                         (void) printf("%s := %s %c=\n",
1738                                       target->string_mb,
1739                                       name->string_mb,
1740                                       append ?
1741                                       (int) plus_char : (int) space_char);
1742                 } else {
1743                         (void) printf("%s := %s %c= %s\n",
1744                                       target->string_mb,
1745                                       name->string_mb,
1746                                       append ?
1747                                       (int) plus_char : (int) space_char,
1748                                       value->string_mb);
1749                 }
1750         }
1751 }
1752 
1753 /*
1754  *      enter_equal(name, value, append)
1755  *
1756  *      Enter "MACRO= value" constructs
1757  *
1758  *      Parameters:
1759  *              name            The name of the macro
1760  *              value           The value for the macro
1761  *              append          Indicates if the assignment is appending or not
1762  *
1763  *      Global variables used:
1764  *              trace_reader    Indicates that we should echo stuff we read
1765  */
1766 void
1767 enter_equal(Name name, Name value, register Boolean append)
1768 {
1769         wchar_t         *string;
1770         Name            temp;
1771 
1772         if (name->colon) {
1773                 sh_transform(&name, &value);
1774         }
1775         (void) SETVAR(name, value, append);
1776 
1777         /* if we're setting FC, we want to set F77 to the same value. */
1778         Wstring nms(name);
1779         wchar_t * wcb = nms.get_string();
1780         string = wcb;
1781         if (string[0]=='F' &&
1782             string[1]=='C' &&
1783             string[2]=='\0') {
1784                 MBSTOWCS(wcs_buffer, NOCATGETS("F77"));
1785                 temp = GETNAME(wcs_buffer, FIND_LENGTH);
1786                 (void) SETVAR(temp, value, append);
1787 /*
1788                 fprintf(stderr, catgets(catd, 1, 111, "warning: FC is obsolete, use F77 instead\n"));
1789  */
1790         }
1791 
1792         if (trace_reader) {
1793                 if (value == NULL) {
1794                         (void) printf("%s %c=\n",
1795                                       name->string_mb,
1796                                       append ?
1797                                       (int) plus_char : (int) space_char);
1798                 } else {
1799                         (void) printf("%s %c= %s\n",
1800                                       name->string_mb,
1801                                       append ?
1802                                       (int) plus_char : (int) space_char,
1803                                       value->string_mb);
1804                 }
1805         }
1806 }
1807 
1808 /*
1809  *      sh_transform(name, value)
1810  *
1811  *      Parameters:
1812  *              name    The name of the macro we might transform
1813  *              value   The value to transform
1814  *
1815  */
1816 static void
1817 sh_transform(Name *name, Name *value)
1818 {
1819         /* Check if we need :sh transform */
1820         wchar_t         *colon;
1821         String_rec      command;
1822         String_rec      destination;
1823         wchar_t         buffer[1000];
1824         wchar_t         buffer1[1000];
1825 
1826         static wchar_t  colon_sh[4];
1827         static wchar_t  colon_shell[7];
1828 
1829         if (colon_sh[0] == (int) nul_char) {
1830                 MBSTOWCS(colon_sh, NOCATGETS(":sh"));
1831                 MBSTOWCS(colon_shell, NOCATGETS(":shell"));
1832         }
1833         Wstring nms((*name));
1834         wchar_t * wcb = nms.get_string();
1835 
1836         colon = (wchar_t *) wsrchr(wcb, (int) colon_char);
1837         if ((colon != NULL) && (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell))) {
1838                 INIT_STRING_FROM_STACK(destination, buffer);
1839 
1840                 if(*value == NULL) {
1841                         buffer[0] = 0;
1842                 } else {
1843                         Wstring wcb1((*value));
1844                         if (IS_WEQUAL(colon, colon_shell)) {
1845                                 INIT_STRING_FROM_STACK(command, buffer1);
1846                                 expand_value(*value, &command, false);
1847                         } else {
1848                                 command.text.p = wcb1.get_string() + (*value)->hash.length;
1849                                 command.text.end = command.text.p;
1850                                 command.buffer.start = wcb1.get_string();
1851                                 command.buffer.end = command.text.p;
1852                         }
1853                         sh_command2string(&command, &destination);
1854                 }
1855 
1856                 (*value) = GETNAME(destination.buffer.start, FIND_LENGTH);
1857                 *colon = (int) nul_char;
1858                 (*name) = GETNAME(wcb, FIND_LENGTH);
1859                 *colon = (int) colon_char;
1860         }
1861 }
1862 
1863 /*
1864  *      fatal_reader(format, args...)
1865  *
1866  *      Parameters:
1867  *              format          printf style format string
1868  *              args            arguments to match the format
1869  *
1870  *      Global variables used:
1871  *              file_being_read Name of the makefile being read
1872  *              line_number     Line that is being read
1873  *              report_pwd      Indicates whether current path should be shown
1874  *              temp_file_name  When reading tempfile we report that name
1875  */
1876 /*VARARGS*/
1877 void
1878 fatal_reader(char * pattern, ...)
1879 {
1880         va_list args;
1881         char    message[1000];
1882 
1883         va_start(args, pattern);
1884         if (file_being_read != NULL) {
1885                 WCSTOMBS(mbs_buffer, file_being_read);
1886                 if (line_number != 0) {
1887                         (void) sprintf(message,
1888                                        catgets(catd, 1, 112, "%s, line %d: %s"),
1889                                        mbs_buffer,
1890                                        line_number,
1891                                        pattern);
1892                 } else {
1893                         (void) sprintf(message,
1894                                        "%s: %s",
1895                                        mbs_buffer,
1896                                        pattern);
1897                 }
1898                 pattern = message;
1899         }
1900 
1901         (void) fflush(stdout);
1902 #ifdef DISTRIBUTED
1903         (void) fprintf(stderr, catgets(catd, 1, 113, "dmake: Fatal error in reader: "));
1904 #else
1905         (void) fprintf(stderr, catgets(catd, 1, 238, "make: Fatal error in reader: "));
1906 #endif
1907         (void) vfprintf(stderr, pattern, args);
1908         (void) fprintf(stderr, "\n");
1909         va_end(args);
1910 
1911         if (temp_file_name != NULL) {
1912                 (void) fprintf(stderr,
1913 #ifdef DISTRIBUTED
1914                                catgets(catd, 1, 114, "dmake: Temp-file %s not removed\n"),
1915 #else
1916                                catgets(catd, 1, 239, "make: Temp-file %s not removed\n"),
1917 #endif
1918                                temp_file_name->string_mb);
1919                 temp_file_name = NULL;
1920         }
1921 
1922         if (report_pwd) {
1923                 (void) fprintf(stderr,
1924                                catgets(catd, 1, 115, "Current working directory %s\n"),
1925                                get_current_path());
1926         }
1927         (void) fflush(stderr);
1928 #if defined(SUN5_0) || defined(HP_UX)
1929         exit_status = 1;
1930 #endif
1931         exit(1);
1932 }
1933