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                 target->has_recursive_dependency = true;
 590                 depes->names[0] = NULL;
 591                 recursive_state = 0;
 592                 dp = NULL;
 593                 dpp = &dp;
 594                 /* Read the dependencies. They are "<directory> <target-made>*/
 595                 /* <makefile>*" */
 596                 for (; depes != NULL; depes = depes->next) {
 597                         for (i = 0; i < depes->used; i++) {
 598                                 if (depes->names[i] != NULL) {
 599                                         switch (recursive_state++) {
 600                                         case 0: /* Directory */
 601                                         {
 602                                                 depstr.init(depes->names[i]);
 603                                                 make_relative(depstr.get_string(),
 604                                                               relative);
 605                                                 directory =
 606                                                   GETNAME(relative,
 607                                                           FIND_LENGTH);
 608                                         }
 609                                                 break;
 610                                         case 1: /* Target */
 611                                                 name = depes->names[i];
 612                                                 break;
 613                                         default:        /* Makefiles */
 614                                                 *dpp = ALLOC(Dependency);
 615                                                 (*dpp)->next = NULL;
 616                                                 (*dpp)->name = depes->names[i];
 617                                                 (*dpp)->automatic = false;
 618                                                 (*dpp)->stale = false;
 619                                                 (*dpp)->built = false;
 620                                                 dpp = &((*dpp)->next);
 621                                                 break;
 622                                         }
 623                                 }
 624                         }
 625                 }
 626                 /* Check if this recursion already has been reported else */
 627                 /* enter the recursive prop for the target */
 628                 /* The has_built flag is used to tell if this .RECURSIVE */
 629                 /* was discovered from this run (read from a tmp file) */
 630                 /* or was from discovered from the original .make.state */
 631                 /* file */
 632                 for (line = get_prop(target->prop, recursive_prop);
 633                      line != NULL;
 634                      line = get_prop(line->next, recursive_prop)) {
 635                         if ((line->body.recursive.directory == directory) &&
 636                             (line->body.recursive.target == name)) {
 637                                 line->body.recursive.makefiles = dp;
 638                                 line->body.recursive.has_built = 
 639                                   (Boolean)
 640                                     (makefile_type == reading_cpp_file);
 641                                 return;
 642                         }
 643                 }
 644                 line2 = append_prop(target, recursive_prop);
 645                 line2->body.recursive.directory = directory;
 646                 line2->body.recursive.target = name;
 647                 line2->body.recursive.makefiles = dp;
 648                 line2->body.recursive.has_built = 
 649                     (Boolean) (makefile_type == reading_cpp_file);
 650                 line2->body.recursive.in_depinfo = false;
 651                 return;
 652         }
 653         /* If this is the first target that doesnt start with a "." in the */
 654         /* makefile we remember that */
 655         Wstring tstr(target);
 656         wchar_t * wcb = tstr.get_string();
 657         if ((makefile_type == reading_makefile) &&
 658             (default_target_to_build == NULL) &&
 659             ((wcb[0] != (int) period_char) ||
 660              wschr(wcb, (int) slash_char))) {
 661 
 662 /* BID 1181577: $(EMPTY_MACRO) + $(EMPTY_MACRO):
 663 ** The target with empty name cannot be default_target_to_build
 664 */
 665                 if (target->hash.length != 0)
 666                         default_target_to_build = target;
 667         }
 668         /* Check if the line is ":" or "::" */
 669         if (makefile_type == reading_makefile) {
 670                 if (target->colons == no_colon) {
 671                         target->colons = separator;
 672                 } else {
 673                         if (target->colons != separator) {
 674                                 fatal_reader(catgets(catd, 1, 92, ":/:: conflict for target `%s'"),
 675                                              target->string_mb);
 676                         }
 677                 }
 678                 if (target->colons == two_colon) {
 679                         if (depes->used == 0) {
 680                                 /* If this is a "::" type line with no */
 681                                 /* dependencies we add one "FRC" type */
 682                                 /* dependency for free */
 683                                 depes->used = 1; /* Force :: targets with no
 684                                                   * depes to always run */
 685                                 depes->names[0] = force;
 686                         }
 687                         /* Do not delete "::" type targets when interrupted */
 688                         target->stat.is_precious = true;
 689                         /*
 690                          * Build a synthetic target "<number>%target"
 691                          * for "target".
 692                          */
 693                         mb_namep = getmem((int) (strlen(target->string_mb) + 10));
 694                         namep = ALLOC_WC((int) (target->hash.length + 10));
 695                         slash = strrchr(target->string_mb, (int) slash_char);
 696                         if (slash == NULL) {
 697                                 (void) sprintf(mb_namep,
 698                                                 "%d@%s",
 699                                                 target->colon_splits++,
 700                                                 target->string_mb);
 701                         } else {
 702                                 *slash = 0;
 703                                 (void) sprintf(mb_namep,
 704                                                 "%s/%d@%s",
 705                                                 target->string_mb,
 706                                                 target->colon_splits++,
 707                                                 slash + 1);
 708                                 *slash = (int) slash_char;
 709                         }
 710                         MBSTOWCS(namep, mb_namep);
 711                         retmem_mb(mb_namep);
 712                         name = GETNAME(namep, FIND_LENGTH);
 713                         retmem(namep);
 714                         if (trace_reader) {
 715                                 (void) printf("%s:\t", target->string_mb);
 716                         }
 717                         /* Make "target" depend on "<number>%target */
 718                         line2 = maybe_append_prop(target, line_prop);
 719                         enter_dependency(line2, name, true);
 720                         line2->body.line.target = target;
 721                         /* Put a prop on "<number>%target that makes */
 722                         /* appear as "target" */
 723                         /* when it is processed */
 724                         maybe_append_prop(name, target_prop)->
 725                           body.target.target = target;
 726                         target->is_double_colon_parent = true;
 727                         name->is_double_colon = true;
 728                         name->has_target_prop = true;
 729                         if (trace_reader) {
 730                                 (void) printf("\n");
 731                         }
 732                         (target = name)->stat.is_file = true;
 733                 }
 734         }
 735         /* This really is a regular dependency line. Just enter it */
 736         line = maybe_append_prop(target, line_prop);
 737         line->body.line.target = target;
 738         /* Depending on what kind of makefile we are reading we have to */
 739         /* treat things differently */
 740         switch (makefile_type) {
 741         case reading_makefile:
 742                 /* Reading regular makefile. Just notice whether this */
 743                 /* redefines the rule for the  target */
 744                 if (command != NULL) {
 745                         if (line->body.line.command_template != NULL) {
 746                                 line->body.line.command_template_redefined =
 747                                   true;
 748                                 if ((wcb[0] == (int) period_char) &&
 749                                     !wschr(wcb, (int) slash_char)) {
 750                                         line->body.line.command_template =
 751                                           command;
 752                                 }
 753                         } else {
 754                                 line->body.line.command_template = command;
 755                         }
 756                 } else {
 757                         if ((wcb[0] == (int) period_char) &&
 758                             !wschr(wcb, (int) slash_char)) {
 759                                 line->body.line.command_template = command;
 760                         }
 761                 }
 762                 break;
 763         case rereading_statefile:
 764                 /* Rereading the statefile. We only enter thing that changed */
 765                 /* since the previous time we read it */
 766                 if (!built_last_make_run_seen) {
 767                         for (Cmd_line next, cmd = command; cmd != NULL; cmd = next) {
 768                                 next = cmd->next;
 769                                 free(cmd);
 770                         }
 771                         return;
 772                 }
 773                 built_last_make_run_seen = false;
 774                 command_changed = true;
 775                 target->ran_command = true;
 776         case reading_statefile:
 777                 /* Reading the statefile for the first time. Enter the rules */
 778                 /* as "Commands used" not "templates to use" */
 779                 if (command != NULL) {
 780                         for (Cmd_line next, cmd = line->body.line.command_used;
 781                              cmd != NULL; cmd = next) {
 782                                 next = cmd->next;
 783                                 free(cmd);
 784                         }
 785                         line->body.line.command_used = command;
 786                 }
 787         case reading_cpp_file:
 788                 /* Reading report file from programs that reports */
 789                 /* dependencies. If this is the first time the target is */
 790                 /* read from this reportfile we clear all old */
 791                 /* automatic depes */
 792                 if (target->temp_file_number == temp_file_number) {
 793                         break;
 794                 }
 795                 target->temp_file_number = temp_file_number;
 796                 command_changed = true;
 797                 if (line != NULL) {
 798                         for (dp = line->body.line.dependencies;
 799                              dp != NULL;
 800                              dp = dp->next) {
 801                                 if (dp->automatic) {
 802                                         dp->stale = true;
 803                                 }
 804                         }
 805                 }
 806                 break;
 807         default:
 808                 fatal_reader(catgets(catd, 1, 93, "Internal error. Unknown makefile type %d"),
 809                              makefile_type);
 810         }
 811         /* A target may only be involved in one target group */
 812         if (line->body.line.target_group != NULL) {
 813                 if (target_group != NULL) {
 814                         fatal_reader(catgets(catd, 1, 94, "Too many target groups for target `%s'"),
 815                                      target->string_mb);
 816                 }
 817         } else {
 818                 line->body.line.target_group = target_group;
 819         }
 820 
 821         if (trace_reader) {
 822                 (void) printf("%s:\t", target->string_mb);
 823         }
 824         /* Enter the dependencies */
 825         register_as_auto = BOOLEAN(makefile_type != reading_makefile);
 826         not_auto_found = false;
 827         for (;
 828              (depes != NULL) && !not_auto_found;
 829              depes = depes->next) {
 830                 for (i = 0; i < depes->used; i++) {
 831                         /* the dependency .NOT_AUTO signals beginning of
 832                          * explicit dependancies which were put at end of
 833                          * list in .make.state file - we stop entering
 834                          * dependencies at this point
 835                          */
 836                         if (depes->names[i] == not_auto) {
 837                                 not_auto_found = true;
 838                                 break;
 839                         }
 840                         enter_dependency(line,
 841                                          depes->names[i],
 842                                          register_as_auto);
 843                 }
 844         }
 845         if (trace_reader) {
 846                 (void) printf("\n");
 847                 print_rule(command);
 848         }
 849 }
 850 
 851 /*
 852  *      enter_dependency(line, depe, automatic)
 853  *
 854  *      Enter one dependency. Do not enter duplicates.
 855  *
 856  *      Parameters:
 857  *              line            The line block that the dependeny is
 858  *                              entered for
 859  *              depe            The dependency to enter
 860  *              automatic       Used to set the field "automatic"
 861  *
 862  *      Global variables used:
 863  *              makefile_type   We do different things for makefile vs. report
 864  *              trace_reader    Indicates that we should echo stuff we read
 865  *              wait_name       The Name ".WAIT", compared against
 866  */
 867 void
 868 enter_dependency(Property line, register Name depe, Boolean automatic)
 869 {
 870         register Dependency     dp;
 871         register Dependency     *insert;
 872 
 873         if (trace_reader) {
 874                 (void) printf("%s ", depe->string_mb);
 875         }
 876         /* Find the end of the list and check for duplicates */
 877         for (insert = &line->body.line.dependencies, dp = *insert;
 878              dp != NULL;
 879              insert = &dp->next, dp = *insert) {
 880                 if ((dp->name == depe) && (depe != wait_name)) {
 881                         if (dp->automatic) {
 882                                 dp->automatic = automatic;
 883                                 if (automatic) {
 884                                         dp->built = false;
 885                                         depe->stat.is_file = true;
 886                                 }
 887                         }
 888                         dp->stale = false;
 889                         return;
 890                 }
 891         }
 892         /* Insert the new dependency since we couldnt find it */
 893         dp = *insert = ALLOC(Dependency);
 894         dp->name = depe;
 895         dp->next = NULL;
 896         dp->automatic = automatic;
 897         dp->stale = false;
 898         dp->built = false;
 899         depe->stat.is_file = true;
 900 
 901         if ((makefile_type == reading_makefile) &&
 902             (line != NULL) &&
 903             (line->body.line.target != NULL)) {
 904                 line->body.line.target->has_regular_dependency = true;
 905         }
 906 }
 907 
 908 /*
 909  *      enter_percent(target, depes, command)
 910  *
 911  *      Enter "x%y : a%b" type lines
 912  *      % patterns are stored in four parts head and tail for target and source
 913  *
 914  *      Parameters:
 915  *              target          Left hand side of pattern
 916  *              depes           The dependency list with the rh pattern
 917  *              command         The command for the pattern
 918  *
 919  *      Global variables used:
 920  *              empty_name      The Name "", compared against
 921  *              percent_list    The list of all percent rules, added to
 922  *              trace_reader    Indicates that we should echo stuff we read
 923  */
 924 Percent
 925 enter_percent(register Name target, Chain target_group, register Name_vector depes, Cmd_line command)
 926 {
 927         register Percent        result = ALLOC(Percent);
 928         register Percent        depe;
 929         register Percent        *depe_tail = &result->dependencies;
 930         register Percent        *insert;
 931         register wchar_t        *cp, *cp1;
 932         Name_vector             nvp;
 933         int                     i;
 934         int                     pattern;
 935 
 936         result->next = NULL;
 937         result->patterns = NULL;
 938         result->patterns_total = 0;
 939         result->command_template = command;
 940         result->being_expanded = false;
 941         result->name = target;
 942         result->dependencies = NULL;
 943         result->target_group = target_group;
 944 
 945         /* get patterns count */
 946         Wstring wcb(target);
 947         cp = wcb.get_string();
 948         while (true) {
 949                 cp = (wchar_t *) wschr(cp, (int) percent_char);
 950                 if (cp != NULL) {
 951                         result->patterns_total++;
 952                         cp++;
 953                 } else {
 954                         break;
 955                 }
 956         }
 957         result->patterns_total++;
 958 
 959         /* allocate storage for patterns */
 960         result->patterns = (Name *) getmem(sizeof(Name) * result->patterns_total);
 961 
 962         /* then create patterns */
 963         cp = wcb.get_string();
 964         pattern = 0;
 965         while (true) {
 966                 cp1 = (wchar_t *) wschr(cp, (int) percent_char);
 967                 if (cp1 != NULL) {
 968                         result->patterns[pattern] = GETNAME(cp, cp1 - cp);
 969                         cp = cp1 + 1;
 970                         pattern++;
 971                 } else {
 972                         result->patterns[pattern] = GETNAME(cp, (int) target->hash.length - (cp - wcb.get_string()));
 973                         break;
 974                 }
 975         }
 976 
 977         Wstring wcb1;
 978 
 979         /* build dependencies list */
 980         for (nvp = depes; nvp != NULL; nvp = nvp->next) {
 981                 for (i = 0; i < nvp->used; i++) {
 982                         depe = ALLOC(Percent);
 983                         depe->next = NULL;
 984                         depe->patterns = NULL;
 985                         depe->patterns_total = 0;
 986                         depe->name = nvp->names[i];
 987                         depe->dependencies = NULL;
 988                         depe->command_template = NULL;
 989                         depe->being_expanded = false;
 990                         depe->target_group = NULL;
 991 
 992                         *depe_tail = depe;
 993                         depe_tail = &depe->next;
 994 
 995                         if (depe->name->percent) {
 996                                 /* get patterns count */
 997                                 wcb1.init(depe->name);
 998                                 cp = wcb1.get_string();
 999                                 while (true) {
1000                                         cp = (wchar_t *) wschr(cp, (int) percent_char);
1001                                         if (cp != NULL) {
1002                                                 depe->patterns_total++;
1003                                                 cp++;
1004                                         } else {
1005                                                 break;
1006                                         }
1007                                 }
1008                                 depe->patterns_total++;
1009 
1010                                 /* allocate storage for patterns */
1011                                 depe->patterns = (Name *) getmem(sizeof(Name) * depe->patterns_total);
1012 
1013                                 /* then create patterns */
1014                                 cp = wcb1.get_string();
1015                                 pattern = 0;
1016                                 while (true) {
1017                                         cp1 = (wchar_t *) wschr(cp, (int) percent_char);
1018                                         if (cp1 != NULL) {
1019                                                 depe->patterns[pattern] = GETNAME(cp, cp1 - cp);
1020                                                 cp = cp1 + 1;
1021                                                 pattern++;
1022                                         } else {
1023                                                 depe->patterns[pattern] = GETNAME(cp, (int) depe->name->hash.length - (cp - wcb1.get_string()));
1024                                                 break;
1025                                         }
1026                                 }
1027                         }
1028                 }
1029         }
1030 
1031         /* Find the end of the percent list and append the new pattern */
1032         for (insert = &percent_list; (*insert) != NULL; insert = &(*insert)->next);
1033         *insert = result;
1034 
1035         if (trace_reader) {
1036                 (void) printf("%s:", result->name->string_mb);
1037 
1038                 for (depe = result->dependencies; depe != NULL; depe = depe->next) {
1039                         (void) printf(" %s", depe->name->string_mb);
1040                 }
1041 
1042                 (void) printf("\n");
1043 
1044                 print_rule(command);
1045         }
1046 
1047         return result;
1048 }
1049 
1050 /*
1051  *      enter_dyntarget(target)
1052  *
1053  *      Enter "$$(MACRO) : b" type lines
1054  *
1055  *      Parameters:
1056  *              target          Left hand side of pattern
1057  *
1058  *      Global variables used:
1059  *              dyntarget_list  The list of all percent rules, added to
1060  *              trace_reader    Indicates that we should echo stuff we read
1061  */
1062 Dyntarget
1063 enter_dyntarget(register Name target)
1064 {
1065         register Dyntarget      result = ALLOC(Dyntarget);
1066         Dyntarget               p;
1067         Dyntarget               *insert;
1068         int                             i;
1069 
1070         result->next = NULL;
1071         result->name = target;
1072 
1073 
1074         /* Find the end of the dyntarget list and append the new pattern */
1075         for (insert = &dyntarget_list, p = *insert;
1076              p != NULL;
1077              insert = &p->next, p = *insert);
1078         *insert = result;
1079 
1080         if (trace_reader) {
1081                 (void) printf(NOCATGETS("Dynamic target %s:\n"), result->name->string_mb);
1082         }
1083         return( result);
1084 }
1085 
1086 
1087 /*
1088  *      special_reader(target, depes, command)
1089  *
1090  *      Read the pseudo targets make knows about
1091  *      This handles the special targets that should not be entered as regular
1092  *      target/dependency sets.
1093  *
1094  *      Parameters:
1095  *              target          The special target
1096  *              depes           The list of dependencies it was entered with
1097  *              command         The command it was entered with
1098  *
1099  *      Static variables used:
1100  *              built_last_make_run_seen Set to indicate .BUILT_LAST... seen
1101  *
1102  *      Global variables used:
1103  *              all_parallel    Set to indicate that everything runs parallel
1104  *              svr4            Set when ".SVR4" target is read
1105  *              svr4_name       The Name ".SVR4"
1106  *              posix           Set when ".POSIX" target is read
1107  *              posix_name      The Name ".POSIX"
1108  *              current_make_version The Name "<current version number>"
1109  *              default_rule    Set when ".DEFAULT" target is read
1110  *              default_rule_name The Name ".DEFAULT", used for tracing
1111  *              dot_keep_state  The Name ".KEEP_STATE", used for tracing
1112  *              ignore_errors   Set if ".IGNORE" target is read
1113  *              ignore_name     The Name ".IGNORE", used for tracing
1114  *              keep_state      Set if ".KEEP_STATE" target is read
1115  *              no_parallel_name The Name ".NO_PARALLEL", used for tracing
1116  *              only_parallel   Set to indicate only some targets runs parallel
1117  *              parallel_name   The Name ".PARALLEL", used for tracing
1118  *              precious        The Name ".PRECIOUS", used for tracing
1119  *              sccs_get_name   The Name ".SCCS_GET", used for tracing
1120  *              sccs_get_posix_name The Name ".SCCS_GET_POSIX", used for tracing
1121  *              get_name        The Name ".GET", used for tracing
1122  *              sccs_get_rule   Set when ".SCCS_GET" target is read
1123  *              silent          Set when ".SILENT" target is read
1124  *              silent_name     The Name ".SILENT", used for tracing
1125  *              trace_reader    Indicates that we should echo stuff we read
1126  */
1127 void
1128 special_reader(Name target, register Name_vector depes, Cmd_line command)
1129 {
1130         register int            n;
1131 
1132         switch (target->special_reader) {
1133 
1134         case svr4_special:
1135                 if (depes->used != 0) {
1136                         fatal_reader(catgets(catd, 1, 98, "Illegal dependencies for target `%s'"),
1137                                      target->string_mb);
1138                 }
1139                 svr4  = true;
1140                 posix  = false;
1141                 keep_state = false;
1142                 all_parallel = false;
1143                 only_parallel = false;
1144                 if (trace_reader) {
1145                         (void) printf("%s:\n", svr4_name->string_mb);
1146                 }
1147                 break;
1148 
1149         case posix_special:
1150                 if(svr4)
1151                   break;
1152                 if (depes->used != 0) {
1153                         fatal_reader(catgets(catd, 1, 99, "Illegal dependencies for target `%s'"),
1154                                      target->string_mb);
1155                 }
1156                 posix  = true;
1157                         /* with posix on, use the posix get rule */
1158                 sccs_get_rule = sccs_get_posix_rule;
1159                         /* turn keep state off being SunPro make specific */
1160                 keep_state = false;
1161                 /* Use /usr/xpg4/bin/sh on Solaris */
1162                 MBSTOWCS(wcs_buffer, NOCATGETS("/usr/xpg4/bin/sh"));
1163                 (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
1164                 if (trace_reader) {
1165                         (void) printf("%s:\n", posix_name->string_mb);
1166                 }
1167                 break;
1168 
1169         case built_last_make_run_special:
1170                 built_last_make_run_seen = true;
1171                 break;
1172 
1173         case default_special:
1174                 if (depes->used != 0) {
1175                         warning(catgets(catd, 1, 100, "Illegal dependency list for target `%s'"),
1176                                 target->string_mb);
1177                 }
1178                 default_rule = command;
1179                 if (trace_reader) {
1180                         (void) printf("%s:\n",
1181                                       default_rule_name->string_mb);
1182                         print_rule(command);
1183                 }
1184                 break;
1185 
1186 
1187         case ignore_special:
1188                 if ((depes->used != 0) &&(!posix)){
1189                         fatal_reader(catgets(catd, 1, 101, "Illegal dependencies for target `%s'"),
1190                                      target->string_mb);
1191                 }
1192                 if (depes->used == 0)
1193                 {
1194                    ignore_errors_all = true;
1195                 }
1196                 if(svr4) {
1197                   ignore_errors_all = true;
1198                   break;
1199                 }
1200                 for (; depes != NULL; depes = depes->next) {
1201                         for (n = 0; n < depes->used; n++) {
1202                                 depes->names[n]->ignore_error_mode = true;
1203                         }
1204                 }
1205                 if (trace_reader) {
1206                         (void) printf("%s:\n", ignore_name->string_mb);
1207                 }
1208                 break;
1209 
1210         case keep_state_special:
1211                 if(svr4)
1212                   break;
1213                         /* ignore keep state, being SunPro make specific */
1214                 if(posix)
1215                   break;
1216                 if (depes->used != 0) {
1217                         fatal_reader(catgets(catd, 1, 102, "Illegal dependencies for target `%s'"),
1218                                      target->string_mb);
1219                 }
1220                 keep_state = true;
1221                 if (trace_reader) {
1222                         (void) printf("%s:\n",
1223                                       dot_keep_state->string_mb);
1224                 }
1225                 break;
1226 
1227         case keep_state_file_special:
1228                 if(svr4)
1229                   break;
1230                 if(posix)
1231                   break;
1232                         /* it's not necessary to specify KEEP_STATE, if this 
1233                         ** is given, so set the keep_state.
1234                         */
1235                 keep_state = true;
1236                 if (depes->used != 0) {
1237                    if((!make_state) ||(!strcmp(make_state->string_mb,NOCATGETS(".make.state")))) {
1238                      make_state = depes->names[0];
1239                    }
1240                 }
1241                 break;
1242         case make_version_special:
1243                 if(svr4)
1244                   break;
1245                 if (depes->used != 1) {
1246                         fatal_reader(catgets(catd, 1, 103, "Illegal dependency list for target `%s'"),
1247                                      target->string_mb);
1248                 }
1249                 if (depes->names[0] != current_make_version) {
1250                         /*
1251                          * Special case the fact that version 1.0 and 1.1
1252                          * are identical.
1253                          */
1254                         if (!IS_EQUAL(depes->names[0]->string_mb,
1255                                       NOCATGETS("VERSION-1.1")) ||
1256                             !IS_EQUAL(current_make_version->string_mb,
1257                                       NOCATGETS("VERSION-1.0"))) {
1258                                 /*
1259                                  * Version mismatches should cause the
1260                                  * .make.state file to be skipped.
1261                                  * This is currently not true - it is read
1262                                  * anyway.
1263                                  */
1264                                 warning(catgets(catd, 1, 104, "Version mismatch between current version `%s' and `%s'"),
1265                                         current_make_version->string_mb,
1266                                         depes->names[0]->string_mb);
1267                         }
1268                 }
1269                 break;
1270 
1271         case no_parallel_special:
1272                 if(svr4)
1273                   break;
1274                 /* Set the no_parallel bit for all the targets on */
1275                 /* the dependency list */
1276                 if (depes->used == 0) {
1277                         /* only those explicitly made parallel */
1278                         only_parallel = true;
1279                         all_parallel = false;
1280                 }
1281                 for (; depes != NULL; depes = depes->next) {
1282                         for (n = 0; n < depes->used; n++) {
1283                                 if (trace_reader) {
1284                                         (void) printf("%s:\t%s\n",
1285                                                       no_parallel_name->string_mb,
1286                                                       depes->names[n]->string_mb);
1287                                 }
1288                                 depes->names[n]->no_parallel = true;
1289                                 depes->names[n]->parallel = false;
1290                         }
1291                 }
1292                 break;
1293 
1294         case parallel_special:
1295                 if(svr4)
1296                   break;
1297                 if (depes->used == 0) {
1298                         /* everything runs in parallel */
1299                         all_parallel = true;
1300                         only_parallel = false;
1301                 }
1302                 /* Set the parallel bit for all the targets on */
1303                 /* the dependency list */
1304                 for (; depes != NULL; depes = depes->next) {
1305                         for (n = 0; n < depes->used; n++) {
1306                                 if (trace_reader) {
1307                                         (void) printf("%s:\t%s\n",
1308                                                       parallel_name->string_mb,
1309                                                       depes->names[n]->string_mb);
1310                                 }
1311                                 depes->names[n]->parallel = true;
1312                                 depes->names[n]->no_parallel = false;
1313                         }
1314                 }
1315                 break;
1316 
1317         case localhost_special:
1318                 if(svr4)
1319                   break;
1320                 /* Set the no_parallel bit for all the targets on */
1321                 /* the dependency list */
1322                 if (depes->used == 0) {
1323                         /* only those explicitly made parallel */
1324                         only_parallel = true;
1325                         all_parallel = false;
1326                 }
1327                 for (; depes != NULL; depes = depes->next) {
1328                         for (n = 0; n < depes->used; n++) {
1329                                 if (trace_reader) {
1330                                         (void) printf("%s:\t%s\n",
1331                                                       localhost_name->string_mb,
1332                                                       depes->names[n]->string_mb);
1333                                 }
1334                                 depes->names[n]->no_parallel = true;
1335                                 depes->names[n]->parallel = false;
1336                                 depes->names[n]->localhost = true;
1337                         }
1338                 }
1339                 break;
1340 
1341         case precious_special:
1342                 if (depes->used == 0) {
1343                         /* everything is precious      */
1344                         all_precious = true;
1345                 } else {
1346                         all_precious = false;
1347                 }
1348                 if(svr4) {
1349                   all_precious = true;
1350                   break;
1351                 }
1352                 /* Set the precious bit for all the targets on */
1353                 /* the dependency list */
1354                 for (; depes != NULL; depes = depes->next) {
1355                         for (n = 0; n < depes->used; n++) {
1356                                 if (trace_reader) {
1357                                         (void) printf("%s:\t%s\n",
1358                                                       precious->string_mb,
1359                                                       depes->names[n]->string_mb);
1360                                 }
1361                                 depes->names[n]->stat.is_precious = true;
1362                         }
1363                 }
1364                 break;
1365 
1366         case sccs_get_special:
1367                 if (depes->used != 0) {
1368                         fatal_reader(catgets(catd, 1, 105, "Illegal dependencies for target `%s'"),
1369                                      target->string_mb);
1370                 }
1371                 sccs_get_rule = command;
1372                 sccs_get_org_rule = command;
1373                 if (trace_reader) {
1374                         (void) printf("%s:\n", sccs_get_name->string_mb);
1375                         print_rule(command);
1376                 }
1377                 break;
1378 
1379         case sccs_get_posix_special:
1380                 if (depes->used != 0) {
1381                         fatal_reader(catgets(catd, 1, 106, "Illegal dependencies for target `%s'"),
1382                                      target->string_mb);
1383                 }
1384                 sccs_get_posix_rule = command;
1385                 if (trace_reader) {
1386                         (void) printf("%s:\n", sccs_get_posix_name->string_mb);
1387                         print_rule(command);
1388                 }
1389                 break;
1390 
1391         case get_posix_special:
1392                 if (depes->used != 0) {
1393                         fatal_reader(catgets(catd, 1, 107, "Illegal dependencies for target `%s'"),
1394                                      target->string_mb);
1395                 }
1396                 get_posix_rule = command;
1397                 if (trace_reader) {
1398                         (void) printf("%s:\n", get_posix_name->string_mb);
1399                         print_rule(command);
1400                 }
1401                 break;
1402 
1403         case get_special:
1404                 if(!svr4) {
1405                   break;
1406                 }
1407                 if (depes->used != 0) {
1408                         fatal_reader(catgets(catd, 1, 108, "Illegal dependencies for target `%s'"),
1409                                      target->string_mb);
1410                 }
1411                 get_rule = command;
1412                 sccs_get_rule = command;
1413                 if (trace_reader) {
1414                         (void) printf("%s:\n", get_name->string_mb);
1415                         print_rule(command);
1416                 }
1417                 break;
1418 
1419         case silent_special:
1420                 if ((depes->used != 0) && (!posix)){
1421                         fatal_reader(catgets(catd, 1, 109, "Illegal dependencies for target `%s'"),
1422                                      target->string_mb);
1423                 }
1424                 if (depes->used == 0)
1425                 {
1426                    silent_all = true;
1427                 }
1428                 if(svr4) {
1429                   silent_all = true;
1430                   break;
1431                 }
1432                 for (; depes != NULL; depes = depes->next) {
1433                         for (n = 0; n < depes->used; n++) {
1434                                 depes->names[n]->silent_mode = true;
1435                         }
1436                 }
1437                 if (trace_reader) {
1438                         (void) printf("%s:\n", silent_name->string_mb);
1439                 }
1440                 break;
1441 
1442         case suffixes_special:
1443                 read_suffixes_list(depes);
1444                 break;
1445 
1446         default:
1447 
1448                 fatal_reader(catgets(catd, 1, 110, "Internal error: Unknown special reader"));
1449         }
1450 }
1451 
1452 /*
1453  *      read_suffixes_list(depes)
1454  *
1455  *      Read the special list .SUFFIXES. If it is empty the old list is
1456  *      cleared. Else the new one is appended. Suffixes with ~ are extracted
1457  *      and marked.
1458  *
1459  *      Parameters:
1460  *              depes           The list of suffixes
1461  *
1462  *      Global variables used:
1463  *              hashtab         The central hashtable for Names.
1464  *              suffixes        The list of suffixes, set or appended to
1465  *              suffixes_name   The Name ".SUFFIXES", used for tracing
1466  *              trace_reader    Indicates that we should echo stuff we read
1467  */
1468 static void
1469 read_suffixes_list(register Name_vector depes)
1470 {
1471         register int            n;
1472         register Dependency     dp;
1473         register Dependency     *insert_dep;
1474         register Name           np;
1475         Name                    np2;
1476         register Boolean        first = true;
1477 
1478         if (depes->used == 0) {
1479                 /* .SUFFIXES with no dependency list clears the */
1480                 /* suffixes list */
1481                 for (Name_set::iterator np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
1482                                 np->with_squiggle =
1483                                   np->without_squiggle =
1484                                     false;
1485                 }
1486                 suffixes = NULL;
1487                 if (trace_reader) {
1488                         (void) printf("%s:\n", suffixes_name->string_mb);
1489                 }
1490                 return;
1491         }
1492         Wstring str;
1493         /* Otherwise we append to the list */
1494         for (; depes != NULL; depes = depes->next) {
1495                 for (n = 0; n < depes->used; n++) {
1496                         np = depes->names[n];
1497                         /* Find the end of the list and check if the */
1498                         /* suffix already has been entered */
1499                         for (insert_dep = &suffixes, dp = *insert_dep;
1500                              dp != NULL;
1501                              insert_dep = &dp->next, dp = *insert_dep) {
1502                                 if (dp->name == np) {
1503                                         goto duplicate_suffix;
1504                                 }
1505                         }
1506                         if (trace_reader) {
1507                                 if (first) {
1508                                         (void) printf("%s:\t",
1509                                                       suffixes_name->string_mb);
1510                                         first = false;
1511                                 }
1512                                 (void) printf("%s ", depes->names[n]->string_mb);
1513                         }
1514                 if(!(posix|svr4)) {
1515                         /* If the suffix is suffixed with "~" we */
1516                         /* strip that and mark the suffix nameblock */
1517                         str.init(np);
1518                         wchar_t * wcb = str.get_string();
1519                         if (wcb[np->hash.length - 1] ==
1520                             (int) tilde_char) {
1521                                 np2 = GETNAME(wcb,
1522                                               (int)(np->hash.length - 1));
1523                                 np2->with_squiggle = true;
1524                                 if (np2->without_squiggle) {
1525                                         continue;
1526                                 }
1527                                 np = np2;
1528                         }
1529                 }
1530                         np->without_squiggle = true;
1531                         /* Add the suffix to the list */
1532                         dp = *insert_dep = ALLOC(Dependency);
1533                         insert_dep = &dp->next;
1534                         dp->next = NULL;
1535                         dp->name = np;
1536                         dp->built = false;
1537                 duplicate_suffix:;
1538                 }
1539         }
1540         if (trace_reader) {
1541                 (void) printf("\n");
1542         }
1543 }
1544 
1545 /*
1546  *      make_relative(to, result)
1547  *
1548  *      Given a file name compose a relative path name from it to the
1549  *      current directory.
1550  *
1551  *      Parameters:
1552  *              to              The path we want to make relative
1553  *              result          Where to put the resulting relative path
1554  *
1555  *      Global variables used:
1556  */
1557 static void
1558 make_relative(wchar_t *to, wchar_t *result)
1559 {
1560         wchar_t                 *from;
1561         wchar_t                 *allocated;
1562         wchar_t                 *cp;
1563         wchar_t                 *tocomp;
1564         int                     ncomps;
1565         int                     i;
1566         int                     len;
1567 
1568         /* Check if the path is already relative. */
1569         if (to[0] != (int) slash_char) {
1570                 (void) wscpy(result, to);
1571                 return;
1572         }
1573 
1574         MBSTOWCS(wcs_buffer, get_current_path());
1575         from = allocated = (wchar_t *) wsdup(wcs_buffer);
1576 
1577         /*
1578          * Find the number of components in the from name.
1579          * ncomp = number of slashes + 1.
1580          */
1581         ncomps = 1;
1582         for (cp = from; *cp != (int) nul_char; cp++) {
1583                 if (*cp == (int) slash_char) {
1584                         ncomps++;
1585                 }
1586         }
1587 
1588         /*
1589          * See how many components match to determine how many "..",
1590          * if any, will be needed.
1591          */
1592         result[0] = (int) nul_char;
1593         tocomp = to;
1594         while ((*from != (int) nul_char) && (*from == *to)) {
1595                 if (*from == (int) slash_char) {
1596                         ncomps--;
1597                         tocomp = &to[1];
1598                 }
1599                 from++;
1600                 to++;
1601         }
1602 
1603         /*
1604          * Now for some special cases. Check for exact matches and
1605          * for either name terminating exactly.
1606          */
1607         if (*from == (int) nul_char) {
1608                 if (*to == (int) nul_char) {
1609                         MBSTOWCS(wcs_buffer, ".");
1610                         (void) wscpy(result, wcs_buffer);
1611                         retmem(allocated);
1612                         return;
1613                 }
1614                 if (*to == (int) slash_char) {
1615                         ncomps--;
1616                         tocomp = &to[1];
1617                 }
1618         } else if ((*from == (int) slash_char) && (*to == (int) nul_char)) {
1619                 ncomps--;
1620                 tocomp = to;
1621         }
1622         /* Add on the ".."s. */
1623         for (i = 0; i < ncomps; i++) {
1624                 MBSTOWCS(wcs_buffer, "../");
1625                 (void) wscat(result, wcs_buffer);
1626         }
1627 
1628         /* Add on the remainder of the to name, if any. */
1629         if (*tocomp == (int) nul_char) {
1630                 len = wslen(result);
1631                 result[len - 1] = (int) nul_char;
1632         } else {
1633                 (void) wscat(result, tocomp);
1634         }
1635         retmem(allocated);
1636         return;
1637 }
1638 
1639 /*
1640  *      print_rule(command)
1641  *
1642  *      Used when tracing the reading of rules
1643  *
1644  *      Parameters:
1645  *              command         Command to print
1646  *
1647  *      Global variables used:
1648  */
1649 static void
1650 print_rule(register Cmd_line command)
1651 {
1652         for (; command != NULL; command = command->next) {
1653                 (void) printf("\t%s\n", command->command_line->string_mb);
1654         }
1655 }
1656 
1657 /*
1658  *      enter_conditional(target, name, value, append)
1659  *
1660  *      Enter "target := MACRO= value" constructs
1661  *
1662  *      Parameters:
1663  *              target          The target the macro is for
1664  *              name            The name of the macro
1665  *              value           The value for the macro
1666  *              append          Indicates if the assignment is appending or not
1667  *
1668  *      Global variables used:
1669  *              conditionals    A special Name that stores all conditionals
1670  *                              where the target is a % pattern
1671  *              trace_reader    Indicates that we should echo stuff we read
1672  */
1673 void
1674 enter_conditional(register Name target, Name name, Name value, register Boolean append)
1675 {
1676         register Property       conditional;
1677         static int              sequence;
1678         Name                    orig_target = target;
1679 
1680         if (name == target_arch) {
1681                 enter_conditional(target, virtual_root, virtual_root, false);
1682         }
1683 
1684         if (target->percent) {
1685                 target = conditionals;
1686         }
1687         
1688         if (name->colon) {
1689                 sh_transform(&name, &value);
1690         }
1691 
1692         /* Count how many conditionals we must activate before building the */
1693         /* target */
1694         if (target->percent) {
1695                 target = conditionals;
1696         }
1697 
1698         target->conditional_cnt++;
1699         maybe_append_prop(name, macro_prop)->body.macro.is_conditional = true;
1700         /* Add the property for the target */
1701         conditional = append_prop(target, conditional_prop);
1702         conditional->body.conditional.target = orig_target;
1703         conditional->body.conditional.name = name;
1704         conditional->body.conditional.value = value;
1705         conditional->body.conditional.sequence = sequence++;
1706         conditional->body.conditional.append = append;
1707         if (trace_reader) {
1708                 if (value == NULL) {
1709                         (void) printf("%s := %s %c=\n",
1710                                       target->string_mb,
1711                                       name->string_mb,
1712                                       append ?
1713                                       (int) plus_char : (int) space_char);
1714                 } else {
1715                         (void) printf("%s := %s %c= %s\n",
1716                                       target->string_mb,
1717                                       name->string_mb,
1718                                       append ?
1719                                       (int) plus_char : (int) space_char,
1720                                       value->string_mb);
1721                 }
1722         }
1723 }
1724 
1725 /*
1726  *      enter_equal(name, value, append)
1727  *
1728  *      Enter "MACRO= value" constructs
1729  *
1730  *      Parameters:
1731  *              name            The name of the macro
1732  *              value           The value for the macro
1733  *              append          Indicates if the assignment is appending or not
1734  *
1735  *      Global variables used:
1736  *              trace_reader    Indicates that we should echo stuff we read
1737  */
1738 void
1739 enter_equal(Name name, Name value, register Boolean append)
1740 {
1741         wchar_t         *string;
1742         Name            temp;
1743 
1744         if (name->colon) {
1745                 sh_transform(&name, &value);
1746         }
1747         (void) SETVAR(name, value, append);
1748 
1749         /* if we're setting FC, we want to set F77 to the same value. */
1750         Wstring nms(name);
1751         wchar_t * wcb = nms.get_string();
1752         string = wcb;
1753         if (string[0]=='F' &&
1754             string[1]=='C' &&
1755             string[2]=='\0') {
1756                 MBSTOWCS(wcs_buffer, NOCATGETS("F77"));
1757                 temp = GETNAME(wcs_buffer, FIND_LENGTH);
1758                 (void) SETVAR(temp, value, append);
1759 /*
1760                 fprintf(stderr, catgets(catd, 1, 111, "warning: FC is obsolete, use F77 instead\n"));
1761  */
1762         }
1763 
1764         if (trace_reader) {
1765                 if (value == NULL) {
1766                         (void) printf("%s %c=\n",
1767                                       name->string_mb,
1768                                       append ?
1769                                       (int) plus_char : (int) space_char);
1770                 } else {
1771                         (void) printf("%s %c= %s\n",
1772                                       name->string_mb,
1773                                       append ?
1774                                       (int) plus_char : (int) space_char,
1775                                       value->string_mb);
1776                 }
1777         }
1778 }
1779 
1780 /*
1781  *      sh_transform(name, value)
1782  *
1783  *      Parameters:
1784  *              name    The name of the macro we might transform
1785  *              value   The value to transform
1786  *
1787  */
1788 static void
1789 sh_transform(Name *name, Name *value)
1790 {
1791         /* Check if we need :sh transform */
1792         wchar_t         *colon;
1793         String_rec      command;
1794         String_rec      destination;
1795         wchar_t         buffer[1000];
1796         wchar_t         buffer1[1000];
1797 
1798         static wchar_t  colon_sh[4];
1799         static wchar_t  colon_shell[7];
1800 
1801         if (colon_sh[0] == (int) nul_char) {
1802                 MBSTOWCS(colon_sh, NOCATGETS(":sh"));
1803                 MBSTOWCS(colon_shell, NOCATGETS(":shell"));
1804         }
1805         Wstring nms((*name));
1806         wchar_t * wcb = nms.get_string();
1807 
1808         colon = (wchar_t *) wsrchr(wcb, (int) colon_char);
1809         if ((colon != NULL) && (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell))) {
1810                 INIT_STRING_FROM_STACK(destination, buffer);
1811 
1812                 if(*value == NULL) {
1813                         buffer[0] = 0;
1814                 } else {
1815                         Wstring wcb1((*value));
1816                         if (IS_WEQUAL(colon, colon_shell)) {
1817                                 INIT_STRING_FROM_STACK(command, buffer1);
1818                                 expand_value(*value, &command, false);
1819                         } else {
1820                                 command.text.p = wcb1.get_string() + (*value)->hash.length;
1821                                 command.text.end = command.text.p;
1822                                 command.buffer.start = wcb1.get_string();
1823                                 command.buffer.end = command.text.p;
1824                         }
1825                         sh_command2string(&command, &destination);
1826                 }
1827 
1828                 (*value) = GETNAME(destination.buffer.start, FIND_LENGTH);
1829                 *colon = (int) nul_char;
1830                 (*name) = GETNAME(wcb, FIND_LENGTH);
1831                 *colon = (int) colon_char;
1832         }
1833 }
1834 
1835 /*
1836  *      fatal_reader(format, args...)
1837  *
1838  *      Parameters:
1839  *              format          printf style format string
1840  *              args            arguments to match the format
1841  *
1842  *      Global variables used:
1843  *              file_being_read Name of the makefile being read
1844  *              line_number     Line that is being read
1845  *              report_pwd      Indicates whether current path should be shown
1846  *              temp_file_name  When reading tempfile we report that name
1847  */
1848 /*VARARGS*/
1849 void
1850 fatal_reader(char * pattern, ...)
1851 {
1852         va_list args;
1853         char    message[1000];
1854 
1855         va_start(args, pattern);
1856         if (file_being_read != NULL) {
1857                 WCSTOMBS(mbs_buffer, file_being_read);
1858                 if (line_number != 0) {
1859                         (void) sprintf(message,
1860                                        catgets(catd, 1, 112, "%s, line %d: %s"),
1861                                        mbs_buffer,
1862                                        line_number,
1863                                        pattern);
1864                 } else {
1865                         (void) sprintf(message,
1866                                        "%s: %s",
1867                                        mbs_buffer,
1868                                        pattern);
1869                 }
1870                 pattern = message;
1871         }
1872 
1873         (void) fflush(stdout);
1874 #ifdef DISTRIBUTED
1875         (void) fprintf(stderr, catgets(catd, 1, 113, "dmake: Fatal error in reader: "));
1876 #else
1877         (void) fprintf(stderr, catgets(catd, 1, 238, "make: Fatal error in reader: "));
1878 #endif
1879         (void) vfprintf(stderr, pattern, args);
1880         (void) fprintf(stderr, "\n");
1881         va_end(args);
1882 
1883         if (temp_file_name != NULL) {
1884                 (void) fprintf(stderr,
1885 #ifdef DISTRIBUTED
1886                                catgets(catd, 1, 114, "dmake: Temp-file %s not removed\n"),
1887 #else
1888                                catgets(catd, 1, 239, "make: Temp-file %s not removed\n"),
1889 #endif
1890                                temp_file_name->string_mb);
1891                 temp_file_name = NULL;
1892         }
1893 
1894         if (report_pwd) {
1895                 (void) fprintf(stderr,
1896                                catgets(catd, 1, 115, "Current working directory %s\n"),
1897                                get_current_path());
1898         }
1899         (void) fflush(stderr);
1900         exit_status = 1;
1901         exit(1);
1902 }
1903