Print this page
make: translate using gettext, rather than the unmaintainable catgets


  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);


 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) {


 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                            }


 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) {


 332                                 enter_dependency(line, source, false);
 333                                 line->body.line.target = true_target;
 334                                 return build_running;
 335                         case build_ok:
 336                                 if(!name_found) {
 337                                         store_name(source);
 338                                 }
 339                                 break;
 340                         case build_failed:
 341                                 if(!name_found) {
 342                                         store_name(source);
 343                                 }
 344                                 if (sourcename != static_string_buf_3M) {
 345                                         retmem(sourcename);
 346                                 }
 347                                 return build_failed;
 348                         }
 349                         
 350                         if (debug_level > 1) {
 351                                 WCSTOMBS(mbs_buffer, sourcename);
 352                                 (void) printf(catgets(catd, 1, 219, "%*sFound %s\n"),
 353                                               recursion_level,
 354                                               "",
 355                                               mbs_buffer);
 356                         }
 357                         
 358                         if (source->depends_on_conditional) {
 359                                 target->depends_on_conditional = true;
 360                         }
 361 /*
 362  * Since it is possible that the same target is built several times during
 363  * the make run, we have to patch the target with all information we found
 364  * here. Thus, the target will have an explicit rule the next time around.
 365  */
 366                         line = maybe_append_prop(target, line_prop);
 367                         if (*command == NULL) {
 368                                 *command = line;
 369                         }
 370                         if ((source->stat.time > (*command)->body.line.dependency_time) &&
 371                             (debug_level > 1)) {
 372                                 (void) printf(catgets(catd, 1, 220, "%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
 373                                               recursion_level,
 374                                               "",
 375                                               source->string_mb,
 376                                               time_to_string(source->
 377                                                              stat.time),
 378                                               true_target->string_mb,
 379                                               time_to_string((*command)->
 380                                                              body.line.
 381                                                              dependency_time));
 382                         }
 383                         /*
 384                          * Determine if this new dependency made the
 385                          * target out of date.
 386                          */
 387                         (*command)->body.line.dependency_time =
 388                           MAX((*command)->body.line.dependency_time,
 389                               source->stat.time);
 390                         Boolean out_of_date;
 391                         if (target->is_member) {
 392                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time,
 393                                                                         (*command)->body.line.dependency_time);
 394                         } else {
 395                                 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time,
 396                                                                     (*command)->body.line.dependency_time);
 397                         }
 398                         if (build_unconditional || out_of_date) {
 399                                 if(!rechecking) {
 400                                         line->body.line.is_out_of_date = true;
 401                                 }
 402                                 if (debug_level > 0) {
 403                                         (void) printf(catgets(catd, 1, 221, "%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"),
 404                                                       recursion_level,
 405                                                       "",
 406                                                       true_target->string_mb,
 407                                                       source_suffix->body.suffix.suffix->string_mb,
 408                                                       target_suffix->string_mb,
 409                                                       source->string_mb);
 410                                 }
 411                         }
 412                         /*
 413                          * Add the implicit rule as the target's explicit
 414                          * rule if none actually given, and register
 415                          * dependency.
 416                          * The time checking above really should be
 417                          * conditional on actual use of implicit rule
 418                          * as well.
 419                          */
 420                         line->body.line.sccs_command = false;
 421                         if (line->body.line.command_template == NULL) {
 422                                 line->body.line.command_template =
 423                                   source_suffix->body.suffix.command_template;
 424                         }
 425                         enter_dependency(line, source, false);
 426                         line->body.line.target = true_target;
 427                         /*
 428                          * Also make sure the rule is built with
 429                          * $* and $< bound properly.
 430                          */
 431                         line->body.line.star = target_body;
 432                         if(svr4|posix) {
 433                           char * p;
 434                           char tstr[256];
 435                           extern Boolean dollarless_flag;
 436                           extern Name dollarless_value;
 437 
 438                           if(tilde_rule) {
 439                               MBSTOWCS(wcs_buffer, NOCATGETS(source->string_mb));
 440                               dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH);
 441                           }
 442                           else {
 443                                    dollarless_flag = false;
 444                           }
 445                         }
 446                         line->body.line.less = source;
 447                         line->body.line.percent = NULL;
 448                         add_target_to_chain(source, &(line->body.line.query));
 449                         if (sourcename != static_string_buf_3M) {
 450                                 retmem(sourcename);
 451                         }
 452                         return build_ok;
 453                 }
 454                 if(posix && posix_tilde_attempt) {
 455                         posix_tilde_attempt = false;
 456                         goto posix_attempts;
 457                 }
 458                 if ((command != NULL) &&
 459                     ((*command) != NULL) &&


 489  *      Global variables used:
 490  *              debug_level     Indicates how much tracing to do
 491  *              dot_a           The Name ".a", compared against
 492  *              recursion_level Used for tracing
 493  *              suffixes        List of suffixes used for scan (from .SUFFIXES)
 494  */
 495 Doname
 496 find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking)
 497 {
 498         wchar_t                 *target_end;
 499         register Dependency     suffix;
 500         register int            suffix_length;
 501         Property                line;
 502         Name                    body;
 503         static Name             dot_a;
 504 
 505         Wstring                 targ_string(true_target);
 506         Wstring                 suf_string;
 507 
 508         if (dot_a == NULL) {
 509                 MBSTOWCS(wcs_buffer, NOCATGETS(".a"));
 510                 dot_a = GETNAME(wcs_buffer, FIND_LENGTH);
 511         }
 512         target_end = targ_string.get_string() + true_target->hash.length;
 513 
 514         /*
 515          * We compare the tail of the target name with the suffixes
 516          * from .SUFFIXES.
 517          */
 518         if (debug_level > 1) {
 519                 (void) printf(NOCATGETS("%*sfind_ar_suffix_rule(%s)\n"),
 520                               recursion_level,
 521                               "",
 522                               true_target->string_mb);
 523         }
 524         /*
 525          * Scan the .SUFFIXES list to see if the target matches any of
 526          * those suffixes.
 527          */
 528         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
 529                 /* Compare one suffix. */
 530                 suffix_length = suffix->name->hash.length;
 531                 suf_string.init(suffix->name);
 532                 if (!IS_WEQUALN(suf_string.get_string(),
 533                                 target_end - suffix_length,
 534                                 suffix_length)) {
 535                         goto not_this_one;
 536                 }
 537                 /*
 538                  * The target tail matched a suffix from the .SUFFIXES list.
 539                  * Now check for a rule to match.


 600 
 601         Wstring                 targ_string;
 602         Wstring                 suf_string;
 603 
 604         /*
 605          * If the target is a constructed one for a "::" target,
 606          * we need to consider that.
 607          */
 608         if (target->has_target_prop) {
 609                 true_target = get_prop(target->prop,
 610                                        target_prop)->body.target.target;
 611         }
 612         targ_string.init(true_target);
 613 
 614         /*
 615          * We compare the tail of the target name with the
 616          * suffixes from .SUFFIXES.
 617          */
 618         target_end = targ_string.get_string() + true_target->hash.length;
 619         if (debug_level > 1) {
 620                 (void) printf(NOCATGETS("%*sfind_double_suffix_rule(%s)\n"),
 621                               recursion_level,
 622                               "",
 623                               true_target->string_mb);
 624         }
 625         /*
 626          * Scan the .SUFFIXES list to see if the target matches
 627          * any of those suffixes.
 628          */
 629         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
 630                 target->suffix_scan_done = false;
 631                 true_target->suffix_scan_done = false;
 632                 /* Compare one suffix. */
 633                 suffix_length = suffix->name->hash.length;
 634                 suf_string.init(suffix->name);
 635                 /* Check the lengths, or else RTC will report rua. */
 636                 if (true_target->hash.length < suffix_length) {
 637                         goto not_this_one;
 638                 } else if (!IS_WEQUALN(suf_string.get_string(),
 639                                 (target_end - suffix_length),
 640                                 suffix_length)) {


 692  *              debug_level     Indicates how much tracing to do
 693  *              recursion_level Used for tracing
 694  *              suffixes        List of suffixes used for scan (from .SUFFIXES)
 695  *              working_on_targets Indicates that this is a real target
 696  */
 697 void
 698 build_suffix_list(register Name target_suffix)
 699 {
 700         register Dependency     source_suffix;
 701         wchar_t                 rule_name[MAXPATHLEN];
 702         register Property       line;
 703         register Property       suffix;
 704         Name                    rule;
 705 
 706         /* If this is before default.mk has been read we just return to try */
 707         /* again later */
 708         if ((suffixes == NULL) || !working_on_targets) {
 709                 return;
 710         }
 711         if (debug_level > 1) {
 712                 (void) printf(NOCATGETS("%*sbuild_suffix_list(%s) "),
 713                               recursion_level,
 714                               "",
 715                               target_suffix->string_mb);
 716         }
 717         /* Mark the target suffix saying we cashed its list */
 718         target_suffix->has_read_suffixes = true;
 719         /* Scan the .SUFFIXES list */
 720         for (source_suffix = suffixes;
 721              source_suffix != NULL;
 722              source_suffix = source_suffix->next) {
 723                 /*
 724                  * Build the name "<suffix-on-list><target-suffix>".
 725                  * (a popular one would be ".c.o").
 726                  */
 727                 (void) mbstowcs(rule_name,
 728                               source_suffix->name->string_mb,
 729                               (int) source_suffix->name->hash.length);
 730                 (void) mbstowcs(rule_name + source_suffix->name->hash.length,
 731                               target_suffix->string_mb,
 732                               (int) target_suffix->hash.length);


 805         wchar_t                 percent_buf[STRING_BUFFER_LENGTH];
 806         Name                    true_target = target;
 807         Name                    less;
 808         Boolean                 nonpattern_less;
 809         Boolean                 dep_name_found = false;
 810         Doname                  result = build_dont_know;
 811         Percent                 rule_candidate = NULL;
 812         Boolean                 rule_maybe_ok;
 813         Boolean                 is_pattern;
 814 
 815         /* If the target is constructed for a "::" target we consider that */
 816         if (target->has_target_prop) {
 817                 true_target = get_prop(target->prop,
 818                                        target_prop)->body.target.target;
 819         }
 820         if (target->has_long_member_name) {
 821                 true_target = get_prop(target->prop,
 822                                        long_member_name_prop)->body.long_member_name.member_name;
 823         }
 824         if (debug_level > 1) {
 825                 (void) printf(catgets(catd, 1, 222, "%*sLooking for %% rule for %s\n"),
 826                               recursion_level,
 827                               "",
 828                               true_target->string_mb);
 829         }
 830         for (pat_rule = percent_list;
 831              pat_rule != NULL;
 832              pat_rule = pat_rule->next) {
 833                 /* Avoid infinite recursion when expanding patterns */
 834                 if (pat_rule->being_expanded == true) {
 835                         continue;
 836                 }
 837 
 838                 /* Mark this pat_rule as "maybe ok". If no % rule is found
 839                    make will use this rule. The following algorithm is used:
 840                    1) make scans all pattern rules in order to find the rule
 841                       where ALL dependencies, including nonpattern ones, exist or
 842                       can be built (GNU behaviour). If such rule is found make
 843                       will apply it.
 844                    2) During this check make also remembers the first pattern rule
 845                       where all PATTERN dependencies can be build (no matter what


 886                                         is_pattern = false;
 887                                         depe_to_check = pat_depe->name;
 888                                         if(depe_to_check->dollar) {
 889                                                 INIT_STRING_FROM_STACK(string, string_buf);
 890                                                 expand_value(depe_to_check, &string, false);
 891                                                 depe_to_check = getname_fn(string.buffer.start,
 892                                                         FIND_LENGTH,
 893                                                         false,
 894                                                         &dep_name_found
 895                                                 );
 896                                         }
 897                                         if (less == NULL) {
 898                                                 less = depe_to_check;
 899                                         }
 900                                 }
 901 
 902                                 if (depe_to_check == empty_name) {
 903                                                 result = build_ok;
 904                                 } else {
 905                                         if (debug_level > 1) {
 906                                                 (void) printf(catgets(catd, 1, 223, "%*sTrying %s\n"),
 907                                                               recursion_level,
 908                                                               "",
 909                                                               depe_to_check->string_mb);
 910                                         }
 911 
 912                                         pat_rule->being_expanded = true;
 913 
 914                                         /* suppress message output */
 915                                         int save_debug_level = debug_level;
 916                                         debug_level = 0;
 917 
 918                                         /* check whether dependency can be built */
 919                                         if (dependency_exists(depe_to_check,
 920                                               get_prop(target->prop,
 921                                                        line_prop)))
 922                                         {
 923                                                 result = (Doname) depe_to_check->state;
 924                                         } else {
 925                                                 if(actual_doname) {
 926                                                         result = doname(depe_to_check, true, true);


 976            or return build_dont_know if there is no candidate.
 977         */
 978         if (result != build_ok && result != build_running) {
 979                 if(rule_candidate) {
 980                         pat_rule = rule_candidate;
 981                 } else {
 982                         return build_dont_know;
 983                 }
 984         }
 985 
 986         /* if we are performing only check whether dependency could be built with existing rules,
 987            return success */
 988         if (command == NULL) {
 989                 if(pat_rule != NULL) {
 990                         pat_rule->being_expanded = false;
 991                 }
 992                 return result;
 993         }
 994 
 995         if (debug_level > 1) {
 996                 (void) printf(catgets(catd, 1, 224, "%*sMatched %s:"),
 997                                       recursion_level,
 998                                       "",
 999                                       target->string_mb);
1000 
1001                 for (pat_depe = pat_rule->dependencies;
1002                      pat_depe != NULL;
1003                      pat_depe = pat_depe->next) {
1004                         if (pat_depe->name->percent) {
1005                                 INIT_STRING_FROM_STACK(string, string_buf);
1006                                 construct_string_from_pattern(pat_depe, &percent, &string);
1007                                 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1008                         } else {
1009                                 depe_to_check = pat_depe->name;
1010                                 if(depe_to_check->dollar) {
1011                                         INIT_STRING_FROM_STACK(string, string_buf);
1012                                         expand_value(depe_to_check, &string, false);
1013                                         depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1014                                 }
1015                         }
1016 
1017                         if (depe_to_check != empty_name) {
1018                                 (void) printf(" %s", depe_to_check->string_mb);
1019                         }
1020                 }
1021 
1022                 (void) printf(catgets(catd, 1, 225, " from: %s:"),
1023                               pat_rule->name->string_mb);
1024 
1025                 for (pat_depe = pat_rule->dependencies;
1026                      pat_depe != NULL;
1027                      pat_depe = pat_depe->next) {
1028                         (void) printf(" %s", pat_depe->name->string_mb);
1029                 }
1030 
1031                 (void) printf("\n");
1032         }
1033 
1034         if (true_target->colons == no_colon) {
1035                 true_target->colons = one_colon;
1036         }
1037 
1038         /* create deppendency list and target group from matched pattern rule */
1039         create_target_group_and_dependencies_list(target, pat_rule, &percent);
1040 
1041         /* save command */
1042         line = get_prop(target->prop, line_prop);


1052         if (line->body.line.dependencies != NULL) {
1053                 /* build all collected dependencies */
1054                 for (depe = line->body.line.dependencies;
1055                      depe != NULL; 
1056                      depe = depe->next) {
1057                         actual_doname = true;
1058                         result = doname_check(depe->name, true, true, depe->automatic);
1059 
1060                         actual_doname = false;
1061                         if (result == build_failed) {
1062                                 pat_rule->being_expanded = false;
1063                                 return build_failed;
1064                         }
1065                         if (result == build_running) {
1066                                 pat_rule->being_expanded = false;
1067                                 return build_running;
1068                         }
1069 
1070                         if ((depe->name->stat.time > line->body.line.dependency_time) &&
1071                             (debug_level > 1)) {
1072                                 (void) printf(catgets(catd, 1, 226, "%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
1073                                               recursion_level,
1074                                               "",
1075                                               depe->name->string_mb,
1076                                               time_to_string(depe->name->stat.time),
1077                                               true_target->string_mb,
1078                                               time_to_string(line->body.line.dependency_time));
1079                         }
1080 
1081                         line->body.line.dependency_time =
1082                           MAX(line->body.line.dependency_time, depe->name->stat.time);
1083 
1084                         /* determine whether this dependency made target out of date */
1085                         Boolean out_of_date;
1086                         if (target->is_member || depe->name->is_member) {
1087                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time);
1088                         } else {
1089                                 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time);
1090                         }
1091                         if (build_unconditional || out_of_date) {
1092                                 if(!rechecking) {
1093                                         line->body.line.is_out_of_date = true;
1094                                 }
1095                                 add_target_to_chain(depe->name, &(line->body.line.query));
1096 
1097                                 if (debug_level > 0) {
1098                                         (void) printf(catgets(catd, 1, 227, "%*sBuilding %s using pattern rule %s:"),
1099                                                       recursion_level,
1100                                                       "",
1101                                                       true_target->string_mb,
1102                                                       pat_rule->name->string_mb);
1103 
1104                                         for (pat_depe = pat_rule->dependencies;
1105                                              pat_depe != NULL;
1106                                              pat_depe = pat_depe->next) {
1107                                                 (void) printf(" %s", pat_depe->name->string_mb);
1108                                         }
1109 
1110                                         (void) printf(catgets(catd, 1, 228, " because it is out of date relative to %s\n"), 
1111                                                       depe->name->string_mb);
1112                                 }       
1113                         }
1114                 }
1115         } else {
1116                 if ((true_target->stat.time <= file_doesnt_exist) ||
1117                     (true_target->stat.time < line->body.line.dependency_time)) {
1118                         if(!rechecking) {
1119                                 line->body.line.is_out_of_date = true;
1120                         }
1121                         if (debug_level > 0) {
1122                                 (void) printf(catgets(catd, 1, 229, "%*sBuilding %s using pattern rule %s: "),
1123                                               recursion_level,
1124                                               "",
1125                                               true_target->string_mb,
1126                                               pat_rule->name->string_mb,
1127                                               (target->stat.time > file_doesnt_exist) ?
1128                                               catgets(catd, 1, 230, "because it is out of date") :
1129                                               catgets(catd, 1, 236, "because it does not exist"));
1130                         }
1131                 }
1132         }
1133 
1134         /* enter explicit rule from percent rule */     
1135         Name lmn_target = true_target;
1136         if (true_target->has_long_member_name) {
1137                 lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name;
1138         }
1139         line->body.line.sccs_command = false;
1140         line->body.line.target = true_target;
1141         line->body.line.command_template = pat_rule->command_template;
1142         line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH);
1143         line->body.line.less = less;
1144 
1145         if (lmn_target->parenleft) {
1146                 Wstring lmn_string(lmn_target);
1147 
1148                 wchar_t *left = (wchar_t *) wschr(lmn_string.get_string(), (int) parenleft_char);
1149                 wchar_t *right = (wchar_t *) wschr(lmn_string.get_string(), (int) parenright_char);




  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      implicit.c
  28  *
  29  *      Handle suffix and percent rules
  30  */
  31 
  32 /*
  33  * Included files
  34  */
  35 #include <mk/defs.h>
  36 #include <mksh/macro.h>           /* expand_value() */
  37 #include <mksh/misc.h>            /* retmem() */
  38 #include <libintl.h>
  39 
  40 /*
  41  * Defined macros
  42  */
  43 
  44 /*
  45  * typedefs & structs
  46  */
  47 
  48 /*
  49  * Static variables
  50  */
  51 static  wchar_t         WIDE_NULL[1] = {(wchar_t) nul_char};
  52 
  53 /*
  54  * File table of contents
  55  */
  56 extern  Doname          find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking);
  57 extern  Doname          find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking);
  58 extern  Doname          find_double_suffix_rule(register Name target, Property *command, Boolean rechecking);


 123         Boolean                 posix_tilde_attempt = true;
 124         int                     src_len = MAXPATHLEN + strlen(target_body->string_mb);
 125 
 126         /*
 127          * To avoid infinite recursion
 128          */
 129         if(we_are_in_tilde) {
 130                 we_are_in_tilde = false;
 131                 return(build_dont_know);
 132         }
 133 
 134         /*
 135          * If the target is a constructed one for a "::" target,
 136          * we need to consider that.
 137          */
 138         if (target->has_target_prop) {
 139                 true_target = get_prop(target->prop,
 140                                        target_prop)->body.target.target;
 141         }
 142         if (debug_level > 1) {
 143                 (void) printf("%*sfind_suffix_rule(%s,%s,%s)\n",
 144                               recursion_level,
 145                               "",
 146                               true_target->string_mb,
 147                               target_body->string_mb,
 148                               target_suffix->string_mb);
 149         }
 150         if (command != NULL) {
 151                 if ((true_target->suffix_scan_done == true) && (*command == NULL)) {
 152                         return build_ok;
 153                 }
 154         }
 155         true_target->suffix_scan_done = true;
 156         /*
 157          * Enter all names from the directory where the target lives as
 158          * files that makes sense.
 159          * This will make finding the synthesized source possible.
 160          */
 161         read_directory_of_file(target_body);
 162         /* Cache the suffixes for this target suffix if not done. */
 163         if (!target_suffix->has_read_suffixes) {


 173         put_suffix = sourcename + target_body->hash.length;
 174         /* Scan the suffix list for the target if one exists. */
 175         if (target_suffix->has_suffixes) {
 176 posix_attempts:
 177                 for (source_suffix = get_prop(target_suffix->prop,
 178                                               suffix_prop);
 179                      source_suffix != NULL;
 180                      source_suffix = get_prop(source_suffix->next,
 181                                               suffix_prop)) {
 182                         /* Build the synthesized source name. */
 183                         (void) mbstowcs(put_suffix,
 184                                       source_suffix->body.
 185                                       suffix.suffix->string_mb,
 186                                       (int) source_suffix->body.
 187                                       suffix.suffix->hash.length);
 188                         put_suffix[source_suffix->body.
 189                                    suffix.suffix->hash.length] =
 190                           (int) nul_char;
 191                         if (debug_level > 1) {
 192                                 WCSTOMBS(mbs_buffer, sourcename);
 193                                 (void) printf(gettext("%*sTrying %s\n"),
 194                                               recursion_level,
 195                                               "",
 196                                               mbs_buffer);
 197                         }
 198                         source = getname_fn(sourcename, FIND_LENGTH, false, &name_found);
 199                         /*
 200                          * If the source file is not registered as
 201                          * a file, this source suffix did not match.
 202                          */
 203                         if(vpath_defined && !posix && !svr4) {
 204                                 (void) exists(source);  
 205                         }
 206                         if (!source->stat.is_file) {
 207                            if(!(posix|svr4))
 208                            {
 209                                 if(!name_found) {
 210                                         free_name(source);
 211                                 }
 212                                 continue;
 213                            }


 223 
 224                            if(source->string_mb[source->hash.length - 1] == '~' &&
 225                               ( svr4 || posix_tilde_attempt ) )
 226                            {
 227                                 char *p, *np; 
 228                                 char *tmpbuf;
 229 
 230                                 tmpbuf = getmem(source->hash.length + 8); 
 231                                 /* + 8 to add "s." or "SCCS/s." */
 232                                 memset(tmpbuf,0,source->hash.length + 8);
 233                                 source->string_mb[source->hash.length - 1] = '\0';
 234                                 if(p = (char *) memchr((char *)source->string_mb,'/',source->hash.length)) 
 235                                 {
 236                                   while(1) {    
 237                                     if(np = (char *) memchr((char *)p+1,'/',source->hash.length - (p - source->string_mb))) {
 238                                       p = np;
 239                                     } else {break;}
 240                                   }
 241                                   /* copy everything including '/' */
 242                                   strncpy(tmpbuf, source->string_mb, p - source->string_mb + 1);
 243                                   strcat(tmpbuf, "s.");
 244                                   strcat(tmpbuf, p+1);
 245                                   retmem((wchar_t *) source->string_mb); 
 246                                   source->string_mb = tmpbuf;
 247                                 
 248                                 } else {
 249                                   strcpy(tmpbuf, "s.");
 250                                   strcat(tmpbuf, source->string_mb);
 251                                   retmem((wchar_t *) source->string_mb); 
 252                                   source->string_mb = tmpbuf;
 253                                 
 254                                 }
 255                                 source->hash.length = strlen(source->string_mb);
 256                                 if(exists(source) == file_doesnt_exist)
 257                                   continue;
 258                                 tilde_rule = true;
 259                                 we_are_in_tilde = true;
 260                            } else {
 261                                 if(!name_found) {
 262                                         free_name(source);
 263                                 }
 264                                 continue;
 265                            }
 266                         } else {
 267                            if(posix && posix_tilde_attempt) {
 268                                 if(exists(source) == file_doesnt_exist) {
 269                                         if(!name_found) {


 333                                 enter_dependency(line, source, false);
 334                                 line->body.line.target = true_target;
 335                                 return build_running;
 336                         case build_ok:
 337                                 if(!name_found) {
 338                                         store_name(source);
 339                                 }
 340                                 break;
 341                         case build_failed:
 342                                 if(!name_found) {
 343                                         store_name(source);
 344                                 }
 345                                 if (sourcename != static_string_buf_3M) {
 346                                         retmem(sourcename);
 347                                 }
 348                                 return build_failed;
 349                         }
 350                         
 351                         if (debug_level > 1) {
 352                                 WCSTOMBS(mbs_buffer, sourcename);
 353                                 (void) printf(gettext("%*sFound %s\n"),
 354                                               recursion_level,
 355                                               "",
 356                                               mbs_buffer);
 357                         }
 358                         
 359                         if (source->depends_on_conditional) {
 360                                 target->depends_on_conditional = true;
 361                         }
 362 /*
 363  * Since it is possible that the same target is built several times during
 364  * the make run, we have to patch the target with all information we found
 365  * here. Thus, the target will have an explicit rule the next time around.
 366  */
 367                         line = maybe_append_prop(target, line_prop);
 368                         if (*command == NULL) {
 369                                 *command = line;
 370                         }
 371                         if ((source->stat.time > (*command)->body.line.dependency_time) &&
 372                             (debug_level > 1)) {
 373                                 (void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
 374                                               recursion_level,
 375                                               "",
 376                                               source->string_mb,
 377                                               time_to_string(source->
 378                                                              stat.time),
 379                                               true_target->string_mb,
 380                                               time_to_string((*command)->
 381                                                              body.line.
 382                                                              dependency_time));
 383                         }
 384                         /*
 385                          * Determine if this new dependency made the
 386                          * target out of date.
 387                          */
 388                         (*command)->body.line.dependency_time =
 389                           MAX((*command)->body.line.dependency_time,
 390                               source->stat.time);
 391                         Boolean out_of_date;
 392                         if (target->is_member) {
 393                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time,
 394                                                                         (*command)->body.line.dependency_time);
 395                         } else {
 396                                 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time,
 397                                                                     (*command)->body.line.dependency_time);
 398                         }
 399                         if (build_unconditional || out_of_date) {
 400                                 if(!rechecking) {
 401                                         line->body.line.is_out_of_date = true;
 402                                 }
 403                                 if (debug_level > 0) {
 404                                         (void) printf(gettext("%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"),
 405                                                       recursion_level,
 406                                                       "",
 407                                                       true_target->string_mb,
 408                                                       source_suffix->body.suffix.suffix->string_mb,
 409                                                       target_suffix->string_mb,
 410                                                       source->string_mb);
 411                                 }
 412                         }
 413                         /*
 414                          * Add the implicit rule as the target's explicit
 415                          * rule if none actually given, and register
 416                          * dependency.
 417                          * The time checking above really should be
 418                          * conditional on actual use of implicit rule
 419                          * as well.
 420                          */
 421                         line->body.line.sccs_command = false;
 422                         if (line->body.line.command_template == NULL) {
 423                                 line->body.line.command_template =
 424                                   source_suffix->body.suffix.command_template;
 425                         }
 426                         enter_dependency(line, source, false);
 427                         line->body.line.target = true_target;
 428                         /*
 429                          * Also make sure the rule is built with
 430                          * $* and $< bound properly.
 431                          */
 432                         line->body.line.star = target_body;
 433                         if(svr4|posix) {
 434                           char * p;
 435                           char tstr[256];
 436                           extern Boolean dollarless_flag;
 437                           extern Name dollarless_value;
 438 
 439                           if(tilde_rule) {
 440                               MBSTOWCS(wcs_buffer, source->string_mb);
 441                               dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH);
 442                           }
 443                           else {
 444                                    dollarless_flag = false;
 445                           }
 446                         }
 447                         line->body.line.less = source;
 448                         line->body.line.percent = NULL;
 449                         add_target_to_chain(source, &(line->body.line.query));
 450                         if (sourcename != static_string_buf_3M) {
 451                                 retmem(sourcename);
 452                         }
 453                         return build_ok;
 454                 }
 455                 if(posix && posix_tilde_attempt) {
 456                         posix_tilde_attempt = false;
 457                         goto posix_attempts;
 458                 }
 459                 if ((command != NULL) &&
 460                     ((*command) != NULL) &&


 490  *      Global variables used:
 491  *              debug_level     Indicates how much tracing to do
 492  *              dot_a           The Name ".a", compared against
 493  *              recursion_level Used for tracing
 494  *              suffixes        List of suffixes used for scan (from .SUFFIXES)
 495  */
 496 Doname
 497 find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking)
 498 {
 499         wchar_t                 *target_end;
 500         register Dependency     suffix;
 501         register int            suffix_length;
 502         Property                line;
 503         Name                    body;
 504         static Name             dot_a;
 505 
 506         Wstring                 targ_string(true_target);
 507         Wstring                 suf_string;
 508 
 509         if (dot_a == NULL) {
 510                 MBSTOWCS(wcs_buffer, ".a");
 511                 dot_a = GETNAME(wcs_buffer, FIND_LENGTH);
 512         }
 513         target_end = targ_string.get_string() + true_target->hash.length;
 514 
 515         /*
 516          * We compare the tail of the target name with the suffixes
 517          * from .SUFFIXES.
 518          */
 519         if (debug_level > 1) {
 520                 (void) printf("%*sfind_ar_suffix_rule(%s)\n",
 521                               recursion_level,
 522                               "",
 523                               true_target->string_mb);
 524         }
 525         /*
 526          * Scan the .SUFFIXES list to see if the target matches any of
 527          * those suffixes.
 528          */
 529         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
 530                 /* Compare one suffix. */
 531                 suffix_length = suffix->name->hash.length;
 532                 suf_string.init(suffix->name);
 533                 if (!IS_WEQUALN(suf_string.get_string(),
 534                                 target_end - suffix_length,
 535                                 suffix_length)) {
 536                         goto not_this_one;
 537                 }
 538                 /*
 539                  * The target tail matched a suffix from the .SUFFIXES list.
 540                  * Now check for a rule to match.


 601 
 602         Wstring                 targ_string;
 603         Wstring                 suf_string;
 604 
 605         /*
 606          * If the target is a constructed one for a "::" target,
 607          * we need to consider that.
 608          */
 609         if (target->has_target_prop) {
 610                 true_target = get_prop(target->prop,
 611                                        target_prop)->body.target.target;
 612         }
 613         targ_string.init(true_target);
 614 
 615         /*
 616          * We compare the tail of the target name with the
 617          * suffixes from .SUFFIXES.
 618          */
 619         target_end = targ_string.get_string() + true_target->hash.length;
 620         if (debug_level > 1) {
 621                 (void) printf("%*sfind_double_suffix_rule(%s)\n",
 622                               recursion_level,
 623                               "",
 624                               true_target->string_mb);
 625         }
 626         /*
 627          * Scan the .SUFFIXES list to see if the target matches
 628          * any of those suffixes.
 629          */
 630         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
 631                 target->suffix_scan_done = false;
 632                 true_target->suffix_scan_done = false;
 633                 /* Compare one suffix. */
 634                 suffix_length = suffix->name->hash.length;
 635                 suf_string.init(suffix->name);
 636                 /* Check the lengths, or else RTC will report rua. */
 637                 if (true_target->hash.length < suffix_length) {
 638                         goto not_this_one;
 639                 } else if (!IS_WEQUALN(suf_string.get_string(),
 640                                 (target_end - suffix_length),
 641                                 suffix_length)) {


 693  *              debug_level     Indicates how much tracing to do
 694  *              recursion_level Used for tracing
 695  *              suffixes        List of suffixes used for scan (from .SUFFIXES)
 696  *              working_on_targets Indicates that this is a real target
 697  */
 698 void
 699 build_suffix_list(register Name target_suffix)
 700 {
 701         register Dependency     source_suffix;
 702         wchar_t                 rule_name[MAXPATHLEN];
 703         register Property       line;
 704         register Property       suffix;
 705         Name                    rule;
 706 
 707         /* If this is before default.mk has been read we just return to try */
 708         /* again later */
 709         if ((suffixes == NULL) || !working_on_targets) {
 710                 return;
 711         }
 712         if (debug_level > 1) {
 713                 (void) printf("%*sbuild_suffix_list(%s) ",
 714                               recursion_level,
 715                               "",
 716                               target_suffix->string_mb);
 717         }
 718         /* Mark the target suffix saying we cashed its list */
 719         target_suffix->has_read_suffixes = true;
 720         /* Scan the .SUFFIXES list */
 721         for (source_suffix = suffixes;
 722              source_suffix != NULL;
 723              source_suffix = source_suffix->next) {
 724                 /*
 725                  * Build the name "<suffix-on-list><target-suffix>".
 726                  * (a popular one would be ".c.o").
 727                  */
 728                 (void) mbstowcs(rule_name,
 729                               source_suffix->name->string_mb,
 730                               (int) source_suffix->name->hash.length);
 731                 (void) mbstowcs(rule_name + source_suffix->name->hash.length,
 732                               target_suffix->string_mb,
 733                               (int) target_suffix->hash.length);


 806         wchar_t                 percent_buf[STRING_BUFFER_LENGTH];
 807         Name                    true_target = target;
 808         Name                    less;
 809         Boolean                 nonpattern_less;
 810         Boolean                 dep_name_found = false;
 811         Doname                  result = build_dont_know;
 812         Percent                 rule_candidate = NULL;
 813         Boolean                 rule_maybe_ok;
 814         Boolean                 is_pattern;
 815 
 816         /* If the target is constructed for a "::" target we consider that */
 817         if (target->has_target_prop) {
 818                 true_target = get_prop(target->prop,
 819                                        target_prop)->body.target.target;
 820         }
 821         if (target->has_long_member_name) {
 822                 true_target = get_prop(target->prop,
 823                                        long_member_name_prop)->body.long_member_name.member_name;
 824         }
 825         if (debug_level > 1) {
 826                 (void) printf(gettext("%*sLooking for %% rule for %s\n"),
 827                               recursion_level,
 828                               "",
 829                               true_target->string_mb);
 830         }
 831         for (pat_rule = percent_list;
 832              pat_rule != NULL;
 833              pat_rule = pat_rule->next) {
 834                 /* Avoid infinite recursion when expanding patterns */
 835                 if (pat_rule->being_expanded == true) {
 836                         continue;
 837                 }
 838 
 839                 /* Mark this pat_rule as "maybe ok". If no % rule is found
 840                    make will use this rule. The following algorithm is used:
 841                    1) make scans all pattern rules in order to find the rule
 842                       where ALL dependencies, including nonpattern ones, exist or
 843                       can be built (GNU behaviour). If such rule is found make
 844                       will apply it.
 845                    2) During this check make also remembers the first pattern rule
 846                       where all PATTERN dependencies can be build (no matter what


 887                                         is_pattern = false;
 888                                         depe_to_check = pat_depe->name;
 889                                         if(depe_to_check->dollar) {
 890                                                 INIT_STRING_FROM_STACK(string, string_buf);
 891                                                 expand_value(depe_to_check, &string, false);
 892                                                 depe_to_check = getname_fn(string.buffer.start,
 893                                                         FIND_LENGTH,
 894                                                         false,
 895                                                         &dep_name_found
 896                                                 );
 897                                         }
 898                                         if (less == NULL) {
 899                                                 less = depe_to_check;
 900                                         }
 901                                 }
 902 
 903                                 if (depe_to_check == empty_name) {
 904                                                 result = build_ok;
 905                                 } else {
 906                                         if (debug_level > 1) {
 907                                                 (void) printf(gettext("%*sTrying %s\n"),
 908                                                               recursion_level,
 909                                                               "",
 910                                                               depe_to_check->string_mb);
 911                                         }
 912 
 913                                         pat_rule->being_expanded = true;
 914 
 915                                         /* suppress message output */
 916                                         int save_debug_level = debug_level;
 917                                         debug_level = 0;
 918 
 919                                         /* check whether dependency can be built */
 920                                         if (dependency_exists(depe_to_check,
 921                                               get_prop(target->prop,
 922                                                        line_prop)))
 923                                         {
 924                                                 result = (Doname) depe_to_check->state;
 925                                         } else {
 926                                                 if(actual_doname) {
 927                                                         result = doname(depe_to_check, true, true);


 977            or return build_dont_know if there is no candidate.
 978         */
 979         if (result != build_ok && result != build_running) {
 980                 if(rule_candidate) {
 981                         pat_rule = rule_candidate;
 982                 } else {
 983                         return build_dont_know;
 984                 }
 985         }
 986 
 987         /* if we are performing only check whether dependency could be built with existing rules,
 988            return success */
 989         if (command == NULL) {
 990                 if(pat_rule != NULL) {
 991                         pat_rule->being_expanded = false;
 992                 }
 993                 return result;
 994         }
 995 
 996         if (debug_level > 1) {
 997                 (void) printf(gettext("%*sMatched %s:"),
 998                                       recursion_level,
 999                                       "",
1000                                       target->string_mb);
1001 
1002                 for (pat_depe = pat_rule->dependencies;
1003                      pat_depe != NULL;
1004                      pat_depe = pat_depe->next) {
1005                         if (pat_depe->name->percent) {
1006                                 INIT_STRING_FROM_STACK(string, string_buf);
1007                                 construct_string_from_pattern(pat_depe, &percent, &string);
1008                                 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1009                         } else {
1010                                 depe_to_check = pat_depe->name;
1011                                 if(depe_to_check->dollar) {
1012                                         INIT_STRING_FROM_STACK(string, string_buf);
1013                                         expand_value(depe_to_check, &string, false);
1014                                         depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1015                                 }
1016                         }
1017 
1018                         if (depe_to_check != empty_name) {
1019                                 (void) printf(" %s", depe_to_check->string_mb);
1020                         }
1021                 }
1022 
1023                 (void) printf(gettext(" from: %s:"),
1024                               pat_rule->name->string_mb);
1025 
1026                 for (pat_depe = pat_rule->dependencies;
1027                      pat_depe != NULL;
1028                      pat_depe = pat_depe->next) {
1029                         (void) printf(" %s", pat_depe->name->string_mb);
1030                 }
1031 
1032                 (void) printf("\n");
1033         }
1034 
1035         if (true_target->colons == no_colon) {
1036                 true_target->colons = one_colon;
1037         }
1038 
1039         /* create deppendency list and target group from matched pattern rule */
1040         create_target_group_and_dependencies_list(target, pat_rule, &percent);
1041 
1042         /* save command */
1043         line = get_prop(target->prop, line_prop);


1053         if (line->body.line.dependencies != NULL) {
1054                 /* build all collected dependencies */
1055                 for (depe = line->body.line.dependencies;
1056                      depe != NULL; 
1057                      depe = depe->next) {
1058                         actual_doname = true;
1059                         result = doname_check(depe->name, true, true, depe->automatic);
1060 
1061                         actual_doname = false;
1062                         if (result == build_failed) {
1063                                 pat_rule->being_expanded = false;
1064                                 return build_failed;
1065                         }
1066                         if (result == build_running) {
1067                                 pat_rule->being_expanded = false;
1068                                 return build_running;
1069                         }
1070 
1071                         if ((depe->name->stat.time > line->body.line.dependency_time) &&
1072                             (debug_level > 1)) {
1073                                 (void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
1074                                               recursion_level,
1075                                               "",
1076                                               depe->name->string_mb,
1077                                               time_to_string(depe->name->stat.time),
1078                                               true_target->string_mb,
1079                                               time_to_string(line->body.line.dependency_time));
1080                         }
1081 
1082                         line->body.line.dependency_time =
1083                           MAX(line->body.line.dependency_time, depe->name->stat.time);
1084 
1085                         /* determine whether this dependency made target out of date */
1086                         Boolean out_of_date;
1087                         if (target->is_member || depe->name->is_member) {
1088                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time);
1089                         } else {
1090                                 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time);
1091                         }
1092                         if (build_unconditional || out_of_date) {
1093                                 if(!rechecking) {
1094                                         line->body.line.is_out_of_date = true;
1095                                 }
1096                                 add_target_to_chain(depe->name, &(line->body.line.query));
1097 
1098                                 if (debug_level > 0) {
1099                                         (void) printf(gettext("%*sBuilding %s using pattern rule %s:"),
1100                                                       recursion_level,
1101                                                       "",
1102                                                       true_target->string_mb,
1103                                                       pat_rule->name->string_mb);
1104 
1105                                         for (pat_depe = pat_rule->dependencies;
1106                                              pat_depe != NULL;
1107                                              pat_depe = pat_depe->next) {
1108                                                 (void) printf(" %s", pat_depe->name->string_mb);
1109                                         }
1110 
1111                                         (void) printf(gettext(" because it is out of date relative to %s\n"), 
1112                                                       depe->name->string_mb);
1113                                 }       
1114                         }
1115                 }
1116         } else {
1117                 if ((true_target->stat.time <= file_doesnt_exist) ||
1118                     (true_target->stat.time < line->body.line.dependency_time)) {
1119                         if(!rechecking) {
1120                                 line->body.line.is_out_of_date = true;
1121                         }
1122                         if (debug_level > 0) {
1123                                 (void) printf(gettext("%*sBuilding %s using pattern rule %s: "),
1124                                               recursion_level,
1125                                               "",
1126                                               true_target->string_mb,
1127                                               pat_rule->name->string_mb,
1128                                               (target->stat.time > file_doesnt_exist) ?
1129                                               gettext("because it is out of date") :
1130                                               gettext("because it does not exist"));
1131                         }
1132                 }
1133         }
1134 
1135         /* enter explicit rule from percent rule */     
1136         Name lmn_target = true_target;
1137         if (true_target->has_long_member_name) {
1138                 lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name;
1139         }
1140         line->body.line.sccs_command = false;
1141         line->body.line.target = true_target;
1142         line->body.line.command_template = pat_rule->command_template;
1143         line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH);
1144         line->body.line.less = less;
1145 
1146         if (lmn_target->parenleft) {
1147                 Wstring lmn_string(lmn_target);
1148 
1149                 wchar_t *left = (wchar_t *) wschr(lmn_string.get_string(), (int) parenleft_char);
1150                 wchar_t *right = (wchar_t *) wschr(lmn_string.get_string(), (int) parenright_char);