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