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