"Fossies" - the Fresh Open Source Software Archive

Member "schily-2021-09-18/sunpro/Make/bin/make/common/read.cc" (6 Sep 2021, 66606 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 2006 Sun Microsystems, Inc. All rights reserved.
   25  * Use is subject to license terms.
   26  */
   27 /*
   28  * @(#)read.cc 1.64 06/12/12
   29  */
   30 
   31 #pragma ident   "@(#)read.cc    1.64    06/12/12"
   32 
   33 /*
   34  * Copyright 2017-2021 J. Schilling
   35  *
   36  * @(#)read.cc  1.35 21/09/06 2017-2021 J. Schilling
   37  */
   38 #include <schily/mconfig.h>
   39 #ifndef lint
   40 static  UConst char sccsid[] =
   41     "@(#)read.cc    1.35 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 <avo/avo_alloca.h>     /* alloca() */
   54 #include <mk/defs.h>
   55 #include <mksh/macro.h>     /* expand_value(), expand_macro() */
   56 #include <mksh/misc.h>      /* getmem() */
   57 #include <mksh/read.h>      /* get_next_block_fn() */
   58 #include <sys/uio.h>        /* read() */
   59 
   60 #if defined(TEAMWARE_MAKE_CMN)
   61 #if defined(HP_UX) || defined(linux)
   62 #include <avo/types.h>
   63 extern "C" Avo_err *avo_find_run_dir(char **dirp);
   64 #endif
   65 #endif
   66 
   67 #include <schily/stdio.h>
   68 #include <schily/wchar.h>
   69 #include <schily/schily.h>
   70 
   71 /*
   72  * We cannot use "using std::wcsdup" as wcsdup() is not always
   73  * in the std namespace.
   74  * The Sun CC compiler in version 4 does not suport using namespace std;
   75  * so be careful.
   76  */
   77 #if !defined(__SUNPRO_CC_COMPAT) || __SUNPRO_CC_COMPAT >= 5
   78 using namespace std;        /* needed for wcsdup() */
   79 #endif
   80 
   81 /*
   82  * typedefs & structs
   83  */
   84 
   85 enum directive {
   86     D_NONE = 0,     /* No valid directive found */
   87     D_INCLUDE,      /* "include" directive found    */
   88     D_IINCLUDE,     /* "-include" directive found   */
   89     D_EXPORT,       /* "export" directive found */
   90     D_UNEXPORT,     /* "unexport" directive found   */
   91     D_READONLY      /* "readonly" directive found   */
   92 };
   93 
   94 /*
   95  * Static variables
   96  */
   97 
   98 static int line_started_with_space=0; // Used to diagnose spaces instead of tabs
   99 
  100 /*
  101  * Make sure that there is space for the null byte after the string.
  102  */
  103 static wchar_t      include_d[8+1];
  104 static wchar_t      iinclude_d[9+1];
  105 static wchar_t      export_d[7+1];
  106 static wchar_t      unexport_d[9+1];
  107 static wchar_t      readonly_d[9+1];
  108 
  109 static struct dent {
  110     wchar_t     *directive;
  111     int     dlen;
  112     enum directive  dir;
  113 } directives[] = {
  114     { include_d,    7, D_INCLUDE },
  115     { iinclude_d,   8, D_IINCLUDE },
  116     { export_d, 6, D_EXPORT },
  117     { unexport_d,   8, D_UNEXPORT },
  118     { readonly_d,   8, D_READONLY },
  119     { NULL,     0, D_NONE }
  120 };
  121 
  122 /*
  123  * File table of contents
  124  */
  125 static  void        parse_makefile(register Name true_makefile_name, register Source source);
  126 static  Source      push_macro_value(register Source bp, register wchar_t *buffer, int size, register Source source);
  127 extern  void        enter_target_groups_and_dependencies(Name_vector target, Name_vector depes, Cmd_line command, Separator separator, Boolean target_group_seen);
  128 extern  Name        normalize_name(register wchar_t *name_string, register int length);
  129 extern  void        doexport(Name name);
  130 extern  void        dounexport(Name name);
  131 extern  void        doreadonly(Name name);
  132 
  133 static Boolean      skip_comment(wchar_t * &source_p, wchar_t * &source_end, Source &source);
  134 static void     init_directives(void);
  135 
  136 /*
  137  *  read_simple_file(makefile_name, chase_path, doname_it,
  138  *       complain, must_exist, report_file, lock_makefile)
  139  *
  140  *  Make the makefile and setup to read it. Actually read it if it is stdio
  141  *
  142  *  Return value:
  143  *              false if the read failed
  144  *
  145  *  Parameters:
  146  *      makefile_name   Name of the file to read
  147  *      chase_path  Use the makefile path when opening file
  148  *      doname_it   Call doname() to build the file first
  149  *      complain    Print message if doname/open fails
  150  *      must_exist  Generate fatal if file is missing
  151  *      report_file Report file when running -P
  152  *      lock_makefile   Lock the makefile when reading
  153  *
  154  *  Static variables used:
  155  *
  156  *  Global variables used:
  157  *      do_not_exec_rule Is -n on?
  158  *      file_being_read Set to the name of the new file
  159  *      line_number The number of the current makefile line
  160  *      makefiles_used  A list of all makefiles used, appended to
  161  */
  162 
  163 
  164 Boolean
  165 read_simple_file(register Name makefile_name, register Boolean chase_path, register Boolean doname_it, Boolean complain, Boolean must_exist, Boolean report_file, Boolean lock_makefile, Boolean is_include)
  166 {
  167     static short        max_include_depth;
  168     register Property   makefile = maybe_append_prop(makefile_name,
  169                                  makefile_prop);
  170     Boolean         forget_after_parse = false;
  171     static pathpt       makefile_path;
  172     register int        n;
  173     char            *path;
  174     register Source     source = ALLOC(Source);
  175     Property        orig_makefile = makefile;
  176     Dependency      *dpp;
  177     Dependency      dp;
  178     register int        length;
  179     wchar_t         *previous_file_being_read = file_being_read;
  180     int         previous_line_number = line_number;
  181     wchar_t         previous_current_makefile[MAXPATHLEN];
  182     Makefile_type       save_makefile_type;
  183     Name            normalized_makefile_name;
  184     register wchar_t        *string_start;
  185     register wchar_t        *string_end;
  186     char                    *run_dir, makerules_dir[BUFSIZ];
  187 
  188 
  189 #if defined(TEAMWARE_MAKE_CMN)
  190 #if defined(HP_UX) || defined(linux)
  191     Avo_err                 *findrundir_err;
  192 #endif
  193 #endif
  194 
  195     wchar_t * wcb = get_wstring(makefile_name->string_mb);
  196 
  197 #ifdef NSE
  198     if (report_file){
  199         wcscpy(previous_current_makefile, current_makefile);
  200         wcscpy(current_makefile, wcb);
  201     }
  202 #endif 
  203     if (max_include_depth++ >= 40) {
  204         fatal(gettext("Too many nested include statements"));
  205     }
  206     if (makefile->body.makefile.contents != NULL) {
  207         retmem(makefile->body.makefile.contents);
  208     }
  209     source->inp_buf =
  210       source->inp_buf_ptr =
  211         source->inp_buf_end = NULL;
  212     source->error_converting = false;
  213     makefile->body.makefile.contents = NULL;
  214     makefile->body.makefile.size = 0;
  215     if ((makefile_name->hash.length != 1) ||
  216         (wcb[0] != (int) hyphen_char)) {
  217         if ((makefile->body.makefile.contents == NULL) &&
  218             (doname_it)) {
  219             if (makefile_path == NULL) {
  220                 add_dir_to_path(".",
  221                         &makefile_path,
  222                         -1);
  223 #if !defined(TEAMWARE_MAKE_CMN)
  224                         run_dir = make_run_dir;
  225                 if (run_dir) {
  226                     if (strstr(run_dir, "xpg4/bin") ||
  227                         strstr(run_dir, "/onbld/")) {
  228                                     (void) sprintf(makerules_dir,
  229                         NOCATGETS("%s/../../share/lib/make"), run_dir);
  230                     } else {
  231                                     (void) sprintf(makerules_dir,
  232                         NOCATGETS("%s/../share/lib/make"), run_dir);
  233                     }
  234                     add_dir_to_path(makerules_dir,
  235                             &makefile_path,
  236                             -1);
  237                 }
  238 #ifdef INS_BASE
  239                 add_dir_to_path(NOCATGETS(INS_BASE "/share/lib/make"),
  240                         &makefile_path,
  241                         -1);
  242 #endif
  243                 add_dir_to_path(NOCATGETS("/usr/share/lib/make"),
  244                         &makefile_path,
  245                         -1);
  246                 add_dir_to_path(NOCATGETS("/etc/default"),
  247                         &makefile_path,
  248                         -1);
  249 #else
  250 #ifdef SUN5_0
  251                 add_dir_to_path(NOCATGETS("/usr/share/lib/make"),
  252                         &makefile_path,
  253                         -1);
  254                 add_dir_to_path(NOCATGETS("/etc/default"),
  255                         &makefile_path,
  256                         -1);
  257 #elif defined(HP_UX)
  258                         findrundir_err = avo_find_run_dir(&run_dir);
  259                         if (! findrundir_err) {
  260                                 (void) sprintf(makerules_dir, NOCATGETS("%s/../share/lib/make"), run_dir);
  261                     add_dir_to_path(makerules_dir,
  262                             &makefile_path,
  263                             -1);
  264                         }
  265 
  266                 add_dir_to_path(NOCATGETS("/opt/SUNWspro/share/lib/make"),
  267                         &makefile_path,
  268                         -1);
  269                 add_dir_to_path(NOCATGETS("/usr/share/lib/make"),
  270                         &makefile_path,
  271                         -1);
  272 #elif defined(linux)
  273                         findrundir_err = avo_find_run_dir(&run_dir);
  274                         if (! findrundir_err) {
  275                                 (void) sprintf(makerules_dir, NOCATGETS("%s/../lib"), run_dir);
  276                     add_dir_to_path(makerules_dir,
  277                             &makefile_path,
  278                             -1);
  279                         }
  280 
  281                 add_dir_to_path(NOCATGETS("/usr/SUNWspro/lib"),
  282                         &makefile_path,
  283                         -1);
  284                 add_dir_to_path(NOCATGETS("/opt/SUNWspro/share/lib/make"),
  285                         &makefile_path,
  286                         -1);
  287                 add_dir_to_path(NOCATGETS("/usr/share/lib/make"),
  288                         &makefile_path,
  289                         -1);
  290 #else
  291                 add_dir_to_path(NOCATGETS("/usr/include/make"),
  292                         &makefile_path,
  293                         -1);
  294 #endif
  295 #endif
  296             }
  297             save_makefile_type = makefile_type;
  298             makefile_type = reading_nothing;
  299             if (doname(makefile_name, true, false) == build_dont_know) {
  300                 /* Try normalized filename */
  301                 string_start=get_wstring(makefile_name->string_mb);
  302                 for (string_end=string_start+1; *string_end != '\0'; string_end++);
  303                 normalized_makefile_name=normalize_name(string_start, string_end - string_start);
  304                 if ((strcmp(makefile_name->string_mb, normalized_makefile_name->string_mb) == 0) || 
  305                     (doname(normalized_makefile_name, true, false) == build_dont_know)) {
  306                     n = access_vroot(makefile_name->string_mb,
  307                          4,
  308                          chase_path ?
  309                          makefile_path : NULL,
  310                          VROOT_DEFAULT);
  311                     if (n == 0) {
  312                         get_vroot_path((char **) NULL,
  313                                &path,
  314                                (char **) NULL);
  315                         if ((path[0] == (int) period_char) &&
  316                             (path[1] == (int) slash_char)) {
  317                             path += 2;
  318                         }
  319                         MBSTOWCS(wcs_buffer, path);
  320                         makefile_name = GETNAME(wcs_buffer,
  321                                 FIND_LENGTH);
  322                     }
  323                 }
  324                 retmem(string_start);
  325                 /* 
  326                  * Commented out: retmem_mb(normalized_makefile_name->string_mb);
  327                  * We have to return this memory, but it seems to trigger a bug
  328                  * in dmake or in Sun C++ 5.7 compiler (it works ok if this code
  329                  * is compiled using Sun C++ 5.6).
  330                  */
  331                 // retmem_mb(normalized_makefile_name->string_mb); 
  332             }
  333             makefile_type = save_makefile_type;
  334         }
  335         source->string.free_after_use = false;
  336         source->previous = NULL;
  337         source->already_expanded = false;
  338         /* Lock the file for read, but not when -n. */
  339         if (lock_makefile && 
  340             !do_not_exec_rule) {
  341 
  342              make_state_lockfile = getmem(strlen(make_state->string_mb) + strlen(NOCATGETS(".lock")) + 1);
  343              (void) sprintf(make_state_lockfile,
  344                         NOCATGETS("%s.lock"),
  345                         make_state->string_mb);
  346             (void) file_lock(make_state->string_mb,
  347                      make_state_lockfile,
  348                      (int *) &make_state_locked,
  349                      0);
  350             if(!make_state_locked) {
  351                 printf(NOCATGETS("-- NO LOCKING for read\n"));
  352                 retmem_mb(make_state_lockfile);
  353                 make_state_lockfile = 0;
  354                 return failed;
  355             }
  356         }
  357         if (makefile->body.makefile.contents == NULL) {
  358             save_makefile_type = makefile_type;
  359             makefile_type = reading_nothing;
  360             if ((doname_it) &&
  361                 (doname(makefile_name, true, false) == build_failed)) {
  362                 if (complain) {
  363                     (void) fprintf(stderr,
  364 #ifdef DISTRIBUTED
  365                                gettext("dmake: Couldn't dmake `%s'\n"),
  366 #else
  367                                gettext("make: Couldn't make `%s'\n"),
  368 #endif
  369                                makefile_name->string_mb);
  370                 }
  371                 max_include_depth--;
  372                 makefile_type = save_makefile_type;
  373                 return failed;
  374             }
  375             makefile_type = save_makefile_type;
  376             //
  377             // Before calling exists() make sure that we have the right timestamp
  378             //
  379             makefile_name->stat.time = file_no_time;
  380 #ifdef  DO_INCLUDE_FAILED
  381             /*
  382              * Only call rule commands for "include", not for
  383              * "-include". This is the case if "complain" is true.
  384              */
  385             if (is_include && complain && include_failed &&
  386                 exists(makefile_name) == file_doesnt_exist) {
  387                 register Property   line;
  388 
  389                 if ((line = get_prop(include_failed_name->prop, line_prop)) != NULL &&
  390                     line->body.line.command_template) {
  391                     struct _Dependency  dep;
  392 
  393                     dep.next = NULL;
  394                     dep.name = makefile_name;
  395                     dep.automatic = dep.stale = dep.built = false;
  396                     line->body.line.dependencies = &dep;    /* Set up $^ */
  397                     makefile_name->stat.time = file_max_time;
  398                     doname(include_failed_name, false, false);
  399                     line->body.line.dependencies = NULL;
  400                     makefile_name->stat.time = file_no_time;
  401                 }
  402             }
  403 #endif
  404 
  405             if (exists(makefile_name) == file_doesnt_exist) {
  406                 if (complain ||
  407                     (makefile_name->stat.stat_errno != ENOENT)) {
  408                     if (must_exist) {
  409                         fatal(gettext("Can't find `%s': %s"),
  410                               makefile_name->string_mb,
  411                               errmsg(makefile_name->
  412                                  stat.stat_errno));
  413                     } else {
  414                         warning(gettext("Can't find `%s': %s"),
  415                             makefile_name->string_mb,
  416                             errmsg(makefile_name->
  417                                    stat.stat_errno));
  418                     }
  419                 }
  420                 max_include_depth--;
  421                 if(make_state_locked && (make_state_lockfile != NULL)) {
  422                     (void) unlink(make_state_lockfile);
  423                     retmem_mb(make_state_lockfile);
  424                     make_state_lockfile = NULL;
  425                     make_state_locked = false;
  426                 }
  427                 retmem(wcb);
  428                 retmem_mb((char *)source);
  429                 return failed;
  430             }
  431             /*
  432              * These values are the size and bytes of
  433              * the MULTI-BYTE makefile.
  434              */
  435             orig_makefile->body.makefile.size =
  436               makefile->body.makefile.size =
  437                 source->bytes_left_in_file =
  438                   makefile_name->stat.size;
  439             if (report_file) {
  440                 for (dpp = &makefiles_used;
  441                      *dpp != NULL;
  442                      dpp = &(*dpp)->next);
  443                 dp = ALLOC(Dependency);
  444                 dp->next = NULL;
  445                 dp->name = makefile_name;
  446                 dp->automatic = false;
  447                 dp->stale = false;
  448                 dp->built = false;
  449                 *dpp = dp;
  450             }
  451             source->fd = open_vroot(makefile_name->string_mb,
  452                         O_RDONLY,
  453                         0,
  454                         NULL,
  455                         VROOT_DEFAULT);
  456             if (source->fd < 0) {
  457                 if (complain || (errno != ENOENT)) {
  458                     if (must_exist) {
  459                         fatal(gettext("Can't open `%s': %s"),
  460                               makefile_name->string_mb,
  461                               errmsg(errno));
  462                     } else {
  463                         warning(gettext("Can't open `%s': %s"),
  464                             makefile_name->string_mb,
  465                             errmsg(errno));
  466                     }
  467                 }
  468                 max_include_depth--;
  469                 return failed;
  470             }
  471             (void) fcntl(source->fd, F_SETFD, 1);
  472             orig_makefile->body.makefile.contents =
  473               makefile->body.makefile.contents =
  474                 source->string.text.p =
  475                   source->string.buffer.start =
  476                 ALLOC_WC((int) (makefile_name->stat.size + 2));
  477             if (makefile_type == reading_cpp_file) {
  478                 forget_after_parse = true;
  479             }
  480             source->string.text.end = source->string.text.p;
  481             source->string.buffer.end =
  482               source->string.text.p + makefile_name->stat.size;
  483         } else {
  484             /* Do we ever reach here? */
  485             source->fd = -1;
  486             source->string.text.p =
  487               source->string.buffer.start =
  488                 makefile->body.makefile.contents;
  489             source->string.text.end =
  490               source->string.buffer.end =
  491                 source->string.text.p + makefile->body.makefile.size;
  492             source->bytes_left_in_file =
  493               makefile->body.makefile.size;
  494         }
  495         file_being_read = wcb;
  496     } else {
  497         char        *stdin_text_p;
  498         char        *stdin_text_end;
  499         char        *stdin_buffer_start;
  500         char        *stdin_buffer_end;
  501         char        *p_mb;
  502         int     num_mb_chars;
  503         size_t      num_wc_chars;
  504 
  505         MBSTOWCS(wcs_buffer, NOCATGETS("Standard in"));
  506         makefile_name = GETNAME(wcs_buffer, FIND_LENGTH);
  507         /*
  508          * Memory to read standard in, then convert it
  509          * to wide char strings.
  510          */
  511         stdin_buffer_start =
  512           stdin_text_p = getmem(length = 1024);
  513         stdin_buffer_end = stdin_text_p + length;
  514         MBSTOWCS(wcs_buffer, NOCATGETS("standard input"));
  515         file_being_read = (wchar_t *) wcsdup(wcs_buffer);
  516         line_number = 0;
  517         while ((n = read(fileno(stdin),
  518                  stdin_text_p,
  519                  length)) > 0) {
  520             length -= n;
  521             stdin_text_p += n;
  522             if (length == 0) {
  523                 p_mb = getmem(length = 1024 +
  524                           (stdin_buffer_end -
  525                            stdin_buffer_start));
  526                 (void) strncpy(p_mb,
  527                            stdin_buffer_start,
  528                            (stdin_buffer_end -
  529                             stdin_buffer_start));
  530                 retmem_mb(stdin_buffer_start);
  531                 stdin_text_p = p_mb +
  532                   (stdin_buffer_end - stdin_buffer_start);
  533                 stdin_buffer_start = p_mb;
  534                 stdin_buffer_end =
  535                   stdin_buffer_start + length;
  536                 length = 1024;
  537             }
  538         }
  539         if (n < 0) {
  540             fatal(gettext("Error reading standard input: %s"),
  541                   errmsg(errno));
  542         }
  543         stdin_text_p = stdin_buffer_start;
  544         stdin_text_end = stdin_buffer_end - length;
  545         num_mb_chars = stdin_text_end - stdin_text_p;
  546 
  547         /*
  548          * Now, convert the sequence of multibyte chars into
  549          * a sequence of corresponding wide character codes.
  550          */
  551         source->string.free_after_use = false;
  552         source->previous = NULL;
  553         source->bytes_left_in_file = 0;
  554         source->fd = -1;
  555         source->already_expanded = false;
  556         source->string.buffer.start =
  557           source->string.text.p = ALLOC_WC(num_mb_chars + 1);
  558         source->string.buffer.end =
  559             source->string.text.p + num_mb_chars;
  560         num_wc_chars = mbstowcs(source->string.text.p,
  561                     stdin_text_p,
  562                     num_mb_chars);
  563         if ((int) num_wc_chars >= 0) {
  564             source->string.text.end =
  565               source->string.text.p + num_wc_chars;
  566         }
  567         (void) retmem_mb(stdin_text_p);
  568     }
  569     line_number = 1;
  570     if (trace_reader) {
  571         (void) printf(gettext(">>>>>>>>>>>>>>>> Reading makefile %s\n"),
  572                   makefile_name->string_mb);
  573     }
  574     parse_makefile(makefile_name, source);
  575     if (trace_reader) {
  576         (void) printf(gettext(">>>>>>>>>>>>>>>> End of makefile %s\n"),
  577                   makefile_name->string_mb);
  578     }
  579 #ifdef NSE
  580     if (report_file && (previous_current_makefile[0] != NULL)) {
  581         wcscpy(current_makefile, previous_current_makefile);
  582     }
  583 #endif
  584     if(file_being_read) {
  585         retmem(file_being_read);
  586     }
  587     file_being_read = previous_file_being_read;
  588     line_number = previous_line_number;
  589     makefile_type = reading_nothing;
  590     max_include_depth--;
  591     if (make_state_locked) {
  592         /* Unlock .make.state. */
  593         unlink(make_state_lockfile);
  594         make_state_locked = false;
  595         retmem_mb(make_state_lockfile);
  596     }
  597     if (forget_after_parse) {
  598         retmem(makefile->body.makefile.contents);
  599         makefile->body.makefile.contents = NULL;
  600     }
  601     retmem_mb((char *)source);
  602     return succeeded;
  603 }
  604 
  605 /*
  606  *  parse_makefile(true_makefile_name, source)
  607  *
  608  *  Strings are read from Sources.
  609  *  When macros are found, their values are represented by a
  610  *  Source that is pushed on a stack. At end of string
  611  *  (that is returned from GET_CHAR() as 0), the block is popped.
  612  *
  613  *  Parameters:
  614  *      true_makefile_name  The name of makefile we are parsing
  615  *      source          The source block to read from
  616  *
  617  *  Global variables used:
  618  *      do_not_exec_rule Is -n on?
  619  *      line_number The number of the current makefile line
  620  *      makefile_type   What kind of makefile are we reading?
  621  *      empty_name  The Name ""
  622  */
  623 static void
  624 parse_makefile(register Name true_makefile_name, register Source source)
  625 {
  626 /*
  627     char            mb_buffer[MB_LEN_MAX];
  628  */
  629     register wchar_t    *source_p;
  630     register wchar_t    *source_end;
  631     register wchar_t    *string_start;
  632     wchar_t         *string_end;
  633     register Boolean    macro_seen_in_string;
  634     Boolean         append;
  635     Boolean         expand;
  636     String_rec      name_string;
  637     wchar_t         name_buffer[STRING_BUFFER_LENGTH];
  638     register int        distance;
  639     register int        paren_count;
  640     int         brace_count;
  641     int         char_number;
  642     Cmd_line        command;
  643     Cmd_line        command_tail;
  644     Name            macro_value;
  645 
  646     Name_vector_rec     target;
  647     Name_vector_rec     depes;
  648     Name_vector_rec     extra_name_vector;
  649     Name_vector     current_names;
  650     Name_vector     extra_names = &extra_name_vector;
  651     Name_vector     nvp;
  652     Boolean         target_group_seen;
  653 
  654     register Reader_state   state;
  655     register Reader_state   on_eoln_state;
  656     register Separator  separator;
  657 
  658     wchar_t                 buffer[4 * STRING_BUFFER_LENGTH];
  659     Source          extrap;
  660 
  661     Boolean                 save_do_not_exec_rule = do_not_exec_rule;
  662     Name                    makefile_name;
  663     Name                    makefile_name_raw;
  664 
  665     static Name     sh_name;
  666     static Name     shell_name;
  667     int         i;
  668 
  669     int         tmp_bytes_left_in_string;
  670     Boolean         tmp_maybe_directive = false;
  671     int             emptycount = 0;
  672     Boolean         first_target;
  673 
  674     enum directive      directive_type; 
  675     int         directive_len;
  676     struct dent     *dp;
  677 
  678     String_rec      include_name;
  679     wchar_t         include_buffer[STRING_BUFFER_LENGTH];
  680 
  681     target.next = depes.next = NULL;
  682     /* Move some values from their struct to register declared locals */
  683     CACHE_SOURCE(0);
  684 
  685  start_new_line:
  686     /*
  687      * Read whitespace on old line. Leave pointer on first char on
  688      * next line.
  689      */
  690     first_target = true;
  691     on_eoln_state = exit_state;
  692 /*
  693     for (WCTOMB(mb_buffer, GET_CHAR());
  694          1;
  695          source_p++, WCTOMB(mb_buffer, GET_CHAR()))
  696         switch (mb_buffer[0]) {
  697  */
  698     for (char_number=0; 1; source_p++,char_number++) switch (GET_CHAR()) {
  699     case nul_char:
  700         /* End of this string. Pop it and return to the previous one */
  701         GET_NEXT_BLOCK(source);
  702         source_p--;
  703         if (source == NULL) {
  704             GOTO_STATE(on_eoln_state);
  705         }
  706         break;
  707     case newline_char:
  708     end_of_line:
  709         source_p++;
  710         if (source->fd >= 0) {
  711             line_number++;
  712         }
  713         switch (GET_CHAR()) {
  714         case nul_char:
  715             GET_NEXT_BLOCK(source);
  716             if (source == NULL) {
  717                 GOTO_STATE(on_eoln_state);
  718             }
  719             /* Go back to the top of this loop */
  720             goto start_new_line;
  721         case newline_char:
  722         case numbersign_char:
  723         case dollar_char:
  724         case space_char:
  725         case tab_char:
  726             /*
  727              * Go back to the top of this loop since the
  728              * new line does not start with a regular char.
  729              */
  730             goto start_new_line;
  731         default:
  732             /* We found the first proper char on the new line */
  733             goto start_new_line_no_skip;
  734         }
  735     case space_char:
  736         if (char_number == 0)
  737             line_started_with_space=line_number;
  738     case tab_char:
  739         /* Whitespace. Just keep going in this loop */
  740         break;
  741     case numbersign_char:
  742         /* Comment. Skip over it */
  743         if (skip_comment(source_p, source_end, source) == false) {
  744             GOTO_STATE(on_eoln_state);
  745         }
  746         /*
  747          * After we skip the comment we go to
  748          * the end of line handler since end of
  749          * line terminates comments.
  750          */
  751         goto end_of_line;
  752     case dollar_char:
  753         /* Macro reference */
  754         if (source->already_expanded) {
  755             /*
  756              * If we are reading from the expansion of a
  757              * macro we already expanded everything enough.
  758              */
  759             goto start_new_line_no_skip;
  760         }
  761         /*
  762          * Expand the value and push the Source on the stack of
  763          * things being read.
  764          */
  765         source_p++;
  766         UNCACHE_SOURCE();
  767         {
  768             Source t = (Source) alloca((int) sizeof (Source_rec));
  769             source = push_macro_value(t,
  770                           buffer,
  771                           sizeof buffer,
  772                           source);
  773         }
  774         CACHE_SOURCE(1);
  775         break;
  776     default:
  777         /* We found the first proper char on the new line */
  778         goto start_new_line_no_skip;
  779     }
  780 
  781     /*
  782      * We found the first normal char (one that starts an identifier)
  783      * on the newline.
  784      */
  785 start_new_line_no_skip:
  786     /* Inspect that first char to see if it maybe is special anyway */
  787     switch (GET_CHAR()) {
  788     case nul_char:
  789         GET_NEXT_BLOCK(source);
  790         if (source == NULL) {
  791             GOTO_STATE(on_eoln_state);
  792         }
  793         goto start_new_line_no_skip;
  794     case newline_char:
  795         /* Just in case */
  796         goto start_new_line;
  797     case exclam_char:
  798         /* Evaluate the line before it is read */
  799         string_start = source_p + 1;
  800         macro_seen_in_string = false;
  801         /* Stuff the line in a string so we can eval it. */
  802         for (; 1; source_p++) {
  803             switch (GET_CHAR()) {
  804             case newline_char:
  805                 goto eoln_1;
  806             case nul_char:
  807                 if (source->fd > 0) {
  808                     if (!macro_seen_in_string) {
  809                         macro_seen_in_string = true;
  810                         INIT_STRING_FROM_STACK(
  811                               name_string, name_buffer);
  812                     }
  813                     append_string(string_start,
  814                               &name_string,
  815                               source_p - string_start);
  816                     GET_NEXT_BLOCK(source);
  817                     string_start = source_p;
  818                     source_p--;
  819                     break;
  820                 }
  821             eoln_1:
  822                 if (!macro_seen_in_string) {
  823                     INIT_STRING_FROM_STACK(name_string,
  824                                    name_buffer);
  825                 }
  826                 append_string(string_start,
  827                           &name_string,
  828                           source_p - string_start);
  829                 extrap = (Source)
  830                   alloca((int) sizeof (Source_rec));
  831                 extrap->string.buffer.start = NULL;
  832                 extrap->inp_buf =
  833                   extrap->inp_buf_ptr =
  834                     extrap->inp_buf_end = NULL;
  835                 extrap->error_converting = false;
  836                 if (*source_p == (int) nul_char) {
  837                     source_p++;
  838                 }
  839                 /* Eval the macro */
  840                 expand_value(GETNAME(name_string.buffer.start,
  841                              FIND_LENGTH),
  842                          &extrap->string,
  843                          false);
  844                 if (name_string.free_after_use) {
  845                     retmem(name_string.buffer.start);
  846                 }
  847                 UNCACHE_SOURCE();
  848                 extrap->string.text.p =
  849                   extrap->string.buffer.start;
  850                 extrap->fd = -1;
  851                 /* And push the value */
  852                 extrap->previous = source;
  853                 source = extrap;
  854                 CACHE_SOURCE(0);
  855                 goto line_evald;
  856             }
  857         }
  858     default:
  859         goto line_evald;
  860     }
  861 
  862     /* We now have a line we can start reading */
  863  line_evald:
  864     if (source == NULL) {
  865         GOTO_STATE(exit_state);
  866     }
  867     /* Check if this is a directive command */
  868     if ((makefile_type == reading_makefile) &&
  869         !source->already_expanded) {
  870 
  871         if (include_d[0] == (int) nul_char)
  872         init_directives();
  873 
  874         directive_len = 0;
  875         directive_type = D_NONE;
  876         for (dp = directives; dp->directive; dp++) {
  877         if (IS_WEQUALN(source_p, dp->directive, dp->dlen)) {
  878             if (source_p[dp->dlen] == (int)space_char ||
  879                 source_p[dp->dlen] == (int)tab_char) {
  880                 directive_len = dp->dlen;
  881                 directive_type = dp->dir;
  882                 break;
  883             }
  884         }
  885         if (sunpro_compat)
  886             break;
  887         }
  888 
  889         if (directive_type) {
  890         source_p += directive_len;
  891     try_next_include:   /* More than one include name on the line? */
  892 
  893         if (!sunpro_compat && *source_p == numbersign_char)
  894             goto start_new_line;
  895         if (iswspace(*source_p)) {
  896             Makefile_type save_makefile_type;
  897             wchar_t     *name_start;
  898             int     name_length;
  899             String_rec  destination;
  900 
  901             /*
  902              * Yes, this is an include.
  903              * Skip spaces to get to the filename.
  904              */
  905             while (iswspace(*source_p) ||
  906                    (*source_p == (int) nul_char)) {
  907                 switch (GET_CHAR()) {
  908                 case newline_char:
  909                     goto start_new_line;
  910 
  911                 case nul_char:
  912                     GET_NEXT_BLOCK(source);
  913                     if (source == NULL) {
  914                         GOTO_STATE(on_eoln_state);
  915                     }
  916                     break;
  917 
  918                 default:
  919                     source_p++;
  920                     break;
  921                 }
  922             }
  923 
  924             string_start = source_p;
  925             /* Find the end of the filename */
  926             macro_seen_in_string = false;
  927             while (!iswspace(*source_p) ||
  928                    (*source_p == (int) nul_char)) {
  929                 switch (GET_CHAR()) {
  930                 case nul_char:
  931                     if (!macro_seen_in_string) {
  932                         INIT_STRING_FROM_STACK(name_string,
  933                                        name_buffer);
  934                     }
  935                     append_string(string_start,
  936                               &name_string,
  937                               source_p - string_start);
  938                     macro_seen_in_string = true;
  939                     GET_NEXT_BLOCK(source);
  940                     string_start = source_p;
  941                     if (source == NULL) {
  942                         GOTO_STATE(on_eoln_state);
  943                     }
  944                     break;
  945 
  946                     case numbersign_char:
  947                     if (!sunpro_compat) {
  948                         if (source_p == string_start)
  949                             goto start_new_line;
  950                         goto string_end;
  951                     }
  952 
  953                 default:
  954                     source_p++;
  955                     break;
  956                 }
  957             }
  958 
  959     string_end:
  960             source->string.text.p = source_p;
  961             if (macro_seen_in_string) {
  962                 append_string(string_start,
  963                           &name_string,
  964                           source_p - string_start);
  965                 name_start = name_string.buffer.start;
  966                 name_length = name_string.text.p - name_start;
  967             } else {
  968                 name_start = string_start;
  969                 name_length = source_p - string_start;
  970             }
  971 
  972             /* Strip "./" from the head of the name */
  973             if ((name_start[0] == (int) period_char) &&
  974                    (name_start[1] == (int) slash_char)) {
  975                 name_start += 2;
  976                 name_length -= 2;
  977             }
  978             /* if include file name is surrounded by double quotes */
  979             if ((name_start[0] == (int) doublequote_char) &&
  980                 (name_start[name_length - 1] == (int) doublequote_char)) {
  981                     name_start += 1;
  982                     name_length -= 2;
  983 
  984                     /* if name does not begin with a slash char */
  985                     if (name_start[0] != (int) slash_char) {
  986                     if ((name_start[0] == (int) period_char) &&
  987                         (name_start[1] == (int) slash_char)) {
  988                         name_start += 2;
  989                         name_length -= 2;
  990                     }
  991 
  992                     INIT_STRING_FROM_STACK(include_name, include_buffer);
  993                     APPEND_NAME(true_makefile_name,
  994                               &include_name,
  995                               true_makefile_name->hash.length);
  996 
  997                     wchar_t *slash = wcsrchr(include_name.buffer.start, (int) slash_char);
  998                     if (slash != NULL) {
  999                         include_name.text.p = slash + 1;
 1000                         append_string(name_start,
 1001                                   &include_name,
 1002                                   name_length);
 1003 
 1004                         name_start = include_name.buffer.start;
 1005                         name_length = include_name.text.p - name_start; 
 1006                     }
 1007                 }
 1008             }
 1009 
 1010             /* Even when we run -n we want to create makefiles */
 1011             do_not_exec_rule = false;
 1012             makefile_name_raw = GETNAME(name_start, name_length);
 1013             if (makefile_name_raw->dollar) {
 1014                 wchar_t     buffer[STRING_BUFFER_LENGTH];
 1015                 wchar_t     *p;
 1016                 wchar_t     *q;
 1017 
 1018                 INIT_STRING_FROM_STACK(destination, buffer);
 1019                 expand_value(makefile_name_raw,
 1020                          &destination,
 1021                          false);
 1022 
 1023                 destination.text.p = destination.buffer.start;
 1024             next_in_var:
 1025                 for (p = destination.text.p;
 1026                      (*p != (int) nul_char) && iswspace(*p);
 1027                      p++);
 1028                 for (q = p;
 1029                      (*q != (int) nul_char) && !iswspace(*q);
 1030                      q++);
 1031                 destination.text.p = q;
 1032 
 1033                 makefile_name = GETNAME(p, q-p);
 1034                 if (destination.text.p >= destination.text.end &&
 1035                     destination.free_after_use) {
 1036                     /*
 1037                      * Free it after we did a complete
 1038                      * parsing of the macro value.
 1039                      */
 1040                     retmem(destination.buffer.start);
 1041                 }
 1042             } else {
 1043                 makefile_name = makefile_name_raw;
 1044             }
 1045             switch (directive_type) {
 1046 
 1047             case D_INCLUDE:
 1048             case D_IINCLUDE:
 1049                 UNCACHE_SOURCE();
 1050                 /* Read the file */
 1051                 save_makefile_type = makefile_type;
 1052                 /*
 1053                  * The original make program from Sun did complain with:
 1054                  * FOO=
 1055                  * include $(FOO)
 1056                  * but this is in conflict with the behavior of smake
 1057                  * and gmake and it would cause prolems if we allow
 1058                  * $(FOO) to expand to more than one incude file name.
 1059                  * So let us be quiet with empty includes.
 1060                  */
 1061                 if (*makefile_name->string_mb != nul_char &&
 1062                     read_simple_file(makefile_name,
 1063                          true,
 1064                          true,
 1065                          directive_type == D_IINCLUDE ? false:true,
 1066                          false,
 1067                          true,
 1068                          false,
 1069                          true) == failed && directive_type != D_IINCLUDE) {
 1070                     fatal_reader(gettext("Read of include file `%s' failed"),
 1071                          makefile_name->string_mb);
 1072                 }
 1073                 makefile_type = save_makefile_type;
 1074                 do_not_exec_rule = save_do_not_exec_rule;
 1075                 CACHE_SOURCE(0);
 1076                 break;
 1077 
 1078             case D_EXPORT:
 1079                 doexport(makefile_name);
 1080                 break;
 1081             case D_UNEXPORT:
 1082                 dounexport(makefile_name);
 1083                 break;
 1084             case D_READONLY:
 1085                 doreadonly(makefile_name);
 1086                 break;
 1087             case D_NONE:
 1088                 /*
 1089                  * Since we checked for directive_type != 0
 1090                  * before, this cannot happen, but it makes
 1091                  * clang quiet.
 1092                  */
 1093                 break;
 1094             }
 1095             if (sunpro_compat) {
 1096                 source_p++;
 1097                 goto start_new_line;
 1098             }
 1099             if (makefile_name != makefile_name_raw) {
 1100                 /*
 1101                  * The "makefile_name" is not from a line in
 1102                  * Makefile, but from a macro expansion. Check
 1103                  * whether there may be more names in the value
 1104                  * of that macro.
 1105                  */
 1106                 if (destination.text.p < destination.text.end)
 1107                     goto next_in_var;
 1108             }
 1109             if (*source_p != newline_char) {
 1110                 /*
 1111                  * The next character after the filename in the
 1112                  * include directive was not a newline, there
 1113                  * may be more names in that directive line.
 1114                  */
 1115                 goto try_next_include;
 1116             }
 1117             source_p++;
 1118             goto start_new_line;
 1119         } else {
 1120             source_p -= directive_len;
 1121         }
 1122         } else {
 1123         /* Check if the directive text was split across 8K boundary. */
 1124         
 1125         tmp_bytes_left_in_string = source->string.text.end - source_p;
 1126         if (tmp_bytes_left_in_string < 9) {
 1127             struct dent *dp;
 1128 
 1129             tmp_maybe_directive = false;
 1130             for (dp = directives; dp->directive; dp++) {
 1131                 if (dp != directives && sunpro_compat)
 1132                     break;
 1133                 if (dp->dlen < tmp_bytes_left_in_string)
 1134                     continue;
 1135                 if (IS_WEQUALN(source_p, dp->directive,
 1136                     dp->dlen)) {
 1137                     tmp_maybe_directive = true;
 1138                     break;
 1139                 }
 1140             }
 1141             if (tmp_maybe_directive) {
 1142                 GET_NEXT_BLOCK(source);
 1143                 tmp_maybe_directive = false;
 1144                 goto line_evald;
 1145             }
 1146         }
 1147         }
 1148     }
 1149 
 1150     /* Reset the status in preparation for the new line */
 1151     for (nvp = &target; nvp != NULL; nvp = nvp->next) {
 1152         nvp->used = 0;
 1153     }
 1154     for (nvp = &depes; nvp != NULL; nvp = nvp->next) {
 1155         nvp->used = 0;
 1156     }
 1157     target_group_seen = false;
 1158     command = command_tail = NULL;
 1159     macro_value = NULL;
 1160     append = false;
 1161     expand = false;
 1162     current_names = &target;
 1163     SET_STATE(scan_name_state);
 1164     on_eoln_state = illegal_eoln_state;
 1165     separator = none_seen;
 1166 
 1167     /* The state machine starts here */
 1168  enter_state:
 1169     while (1) switch (state) {
 1170 
 1171 /****************************************************************
 1172  *  Scan name state
 1173  */
 1174 case scan_name_state:
 1175     /* Scan an identifier. We skip over chars until we find a break char */
 1176     /* First skip white space. */
 1177     for (; 1; source_p++) switch (GET_CHAR()) {
 1178     case nul_char:
 1179         GET_NEXT_BLOCK(source);
 1180         source_p--;
 1181         if (source == NULL) {
 1182             GOTO_STATE(on_eoln_state);
 1183         }
 1184         break;
 1185     case newline_char:
 1186         /* We found the end of the line. */
 1187         /* Do postprocessing or return error */
 1188         source_p++;
 1189         if (source->fd >= 0) {
 1190             line_number++;
 1191         }
 1192         GOTO_STATE(on_eoln_state);
 1193     case backslash_char:
 1194         /* Continuation */
 1195         if (*++source_p == (int) nul_char) {
 1196             GET_NEXT_BLOCK(source);
 1197             if (source == NULL) {
 1198                 GOTO_STATE(on_eoln_state);
 1199             }
 1200         }
 1201         if (*source_p == (int) newline_char) {
 1202             if (source->fd >= 0) {
 1203                 line_number++;
 1204             }
 1205         } else {
 1206             source_p--;
 1207         }
 1208         break;
 1209     case tab_char:
 1210     case space_char:
 1211         /* Whitespace is skipped */
 1212         break;
 1213     case numbersign_char:
 1214         /* Comment. Skip over it */
 1215         if (skip_comment(source_p, source_end, source) == true) {
 1216             source_p++;
 1217             if (source->fd >= 0) {
 1218                 line_number++;
 1219             }
 1220         }
 1221         GOTO_STATE(on_eoln_state);
 1222     case dollar_char:
 1223         /* Macro reference. Expand and push value */
 1224         if (source->already_expanded) {
 1225             goto scan_name;
 1226         }
 1227         source_p++;
 1228         UNCACHE_SOURCE();
 1229         {
 1230             Source t = (Source) alloca((int) sizeof (Source_rec));
 1231             source = push_macro_value(t,
 1232                           buffer,
 1233                           sizeof buffer,
 1234                           source);
 1235         }
 1236         CACHE_SOURCE(1);
 1237         break;
 1238     default:
 1239         /* End of white space */
 1240         goto scan_name;
 1241     }
 1242 
 1243     /* First proper identifier character */
 1244  scan_name:
 1245 
 1246     string_start = source_p;
 1247     paren_count = brace_count = 0;
 1248     macro_seen_in_string = false;
 1249     resume_name_scan:
 1250     for (; 1; source_p++) {
 1251         switch (GET_CHAR()) {
 1252         case nul_char:
 1253             /* Save what we have seen so far of the identifier */
 1254             if (source_p != string_start) {
 1255                 if (!macro_seen_in_string) {
 1256                     INIT_STRING_FROM_STACK(name_string,
 1257                                    name_buffer);
 1258                 }
 1259                 append_string(string_start,
 1260                           &name_string,
 1261                           source_p - string_start);
 1262                 macro_seen_in_string = true;
 1263             }
 1264             /* Get more text to read */
 1265             GET_NEXT_BLOCK(source);
 1266             string_start = source_p;
 1267             source_p--;
 1268             if (source == NULL) {
 1269                 GOTO_STATE(on_eoln_state);
 1270             }
 1271             break;
 1272         case newline_char:
 1273             if (paren_count > 0) {
 1274                 fatal_reader(gettext("Unmatched `(' on line"));
 1275             }
 1276             if (brace_count > 0) {
 1277                 fatal_reader(gettext("Unmatched `{' on line"));
 1278             }
 1279             source_p++;
 1280             /* Enter name */
 1281             current_names = enter_name(&name_string,
 1282                            macro_seen_in_string,
 1283                            string_start,
 1284                            source_p - 1,
 1285                            current_names,
 1286                            &extra_names,
 1287                            &target_group_seen);
 1288             first_target = false;
 1289             if (extra_names == NULL) {
 1290                 extra_names = (Name_vector)
 1291                   alloca((int) sizeof (Name_vector_rec));
 1292             }
 1293             /* Do postprocessing or return error */
 1294             if (source->fd >= 0) {
 1295                 line_number++;
 1296             }
 1297             GOTO_STATE(on_eoln_state);
 1298         case backslash_char:
 1299             /* Check if this is a quoting backslash */
 1300             if (!macro_seen_in_string) {
 1301                 INIT_STRING_FROM_STACK(name_string,
 1302                                name_buffer);
 1303                 macro_seen_in_string = true;
 1304             }
 1305             append_string(string_start,
 1306                       &name_string,
 1307                       source_p - string_start);
 1308             if (*++source_p == (int) nul_char) {
 1309                 GET_NEXT_BLOCK(source);
 1310                 if (source == NULL) {
 1311                     GOTO_STATE(on_eoln_state);
 1312                 }
 1313             }
 1314             if (*source_p == (int) newline_char) {
 1315                 if (source->fd >= 0) {
 1316                     line_number++;
 1317                 }
 1318                 *source_p = (int) space_char;
 1319                 string_start = source_p;
 1320                 goto resume_name_scan;
 1321             } else {
 1322                 string_start = source_p;
 1323                 break;
 1324             }
 1325             break;
 1326         case numbersign_char:
 1327             if (paren_count + brace_count > 0) {
 1328                 break;
 1329             }
 1330             fatal_reader(gettext("Unexpected comment seen"));
 1331         case dollar_char:
 1332             if (source->already_expanded) {
 1333                 break;
 1334             }
 1335             /* Save the identifier so far */
 1336             if (source_p != string_start) {
 1337                 if (!macro_seen_in_string) {
 1338                     INIT_STRING_FROM_STACK(name_string,
 1339                                    name_buffer);
 1340                 }
 1341                 append_string(string_start,
 1342                           &name_string,
 1343                           source_p - string_start);
 1344                 macro_seen_in_string = true;
 1345             }
 1346             /* Eval and push the macro */
 1347             source_p++;
 1348             UNCACHE_SOURCE();
 1349             {
 1350                 Source t =
 1351                   (Source) alloca((int) sizeof (Source_rec));
 1352                 source = push_macro_value(t,
 1353                               buffer,
 1354                               sizeof buffer,
 1355                               source);
 1356             }
 1357             CACHE_SOURCE(1);
 1358             string_start = source_p + 1;
 1359             break;
 1360         case parenleft_char:
 1361             paren_count++;
 1362             break;
 1363         case parenright_char:
 1364             if (--paren_count < 0) {
 1365                 fatal_reader(gettext("Unmatched `)' on line"));
 1366             }
 1367             break;
 1368         case braceleft_char:
 1369             brace_count++;
 1370             break;
 1371         case braceright_char:
 1372             if (--brace_count < 0) {
 1373                 fatal_reader(gettext("Unmatched `}' on line"));
 1374             }
 1375             break;
 1376         case ampersand_char:
 1377         case greater_char:
 1378         case bar_char:
 1379             if (paren_count + brace_count == 0) {
 1380                 source_p++;
 1381             }
 1382             /* Fall into */
 1383         case tab_char:
 1384         case space_char:
 1385             if (paren_count + brace_count > 0) {
 1386                 break;
 1387             }
 1388             current_names = enter_name(&name_string,
 1389                            macro_seen_in_string,
 1390                            string_start,
 1391                            source_p,
 1392                            current_names,
 1393                            &extra_names,
 1394                            &target_group_seen);
 1395             first_target = false;
 1396             if (extra_names == NULL) {
 1397                 extra_names = (Name_vector)
 1398                   alloca((int) sizeof (Name_vector_rec));
 1399             }
 1400             goto enter_state;
 1401         case colon_char:
 1402             if (paren_count + brace_count > 0) {
 1403                 break;
 1404             }
 1405             if (separator == conditional_seen) {
 1406                 break;
 1407             }
 1408 /** POSIX **/
 1409 #if 0
 1410             if(posix) {
 1411               emptycount = 0;
 1412             }
 1413 #endif
 1414 /** END POSIX **/
 1415             /* End of the target list. We now start reading */
 1416             /* dependencies or a conditional assignment */
 1417             if (separator != none_seen &&
 1418                 ((sunpro_compat || svr4) ||
 1419                 (separator != two_colon))) {
 1420                 fatal_reader(gettext("Extra `:', `::', or `:=' on dependency line"));
 1421             }
 1422             /* Enter the last target */
 1423             if ((string_start != source_p) ||
 1424                 macro_seen_in_string) {
 1425                 current_names =
 1426                   enter_name(&name_string,
 1427                          macro_seen_in_string,
 1428                          string_start,
 1429                          source_p,
 1430                          current_names,
 1431                          &extra_names,
 1432                          &target_group_seen);
 1433                 first_target = false;
 1434                 if (extra_names == NULL) {
 1435                     extra_names = (Name_vector)
 1436                       alloca((int)
 1437                          sizeof (Name_vector_rec));
 1438                 }
 1439             }
 1440             /* Check if it is ":" "::" or ":=" */
 1441         scan_colon_label:
 1442             switch (*++source_p) {
 1443             case nul_char:
 1444                 GET_NEXT_BLOCK(source);
 1445                 source_p--;
 1446                 if (source == NULL) {
 1447                     GOTO_STATE(enter_dependencies_state);
 1448                 }
 1449                 goto scan_colon_label;
 1450             case equal_char:
 1451                 if(svr4) {
 1452                   fatal_reader(gettext("syntax error"));
 1453                 }
 1454                 if (separator == two_colon) {
 1455                     separator = three_colon;
 1456                     break;
 1457                 }
 1458                 separator = conditional_seen;
 1459                 source_p++;
 1460                 current_names = &depes;
 1461                 GOTO_STATE(scan_name_state);
 1462             case colon_char:
 1463                 separator = two_colon;
 1464                 source_p++;
 1465                 break;
 1466             default:
 1467                 separator = one_colon;
 1468             }
 1469             current_names = &depes;
 1470             on_eoln_state = enter_dependencies_state;
 1471             GOTO_STATE(scan_name_state);
 1472         case semicolon_char:
 1473             if (paren_count + brace_count > 0) {
 1474                 break;
 1475             }
 1476             /* End of reading names. Start reading the rule */
 1477             if ((separator != one_colon) &&
 1478                 (separator != two_colon)) {
 1479                 fatal_reader(gettext("Unexpected command seen"));
 1480             }
 1481             /* Enter the last dependency */
 1482             if ((string_start != source_p) ||
 1483                 macro_seen_in_string) {
 1484                 current_names =
 1485                   enter_name(&name_string,
 1486                          macro_seen_in_string,
 1487                          string_start,
 1488                          source_p,
 1489                          current_names,
 1490                          &extra_names,
 1491                          &target_group_seen);
 1492                 first_target = false;
 1493                 if (extra_names == NULL) {
 1494                     extra_names = (Name_vector)
 1495                       alloca((int)
 1496                          sizeof (Name_vector_rec));
 1497                 }
 1498             }
 1499             source_p++;
 1500             /* Make sure to enter a rule even if the is */
 1501             /* no text here */
 1502             command = command_tail = ALLOC(Cmd_line);
 1503             command->next = NULL;
 1504             command->command_line = empty_name;
 1505             command->make_refd = false;
 1506             command->ignore_command_dependency = false;
 1507             command->assign = false;
 1508             command->ignore_error = false;
 1509             command->silent = false;
 1510 
 1511             GOTO_STATE(scan_command_state);
 1512 
 1513         case question_char:
 1514             if (sunpro_compat || svr4)
 1515                 break;
 1516             if (source_p != string_start) {
 1517                 /* "?" is not a break char. */
 1518                 /* Ignore it if it is part of an identifier */
 1519                 source_p++;
 1520                 goto resume_name_scan;
 1521             }
 1522             /* Make sure the "?" is followed by a "=" */
 1523         scan_quest_label:
 1524             switch (source_p[1]) {
 1525             case nul_char:
 1526                 GET_NEXT_BLOCK(source);
 1527                 string_start = source_p;
 1528                 if (source == NULL) {
 1529                     GOTO_STATE(on_eoln_state);
 1530                 }
 1531                 goto scan_quest_label;
 1532 
 1533             case equal_char:
 1534                 separator = one_quest;
 1535                 string_start = ++source_p;
 1536                 goto scan_equal;
 1537             }
 1538             break;
 1539 
 1540         case plus_char:
 1541             /*
 1542             ** following code drops the target separator plus char if it starts
 1543             ** a line.
 1544             */ 
 1545             if(first_target && !macro_seen_in_string &&
 1546                     source_p == string_start) {
 1547                 for (; 1; source_p++)
 1548                 switch (GET_CHAR()) {
 1549                 case nul_char:
 1550                     if (source_p != string_start) {
 1551                         if (!macro_seen_in_string) {
 1552                             INIT_STRING_FROM_STACK(name_string,
 1553                                            name_buffer);
 1554                         }
 1555                         append_string(string_start,
 1556                                   &name_string,
 1557                                   source_p - string_start);
 1558                         macro_seen_in_string = true;
 1559                     }
 1560                     GET_NEXT_BLOCK(source);
 1561                     string_start = source_p;
 1562                     source_p--;
 1563                     if (source == NULL) {
 1564                         GOTO_STATE(on_eoln_state);
 1565                     }
 1566                     break;
 1567                 case plus_char:
 1568                     source_p++;
 1569                     while (*source_p == (int) nul_char) {
 1570                         if (source_p != string_start) {
 1571                             if (!macro_seen_in_string) {
 1572                                 INIT_STRING_FROM_STACK(name_string,
 1573                                            name_buffer);
 1574                             }
 1575                             append_string(string_start,
 1576                                       &name_string,
 1577                                       source_p - string_start);
 1578                             macro_seen_in_string = true;
 1579                         }
 1580                         GET_NEXT_BLOCK(source);
 1581                         string_start = source_p;
 1582                         if (source == NULL) {
 1583                             GOTO_STATE(on_eoln_state);
 1584                         }
 1585                     }
 1586                     if (*source_p == (int) tab_char ||
 1587                             *source_p == (int) space_char) {
 1588                         macro_seen_in_string = false;
 1589                         string_start = source_p + 1;
 1590                     } else {
 1591                         goto resume_name_scan;
 1592                     }
 1593                     break;
 1594                 case tab_char:
 1595                 case space_char:
 1596                     string_start = source_p + 1;
 1597                     break;
 1598                 default:
 1599                     goto resume_name_scan;
 1600                 }
 1601             }
 1602             if (paren_count + brace_count > 0) {
 1603                 break;
 1604             }
 1605             /* We found "+=" construct */
 1606             if (source_p != string_start) {
 1607                 /* "+" is not a break char. */
 1608                 /* Ignore it if it is part of an identifier */
 1609                 source_p++;
 1610                 goto resume_name_scan;
 1611             }
 1612             /*
 1613              * Make sure the "+" is followed by a "="
 1614              * or by a ":="
 1615              */
 1616         scan_append:
 1617             switch (*++source_p) {
 1618             case nul_char:
 1619             wasnull:
 1620                 if (!macro_seen_in_string) {
 1621                     INIT_STRING_FROM_STACK(name_string,
 1622                                    name_buffer);
 1623                 }
 1624                 append_string(string_start,
 1625                           &name_string,
 1626                           source_p - string_start);
 1627                 GET_NEXT_BLOCK(source);
 1628                 source_p--;
 1629                 string_start = source_p;
 1630                 if (source == NULL) {
 1631                     GOTO_STATE(illegal_eoln_state);
 1632                 }
 1633                 goto scan_append;
 1634             case colon_char:    /* This might be +:= */
 1635                 if (source_p[1] == nul_char)
 1636                     goto wasnull;
 1637                 if ((sunpro_compat || svr4) ||
 1638                     source_p[1] != equal_char) {
 1639                     goto resume_name_scan;
 1640                 }
 1641                 source_p++; /* skip ':' from +:= */
 1642                 expand = true;
 1643             case equal_char:
 1644                 if(!svr4) {
 1645                   append = true;
 1646                 } else {
 1647                   fatal_reader(gettext("Must be a separator on rules"));
 1648                 }
 1649                 break;
 1650             default:
 1651                 /* The "+" just starts a regular name. */
 1652                 /* Start reading that name */
 1653                 goto resume_name_scan;
 1654             }
 1655             /* Fall into */
 1656         case equal_char:
 1657         scan_equal:
 1658             if (paren_count + brace_count > 0) {
 1659                 break;
 1660             }
 1661             /* We found macro assignment. */
 1662             /* Check if it is legal and if it is appending */
 1663             switch (separator) {
 1664             case none_seen:
 1665                 separator = equal_seen;
 1666                 on_eoln_state = enter_equal_state;
 1667                 break;
 1668             case conditional_seen:
 1669                 on_eoln_state = enter_conditional_state;
 1670                 break;
 1671             case one_quest:
 1672                 if (!sunpro_compat && !svr4) {
 1673                     separator = condequal_seen;
 1674                     on_eoln_state = enter_equal_state;
 1675                     break;
 1676                 }
 1677             case two_colon:
 1678                 if (separator == two_colon) /* fallthrough? */
 1679 #ifdef  GNU_ASSIGN_BY_DEFAULT
 1680                 if (
 1681 #else
 1682                 if ((posix || gnu_style) &&
 1683 #endif
 1684                     !sunpro_compat && !svr4) {
 1685                     separator = gnu_assign_seen;
 1686                     on_eoln_state = enter_equal_state;
 1687                     break;
 1688                 }
 1689             case three_colon:
 1690                 if (separator == three_colon) /* fallthrough? */
 1691                 if (!sunpro_compat && !svr4) {
 1692                     separator = assign_seen;
 1693                     on_eoln_state = enter_equal_state;
 1694                     break;
 1695                 }
 1696             default:
 1697                 /* Reader must special check for "MACRO:sh=" */
 1698                 /* notation */
 1699                 if (sh_name == NULL) {
 1700                     MBSTOWCS(wcs_buffer, NOCATGETS("sh"));
 1701                     sh_name = GETNAME(wcs_buffer, FIND_LENGTH);
 1702                     MBSTOWCS(wcs_buffer, NOCATGETS("shell"));
 1703                     shell_name = GETNAME(wcs_buffer, FIND_LENGTH);
 1704                 }
 1705 
 1706                 if (!macro_seen_in_string) {
 1707                     INIT_STRING_FROM_STACK(name_string,
 1708                                name_buffer);
 1709                 }
 1710                 append_string(string_start,
 1711                           &name_string,
 1712                           source_p - string_start
 1713                 );
 1714 
 1715                 if ( (((target.used == 1) &&
 1716                      (depes.used == 1) &&
 1717                      (depes.names[0] == sh_name)) ||
 1718                     ((target.used == 1) &&
 1719                      (depes.used == 0) &&
 1720                      (separator == one_colon) &&
 1721                      (GETNAME(name_string.buffer.start,FIND_LENGTH) == sh_name))) &&
 1722                     (!svr4)) {
 1723                     String_rec  macro_name;
 1724                     wchar_t     buffer[100];
 1725 
 1726                     INIT_STRING_FROM_STACK(macro_name,
 1727                                    buffer);
 1728                     APPEND_NAME(target.names[0],
 1729                               &macro_name,
 1730                               FIND_LENGTH);
 1731                     append_char((int) colon_char,
 1732                             &macro_name);
 1733                     APPEND_NAME(sh_name,
 1734                               &macro_name,
 1735                               FIND_LENGTH);
 1736                     target.names[0] =
 1737                       GETNAME(macro_name.buffer.start,
 1738                           FIND_LENGTH);
 1739                     separator = equal_seen;
 1740                     on_eoln_state = enter_equal_state;
 1741                     break;
 1742                 } else if ( (((target.used == 1) &&
 1743                         (depes.used == 1) &&
 1744                         (depes.names[0] == shell_name)) ||
 1745                        ((target.used == 1) &&
 1746                         (depes.used == 0) &&
 1747                         (separator == one_colon) &&
 1748                         (GETNAME(name_string.buffer.start,FIND_LENGTH) == shell_name))) &&
 1749                        (!svr4)) {
 1750                     String_rec  macro_name;
 1751                     wchar_t     buffer[100];
 1752 
 1753                     INIT_STRING_FROM_STACK(macro_name,
 1754                                    buffer);
 1755                     APPEND_NAME(target.names[0],
 1756                               &macro_name,
 1757                               FIND_LENGTH);
 1758                     append_char((int) colon_char,
 1759                             &macro_name);
 1760                     APPEND_NAME(shell_name,
 1761                               &macro_name,
 1762                               FIND_LENGTH);
 1763                     target.names[0] =
 1764                       GETNAME(macro_name.buffer.start,
 1765                           FIND_LENGTH);
 1766                     separator = equal_seen;
 1767                     on_eoln_state = enter_equal_state;
 1768                     break;
 1769                 } 
 1770                 if(svr4) {
 1771                   fatal_reader(gettext("syntax error"));
 1772                 }
 1773                 else {
 1774                   fatal_reader(gettext("Macro assignment on dependency line"));
 1775                 }
 1776             }
 1777             if (append) {
 1778                 source_p--;
 1779                 if (*source_p == colon_char)
 1780                     source_p--;
 1781             }
 1782             /* Enter the macro name */
 1783             if ((string_start != source_p) ||
 1784                 macro_seen_in_string) {
 1785                 current_names =
 1786                   enter_name(&name_string,
 1787                          macro_seen_in_string,
 1788                          string_start,
 1789                          source_p,
 1790                          current_names,
 1791                          &extra_names,
 1792                          &target_group_seen);
 1793                 first_target = false;
 1794                 if (extra_names == NULL) {
 1795                     extra_names = (Name_vector)
 1796                       alloca((int)
 1797                          sizeof (Name_vector_rec));
 1798                 }
 1799             }
 1800             if (append) {
 1801                 source_p++;
 1802                 if (*source_p == colon_char)
 1803                     source_p++;
 1804             }
 1805             macro_value = NULL;
 1806             source_p++;
 1807             distance = 0;
 1808             /* Skip whitespace to the start of the value */
 1809             macro_seen_in_string = false;
 1810             for (; 1; source_p++) {
 1811                 switch (GET_CHAR()) {
 1812                 case nul_char:
 1813                     GET_NEXT_BLOCK(source);
 1814                     source_p--;
 1815                     if (source == NULL) {
 1816                         GOTO_STATE(on_eoln_state);
 1817                     }
 1818                     break;
 1819                 case backslash_char:
 1820                     if (*++source_p == (int) nul_char) {
 1821                         GET_NEXT_BLOCK(source);
 1822                         if (source == NULL) {
 1823                             GOTO_STATE(on_eoln_state);
 1824                         }
 1825                     }
 1826                     if (*source_p != (int) newline_char) {
 1827                         if (!macro_seen_in_string) {
 1828                             macro_seen_in_string =
 1829                               true;
 1830                             INIT_STRING_FROM_STACK(name_string,
 1831                                            name_buffer);
 1832                         }
 1833                         append_char((int)
 1834                                 backslash_char,
 1835                                 &name_string);
 1836                         append_char(*source_p,
 1837                                 &name_string);
 1838                         string_start = source_p+1;
 1839                         goto macro_value_start;
 1840                     } else {
 1841                                             if (source->fd >= 0) {
 1842                                                 line_number++;
 1843                                             }
 1844                                         }
 1845                     break;
 1846                 case newline_char:
 1847                 case numbersign_char:
 1848                     string_start = source_p;
 1849                     goto macro_value_end;
 1850                 case tab_char:
 1851                 case space_char:
 1852                     break;
 1853                 default:
 1854                     string_start = source_p;
 1855                     goto macro_value_start;
 1856                 }
 1857             }
 1858         macro_value_start:
 1859             /* Find the end of the value */
 1860             for (; 1; source_p++) {
 1861                 if (distance != 0) {
 1862                     *source_p = *(source_p + distance);
 1863                 }
 1864                 switch (GET_CHAR()) {
 1865                 case nul_char:
 1866                     if (!macro_seen_in_string) {
 1867                         macro_seen_in_string = true;
 1868                         INIT_STRING_FROM_STACK(name_string,
 1869                                        name_buffer);
 1870                     }
 1871                     append_string(string_start,
 1872                               &name_string,
 1873                               source_p - string_start);
 1874                     GET_NEXT_BLOCK(source);
 1875                     string_start = source_p;
 1876                     source_p--;
 1877                     if (source == NULL) {
 1878                         GOTO_STATE(on_eoln_state);
 1879                     }
 1880                     break;
 1881                 case backslash_char:
 1882                     source_p++;
 1883                     if (distance != 0) {
 1884                         *source_p =
 1885                           *(source_p + distance);
 1886                     }
 1887                     if (*source_p == (int) nul_char) {
 1888                         if (!macro_seen_in_string) {
 1889                             macro_seen_in_string =
 1890                               true;
 1891                             INIT_STRING_FROM_STACK(name_string,
 1892                                            name_buffer);
 1893                         }
 1894 
 1895 /*  BID_1225561 */
 1896                         *(source_p - 1) = (int) space_char;
 1897                         append_string(string_start,
 1898                                   &name_string,
 1899                                   source_p -
 1900                                   string_start - 1);
 1901                         GET_NEXT_BLOCK(source);
 1902                         string_start = source_p;
 1903                         if (source == NULL) {
 1904                             GOTO_STATE(on_eoln_state);
 1905                         }
 1906                         if (distance != 0) {
 1907                             *source_p =
 1908                               *(source_p +
 1909                                 distance);
 1910                         }
 1911                         if (*source_p == (int) newline_char) {
 1912                             append_char((int) space_char, &name_string);
 1913                         } else {
 1914                             append_char((int) backslash_char, &name_string);
 1915                         }
 1916 /****************/
 1917                     }
 1918                     if (*source_p == (int) newline_char) {
 1919                         source_p--;
 1920                         line_number++;
 1921                         distance++;
 1922                         *source_p = (int) space_char;
 1923                         while ((*(source_p +
 1924                               distance + 1) ==
 1925                             (int) tab_char) ||
 1926                                (*(source_p +
 1927                               distance + 1) ==
 1928                             (int) space_char)) {
 1929                             distance++;
 1930                         }
 1931                     }
 1932                     break;
 1933                 case newline_char:
 1934                 case numbersign_char:
 1935                     goto macro_value_end;
 1936                 }
 1937             }
 1938         macro_value_end:
 1939             /* Complete the value in the string */
 1940             if (!macro_seen_in_string) {
 1941                 macro_seen_in_string = true;
 1942                 INIT_STRING_FROM_STACK(name_string,
 1943                                name_buffer);
 1944             }
 1945             append_string(string_start,
 1946                       &name_string,
 1947                       source_p - string_start);
 1948             if (name_string.buffer.start != name_string.text.p) {
 1949                     macro_value =
 1950                       GETNAME(name_string.buffer.start,
 1951                           FIND_LENGTH);
 1952                 }
 1953             if (name_string.free_after_use) {
 1954                 retmem(name_string.buffer.start);
 1955             }
 1956             for (; distance > 0; distance--) {
 1957                 *source_p++ = (int) space_char;
 1958             }
 1959             GOTO_STATE(on_eoln_state);
 1960         }
 1961     }
 1962 
 1963 /****************************************************************
 1964  *  enter dependencies state
 1965  */
 1966  case enter_dependencies_state:
 1967  enter_dependencies_label:
 1968 /* Expects pointer on first non whitespace char after last dependency. (On */
 1969 /* next line.) We end up here after having read a "targets : dependencies" */
 1970 /* line. The state checks if there is a rule to read and if so dispatches */
 1971 /* to scan_command_state scan_command_state reads one rule line and the */
 1972 /* returns here */
 1973 
 1974     /* First check if the first char on the next line is special */
 1975     switch (GET_CHAR()) {
 1976     case nul_char:
 1977         GET_NEXT_BLOCK(source);
 1978         if (source == NULL) {
 1979             break;
 1980         }
 1981         goto enter_dependencies_label;
 1982     case exclam_char:
 1983         /* The line should be evaluate before it is read */
 1984         macro_seen_in_string = false;
 1985         string_start = source_p + 1;
 1986         for (; 1; source_p++) {
 1987             switch (GET_CHAR()) {
 1988             case newline_char:
 1989                 goto eoln_2;
 1990             case nul_char:
 1991                 if (source->fd > 0) {
 1992                     if (!macro_seen_in_string) {
 1993                         macro_seen_in_string = true;
 1994                         INIT_STRING_FROM_STACK(name_string,
 1995                                        name_buffer);
 1996                     }
 1997                     append_string(string_start,
 1998                               &name_string,
 1999                               source_p - string_start);
 2000                     GET_NEXT_BLOCK(source);
 2001                     string_start = source_p;
 2002                     source_p--;
 2003                     break;
 2004                 }
 2005             eoln_2:
 2006                 if (!macro_seen_in_string) {
 2007                     INIT_STRING_FROM_STACK(name_string,
 2008                                    name_buffer);
 2009                 }
 2010                 append_string(string_start,
 2011                           &name_string,
 2012                           source_p - string_start);
 2013                 extrap = (Source)
 2014                   alloca((int) sizeof (Source_rec));
 2015                 extrap->string.buffer.start = NULL;
 2016                 extrap->inp_buf =
 2017                   extrap->inp_buf_ptr =
 2018                     extrap->inp_buf_end = NULL;
 2019                 extrap->error_converting = false;
 2020                 expand_value(GETNAME(name_string.buffer.start,
 2021                              FIND_LENGTH),
 2022                          &extrap->string,
 2023                          false);
 2024                 if (name_string.free_after_use) {
 2025                     retmem(name_string.buffer.start);
 2026                 }
 2027                 UNCACHE_SOURCE();
 2028                 extrap->string.text.p =
 2029                   extrap->string.buffer.start;
 2030                 extrap->fd = -1;
 2031                 extrap->previous = source;
 2032                 source = extrap;
 2033                 CACHE_SOURCE(0);
 2034                 goto enter_dependencies_label;
 2035             }
 2036         }
 2037     case dollar_char:
 2038         if (source->already_expanded) {
 2039             break;
 2040         }
 2041         source_p++;
 2042         UNCACHE_SOURCE();
 2043         {
 2044             Source t = (Source) alloca((int) sizeof (Source_rec));
 2045             source = push_macro_value(t,
 2046                           buffer,
 2047                           sizeof buffer,
 2048                           source);
 2049         }
 2050         CACHE_SOURCE(0);
 2051         goto enter_dependencies_label;
 2052     case numbersign_char:
 2053         if (makefile_type != reading_makefile) {
 2054             source_p++;
 2055             GOTO_STATE(scan_command_state);
 2056         }
 2057         for (; 1; source_p++) {
 2058             switch (GET_CHAR()) {
 2059             case nul_char:
 2060                 GET_NEXT_BLOCK_NOCHK(source);
 2061                 if (source == NULL) {
 2062                     GOTO_STATE(on_eoln_state);
 2063                 }
 2064                 if (source->error_converting) {
 2065                 // Illegal byte sequence - skip its first byte
 2066                     source->inp_buf_ptr++;
 2067                 }
 2068                 source_p--;
 2069                 break;
 2070             case backslash_char:
 2071                 if (*++source_p == (int) nul_char) {
 2072                     GET_NEXT_BLOCK_NOCHK(source);
 2073                     if (source == NULL) {
 2074                         GOTO_STATE(on_eoln_state);
 2075                     }
 2076                     if (source->error_converting) {
 2077                     // Illegal byte sequence - skip its first byte
 2078                         source->inp_buf_ptr++;
 2079                         source_p--;
 2080                         break;
 2081                     }
 2082                 }
 2083                 if(*source_p == (int) newline_char) {
 2084                     if (source->fd >= 0) {
 2085                         line_number++;
 2086                     }
 2087                 }
 2088                 break;
 2089             case newline_char:
 2090                 source_p++;
 2091                 if (source->fd >= 0) {
 2092                     line_number++;
 2093                 }
 2094                 goto enter_dependencies_label;
 2095             }
 2096         }
 2097 
 2098     case tab_char:
 2099         GOTO_STATE(scan_command_state);
 2100     }
 2101 
 2102     /* We read all the command lines for the target/dependency line. */
 2103     /* Enter the stuff */
 2104     enter_target_groups_and_dependencies( &target, &depes, command, 
 2105                          separator, target_group_seen);
 2106 
 2107     goto start_new_line;
 2108 
 2109 /****************************************************************
 2110  *  scan command state
 2111  */
 2112 case scan_command_state:
 2113     /* We need to read one rule line. Do that and return to */
 2114     /* the enter dependencies state */
 2115     string_start = source_p;
 2116     macro_seen_in_string = false;
 2117     for (; 1; source_p++) {
 2118         switch (GET_CHAR()) {
 2119         case backslash_char:
 2120             if (!macro_seen_in_string) {
 2121                 INIT_STRING_FROM_STACK(name_string,
 2122                                name_buffer);
 2123             }
 2124             append_string(string_start,
 2125                       &name_string,
 2126                       source_p - string_start);
 2127             macro_seen_in_string = true;
 2128             if (*++source_p == (int) nul_char) {
 2129                 GET_NEXT_BLOCK(source);
 2130                 if (source == NULL) {
 2131                     string_start = source_p;
 2132                     goto command_newline;
 2133                 }
 2134             }
 2135             append_char((int) backslash_char, &name_string);
 2136             append_char(*source_p, &name_string);
 2137             if (*source_p == (int) newline_char) {
 2138                 if (source->fd >= 0) {
 2139                     line_number++;
 2140                 }
 2141                 if (*++source_p == (int) nul_char) {
 2142                     GET_NEXT_BLOCK(source);
 2143                     if (source == NULL) {
 2144                         string_start = source_p;
 2145                         goto command_newline;
 2146                     }
 2147                 }
 2148                 if (*source_p == (int) tab_char) {
 2149                     source_p++;
 2150                 }
 2151             } else {
 2152                 if (*++source_p == (int) nul_char) {
 2153                     GET_NEXT_BLOCK(source);
 2154                     if (source == NULL) {
 2155                         string_start = source_p;
 2156                         goto command_newline;
 2157                     }
 2158                 }
 2159             }
 2160             string_start = source_p;
 2161             if ((*source_p == (int) newline_char) ||
 2162                 (*source_p == (int) backslash_char) ||
 2163                 (*source_p == (int) nul_char)) {
 2164                 source_p--;
 2165             }
 2166             break;
 2167         case newline_char:
 2168         command_newline:
 2169             if ((string_start != source_p) ||
 2170                 macro_seen_in_string) {
 2171                 if (macro_seen_in_string) {
 2172                     append_string(string_start,
 2173                               &name_string,
 2174                               source_p - string_start);
 2175                     string_start =
 2176                       name_string.buffer.start;
 2177                     string_end = name_string.text.p;
 2178                 } else {
 2179                     string_end = source_p;
 2180                 }
 2181                 while ((*string_start != (int) newline_char) &&
 2182                        iswspace(*string_start)){
 2183                     string_start++;
 2184                 }
 2185                 if ((string_end > string_start) ||
 2186                     (makefile_type == reading_statefile)) {
 2187                     if (command_tail == NULL) {
 2188                         command =
 2189                           command_tail =
 2190                             ALLOC(Cmd_line);
 2191                     } else {
 2192                         command_tail->next =
 2193                           ALLOC(Cmd_line);
 2194                         command_tail =
 2195                           command_tail->next;
 2196                     }
 2197                     command_tail->next = NULL;
 2198                     command_tail->make_refd = false;
 2199                     command_tail->ignore_command_dependency = false;
 2200                     command_tail->assign = false;
 2201                     command_tail->ignore_error = false;
 2202                     command_tail->silent = false;
 2203                     command_tail->command_line =
 2204                       GETNAME(string_start,
 2205                           string_end - string_start);
 2206                     if (macro_seen_in_string &&
 2207                         name_string.free_after_use) {
 2208                         retmem(name_string.
 2209                                buffer.start);
 2210                     }
 2211                 }
 2212             }
 2213             do {
 2214                 if ((source != NULL) && (source->fd >= 0)) {
 2215                     line_number++;
 2216                 }
 2217                 if ((source != NULL) &&
 2218                     (*++source_p == (int) nul_char)) {
 2219                     GET_NEXT_BLOCK(source);
 2220                     if (source == NULL) {
 2221                         GOTO_STATE(on_eoln_state);
 2222                     }
 2223                 }
 2224             } while (*source_p == (int) newline_char);
 2225 
 2226             GOTO_STATE(enter_dependencies_state);
 2227         case nul_char:
 2228             if (!macro_seen_in_string) {
 2229                 INIT_STRING_FROM_STACK(name_string,
 2230                                name_buffer);
 2231             }
 2232             append_string(string_start,
 2233                       &name_string,
 2234                       source_p - string_start);
 2235             macro_seen_in_string = true;
 2236             GET_NEXT_BLOCK(source);
 2237             string_start = source_p;
 2238             source_p--;
 2239             if (source == NULL) {
 2240                 GOTO_STATE(enter_dependencies_state);
 2241             }
 2242             break;
 2243         }
 2244     }
 2245 
 2246 /****************************************************************
 2247  *  enter equal state
 2248  */
 2249 case enter_equal_state:
 2250     if (target.used != 1) {
 2251         GOTO_STATE(poorly_formed_macro_state);
 2252     }
 2253     if (append && expand)           /* +:= seen */
 2254         separator = append_assign_seen;
 2255     enter_equal(target.names[0], macro_value, append, separator);
 2256     goto start_new_line;
 2257 
 2258 /****************************************************************
 2259  *  enter conditional state
 2260  */
 2261 case enter_conditional_state:
 2262     if (depes.used != 1) {
 2263         GOTO_STATE(poorly_formed_macro_state);
 2264     }
 2265     for (nvp = &target; nvp != NULL; nvp = nvp->next) {
 2266         for (i = 0; i < nvp->used; i++) {
 2267             enter_conditional(nvp->names[i],
 2268                       depes.names[0],
 2269                       macro_value,
 2270                       append);
 2271         }
 2272     }
 2273     goto start_new_line;
 2274 
 2275 /****************************************************************
 2276  *  Error states
 2277  */
 2278 case illegal_bytes_state:
 2279     fatal_reader(gettext("Invalid byte sequence"));
 2280 case illegal_eoln_state:
 2281     if (line_number > 1) {
 2282         if (line_started_with_space == (line_number - 1)) {
 2283             line_number--;
 2284             fatal_reader(gettext("Unexpected end of line seen\n\t*** missing separator (did you mean TAB instead of 8 spaces?)"));
 2285         }
 2286     }
 2287     fatal_reader(gettext("Unexpected end of line seen"));
 2288 case poorly_formed_macro_state:
 2289     fatal_reader(gettext("Badly formed macro assignment"));
 2290 case exit_state:
 2291     return;
 2292 default:
 2293     fatal_reader(gettext("Internal error. Unknown reader state"));
 2294 }
 2295 }
 2296 
 2297 /*
 2298  *  push_macro_value(bp, buffer, size, source)
 2299  *
 2300  *  Macro and function that evaluates one macro
 2301  *  and makes the reader read from the value of it
 2302  *
 2303  *  Return value:
 2304  *              The source block to read the macro from
 2305  *
 2306  *  Parameters:
 2307  *      bp      The new source block to fill in
 2308  *      buffer      Buffer to read from
 2309  *      size        size of the buffer
 2310  *      source      The old source block
 2311  *
 2312  *  Global variables used:
 2313  */
 2314 static Source
 2315 push_macro_value(register Source bp, register wchar_t *buffer, int size, register Source source)
 2316 {
 2317     bp->string.buffer.start = bp->string.text.p = buffer;
 2318     bp->string.text.end = NULL;
 2319     bp->string.buffer.end = buffer + (size/SIZEOFWCHAR_T);
 2320     bp->string.free_after_use = false;
 2321     bp->inp_buf =
 2322       bp->inp_buf_ptr =
 2323         bp->inp_buf_end = NULL;
 2324     bp->error_converting = false;
 2325     expand_macro(source, &bp->string, (wchar_t *) NULL, false, no_expand);
 2326     bp->string.text.p = bp->string.buffer.start;
 2327 
 2328     /* 4209588: 'make' doesn't understand a macro with whitespaces in the head as target.
 2329      * strip whitespace from the begining of the macro value
 2330      */
 2331     while (iswspace(*bp->string.text.p)) {
 2332         bp->string.text.p++;
 2333     }
 2334 
 2335     bp->fd = -1;
 2336     bp->already_expanded = true;
 2337     bp->previous = source;
 2338     return bp;
 2339 }
 2340 
 2341 /*
 2342  *  enter_target_groups_and_dependencies(target, depes, command, separator,
 2343  *                       target_group_seen)
 2344  *
 2345  *  Parameters:
 2346  *      target      Structure that shows the target(s) on the line
 2347  *              we are currently parsing. This can looks like
 2348  *              target1 .. targetN : dependencies
 2349  *                          commands
 2350  *              or
 2351  *              target1 + .. + targetN : dependencies
 2352  *                           commands
 2353  *      depes       Dependencies
 2354  *      command     Points to the command(s) to be executed for 
 2355  *              this target.
 2356  *      separator   : or :: or :=
 2357  *      target_group_seen   Set if we have target1 + .. + targetN
 2358  *      
 2359  *      
 2360  *  After reading the command lines for a target, this routine 
 2361  *  is called to setup the dependencies and the commands for it.
 2362  *  If the target is a % pattern or part of a target group, then 
 2363  *      the appropriate routines are called.
 2364  */
 2365     
 2366 void
 2367 enter_target_groups_and_dependencies(Name_vector target, Name_vector depes, Cmd_line command, Separator separator, Boolean target_group_seen)
 2368 {
 2369     int         i;
 2370     Boolean         reset= true;
 2371     Chain           target_group_member;
 2372     Percent         percent_ptr;
 2373 
 2374     for (; target != NULL; target = target->next) {
 2375         for (i = 0; i < target->used; i++) {
 2376             if (target->names[i] != NULL) {
 2377                 if (target_group_seen) {
 2378                     target_group_member =
 2379                       find_target_groups(target, i, reset);
 2380                     if(target_group_member == NULL) {
 2381                         fatal_reader(gettext("Unexpected '+' on dependency line"));
 2382                     }
 2383                 }
 2384                 reset = false;
 2385 
 2386                 /* If we saw it in the makefile it must be
 2387                  * a file */
 2388                 target->names[i]->stat.is_file = true;
 2389                 /* Make sure that we use dependencies 
 2390                  * entered for makefiles */
 2391                 target->names[i]->state = build_dont_know;
 2392 
 2393                 /* If the target is special we delegate 
 2394                  * the processing */
 2395                 if (target->names[i]->special_reader 
 2396                     != no_special) {
 2397                     special_reader(target->names[i], 
 2398                                depes, 
 2399                                command,
 2400                                separator);
 2401                 }   
 2402                 /* Check if this is a "a%b : x%y" type rule */
 2403                 else if (target->names[i]->percent) {
 2404                     percent_ptr = 
 2405                       enter_percent(target->names[i], 
 2406                             target->target_group[i], 
 2407                             depes, command);
 2408                     if (target_group_seen) {
 2409                         target_group_member->percent_member =
 2410                           percent_ptr;
 2411                     }
 2412                 } else if (target->names[i]->dollar) {
 2413                     enter_dyntarget(target->names[i]);
 2414                     enter_dependencies
 2415                       (target->names[i],
 2416                        target->target_group[i],
 2417                        depes,   
 2418                        command,
 2419                        separator);
 2420                 } else {
 2421                     if (target_group_seen) {
 2422                         target_group_member->percent_member =
 2423                           NULL;
 2424                     }
 2425                 
 2426                     enter_dependencies
 2427                       (target->names[i],
 2428                        target->target_group[i],
 2429                        depes,   
 2430                        command,
 2431                        separator);
 2432                 }
 2433             }
 2434         }
 2435     }
 2436 }
 2437 
 2438 void
 2439 doexport(Name name)
 2440 {
 2441     Name        val;
 2442     char        *eval;
 2443     size_t      len;
 2444 
 2445     if (strcmp(name->string_mb, NOCATGETS("SHELL")) == 0)
 2446         return;
 2447 
 2448     val = getvar(name);
 2449     len = strlen(name->string_mb) + 1 + strlen(val->string_mb) + 1;
 2450     eval = (char *)malloc(len);
 2451     strcpy(eval, name->string_mb);
 2452     strcat(eval, "=");
 2453     strcat(eval, val->string_mb);
 2454 
 2455     putenv(eval);
 2456 }
 2457 
 2458 void
 2459 dounexport(Name name)
 2460 {
 2461     Name        val;
 2462     char        *eval;
 2463     size_t      len;
 2464 
 2465     if (strcmp(name->string_mb, NOCATGETS("SHELL")) == 0)
 2466         return;
 2467 
 2468     unsetenv(name->string_mb);
 2469 }
 2470 
 2471 void
 2472 doreadonly(Name name)
 2473 {
 2474     Property    macro;
 2475 
 2476     if ((macro = get_prop(name->prop, macro_prop)) != NULL)
 2477         macro->body.macro.read_only = true;
 2478 }
 2479 
 2480 static Boolean
 2481 skip_comment(wchar_t * &source_p, wchar_t * &source_end, Source &source)
 2482 {
 2483     /* Comment. Skip over it */
 2484     for (; 1; source_p++) {
 2485         switch (GET_CHAR()) {
 2486         case nul_char:
 2487             GET_NEXT_BLOCK_NOCHK(source);
 2488             if (source == NULL) {
 2489                 return (false);
 2490             }
 2491             if (source->error_converting) {
 2492             // Illegal byte sequence - skip its first byte
 2493                 source->inp_buf_ptr++;
 2494             }
 2495             source_p--;
 2496             break;
 2497         case backslash_char:
 2498             /* Comments can be continued */
 2499             if (*++source_p == (int) nul_char) {
 2500                 GET_NEXT_BLOCK_NOCHK(source);
 2501                 if (source == NULL) {
 2502                     return (false);
 2503                 }
 2504                 if (source->error_converting) {
 2505                 // Illegal byte sequence - skip its first byte
 2506                     source->inp_buf_ptr++;
 2507                     source_p--;
 2508                     break;
 2509                 }
 2510             }
 2511             if(*source_p == (int) newline_char) {
 2512                 if (source->fd >= 0) {
 2513                     line_number++;
 2514                 }
 2515             }
 2516             break;
 2517         case newline_char:
 2518             return (true);
 2519         }
 2520     }
 2521 }
 2522 
 2523 static void
 2524 init_directives(void)
 2525 {
 2526     MBSTOWCS(include_d,  NOCATGETS("include "));
 2527     MBSTOWCS(iinclude_d, NOCATGETS("-include "));
 2528     MBSTOWCS(export_d,   NOCATGETS("export "));
 2529     MBSTOWCS(unexport_d, NOCATGETS("unexport "));
 2530     MBSTOWCS(readonly_d, NOCATGETS("readonly "));
 2531 }