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