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