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