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 2004 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      implicit.c
  28  *
  29  *      Handle suffix and percent rules
  30  */
  31 
  32 /*
  33  * Included files
  34  */
  35 #include <mk/defs.h>
  36 #include <mksh/macro.h>           /* expand_value() */
  37 #include <mksh/misc.h>            /* retmem() */
  38 #include <libintl.h>
  39 
  40 /*
  41  * Defined macros
  42  */
  43 
  44 /*
  45  * typedefs & structs
  46  */
  47 
  48 /*
  49  * Static variables
  50  */
  51 static  wchar_t         WIDE_NULL[1] = {(wchar_t) nul_char};
  52 
  53 /*
  54  * File table of contents
  55  */
  56 extern  Doname          find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking);
  57 extern  Doname          find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking);
  58 extern  Doname          find_double_suffix_rule(register Name target, Property *command, Boolean rechecking);
  59 extern  void            build_suffix_list(register Name target_suffix);
  60 extern  Doname          find_percent_rule(register Name target, Property *command, Boolean rechecking);
  61 static  void            create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent);
  62 static  Boolean         match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf);
  63 static  void            construct_string_from_pattern(Percent pat_rule, String percent, String result);
  64 static  Boolean         dependency_exists(Name target, Property line);
  65 extern  Property        maybe_append_prop(Name, Property_id);
  66 extern  void            add_target_to_chain(Name target, Chain * query);
  67 
  68 /*
  69  *      find_suffix_rule(target, target_body, target_suffix, command, rechecking)
  70  * 
  71  *      Does the lookup for single and double suffix rules.
  72  *      It calls build_suffix_list() to build the list of possible suffixes
  73  *      for the given target.
  74  *      It then scans the list to find the first possible source file that
  75  *      exists. This is done by concatenating the body of the target name
  76  *      (target name less target suffix) and the source suffix and checking
  77  *      if the resulting file exists.
  78  *
  79  *      Return value:
  80  *                              Indicates if search failed or not
  81  *
  82  *      Parameters:
  83  *              target          The target we need a rule for
  84  *              target_body     The target name without the suffix
  85  *              target_suffix   The suffix of the target
  86  *              command         Pointer to slot to deposit cmd in if found
  87  *              rechecking      true if we are rechecking target which depends
  88  *                              on conditional macro and keep_state is set
  89  *
  90  *      Global variables used:
  91  *              debug_level     Indicates how much tracing to do
  92  *              recursion_level Used for tracing
  93  */
  94 
  95 extern int printf (const char *, ...);
  96 
  97 static Boolean actual_doname = false;
  98 
  99 /* /tolik/
 100  * fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
 101  * When make attemps to apply % rule it didn't look for a single suffix rule because
 102  * if "doname" is called from "find_percent_rule" argument "implicit" is set to true
 103  * and find_suffix_rule was not called. I've commented the checking of "implicit"
 104  * in "doname" and make got infinite recursion for SVR4 tilde rules.
 105  * Usage of "we_are_in_tilde" is intended to avoid this recursion.
 106  */
 107 
 108 static Boolean we_are_in_tilde = false; 
 109 
 110 Doname
 111 find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking)
 112 {
 113         static wchar_t          static_string_buf_3M [ 3 * MAXPATHLEN ];
 114         Name                    true_target = target;
 115         wchar_t                 *sourcename = (wchar_t*)static_string_buf_3M;
 116         register wchar_t        *put_suffix;
 117         register Property       source_suffix;
 118         register Name           source;
 119         Doname                  result;
 120         register Property       line;
 121         extern Boolean          tilde_rule;
 122         Boolean                 name_found = true;
 123         Boolean                 posix_tilde_attempt = true;
 124         int                     src_len = MAXPATHLEN + strlen(target_body->string_mb);
 125 
 126         /*
 127          * To avoid infinite recursion
 128          */
 129         if(we_are_in_tilde) {
 130                 we_are_in_tilde = false;
 131                 return(build_dont_know);
 132         }
 133 
 134         /*
 135          * If the target is a constructed one for a "::" target,
 136          * we need to consider that.
 137          */
 138         if (target->has_target_prop) {
 139                 true_target = get_prop(target->prop,
 140                                        target_prop)->body.target.target;
 141         }
 142         if (debug_level > 1) {
 143                 (void) printf("%*sfind_suffix_rule(%s,%s,%s)\n",
 144                               recursion_level,
 145                               "",
 146                               true_target->string_mb,
 147                               target_body->string_mb,
 148                               target_suffix->string_mb);
 149         }
 150         if (command != NULL) {
 151                 if ((true_target->suffix_scan_done == true) && (*command == NULL)) {
 152                         return build_ok;
 153                 }
 154         }
 155         true_target->suffix_scan_done = true;
 156         /*
 157          * Enter all names from the directory where the target lives as
 158          * files that makes sense.
 159          * This will make finding the synthesized source possible.
 160          */
 161         read_directory_of_file(target_body);
 162         /* Cache the suffixes for this target suffix if not done. */
 163         if (!target_suffix->has_read_suffixes) {
 164                 build_suffix_list(target_suffix);
 165         }
 166         /* Preload the sourcename vector with the head of the target name. */
 167         if (src_len >= sizeof(static_string_buf_3M)) {
 168                 sourcename = ALLOC_WC(src_len);
 169         }
 170         (void) mbstowcs(sourcename,
 171                       target_body->string_mb,
 172                       (int) target_body->hash.length);
 173         put_suffix = sourcename + target_body->hash.length;
 174         /* Scan the suffix list for the target if one exists. */
 175         if (target_suffix->has_suffixes) {
 176 posix_attempts:
 177                 for (source_suffix = get_prop(target_suffix->prop,
 178                                               suffix_prop);
 179                      source_suffix != NULL;
 180                      source_suffix = get_prop(source_suffix->next,
 181                                               suffix_prop)) {
 182                         /* Build the synthesized source name. */
 183                         (void) mbstowcs(put_suffix,
 184                                       source_suffix->body.
 185                                       suffix.suffix->string_mb,
 186                                       (int) source_suffix->body.
 187                                       suffix.suffix->hash.length);
 188                         put_suffix[source_suffix->body.
 189                                    suffix.suffix->hash.length] =
 190                           (int) nul_char;
 191                         if (debug_level > 1) {
 192                                 WCSTOMBS(mbs_buffer, sourcename);
 193                                 (void) printf(gettext("%*sTrying %s\n"),
 194                                               recursion_level,
 195                                               "",
 196                                               mbs_buffer);
 197                         }
 198                         source = getname_fn(sourcename, FIND_LENGTH, false, &name_found);
 199                         /*
 200                          * If the source file is not registered as
 201                          * a file, this source suffix did not match.
 202                          */
 203                         if(vpath_defined && !posix && !svr4) {
 204                                 (void) exists(source);  
 205                         }
 206                         if (!source->stat.is_file) {
 207                            if(!(posix|svr4))
 208                            {
 209                                 if(!name_found) {
 210                                         free_name(source);
 211                                 }
 212                                 continue;
 213                            }
 214 
 215                            /* following code will ensure that the corresponding
 216                            ** tilde rules are executed when corresponding s. file
 217                            ** exists in the current directory. Though the current
 218                            ** target ends with a ~ character, there wont be any
 219                            ** any file in the current directory with that suffix
 220                            ** as it's fictitious. Even if it exists, it'll
 221                            ** execute all the rules for the ~ target.
 222                            */
 223 
 224                            if(source->string_mb[source->hash.length - 1] == '~' &&
 225                               ( svr4 || posix_tilde_attempt ) )
 226                            {
 227                                 char *p, *np; 
 228                                 char *tmpbuf;
 229 
 230                                 tmpbuf = getmem(source->hash.length + 8); 
 231                                 /* + 8 to add "s." or "SCCS/s." */
 232                                 memset(tmpbuf,0,source->hash.length + 8);
 233                                 source->string_mb[source->hash.length - 1] = '\0';
 234                                 if(p = (char *) memchr((char *)source->string_mb,'/',source->hash.length)) 
 235                                 {
 236                                   while(1) {    
 237                                     if(np = (char *) memchr((char *)p+1,'/',source->hash.length - (p - source->string_mb))) {
 238                                       p = np;
 239                                     } else {break;}
 240                                   }
 241                                   /* copy everything including '/' */
 242                                   strncpy(tmpbuf, source->string_mb, p - source->string_mb + 1);
 243                                   strcat(tmpbuf, "s.");
 244                                   strcat(tmpbuf, p+1);
 245                                   retmem((wchar_t *) source->string_mb); 
 246                                   source->string_mb = tmpbuf;
 247                                 
 248                                 } else {
 249                                   strcpy(tmpbuf, "s.");
 250                                   strcat(tmpbuf, source->string_mb);
 251                                   retmem((wchar_t *) source->string_mb); 
 252                                   source->string_mb = tmpbuf;
 253                                 
 254                                 }
 255                                 source->hash.length = strlen(source->string_mb);
 256                                 if(exists(source) == file_doesnt_exist)
 257                                   continue;
 258                                 tilde_rule = true;
 259                                 we_are_in_tilde = true;
 260                            } else {
 261                                 if(!name_found) {
 262                                         free_name(source);
 263                                 }
 264                                 continue;
 265                            }
 266                         } else {
 267                            if(posix && posix_tilde_attempt) {
 268                                 if(exists(source) == file_doesnt_exist) {
 269                                         if(!name_found) {
 270                                                 free_name(source);
 271                                         }
 272                                         continue;
 273                                 }
 274                            } 
 275                         }
 276                         
 277                         if (command != NULL) {
 278                                 if(!name_found) {
 279                                         store_name(source);
 280                                 }
 281                                 /*
 282                                  * The source file is a file.
 283                                  * Make sure it is up to date.
 284                                  */
 285                                 if (dependency_exists(source,
 286                                                       get_prop(target->prop,
 287                                                                line_prop))) {
 288                                         result = (Doname) source->state;
 289                                 } else {
 290 #if 0  /* with_squiggle sends false, which is buggy. : djay */
 291                                         result = doname(source,
 292                                                         (Boolean) source_suffix->body.
 293                                                         suffix.suffix->with_squiggle,
 294                                                         true);
 295 #else
 296                                         result = doname(source,
 297                                                         true,
 298                                                         true);
 299 #endif
 300                                 }       
 301                         } else {
 302                                 result = target_can_be_built(source);
 303                                 
 304                                 if (result == build_ok) {
 305                                         return result;
 306                                 } else {
 307                                         if(!name_found) {
 308                                                 free_name(source);
 309                                         }
 310                                         continue;
 311                                 }
 312                         }
 313                         
 314                         switch (result) {
 315                         case build_dont_know:
 316                                 /*
 317                                  * If we still can't build the source,
 318                                  * this rule is not a match,
 319                                  * try the next one.
 320                                  */
 321                                 if (source->stat.time == file_doesnt_exist) {
 322                                         if(!name_found) {
 323                                                 free_name(source);
 324                                         }
 325                                         continue;
 326                                 }
 327                         case build_running:
 328                                 if(!name_found) {
 329                                         store_name(source);
 330                                 }
 331                                 true_target->suffix_scan_done = false;
 332                                 line = maybe_append_prop(target, line_prop);
 333                                 enter_dependency(line, source, false);
 334                                 line->body.line.target = true_target;
 335                                 return build_running;
 336                         case build_ok:
 337                                 if(!name_found) {
 338                                         store_name(source);
 339                                 }
 340                                 break;
 341                         case build_failed:
 342                                 if(!name_found) {
 343                                         store_name(source);
 344                                 }
 345                                 if (sourcename != static_string_buf_3M) {
 346                                         retmem(sourcename);
 347                                 }
 348                                 return build_failed;
 349                         }
 350                         
 351                         if (debug_level > 1) {
 352                                 WCSTOMBS(mbs_buffer, sourcename);
 353                                 (void) printf(gettext("%*sFound %s\n"),
 354                                               recursion_level,
 355                                               "",
 356                                               mbs_buffer);
 357                         }
 358                         
 359                         if (source->depends_on_conditional) {
 360                                 target->depends_on_conditional = true;
 361                         }
 362 /*
 363  * Since it is possible that the same target is built several times during
 364  * the make run, we have to patch the target with all information we found
 365  * here. Thus, the target will have an explicit rule the next time around.
 366  */
 367                         line = maybe_append_prop(target, line_prop);
 368                         if (*command == NULL) {
 369                                 *command = line;
 370                         }
 371                         if ((source->stat.time > (*command)->body.line.dependency_time) &&
 372                             (debug_level > 1)) {
 373                                 (void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
 374                                               recursion_level,
 375                                               "",
 376                                               source->string_mb,
 377                                               time_to_string(source->
 378                                                              stat.time),
 379                                               true_target->string_mb,
 380                                               time_to_string((*command)->
 381                                                              body.line.
 382                                                              dependency_time));
 383                         }
 384                         /*
 385                          * Determine if this new dependency made the
 386                          * target out of date.
 387                          */
 388                         (*command)->body.line.dependency_time =
 389                           MAX((*command)->body.line.dependency_time,
 390                               source->stat.time);
 391                         Boolean out_of_date;
 392                         if (target->is_member) {
 393                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time,
 394                                                                         (*command)->body.line.dependency_time);
 395                         } else {
 396                                 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time,
 397                                                                     (*command)->body.line.dependency_time);
 398                         }
 399                         if (build_unconditional || out_of_date) {
 400                                 if(!rechecking) {
 401                                         line->body.line.is_out_of_date = true;
 402                                 }
 403                                 if (debug_level > 0) {
 404                                         (void) printf(gettext("%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"),
 405                                                       recursion_level,
 406                                                       "",
 407                                                       true_target->string_mb,
 408                                                       source_suffix->body.suffix.suffix->string_mb,
 409                                                       target_suffix->string_mb,
 410                                                       source->string_mb);
 411                                 }
 412                         }
 413                         /*
 414                          * Add the implicit rule as the target's explicit
 415                          * rule if none actually given, and register
 416                          * dependency.
 417                          * The time checking above really should be
 418                          * conditional on actual use of implicit rule
 419                          * as well.
 420                          */
 421                         line->body.line.sccs_command = false;
 422                         if (line->body.line.command_template == NULL) {
 423                                 line->body.line.command_template =
 424                                   source_suffix->body.suffix.command_template;
 425                         }
 426                         enter_dependency(line, source, false);
 427                         line->body.line.target = true_target;
 428                         /*
 429                          * Also make sure the rule is built with
 430                          * $* and $< bound properly.
 431                          */
 432                         line->body.line.star = target_body;
 433                         if(svr4|posix) {
 434                           char * p;
 435                           char tstr[256];
 436                           extern Boolean dollarless_flag;
 437                           extern Name dollarless_value;
 438 
 439                           if(tilde_rule) {
 440                               MBSTOWCS(wcs_buffer, source->string_mb);
 441                               dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH);
 442                           }
 443                           else {
 444                                    dollarless_flag = false;
 445                           }
 446                         }
 447                         line->body.line.less = source;
 448                         line->body.line.percent = NULL;
 449                         add_target_to_chain(source, &(line->body.line.query));
 450                         if (sourcename != static_string_buf_3M) {
 451                                 retmem(sourcename);
 452                         }
 453                         return build_ok;
 454                 }
 455                 if(posix && posix_tilde_attempt) {
 456                         posix_tilde_attempt = false;
 457                         goto posix_attempts;
 458                 }
 459                 if ((command != NULL) &&
 460                     ((*command) != NULL) &&
 461                     ((*command)->body.line.star == NULL)) {
 462                         (*command)->body.line.star = target_body;
 463                 }
 464         }
 465         if (sourcename != static_string_buf_3M) {
 466                 retmem(sourcename);
 467         }
 468         /* Return here in case no rule matched the target */
 469         return build_dont_know;
 470 }
 471 
 472 /*
 473  *      find_ar_suffix_rule(target, true_target, command, rechecking)
 474  *
 475  *      Scans the .SUFFIXES list and tries
 476  *      to find a suffix on it that matches the tail of the target member name.
 477  *      If it finds a matching suffix it calls find_suffix_rule() to find
 478  *      a rule for the target using the suffix ".a".
 479  *
 480  *      Return value:
 481  *                              Indicates if search failed or not
 482  *
 483  *      Parameters:
 484  *              target          The target we need a rule for
 485  *              true_target     The proper name
 486  *              command         Pointer to slot where we stuff cmd, if found
 487  *              rechecking      true if we are rechecking target which depends
 488  *                              on conditional macro and keep_state is set
 489  *
 490  *      Global variables used:
 491  *              debug_level     Indicates how much tracing to do
 492  *              dot_a           The Name ".a", compared against
 493  *              recursion_level Used for tracing
 494  *              suffixes        List of suffixes used for scan (from .SUFFIXES)
 495  */
 496 Doname
 497 find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking)
 498 {
 499         wchar_t                 *target_end;
 500         register Dependency     suffix;
 501         register int            suffix_length;
 502         Property                line;
 503         Name                    body;
 504         static Name             dot_a;
 505 
 506         Wstring                 targ_string(true_target);
 507         Wstring                 suf_string;
 508 
 509         if (dot_a == NULL) {
 510                 MBSTOWCS(wcs_buffer, ".a");
 511                 dot_a = GETNAME(wcs_buffer, FIND_LENGTH);
 512         }
 513         target_end = targ_string.get_string() + true_target->hash.length;
 514 
 515         /*
 516          * We compare the tail of the target name with the suffixes
 517          * from .SUFFIXES.
 518          */
 519         if (debug_level > 1) {
 520                 (void) printf("%*sfind_ar_suffix_rule(%s)\n",
 521                               recursion_level,
 522                               "",
 523                               true_target->string_mb);
 524         }
 525         /*
 526          * Scan the .SUFFIXES list to see if the target matches any of
 527          * those suffixes.
 528          */
 529         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
 530                 /* Compare one suffix. */
 531                 suffix_length = suffix->name->hash.length;
 532                 suf_string.init(suffix->name);
 533                 if (!IS_WEQUALN(suf_string.get_string(),
 534                                 target_end - suffix_length,
 535                                 suffix_length)) {
 536                         goto not_this_one;
 537                 }
 538                 /*
 539                  * The target tail matched a suffix from the .SUFFIXES list.
 540                  * Now check for a rule to match.
 541                  */
 542                 target->suffix_scan_done = false;
 543                 body = GETNAME(targ_string.get_string(),
 544                                (int)(true_target->hash.length -
 545                                      suffix_length));
 546                 we_are_in_tilde = false;
 547                 switch (find_suffix_rule(target,
 548                                          body,
 549                                          dot_a,
 550                                          command,
 551                                          rechecking)) {
 552                 case build_ok:
 553                         line = get_prop(target->prop, line_prop);
 554                         line->body.line.star = body;
 555                         return build_ok;
 556                 case build_running:
 557                         return build_running;
 558                 }
 559                 /*
 560                  * If no rule was found, we try the next suffix to see
 561                  * if it matches the target tail, and so on.
 562                  * Go here if the suffix did not match the target tail.
 563                  */
 564         not_this_one:;                   
 565         }
 566         return build_dont_know;
 567 }
 568 
 569 /*
 570  *      find_double_suffix_rule(target, command, rechecking)
 571  *
 572  *      Scans the .SUFFIXES list and tries
 573  *      to find a suffix on it that matches the tail of the target name.
 574  *      If it finds a matching suffix it calls find_suffix_rule() to find
 575  *      a rule for the target.
 576  *
 577  *      Return value:
 578  *                              Indicates if scan failed or not
 579  *
 580  *      Parameters:
 581  *              target          Target we need a rule for
 582  *              command         Pointer to slot where we stuff cmd, if found
 583  *              rechecking      true if we are rechecking target which depends
 584  *                              on conditional macro and keep_state is set
 585  *
 586  *      Global variables used:
 587  *              debug_level     Indicates how much tracing to do
 588  *              recursion_level Used for tracing
 589  *              suffixes        List of suffixes used for scan (from .SUFFIXES)
 590  */
 591 Doname
 592 find_double_suffix_rule(register Name target, Property *command, Boolean rechecking)
 593 {
 594         Name                    true_target = target;
 595         Name                    target_body;
 596         register wchar_t        *target_end;
 597         register Dependency     suffix;
 598         register int            suffix_length;
 599         Boolean                 scanned_once = false;
 600         Boolean                 name_found = true;
 601 
 602         Wstring                 targ_string;
 603         Wstring                 suf_string;
 604 
 605         /*
 606          * If the target is a constructed one for a "::" target,
 607          * we need to consider that.
 608          */
 609         if (target->has_target_prop) {
 610                 true_target = get_prop(target->prop,
 611                                        target_prop)->body.target.target;
 612         }
 613         targ_string.init(true_target);
 614 
 615         /*
 616          * We compare the tail of the target name with the
 617          * suffixes from .SUFFIXES.
 618          */
 619         target_end = targ_string.get_string() + true_target->hash.length;
 620         if (debug_level > 1) {
 621                 (void) printf("%*sfind_double_suffix_rule(%s)\n",
 622                               recursion_level,
 623                               "",
 624                               true_target->string_mb);
 625         }
 626         /*
 627          * Scan the .SUFFIXES list to see if the target matches
 628          * any of those suffixes.
 629          */
 630         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
 631                 target->suffix_scan_done = false;
 632                 true_target->suffix_scan_done = false;
 633                 /* Compare one suffix. */
 634                 suffix_length = suffix->name->hash.length;
 635                 suf_string.init(suffix->name);
 636                 /* Check the lengths, or else RTC will report rua. */
 637                 if (true_target->hash.length < suffix_length) {
 638                         goto not_this_one;
 639                 } else if (!IS_WEQUALN(suf_string.get_string(),
 640                                 (target_end - suffix_length),
 641                                 suffix_length)) {
 642                         goto not_this_one;
 643                 }
 644                 /*
 645                  * The target tail matched a suffix from the .SUFFIXES list.
 646                  * Now check for a rule to match.
 647                  */
 648                 we_are_in_tilde = false;
 649                 target_body = GETNAME(
 650                         targ_string.get_string(),
 651                         (int)(true_target->hash.length - suffix_length)
 652                 );
 653                 switch (find_suffix_rule(target,
 654                                          target_body,
 655                                          suffix->name,
 656                                          command,
 657                                          rechecking)) {
 658                 case build_ok:
 659                         return build_ok;
 660                 case build_running:
 661                         return build_running;
 662                 }
 663                 if (true_target->suffix_scan_done == true) {
 664                         scanned_once = true;
 665                 }
 666                 /*
 667                  * If no rule was found, we try the next suffix to see
 668                  * if it matches the target tail. And so on.
 669                  * Go here if the suffix did not match the target tail.
 670                  */
 671         not_this_one:;                   
 672         }
 673         if (scanned_once)
 674                 true_target->suffix_scan_done = true;
 675         return build_dont_know;
 676 }
 677 
 678 /*
 679  *      build_suffix_list(target_suffix)
 680  *
 681  *      Scans the .SUFFIXES list and figures out
 682  *      which suffixes this target can be derived from.
 683  *      The target itself is not know here, we just know the suffix of the
 684  *      target. For each suffix on the list the target can be derived iff
 685  *      a rule exists for the name "<suffix-on-list><target-suffix>".
 686  *      A list of all possible building suffixes is built, with the rule for
 687  *      each, and tacked to the target suffix nameblock.
 688  *
 689  *      Parameters:
 690  *              target_suffix   The suffix we build a match list for
 691  *
 692  *      Global variables used:
 693  *              debug_level     Indicates how much tracing to do
 694  *              recursion_level Used for tracing
 695  *              suffixes        List of suffixes used for scan (from .SUFFIXES)
 696  *              working_on_targets Indicates that this is a real target
 697  */
 698 void
 699 build_suffix_list(register Name target_suffix)
 700 {
 701         register Dependency     source_suffix;
 702         wchar_t                 rule_name[MAXPATHLEN];
 703         register Property       line;
 704         register Property       suffix;
 705         Name                    rule;
 706 
 707         /* If this is before default.mk has been read we just return to try */
 708         /* again later */
 709         if ((suffixes == NULL) || !working_on_targets) {
 710                 return;
 711         }
 712         if (debug_level > 1) {
 713                 (void) printf("%*sbuild_suffix_list(%s) ",
 714                               recursion_level,
 715                               "",
 716                               target_suffix->string_mb);
 717         }
 718         /* Mark the target suffix saying we cashed its list */
 719         target_suffix->has_read_suffixes = true;
 720         /* Scan the .SUFFIXES list */
 721         for (source_suffix = suffixes;
 722              source_suffix != NULL;
 723              source_suffix = source_suffix->next) {
 724                 /*
 725                  * Build the name "<suffix-on-list><target-suffix>".
 726                  * (a popular one would be ".c.o").
 727                  */
 728                 (void) mbstowcs(rule_name,
 729                               source_suffix->name->string_mb,
 730                               (int) source_suffix->name->hash.length);
 731                 (void) mbstowcs(rule_name + source_suffix->name->hash.length,
 732                               target_suffix->string_mb,
 733                               (int) target_suffix->hash.length);
 734                 /*
 735                  * Check if that name has a rule. If not, it cannot match
 736                  * any implicit rule scan and is ignored.
 737                  * The GETNAME() call only checks for presence, it will not
 738                  * enter the name if it is not defined.
 739                  */
 740                 if (((rule = getname_fn(rule_name,
 741                                         (int) (source_suffix->name->
 742                                                hash.length +
 743                                                target_suffix->hash.length),
 744                                         true)) != NULL) &&
 745                     ((line = get_prop(rule->prop, line_prop)) != NULL)) {
 746                         if (debug_level > 1) {
 747                                 (void) printf("%s ", rule->string_mb);
 748                         }
 749                         /*
 750                          * This makes it possible to quickly determine if
 751                          * it will pay to look for a suffix property.
 752                          */
 753                         target_suffix->has_suffixes = true;
 754                         /*
 755                          * Add the suffix property to the target suffix
 756                          * and save the rule with it.
 757                          * All information the implicit rule scanner need
 758                          * is saved in the suffix property.
 759                          */
 760                         suffix = append_prop(target_suffix, suffix_prop);
 761                         suffix->body.suffix.suffix = source_suffix->name;
 762                         suffix->body.suffix.command_template =
 763                           line->body.line.command_template;
 764                 }
 765         }
 766         if (debug_level > 1) {
 767                 (void) printf("\n");
 768         }
 769 }
 770 
 771 /*
 772  *      find_percent_rule(target, command, rechecking)
 773  *
 774  *      Tries to find a rule from the list of wildcard matched rules.
 775  *      It scans the list attempting to match the target.
 776  *      For each target match it checks if the corresponding source exists.
 777  *      If it does the match is returned.
 778  *      The percent_list is built at makefile read time.
 779  *      Each percent rule get one entry on the list.
 780  *
 781  *      Return value:
 782  *                              Indicates if the scan failed or not
 783  *
 784  *      Parameters:
 785  *              target          The target we need a rule for
 786  *              command         Pointer to slot where we stuff cmd, if found
 787  *              rechecking      true if we are rechecking target which depends
 788  *                              on conditional macro and keep_state is set
 789  *
 790  *      Global variables used:
 791  *              debug_level     Indicates how much tracing to do
 792  *              percent_list    List of all percent rules
 793  *              recursion_level Used for tracing
 794  *              empty_name
 795  */
 796 Doname
 797 find_percent_rule(register Name target, Property *command, Boolean rechecking)
 798 {
 799         register Percent        pat_rule, pat_depe;
 800         register Name           depe_to_check;
 801         register Dependency     depe;
 802         register Property       line;
 803         String_rec              string;
 804         wchar_t                 string_buf[STRING_BUFFER_LENGTH];
 805         String_rec              percent;
 806         wchar_t                 percent_buf[STRING_BUFFER_LENGTH];
 807         Name                    true_target = target;
 808         Name                    less;
 809         Boolean                 nonpattern_less;
 810         Boolean                 dep_name_found = false;
 811         Doname                  result = build_dont_know;
 812         Percent                 rule_candidate = NULL;
 813         Boolean                 rule_maybe_ok;
 814         Boolean                 is_pattern;
 815 
 816         /* If the target is constructed for a "::" target we consider that */
 817         if (target->has_target_prop) {
 818                 true_target = get_prop(target->prop,
 819                                        target_prop)->body.target.target;
 820         }
 821         if (target->has_long_member_name) {
 822                 true_target = get_prop(target->prop,
 823                                        long_member_name_prop)->body.long_member_name.member_name;
 824         }
 825         if (debug_level > 1) {
 826                 (void) printf(gettext("%*sLooking for %% rule for %s\n"),
 827                               recursion_level,
 828                               "",
 829                               true_target->string_mb);
 830         }
 831         for (pat_rule = percent_list;
 832              pat_rule != NULL;
 833              pat_rule = pat_rule->next) {
 834                 /* Avoid infinite recursion when expanding patterns */
 835                 if (pat_rule->being_expanded == true) {
 836                         continue;
 837                 }
 838 
 839                 /* Mark this pat_rule as "maybe ok". If no % rule is found
 840                    make will use this rule. The following algorithm is used:
 841                    1) make scans all pattern rules in order to find the rule
 842                       where ALL dependencies, including nonpattern ones, exist or
 843                       can be built (GNU behaviour). If such rule is found make
 844                       will apply it.
 845                    2) During this check make also remembers the first pattern rule
 846                       where all PATTERN dependencies can be build (no matter what
 847                       happens with nonpattern dependencies).
 848                    3) If no rule satisfying 1) is found, make will apply the rule
 849                       remembered in 2) if there is one.
 850                 */
 851                 rule_maybe_ok = true;
 852 
 853                 /* used to track first percent dependency */
 854                 less = NULL;
 855                 nonpattern_less = true;
 856 
 857                 /* check whether pattern matches.
 858                    if it matches, percent string will contain matched percent part of pattern */
 859                 if (!match_found_with_pattern(true_target, pat_rule, &percent, percent_buf)) {
 860                         continue;
 861                 }
 862                 if (pat_rule->dependencies != NULL) {
 863                         for (pat_depe = pat_rule->dependencies;
 864                              pat_depe != NULL;
 865                              pat_depe = pat_depe->next) {
 866                                 /* checking result for dependency */
 867                                 result = build_dont_know;
 868 
 869                                 dep_name_found = true;
 870                                 if (pat_depe->name->percent) {
 871                                         is_pattern = true;
 872                                         /* build dependency name */
 873                                         INIT_STRING_FROM_STACK(string, string_buf);
 874                                         construct_string_from_pattern(pat_depe, &percent, &string); 
 875                                         depe_to_check = getname_fn(string.buffer.start,
 876                                                 FIND_LENGTH,
 877                                                 false,
 878                                                 &dep_name_found
 879                                         );
 880 
 881                                         if ((less == NULL) || nonpattern_less) {
 882                                                 less = depe_to_check;
 883                                                 nonpattern_less = false;
 884                                         }
 885                                 } else {
 886                                         /* nonpattern dependency */
 887                                         is_pattern = false;
 888                                         depe_to_check = pat_depe->name;
 889                                         if(depe_to_check->dollar) {
 890                                                 INIT_STRING_FROM_STACK(string, string_buf);
 891                                                 expand_value(depe_to_check, &string, false);
 892                                                 depe_to_check = getname_fn(string.buffer.start,
 893                                                         FIND_LENGTH,
 894                                                         false,
 895                                                         &dep_name_found
 896                                                 );
 897                                         }
 898                                         if (less == NULL) {
 899                                                 less = depe_to_check;
 900                                         }
 901                                 }
 902 
 903                                 if (depe_to_check == empty_name) {
 904                                                 result = build_ok;
 905                                 } else {
 906                                         if (debug_level > 1) {
 907                                                 (void) printf(gettext("%*sTrying %s\n"),
 908                                                               recursion_level,
 909                                                               "",
 910                                                               depe_to_check->string_mb);
 911                                         }
 912 
 913                                         pat_rule->being_expanded = true;
 914 
 915                                         /* suppress message output */
 916                                         int save_debug_level = debug_level;
 917                                         debug_level = 0;
 918 
 919                                         /* check whether dependency can be built */
 920                                         if (dependency_exists(depe_to_check,
 921                                               get_prop(target->prop,
 922                                                        line_prop)))
 923                                         {
 924                                                 result = (Doname) depe_to_check->state;
 925                                         } else {
 926                                                 if(actual_doname) {
 927                                                         result = doname(depe_to_check, true, true);
 928                                                 } else {
 929                                                         result = target_can_be_built(depe_to_check);
 930                                                 }
 931                                                 if(!dep_name_found) {
 932                                                         if(result != build_ok && result != build_running) {
 933                                                                 free_name(depe_to_check);
 934                                                         } else {
 935                                                                 store_name(depe_to_check);
 936                                                         }
 937                                                 }
 938                                         }
 939                                         if(result != build_ok && is_pattern) {
 940                                                 rule_maybe_ok = false;
 941                                         }
 942 
 943                                         /* restore debug_level */
 944                                         debug_level = save_debug_level;
 945                                 }
 946 
 947                                 if (pat_depe->name->percent) {
 948                                         if (string.free_after_use) {
 949                                                 retmem(string.buffer.start);
 950                                         }
 951                                 }
 952                                 /* make can't figure out how to make this dependency */
 953                                 if (result != build_ok && result != build_running) {
 954                                         pat_rule->being_expanded = false;
 955                                         break;
 956                                 }
 957                         }
 958                 } else {
 959                         result = build_ok;
 960                 }
 961 
 962                 /* this pattern rule is the needed one since all dependencies could be built */
 963                 if (result == build_ok || result == build_running) {
 964                         break;
 965                 }
 966 
 967                 /* Make does not know how to build some of dependencies from this rule.
 968                    But if all "pattern" dependencies can be built, we remember this rule
 969                    as a candidate for the case if no other pattern rule found.
 970                 */
 971                 if(rule_maybe_ok && rule_candidate == NULL) {
 972                         rule_candidate = pat_rule;
 973                 }
 974         }
 975 
 976         /* if no pattern matching rule was found, use the remembered candidate
 977            or return build_dont_know if there is no candidate.
 978         */
 979         if (result != build_ok && result != build_running) {
 980                 if(rule_candidate) {
 981                         pat_rule = rule_candidate;
 982                 } else {
 983                         return build_dont_know;
 984                 }
 985         }
 986 
 987         /* if we are performing only check whether dependency could be built with existing rules,
 988            return success */
 989         if (command == NULL) {
 990                 if(pat_rule != NULL) {
 991                         pat_rule->being_expanded = false;
 992                 }
 993                 return result;
 994         }
 995 
 996         if (debug_level > 1) {
 997                 (void) printf(gettext("%*sMatched %s:"),
 998                                       recursion_level,
 999                                       "",
1000                                       target->string_mb);
1001 
1002                 for (pat_depe = pat_rule->dependencies;
1003                      pat_depe != NULL;
1004                      pat_depe = pat_depe->next) {
1005                         if (pat_depe->name->percent) {
1006                                 INIT_STRING_FROM_STACK(string, string_buf);
1007                                 construct_string_from_pattern(pat_depe, &percent, &string);
1008                                 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1009                         } else {
1010                                 depe_to_check = pat_depe->name;
1011                                 if(depe_to_check->dollar) {
1012                                         INIT_STRING_FROM_STACK(string, string_buf);
1013                                         expand_value(depe_to_check, &string, false);
1014                                         depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1015                                 }
1016                         }
1017 
1018                         if (depe_to_check != empty_name) {
1019                                 (void) printf(" %s", depe_to_check->string_mb);
1020                         }
1021                 }
1022 
1023                 (void) printf(gettext(" from: %s:"),
1024                               pat_rule->name->string_mb);
1025 
1026                 for (pat_depe = pat_rule->dependencies;
1027                      pat_depe != NULL;
1028                      pat_depe = pat_depe->next) {
1029                         (void) printf(" %s", pat_depe->name->string_mb);
1030                 }
1031 
1032                 (void) printf("\n");
1033         }
1034 
1035         if (true_target->colons == no_colon) {
1036                 true_target->colons = one_colon;
1037         }
1038 
1039         /* create deppendency list and target group from matched pattern rule */
1040         create_target_group_and_dependencies_list(target, pat_rule, &percent);
1041 
1042         /* save command */
1043         line = get_prop(target->prop, line_prop);
1044         *command = line;
1045 
1046         /* free query chain if one exist */
1047         while(line->body.line.query != NULL) {
1048                 Chain to_free = line->body.line.query;
1049                 line->body.line.query = line->body.line.query->next;
1050                 retmem_mb((char *) to_free);
1051         }
1052 
1053         if (line->body.line.dependencies != NULL) {
1054                 /* build all collected dependencies */
1055                 for (depe = line->body.line.dependencies;
1056                      depe != NULL; 
1057                      depe = depe->next) {
1058                         actual_doname = true;
1059                         result = doname_check(depe->name, true, true, depe->automatic);
1060 
1061                         actual_doname = false;
1062                         if (result == build_failed) {
1063                                 pat_rule->being_expanded = false;
1064                                 return build_failed;
1065                         }
1066                         if (result == build_running) {
1067                                 pat_rule->being_expanded = false;
1068                                 return build_running;
1069                         }
1070 
1071                         if ((depe->name->stat.time > line->body.line.dependency_time) &&
1072                             (debug_level > 1)) {
1073                                 (void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
1074                                               recursion_level,
1075                                               "",
1076                                               depe->name->string_mb,
1077                                               time_to_string(depe->name->stat.time),
1078                                               true_target->string_mb,
1079                                               time_to_string(line->body.line.dependency_time));
1080                         }
1081 
1082                         line->body.line.dependency_time =
1083                           MAX(line->body.line.dependency_time, depe->name->stat.time);
1084 
1085                         /* determine whether this dependency made target out of date */
1086                         Boolean out_of_date;
1087                         if (target->is_member || depe->name->is_member) {
1088                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time);
1089                         } else {
1090                                 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time);
1091                         }
1092                         if (build_unconditional || out_of_date) {
1093                                 if(!rechecking) {
1094                                         line->body.line.is_out_of_date = true;
1095                                 }
1096                                 add_target_to_chain(depe->name, &(line->body.line.query));
1097 
1098                                 if (debug_level > 0) {
1099                                         (void) printf(gettext("%*sBuilding %s using pattern rule %s:"),
1100                                                       recursion_level,
1101                                                       "",
1102                                                       true_target->string_mb,
1103                                                       pat_rule->name->string_mb);
1104 
1105                                         for (pat_depe = pat_rule->dependencies;
1106                                              pat_depe != NULL;
1107                                              pat_depe = pat_depe->next) {
1108                                                 (void) printf(" %s", pat_depe->name->string_mb);
1109                                         }
1110 
1111                                         (void) printf(gettext(" because it is out of date relative to %s\n"), 
1112                                                       depe->name->string_mb);
1113                                 }       
1114                         }
1115                 }
1116         } else {
1117                 if ((true_target->stat.time <= file_doesnt_exist) ||
1118                     (true_target->stat.time < line->body.line.dependency_time)) {
1119                         if(!rechecking) {
1120                                 line->body.line.is_out_of_date = true;
1121                         }
1122                         if (debug_level > 0) {
1123                                 (void) printf(gettext("%*sBuilding %s using pattern rule %s: "),
1124                                               recursion_level,
1125                                               "",
1126                                               true_target->string_mb,
1127                                               pat_rule->name->string_mb,
1128                                               (target->stat.time > file_doesnt_exist) ?
1129                                               gettext("because it is out of date") :
1130                                               gettext("because it does not exist"));
1131                         }
1132                 }
1133         }
1134 
1135         /* enter explicit rule from percent rule */     
1136         Name lmn_target = true_target;
1137         if (true_target->has_long_member_name) {
1138                 lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name;
1139         }
1140         line->body.line.sccs_command = false;
1141         line->body.line.target = true_target;
1142         line->body.line.command_template = pat_rule->command_template;
1143         line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH);
1144         line->body.line.less = less;
1145 
1146         if (lmn_target->parenleft) {
1147                 Wstring lmn_string(lmn_target);
1148 
1149                 wchar_t *left = (wchar_t *) wcschr(lmn_string.get_string(), (int) parenleft_char);
1150                 wchar_t *right = (wchar_t *) wcschr(lmn_string.get_string(), (int) parenright_char);
1151 
1152                 if ((left == NULL) || (right == NULL)) {
1153                         line->body.line.percent = NULL;
1154                 } else {
1155                         line->body.line.percent = GETNAME(left + 1, right - left - 1);
1156                 }
1157         } else {
1158                 line->body.line.percent = NULL;
1159         }
1160         pat_rule->being_expanded = false;
1161 
1162         return result;
1163 }
1164 
1165 /*
1166  *      match_found_with_pattern 
1167  *           ( target, pat_rule, percent, percent_buf)
1168  *      
1169  *      matches "target->string" with a % pattern.
1170  *      If pattern contains a MACRO definition, it's expanded first.
1171  *
1172  *      Return value:
1173  *                              true if a match was found
1174  *
1175  *      Parameters:
1176  *              target          The target we're trying to match
1177  *              pattern         
1178  *              percent         record that contains "percent_buf" below
1179  *              percent_buf     This is where the patched % part of pattern is stored 
1180  *
1181  */
1182 
1183 static Boolean
1184 match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf) {
1185         String_rec              string;
1186         wchar_t                 string_buf[STRING_BUFFER_LENGTH];
1187 
1188         /* construct prefix string and check whether prefix matches */
1189         Name prefix = pat_rule->patterns[0];
1190         int prefix_length;
1191 
1192         Wstring targ_string(target);
1193         Wstring pref_string(prefix);
1194         Wstring suf_string;
1195 
1196         if (prefix->dollar) {        
1197                 INIT_STRING_FROM_STACK(string, string_buf);
1198                 expand_value(prefix, &string, false);
1199                 prefix_length = string.text.p - string.buffer.start;
1200                 if ((string.buffer.start[0] == (int) period_char) &&
1201                     (string.buffer.start[1] == (int) slash_char)) {
1202                         string.buffer.start += 2;
1203                         prefix_length -= 2;
1204                 }
1205                 if (!targ_string.equaln(string.buffer.start, prefix_length)) {
1206                         return false;
1207                 }
1208         } else {
1209                 prefix_length = prefix->hash.length;
1210                 if (!targ_string.equaln(&pref_string, prefix_length)) {
1211                         return false;
1212                 }
1213         }
1214 
1215         /* do the same with pattern suffix */
1216         Name suffix = pat_rule->patterns[pat_rule->patterns_total - 1];
1217         suf_string.init(suffix);
1218 
1219         int suffix_length;
1220         if (suffix->dollar) {
1221                 INIT_STRING_FROM_STACK(string, string_buf);
1222                 expand_value(suffix, &string, false);
1223                 suffix_length = string.text.p - string.buffer.start;
1224                 if(suffix_length > target->hash.length) {
1225                         return false;
1226                 }
1227                 if (!targ_string.equal(string.buffer.start, target->hash.length - suffix_length)) {
1228                         return false;
1229                 }
1230         } else {
1231                 suffix_length = (int) suffix->hash.length;
1232                 if(suffix_length > target->hash.length) {
1233                         return false;
1234                 }
1235                 if (!targ_string.equal(&suf_string, target->hash.length - suffix_length)) {
1236                         return false;
1237                 }
1238         }
1239 
1240         Boolean match_found = false;
1241         int percent_length = target->hash.length - prefix_length - suffix_length;
1242         
1243         while (!match_found && (percent_length >= 0)) {
1244                 /* init result string */
1245                 INIT_STRING_FROM_STACK(string, string_buf);
1246 
1247                 /* init percent string */
1248                 percent->buffer.start = percent_buf;
1249                 percent->text.p = percent_buf;
1250                 percent->text.end = NULL;
1251                 percent->free_after_use = false;
1252                 percent->buffer.end = percent_buf + STRING_BUFFER_LENGTH;
1253 
1254                 /* construct percent and result strings */
1255                 targ_string.append_to_str(percent, prefix_length, percent_length);
1256                 construct_string_from_pattern(pat_rule, percent, &string);
1257 
1258                 /* check for match */
1259                 if (targ_string.equal(string.buffer.start, 0)) {
1260                         match_found = true;
1261                 } else {
1262                         percent_length--;
1263                 }
1264         }
1265         
1266         /* result */
1267         return match_found;
1268 }
1269 
1270 
1271 /*
1272  *      create_target_group_and_dependencies_list
1273  *           (target, pat_rule, percent)
1274  *      
1275  *      constructs dependency list and a target group from pattern.
1276  *
1277  *      If we have the lines
1278  *              %/%.a + %/%.b + C%/CC%.c: yyy %.d bb%/BB%.e
1279  *                      commands
1280  *
1281  *      and we have matched the pattern xx/xx.a with %/%.a, then we
1282  *      construct a target group that looks like this:
1283  *              xx/xx.a + xx/xx.b + Cxx/CCxx.c: dependencies
1284  *
1285  *      and construct dependency list that looks like this:
1286  *      yyy xx.d bbxx/BBxx.e + already existed dependencies
1287  *      
1288  *      Return value:
1289  *                              none
1290  *
1291  *      Parameters:
1292  *              target          The target we are building, in the previous
1293  *                              example, this is xx/xx.a
1294  *              pat_rule        the % pattern that matched "target", here %/%.a
1295  *              percent         string containing matched % part. In the example=xx.
1296  *
1297  *      Global variables used:
1298  *              empty_name
1299  */
1300 
1301 static void
1302 create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent) {
1303         String_rec      string;
1304         wchar_t         string_buf[STRING_BUFFER_LENGTH];
1305         Percent         pat_depe;
1306         Name            depe;
1307         Property        line = maybe_append_prop(target, line_prop);
1308         Chain           new_target_group = NULL;
1309         Chain           *new_target_group_tail = &new_target_group;
1310         Chain           group_member;
1311         
1312         /* create and append dependencies from rule */
1313         for (pat_depe = pat_rule->dependencies; pat_depe != NULL; pat_depe = pat_depe->next) {
1314                 if (pat_depe->name->percent) {
1315                         INIT_STRING_FROM_STACK(string, string_buf);
1316                         construct_string_from_pattern(pat_depe, percent, &string);
1317                         depe = GETNAME(string.buffer.start, FIND_LENGTH);
1318                         if (depe != empty_name) {
1319                                 enter_dependency(line, depe, false);
1320                         }
1321                 } else {
1322                         depe = pat_depe->name;
1323                         if(depe->dollar) {
1324                                 INIT_STRING_FROM_STACK(string, string_buf);
1325                                 expand_value(depe, &string, false);
1326                                 depe = GETNAME(string.buffer.start, FIND_LENGTH);
1327                         }
1328                         enter_dependency(line, depe, false);
1329                 }
1330         }
1331         
1332         /* if matched pattern is a group member, create new target group */
1333         for (group_member = pat_rule->target_group; group_member != NULL; group_member = group_member->next) {
1334                 Name new_target = group_member->name;
1335                 if (group_member->name->percent) {
1336                         INIT_STRING_FROM_STACK(string, string_buf);
1337                         construct_string_from_pattern(group_member->percent_member, percent, &string);
1338                         new_target = GETNAME(string.buffer.start, FIND_LENGTH);
1339                         if (new_target == empty_name) {
1340                                 continue;
1341                         }
1342                 }
1343 
1344                 /* check for duplicates */
1345                 Chain   tgm;
1346                 for (tgm = new_target_group; tgm != NULL; tgm = tgm->next) {
1347                         if (new_target == tgm->name) {
1348                                 break;
1349                         }
1350                 }
1351                 if (tgm != NULL) {
1352                         continue;
1353                 }
1354                 
1355                 /* insert it into the targets list */
1356                 (*new_target_group_tail) = ALLOC(Chain);
1357                 (*new_target_group_tail)->name = new_target;
1358                 (*new_target_group_tail)->next = NULL;
1359                 new_target_group_tail = &(*new_target_group_tail)->next;
1360         }
1361         
1362         /* now we gathered all dependencies and created target group */
1363         line->body.line.target_group = new_target_group;
1364 
1365         /* update properties for group members */
1366         for (group_member = new_target_group; group_member != NULL; group_member = group_member->next) {
1367                 if (group_member->name != target) {
1368                         group_member->name->prop = target->prop;
1369                         group_member->name->conditional_cnt = target->conditional_cnt;
1370                 }
1371         }
1372 }
1373 
1374 /*
1375  *      construct_string_from_pattern
1376  *              (pat_rule, percent, result)
1377  *
1378  *      after pattern matched a target this routine is called to construct targets and dependencies
1379  *      strings from this matched pattern rule and a string (percent) with substitutes % sign in pattern.
1380  *
1381  *      Return value:
1382  *                              none
1383  *
1384  *      Parameters:
1385  *              pat_rule        matched pattern rule
1386  *              percent         string containing matched % sign part.
1387  *              result          holds the result of string construction.
1388  *
1389  */
1390 static void
1391 construct_string_from_pattern(Percent pat_rule, String percent, String result) {
1392         for (int i = 0; i < pat_rule->patterns_total; i++) {
1393                 if (pat_rule->patterns[i]->dollar) {
1394                         expand_value(pat_rule->patterns[i],
1395                                      result,
1396                                      false);
1397                         
1398                 } else {
1399                         append_string(pat_rule->patterns[i]->string_mb,
1400                                       result,
1401                                       pat_rule->patterns[i]->hash.length);
1402                 }
1403                 
1404                 if (i < pat_rule->patterns_total - 1) {
1405                         append_string(percent->buffer.start,
1406                                       result,
1407                                       percent->text.p - percent->buffer.start);
1408                 }
1409         }
1410         
1411         if ((result->buffer.start[0] == (int) period_char) &&
1412             (result->buffer.start[1] == (int) slash_char)) {
1413                 result->buffer.start += 2;
1414         }
1415 }
1416 
1417 /*
1418  *      dependency_exists(target, line)
1419  *
1420  *      Returns true if the target exists in the
1421  *      dependency list of the line.
1422  *
1423  *      Return value:
1424  *                              True if target is on dependency list
1425  *
1426  *      Parameters:
1427  *              target          Target we scan for
1428  *              line            We get the dependency list from here
1429  *
1430  *      Global variables used:
1431  */
1432 static Boolean
1433 dependency_exists(Name target, Property line)
1434 {
1435         Dependency      dp;
1436 
1437         if (line == NULL) {
1438                 return false;
1439         }
1440         for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
1441                 if (dp->name == target) {
1442                         return true;
1443                 }
1444         }
1445         return false;
1446 }
1447 
1448 void
1449 add_target_to_chain(Name target, Chain * query)
1450 {
1451         if (target->is_member && (get_prop(target->prop, member_prop) != NULL)) {
1452                 target = get_prop(target->prop, member_prop)->body.member.member;
1453         }
1454         Chain   *query_tail;
1455         for (query_tail = query; *query_tail != NULL; query_tail = &(*query_tail)->next) {
1456                 if ((*query_tail)->name == target) {
1457                         return;
1458                 }
1459         }
1460         *query_tail = ALLOC(Chain);
1461         (*query_tail)->name = target;
1462         (*query_tail)->next = NULL;
1463 }
1464