"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. For more information about "read.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes reports: 2021-09-01_vs_2021-09-18 or 2021-08-14_vs_2021-09-18 or 2021-07-29_vs_2021-09-18.

    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 }