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