"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/sunpro/Make/bin/make/common/read2.cc" (6 Sep 2021, 56302 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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