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