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