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                 /* Use /usr/xpg4/bin/sh on Solaris */
1176                 MBSTOWCS(wcs_buffer, NOCATGETS("/usr/xpg4/bin/sh"));
1177                 (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
1178                 if (trace_reader) {
1179                         (void) printf("%s:\n", posix_name->string_mb);
1180                 }
1181                 break;
1182 
1183         case built_last_make_run_special:
1184                 built_last_make_run_seen = true;
1185                 break;
1186 
1187         case default_special:
1188                 if (depes->used != 0) {
1189                         warning(catgets(catd, 1, 100, "Illegal dependency list for target `%s'"),
1190                                 target->string_mb);
1191                 }
1192                 default_rule = command;
1193                 if (trace_reader) {
1194                         (void) printf("%s:\n",
1195                                       default_rule_name->string_mb);
1196                         print_rule(command);
1197                 }
1198                 break;
1199 
1200 #ifdef NSE
1201         case derived_src_special:
1202                 for (; depes != NULL; depes= depes->next)
1203                         for (n= 0; n < depes->used; n++) {
1204                                 if (trace_reader)
1205                                         (void)printf("%s:\t%s\n",
1206                                         precious->string_mb,
1207                                         depes->names[n]->string_mb);
1208                                 depes->names[n]->stat.is_derived_src= true;
1209                         };
1210                 break;
1211 #endif
1212 
1213         case ignore_special:
1214                 if ((depes->used != 0) &&(!posix)){
1215                         fatal_reader(catgets(catd, 1, 101, "Illegal dependencies for target `%s'"),
1216                                      target->string_mb);
1217                 }
1218                 if (depes->used == 0)
1219                 {
1220                    ignore_errors_all = true;
1221                 }
1222                 if(svr4) {
1223                   ignore_errors_all = true;
1224                   break;
1225                 }
1226                 for (; depes != NULL; depes = depes->next) {
1227                         for (n = 0; n < depes->used; n++) {
1228                                 depes->names[n]->ignore_error_mode = true;
1229                         }
1230                 }
1231                 if (trace_reader) {
1232                         (void) printf("%s:\n", ignore_name->string_mb);
1233                 }
1234                 break;
1235 
1236         case keep_state_special:
1237                 if(svr4)
1238                   break;
1239                         /* ignore keep state, being SunPro make specific */
1240                 if(posix)
1241                   break;
1242                 if (depes->used != 0) {
1243                         fatal_reader(catgets(catd, 1, 102, "Illegal dependencies for target `%s'"),
1244                                      target->string_mb);
1245                 }
1246                 keep_state = true;
1247                 if (trace_reader) {
1248                         (void) printf("%s:\n",
1249                                       dot_keep_state->string_mb);
1250                 }
1251                 break;
1252 
1253         case keep_state_file_special:
1254                 if(svr4)
1255                   break;
1256                 if(posix)
1257                   break;
1258                         /* it's not necessary to specify KEEP_STATE, if this 
1259                         ** is given, so set the keep_state.
1260                         */
1261                 keep_state = true;
1262                 if (depes->used != 0) {
1263                    if((!make_state) ||(!strcmp(make_state->string_mb,NOCATGETS(".make.state")))) {
1264                      make_state = depes->names[0];
1265                    }
1266                 }
1267                 break;
1268         case make_version_special:
1269                 if(svr4)
1270                   break;
1271                 if (depes->used != 1) {
1272                         fatal_reader(catgets(catd, 1, 103, "Illegal dependency list for target `%s'"),
1273                                      target->string_mb);
1274                 }
1275                 if (depes->names[0] != current_make_version) {
1276                         /*
1277                          * Special case the fact that version 1.0 and 1.1
1278                          * are identical.
1279                          */
1280                         if (!IS_EQUAL(depes->names[0]->string_mb,
1281                                       NOCATGETS("VERSION-1.1")) ||
1282                             !IS_EQUAL(current_make_version->string_mb,
1283                                       NOCATGETS("VERSION-1.0"))) {
1284                                 /*
1285                                  * Version mismatches should cause the
1286                                  * .make.state file to be skipped.
1287                                  * This is currently not true - it is read
1288                                  * anyway.
1289                                  */
1290                                 warning(catgets(catd, 1, 104, "Version mismatch between current version `%s' and `%s'"),
1291                                         current_make_version->string_mb,
1292                                         depes->names[0]->string_mb);
1293                         }
1294                 }
1295                 break;
1296 
1297         case no_parallel_special:
1298                 if(svr4)
1299                   break;
1300                 /* Set the no_parallel bit for all the targets on */
1301                 /* the dependency list */
1302                 if (depes->used == 0) {
1303                         /* only those explicitly made parallel */
1304                         only_parallel = true;
1305                         all_parallel = false;
1306                 }
1307                 for (; depes != NULL; depes = depes->next) {
1308                         for (n = 0; n < depes->used; n++) {
1309                                 if (trace_reader) {
1310                                         (void) printf("%s:\t%s\n",
1311                                                       no_parallel_name->string_mb,
1312                                                       depes->names[n]->string_mb);
1313                                 }
1314                                 depes->names[n]->no_parallel = true;
1315                                 depes->names[n]->parallel = false;
1316                         }
1317                 }
1318                 break;
1319 
1320         case parallel_special:
1321                 if(svr4)
1322                   break;
1323                 if (depes->used == 0) {
1324                         /* everything runs in parallel */
1325                         all_parallel = true;
1326                         only_parallel = false;
1327                 }
1328                 /* Set the parallel bit for all the targets on */
1329                 /* the dependency list */
1330                 for (; depes != NULL; depes = depes->next) {
1331                         for (n = 0; n < depes->used; n++) {
1332                                 if (trace_reader) {
1333                                         (void) printf("%s:\t%s\n",
1334                                                       parallel_name->string_mb,
1335                                                       depes->names[n]->string_mb);
1336                                 }
1337                                 depes->names[n]->parallel = true;
1338                                 depes->names[n]->no_parallel = false;
1339                         }
1340                 }
1341                 break;
1342 
1343         case localhost_special:
1344                 if(svr4)
1345                   break;
1346                 /* Set the no_parallel bit for all the targets on */
1347                 /* the dependency list */
1348                 if (depes->used == 0) {
1349                         /* only those explicitly made parallel */
1350                         only_parallel = true;
1351                         all_parallel = false;
1352                 }
1353                 for (; depes != NULL; depes = depes->next) {
1354                         for (n = 0; n < depes->used; n++) {
1355                                 if (trace_reader) {
1356                                         (void) printf("%s:\t%s\n",
1357                                                       localhost_name->string_mb,
1358                                                       depes->names[n]->string_mb);
1359                                 }
1360                                 depes->names[n]->no_parallel = true;
1361                                 depes->names[n]->parallel = false;
1362                                 depes->names[n]->localhost = true;
1363                         }
1364                 }
1365                 break;
1366 
1367         case precious_special:
1368                 if (depes->used == 0) {
1369                         /* everything is precious      */
1370                         all_precious = true;
1371                 } else {
1372                         all_precious = false;
1373                 }
1374                 if(svr4) {
1375                   all_precious = true;
1376                   break;
1377                 }
1378                 /* Set the precious bit for all the targets on */
1379                 /* the dependency list */
1380                 for (; depes != NULL; depes = depes->next) {
1381                         for (n = 0; n < depes->used; n++) {
1382                                 if (trace_reader) {
1383                                         (void) printf("%s:\t%s\n",
1384                                                       precious->string_mb,
1385                                                       depes->names[n]->string_mb);
1386                                 }
1387                                 depes->names[n]->stat.is_precious = true;
1388                         }
1389                 }
1390                 break;
1391 
1392         case sccs_get_special:
1393                 if (depes->used != 0) {
1394                         fatal_reader(catgets(catd, 1, 105, "Illegal dependencies for target `%s'"),
1395                                      target->string_mb);
1396                 }
1397                 sccs_get_rule = command;
1398                 sccs_get_org_rule = command;
1399                 if (trace_reader) {
1400                         (void) printf("%s:\n", sccs_get_name->string_mb);
1401                         print_rule(command);
1402                 }
1403                 break;
1404 
1405         case sccs_get_posix_special:
1406                 if (depes->used != 0) {
1407                         fatal_reader(catgets(catd, 1, 106, "Illegal dependencies for target `%s'"),
1408                                      target->string_mb);
1409                 }
1410                 sccs_get_posix_rule = command;
1411                 if (trace_reader) {
1412                         (void) printf("%s:\n", sccs_get_posix_name->string_mb);
1413                         print_rule(command);
1414                 }
1415                 break;
1416 
1417         case get_posix_special:
1418                 if (depes->used != 0) {
1419                         fatal_reader(catgets(catd, 1, 107, "Illegal dependencies for target `%s'"),
1420                                      target->string_mb);
1421                 }
1422                 get_posix_rule = command;
1423                 if (trace_reader) {
1424                         (void) printf("%s:\n", get_posix_name->string_mb);
1425                         print_rule(command);
1426                 }
1427                 break;
1428 
1429         case get_special:
1430                 if(!svr4) {
1431                   break;
1432                 }
1433                 if (depes->used != 0) {
1434                         fatal_reader(catgets(catd, 1, 108, "Illegal dependencies for target `%s'"),
1435                                      target->string_mb);
1436                 }
1437                 get_rule = command;
1438                 sccs_get_rule = command;
1439                 if (trace_reader) {
1440                         (void) printf("%s:\n", get_name->string_mb);
1441                         print_rule(command);
1442                 }
1443                 break;
1444 
1445         case silent_special:
1446                 if ((depes->used != 0) && (!posix)){
1447                         fatal_reader(catgets(catd, 1, 109, "Illegal dependencies for target `%s'"),
1448                                      target->string_mb);
1449                 }
1450                 if (depes->used == 0)
1451                 {
1452                    silent_all = true;
1453                 }
1454                 if(svr4) {
1455                   silent_all = true;
1456                   break;
1457                 }
1458                 for (; depes != NULL; depes = depes->next) {
1459                         for (n = 0; n < depes->used; n++) {
1460                                 depes->names[n]->silent_mode = true;
1461                         }
1462                 }
1463                 if (trace_reader) {
1464                         (void) printf("%s:\n", silent_name->string_mb);
1465                 }
1466                 break;
1467 
1468         case suffixes_special:
1469                 read_suffixes_list(depes);
1470                 break;
1471 
1472         default:
1473 
1474                 fatal_reader(catgets(catd, 1, 110, "Internal error: Unknown special reader"));
1475         }
1476 }
1477 
1478 /*
1479  *      read_suffixes_list(depes)
1480  *
1481  *      Read the special list .SUFFIXES. If it is empty the old list is
1482  *      cleared. Else the new one is appended. Suffixes with ~ are extracted
1483  *      and marked.
1484  *
1485  *      Parameters:
1486  *              depes           The list of suffixes
1487  *
1488  *      Global variables used:
1489  *              hashtab         The central hashtable for Names.
1490  *              suffixes        The list of suffixes, set or appended to
1491  *              suffixes_name   The Name ".SUFFIXES", used for tracing
1492  *              trace_reader    Indicates that we should echo stuff we read
1493  */
1494 static void
1495 read_suffixes_list(register Name_vector depes)
1496 {
1497         register int            n;
1498         register Dependency     dp;
1499         register Dependency     *insert_dep;
1500         register Name           np;
1501         Name                    np2;
1502         register Boolean        first = true;
1503 
1504         if (depes->used == 0) {
1505                 /* .SUFFIXES with no dependency list clears the */
1506                 /* suffixes list */
1507                 for (Name_set::iterator np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
1508                                 np->with_squiggle =
1509                                   np->without_squiggle =
1510                                     false;
1511                 }
1512                 suffixes = NULL;
1513                 if (trace_reader) {
1514                         (void) printf("%s:\n", suffixes_name->string_mb);
1515                 }
1516                 return;
1517         }
1518         Wstring str;
1519         /* Otherwise we append to the list */
1520         for (; depes != NULL; depes = depes->next) {
1521                 for (n = 0; n < depes->used; n++) {
1522                         np = depes->names[n];
1523                         /* Find the end of the list and check if the */
1524                         /* suffix already has been entered */
1525                         for (insert_dep = &suffixes, dp = *insert_dep;
1526                              dp != NULL;
1527                              insert_dep = &dp->next, dp = *insert_dep) {
1528                                 if (dp->name == np) {
1529                                         goto duplicate_suffix;
1530                                 }
1531                         }
1532                         if (trace_reader) {
1533                                 if (first) {
1534                                         (void) printf("%s:\t",
1535                                                       suffixes_name->string_mb);
1536                                         first = false;
1537                                 }
1538                                 (void) printf("%s ", depes->names[n]->string_mb);
1539                         }
1540                 if(!(posix|svr4)) {
1541                         /* If the suffix is suffixed with "~" we */
1542                         /* strip that and mark the suffix nameblock */
1543                         str.init(np);
1544                         wchar_t * wcb = str.get_string();
1545                         if (wcb[np->hash.length - 1] ==
1546                             (int) tilde_char) {
1547                                 np2 = GETNAME(wcb,
1548                                               (int)(np->hash.length - 1));
1549                                 np2->with_squiggle = true;
1550                                 if (np2->without_squiggle) {
1551                                         continue;
1552                                 }
1553                                 np = np2;
1554                         }
1555                 }
1556                         np->without_squiggle = true;
1557                         /* Add the suffix to the list */
1558                         dp = *insert_dep = ALLOC(Dependency);
1559                         insert_dep = &dp->next;
1560                         dp->next = NULL;
1561                         dp->name = np;
1562                         dp->built = false;
1563                 duplicate_suffix:;
1564                 }
1565         }
1566         if (trace_reader) {
1567                 (void) printf("\n");
1568         }
1569 }
1570 
1571 /*
1572  *      make_relative(to, result)
1573  *
1574  *      Given a file name compose a relative path name from it to the
1575  *      current directory.
1576  *
1577  *      Parameters:
1578  *              to              The path we want to make relative
1579  *              result          Where to put the resulting relative path
1580  *
1581  *      Global variables used:
1582  */
1583 static void
1584 make_relative(wchar_t *to, wchar_t *result)
1585 {
1586         wchar_t                 *from;
1587         wchar_t                 *allocated;
1588         wchar_t                 *cp;
1589         wchar_t                 *tocomp;
1590         int                     ncomps;
1591         int                     i;
1592         int                     len;
1593 
1594         /* Check if the path is already relative. */
1595         if (to[0] != (int) slash_char) {
1596                 (void) wscpy(result, to);
1597                 return;
1598         }
1599 
1600         MBSTOWCS(wcs_buffer, get_current_path());
1601         from = allocated = (wchar_t *) wsdup(wcs_buffer);
1602 
1603         /*
1604          * Find the number of components in the from name.
1605          * ncomp = number of slashes + 1.
1606          */
1607         ncomps = 1;
1608         for (cp = from; *cp != (int) nul_char; cp++) {
1609                 if (*cp == (int) slash_char) {
1610                         ncomps++;
1611                 }
1612         }
1613 
1614         /*
1615          * See how many components match to determine how many "..",
1616          * if any, will be needed.
1617          */
1618         result[0] = (int) nul_char;
1619         tocomp = to;
1620         while ((*from != (int) nul_char) && (*from == *to)) {
1621                 if (*from == (int) slash_char) {
1622                         ncomps--;
1623                         tocomp = &to[1];
1624                 }
1625                 from++;
1626                 to++;
1627         }
1628 
1629         /*
1630          * Now for some special cases. Check for exact matches and
1631          * for either name terminating exactly.
1632          */
1633         if (*from == (int) nul_char) {
1634                 if (*to == (int) nul_char) {
1635                         MBSTOWCS(wcs_buffer, ".");
1636                         (void) wscpy(result, wcs_buffer);
1637                         retmem(allocated);
1638                         return;
1639                 }
1640                 if (*to == (int) slash_char) {
1641                         ncomps--;
1642                         tocomp = &to[1];
1643                 }
1644         } else if ((*from == (int) slash_char) && (*to == (int) nul_char)) {
1645                 ncomps--;
1646                 tocomp = to;
1647         }
1648         /* Add on the ".."s. */
1649         for (i = 0; i < ncomps; i++) {
1650                 MBSTOWCS(wcs_buffer, "../");
1651                 (void) wscat(result, wcs_buffer);
1652         }
1653 
1654         /* Add on the remainder of the to name, if any. */
1655         if (*tocomp == (int) nul_char) {
1656                 len = wslen(result);
1657                 result[len - 1] = (int) nul_char;
1658         } else {
1659                 (void) wscat(result, tocomp);
1660         }
1661         retmem(allocated);
1662         return;
1663 }
1664 
1665 /*
1666  *      print_rule(command)
1667  *
1668  *      Used when tracing the reading of rules
1669  *
1670  *      Parameters:
1671  *              command         Command to print
1672  *
1673  *      Global variables used:
1674  */
1675 static void
1676 print_rule(register Cmd_line command)
1677 {
1678         for (; command != NULL; command = command->next) {
1679                 (void) printf("\t%s\n", command->command_line->string_mb);
1680         }
1681 }
1682 
1683 /*
1684  *      enter_conditional(target, name, value, append)
1685  *
1686  *      Enter "target := MACRO= value" constructs
1687  *
1688  *      Parameters:
1689  *              target          The target the macro is for
1690  *              name            The name of the macro
1691  *              value           The value for the macro
1692  *              append          Indicates if the assignment is appending or not
1693  *
1694  *      Global variables used:
1695  *              conditionals    A special Name that stores all conditionals
1696  *                              where the target is a % pattern
1697  *              trace_reader    Indicates that we should echo stuff we read
1698  */
1699 void
1700 enter_conditional(register Name target, Name name, Name value, register Boolean append)
1701 {
1702         register Property       conditional;
1703         static int              sequence;
1704         Name                    orig_target = target;
1705 
1706         if (name == target_arch) {
1707                 enter_conditional(target, virtual_root, virtual_root, false);
1708         }
1709 
1710         if (target->percent) {
1711                 target = conditionals;
1712         }
1713         
1714         if (name->colon) {
1715                 sh_transform(&name, &value);
1716         }
1717 
1718         /* Count how many conditionals we must activate before building the */
1719         /* target */
1720         if (target->percent) {
1721                 target = conditionals;
1722         }
1723 
1724         target->conditional_cnt++;
1725         maybe_append_prop(name, macro_prop)->body.macro.is_conditional = true;
1726         /* Add the property for the target */
1727         conditional = append_prop(target, conditional_prop);
1728         conditional->body.conditional.target = orig_target;
1729         conditional->body.conditional.name = name;
1730         conditional->body.conditional.value = value;
1731         conditional->body.conditional.sequence = sequence++;
1732         conditional->body.conditional.append = append;
1733         if (trace_reader) {
1734                 if (value == NULL) {
1735                         (void) printf("%s := %s %c=\n",
1736                                       target->string_mb,
1737                                       name->string_mb,
1738                                       append ?
1739                                       (int) plus_char : (int) space_char);
1740                 } else {
1741                         (void) printf("%s := %s %c= %s\n",
1742                                       target->string_mb,
1743                                       name->string_mb,
1744                                       append ?
1745                                       (int) plus_char : (int) space_char,
1746                                       value->string_mb);
1747                 }
1748         }
1749 }
1750 
1751 /*
1752  *      enter_equal(name, value, append)
1753  *
1754  *      Enter "MACRO= value" constructs
1755  *
1756  *      Parameters:
1757  *              name            The name of the macro
1758  *              value           The value for the macro
1759  *              append          Indicates if the assignment is appending or not
1760  *
1761  *      Global variables used:
1762  *              trace_reader    Indicates that we should echo stuff we read
1763  */
1764 void
1765 enter_equal(Name name, Name value, register Boolean append)
1766 {
1767         wchar_t         *string;
1768         Name            temp;
1769 
1770         if (name->colon) {
1771                 sh_transform(&name, &value);
1772         }
1773         (void) SETVAR(name, value, append);
1774 
1775         /* if we're setting FC, we want to set F77 to the same value. */
1776         Wstring nms(name);
1777         wchar_t * wcb = nms.get_string();
1778         string = wcb;
1779         if (string[0]=='F' &&
1780             string[1]=='C' &&
1781             string[2]=='\0') {
1782                 MBSTOWCS(wcs_buffer, NOCATGETS("F77"));
1783                 temp = GETNAME(wcs_buffer, FIND_LENGTH);
1784                 (void) SETVAR(temp, value, append);
1785 /*
1786                 fprintf(stderr, catgets(catd, 1, 111, "warning: FC is obsolete, use F77 instead\n"));
1787  */
1788         }
1789 
1790         if (trace_reader) {
1791                 if (value == NULL) {
1792                         (void) printf("%s %c=\n",
1793                                       name->string_mb,
1794                                       append ?
1795                                       (int) plus_char : (int) space_char);
1796                 } else {
1797                         (void) printf("%s %c= %s\n",
1798                                       name->string_mb,
1799                                       append ?
1800                                       (int) plus_char : (int) space_char,
1801                                       value->string_mb);
1802                 }
1803         }
1804 }
1805 
1806 /*
1807  *      sh_transform(name, value)
1808  *
1809  *      Parameters:
1810  *              name    The name of the macro we might transform
1811  *              value   The value to transform
1812  *
1813  */
1814 static void
1815 sh_transform(Name *name, Name *value)
1816 {
1817         /* Check if we need :sh transform */
1818         wchar_t         *colon;
1819         String_rec      command;
1820         String_rec      destination;
1821         wchar_t         buffer[1000];
1822         wchar_t         buffer1[1000];
1823 
1824         static wchar_t  colon_sh[4];
1825         static wchar_t  colon_shell[7];
1826 
1827         if (colon_sh[0] == (int) nul_char) {
1828                 MBSTOWCS(colon_sh, NOCATGETS(":sh"));
1829                 MBSTOWCS(colon_shell, NOCATGETS(":shell"));
1830         }
1831         Wstring nms((*name));
1832         wchar_t * wcb = nms.get_string();
1833 
1834         colon = (wchar_t *) wsrchr(wcb, (int) colon_char);
1835         if ((colon != NULL) && (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell))) {
1836                 INIT_STRING_FROM_STACK(destination, buffer);
1837 
1838                 if(*value == NULL) {
1839                         buffer[0] = 0;
1840                 } else {
1841                         Wstring wcb1((*value));
1842                         if (IS_WEQUAL(colon, colon_shell)) {
1843                                 INIT_STRING_FROM_STACK(command, buffer1);
1844                                 expand_value(*value, &command, false);
1845                         } else {
1846                                 command.text.p = wcb1.get_string() + (*value)->hash.length;
1847                                 command.text.end = command.text.p;
1848                                 command.buffer.start = wcb1.get_string();
1849                                 command.buffer.end = command.text.p;
1850                         }
1851                         sh_command2string(&command, &destination);
1852                 }
1853 
1854                 (*value) = GETNAME(destination.buffer.start, FIND_LENGTH);
1855                 *colon = (int) nul_char;
1856                 (*name) = GETNAME(wcb, FIND_LENGTH);
1857                 *colon = (int) colon_char;
1858         }
1859 }
1860 
1861 /*
1862  *      fatal_reader(format, args...)
1863  *
1864  *      Parameters:
1865  *              format          printf style format string
1866  *              args            arguments to match the format
1867  *
1868  *      Global variables used:
1869  *              file_being_read Name of the makefile being read
1870  *              line_number     Line that is being read
1871  *              report_pwd      Indicates whether current path should be shown
1872  *              temp_file_name  When reading tempfile we report that name
1873  */
1874 /*VARARGS*/
1875 void
1876 fatal_reader(char * pattern, ...)
1877 {
1878         va_list args;
1879         char    message[1000];
1880 
1881         va_start(args, pattern);
1882         if (file_being_read != NULL) {
1883                 WCSTOMBS(mbs_buffer, file_being_read);
1884                 if (line_number != 0) {
1885                         (void) sprintf(message,
1886                                        catgets(catd, 1, 112, "%s, line %d: %s"),
1887                                        mbs_buffer,
1888                                        line_number,
1889                                        pattern);
1890                 } else {
1891                         (void) sprintf(message,
1892                                        "%s: %s",
1893                                        mbs_buffer,
1894                                        pattern);
1895                 }
1896                 pattern = message;
1897         }
1898 
1899         (void) fflush(stdout);
1900 #ifdef DISTRIBUTED
1901         (void) fprintf(stderr, catgets(catd, 1, 113, "dmake: Fatal error in reader: "));
1902 #else
1903         (void) fprintf(stderr, catgets(catd, 1, 238, "make: Fatal error in reader: "));
1904 #endif
1905         (void) vfprintf(stderr, pattern, args);
1906         (void) fprintf(stderr, "\n");
1907         va_end(args);
1908 
1909         if (temp_file_name != NULL) {
1910                 (void) fprintf(stderr,
1911 #ifdef DISTRIBUTED
1912                                catgets(catd, 1, 114, "dmake: Temp-file %s not removed\n"),
1913 #else
1914                                catgets(catd, 1, 239, "make: Temp-file %s not removed\n"),
1915 #endif
1916                                temp_file_name->string_mb);
1917                 temp_file_name = NULL;
1918         }
1919 
1920         if (report_pwd) {
1921                 (void) fprintf(stderr,
1922                                catgets(catd, 1, 115, "Current working directory %s\n"),
1923                                get_current_path());
1924         }
1925         (void) fflush(stderr);
1926         exit_status = 1;
1927         exit(1);
1928 }
1929