1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 #endif /* not lint */ 34 35 /* 36 * Build the makefile for the system, from 37 * the information in the files files and the 38 * additional files for the machine being compiled to. 39 */ 40 #include <sys/param.h> 41 42 #include <cerrno> 43 #include <ctype.h> 44 #include <err.h> 45 #include <stdarg.h> 46 #include <stdbool.h> 47 #include <stdio.h> 48 #include <string.h> 49 #include <string> 50 #include <unordered_map> 51 52 #include "y.tab.h" 53 #include "config.h" 54 #include "configvers.h" 55 56 typedef std::unordered_map<std::string, std::string> env_map; 57 58 static char *tail(char *); 59 static void do_clean(FILE *); 60 static void do_rules(FILE *); 61 static void do_xxfiles(char *, FILE *); 62 static void do_objs(FILE *); 63 static void do_before_depend(FILE *); 64 static void read_files(void); 65 static void sanitize_envline(char *result, const char *src); 66 static bool preprocess(char *line, char *result); 67 static void process_into_file(char *line, FILE *ofp); 68 static int process_into_map(char *line, env_map &emap); 69 static void dump_map(env_map &emap, FILE *ofp); 70 71 static void __printflike(1, 2) 72 errout(const char *fmt, ...) 73 { 74 va_list ap; 75 76 va_start(ap, fmt); 77 vfprintf(stderr, fmt, ap); 78 va_end(ap); 79 exit(1); 80 } 81 82 /* 83 * Lookup a file, by name. 84 */ 85 static struct file_list * 86 fl_lookup(char *file) 87 { 88 struct file_list *fp; 89 90 STAILQ_FOREACH(fp, &ftab, f_next) { 91 if (eq(fp->f_fn, file)) 92 return (fp); 93 } 94 return (0); 95 } 96 97 /* 98 * Make a new file list entry 99 */ 100 static struct file_list * 101 new_fent(void) 102 { 103 struct file_list *fp; 104 105 fp = (struct file_list *) calloc(1, sizeof *fp); 106 if (fp == NULL) 107 err(EXIT_FAILURE, "calloc"); 108 STAILQ_INSERT_TAIL(&ftab, fp, f_next); 109 return (fp); 110 } 111 112 /* 113 * Open the correct Makefile and return it, or error out. 114 */ 115 FILE * 116 open_makefile_template(void) 117 { 118 FILE *ifp; 119 char line[BUFSIZ]; 120 121 snprintf(line, sizeof(line), "../../conf/Makefile.%s", machinename); 122 ifp = fopen(line, "r"); 123 if (ifp == NULL) { 124 snprintf(line, sizeof(line), "Makefile.%s", machinename); 125 ifp = fopen(line, "r"); 126 } 127 if (ifp == NULL) 128 err(1, "%s", line); 129 return (ifp); 130 } 131 132 /* 133 * Build the makefile from the skeleton 134 */ 135 void 136 makefile(void) 137 { 138 FILE *ifp, *ofp; 139 char line[BUFSIZ]; 140 struct opt *op, *t; 141 142 read_files(); 143 ifp = open_makefile_template(); 144 ofp = fopen(path("Makefile.new"), "w"); 145 if (ofp == NULL) 146 err(1, "%s", path("Makefile.new")); 147 fprintf(ofp, "KERN_IDENT=%s\n", ident); 148 fprintf(ofp, "MACHINE=%s\n", machinename); 149 fprintf(ofp, "MACHINE_ARCH=%s\n", machinearch); 150 SLIST_FOREACH_SAFE(op, &mkopt, op_next, t) { 151 fprintf(ofp, "%s=%s", op->op_name, op->op_value); 152 while ((op = SLIST_NEXT(op, op_append)) != NULL) 153 fprintf(ofp, " %s", op->op_value); 154 fprintf(ofp, "\n"); 155 } 156 if (debugging) 157 fprintf(ofp, "DEBUG=-g\n"); 158 if (*srcdir != '\0') 159 fprintf(ofp,"S=%s\n", srcdir); 160 while (fgets(line, BUFSIZ, ifp) != NULL) { 161 if (*line != '%') { 162 fprintf(ofp, "%s", line); 163 continue; 164 } 165 if (eq(line, "%BEFORE_DEPEND\n")) 166 do_before_depend(ofp); 167 else if (eq(line, "%OBJS\n")) 168 do_objs(ofp); 169 else if (strncmp(line, "%FILES.", 7) == 0) 170 do_xxfiles(line, ofp); 171 else if (eq(line, "%RULES\n")) 172 do_rules(ofp); 173 else if (eq(line, "%CLEAN\n")) 174 do_clean(ofp); 175 else if (strncmp(line, "%VERSREQ=", 9) == 0) 176 line[0] = '\0'; /* handled elsewhere */ 177 else 178 fprintf(stderr, 179 "Unknown %% construct in generic makefile: %s", 180 line); 181 } 182 (void) fclose(ifp); 183 (void) fclose(ofp); 184 moveifchanged("Makefile.new", "Makefile"); 185 } 186 187 static void 188 sanitize_envline(char *result, const char *src) 189 { 190 const char *eq; 191 char c, *dst; 192 bool leading; 193 194 /* If there is no '=' it's not a well-formed name=value line. */ 195 if ((eq = strchr(src, '=')) == NULL) { 196 *result = '\0'; 197 return; 198 } 199 dst = result; 200 201 /* Copy chars before the '=', skipping any leading spaces/quotes. */ 202 leading = true; 203 while (src < eq) { 204 c = *src++; 205 if (leading && (isspace(c) || c == '"')) 206 continue; 207 *dst++ = c; 208 leading = false; 209 } 210 211 /* If it was all leading space, we don't have a well-formed line. */ 212 if (leading) { 213 *result = '\0'; 214 return; 215 } 216 217 /* Trim spaces/quotes immediately before the '=', then copy the '='. */ 218 while (isspace(dst[-1]) || dst[-1] == '"') 219 --dst; 220 *dst++ = *src++; 221 222 /* Copy chars after the '=', skipping any leading whitespace. */ 223 leading = true; 224 while ((c = *src++) != '\0') { 225 if (leading && (isspace(c) || c == '"')) 226 continue; 227 *dst++ = c; 228 leading = false; 229 } 230 231 /* If it was all leading space, it's a valid 'var=' (nil value). */ 232 if (leading) { 233 *dst = '\0'; 234 return; 235 } 236 237 /* Trim trailing whitespace and quotes. */ 238 while (isspace(dst[-1]) || dst[-1] == '"') 239 --dst; 240 241 *dst = '\0'; 242 } 243 244 /* 245 * Returns true if the caller may use the string. 246 */ 247 static bool 248 preprocess(char *line, char *result) 249 { 250 char *s; 251 252 /* Strip any comments */ 253 if ((s = strchr(line, '#')) != NULL) 254 *s = '\0'; 255 sanitize_envline(result, line); 256 /* Return true if it's non-empty */ 257 return (*result != '\0'); 258 } 259 260 static void 261 process_into_file(char *line, FILE *ofp) 262 { 263 char result[BUFSIZ]; 264 265 if (preprocess(line, result)) 266 fprintf(ofp, "\"%s\\0\"\n", result); 267 } 268 269 static int 270 process_into_map(char *line, env_map &emap) 271 { 272 char result[BUFSIZ], *s; 273 274 if (preprocess(line, result)) { 275 s = strchr(result, '='); 276 if (s == NULL) 277 return (EINVAL); 278 *s = '\0'; 279 emap[result] = s + 1; 280 } 281 282 return (0); 283 } 284 285 static void 286 dump_map(env_map &emap, FILE *ofp) 287 { 288 289 for (auto iter : emap) { 290 fprintf(ofp, "\"%s=%s\\0\"\n", iter.first.c_str(), 291 iter.second.c_str()); 292 } 293 } 294 295 /* 296 * Build hints.c from the skeleton 297 */ 298 void 299 makehints(void) 300 { 301 FILE *ifp, *ofp; 302 env_map emap; 303 char line[BUFSIZ]; 304 struct hint *hint; 305 306 ofp = fopen(path("hints.c.new"), "w"); 307 if (ofp == NULL) 308 err(1, "%s", path("hints.c.new")); 309 fprintf(ofp, "#include <sys/types.h>\n"); 310 fprintf(ofp, "#include <sys/systm.h>\n"); 311 fprintf(ofp, "\n"); 312 /* 313 * Write out hintmode for older kernels. Remove when config(8) major 314 * version rolls over. 315 */ 316 if (versreq <= CONFIGVERS_ENVMODE_REQ) 317 fprintf(ofp, "int hintmode = %d;\n", 318 !STAILQ_EMPTY(&hints) ? 1 : 0); 319 fprintf(ofp, "char static_hints[] = {\n"); 320 STAILQ_FOREACH(hint, &hints, hint_next) { 321 ifp = fopen(hint->hint_name, "r"); 322 if (ifp == NULL) 323 err(1, "%s", hint->hint_name); 324 while (fgets(line, BUFSIZ, ifp) != NULL) { 325 if (process_into_map(line, emap) != 0) 326 errout("%s: malformed line: %s\n", 327 hint->hint_name, line); 328 } 329 dump_map(emap, ofp); 330 fclose(ifp); 331 } 332 fprintf(ofp, "\"\\0\"\n};\n"); 333 fclose(ofp); 334 moveifchanged("hints.c.new", "hints.c"); 335 } 336 337 /* 338 * Build env.c from the skeleton 339 */ 340 void 341 makeenv(void) 342 { 343 FILE *ifp, *ofp; 344 env_map emap; 345 char line[BUFSIZ]; 346 struct envvar *envvar; 347 348 ofp = fopen(path("env.c.new"), "w"); 349 if (ofp == NULL) 350 err(1, "%s", path("env.c.new")); 351 fprintf(ofp, "#include <sys/types.h>\n"); 352 fprintf(ofp, "#include <sys/systm.h>\n"); 353 fprintf(ofp, "\n"); 354 /* 355 * Write out envmode for older kernels. Remove when config(8) major 356 * version rolls over. 357 */ 358 if (versreq <= CONFIGVERS_ENVMODE_REQ) 359 fprintf(ofp, "int envmode = %d;\n", 360 !STAILQ_EMPTY(&envvars) ? 1 : 0); 361 fprintf(ofp, "char static_env[] = {\n"); 362 STAILQ_FOREACH(envvar, &envvars, envvar_next) { 363 if (envvar->env_is_file) { 364 ifp = fopen(envvar->env_str, "r"); 365 if (ifp == NULL) 366 err(1, "%s", envvar->env_str); 367 while (fgets(line, BUFSIZ, ifp) != NULL) { 368 if (process_into_map(line, emap) != 0) 369 errout("%s: malformed line: %s\n", 370 envvar->env_str, line); 371 } 372 dump_map(emap, ofp); 373 fclose(ifp); 374 } else 375 process_into_file(envvar->env_str, ofp); 376 } 377 fprintf(ofp, "\"\\0\"\n};\n"); 378 fclose(ofp); 379 moveifchanged("env.c.new", "env.c"); 380 } 381 382 static void 383 read_file(char *fname) 384 { 385 char ifname[MAXPATHLEN]; 386 FILE *fp; 387 struct file_list *tp; 388 struct device *dp; 389 struct opt *op; 390 configword wd; 391 char *rfile, *compilewith, *depends, *clean, *warning; 392 const char *objprefix; 393 int compile, match, nreqs, std, filetype, negate, 394 imp_rule, no_ctfconvert, no_obj, before_depend, nowerror; 395 396 fp = fopen(fname, "r"); 397 if (fp == NULL) 398 err(1, "%s", fname); 399 next: 400 /* 401 * include "filename" 402 * filename [ standard | optional ] 403 * [ dev* [ | dev* ... ] | [ no-obj ] 404 * [ compile-with "compile rule" [no-implicit-rule] ] 405 * [ dependency "dependency-list"] [ before-depend ] 406 * [ clean "file-list"] [ warning "text warning" ] 407 * [ obj-prefix "file prefix"] 408 * [ nowerror ] [ local ] 409 */ 410 wd = get_word(fp); 411 if (wd.eof()) { 412 (void) fclose(fp); 413 return; 414 } 415 if (wd.eol()) 416 goto next; 417 if (wd[0] == '#') 418 { 419 while (!(wd = get_word(fp)).eof() && !wd.eol()) 420 ; 421 goto next; 422 } 423 if (eq(wd, "include")) { 424 wd = get_quoted_word(fp); 425 if (wd.eof() || wd.eol()) 426 errout("%s: missing include filename.\n", fname); 427 (void) snprintf(ifname, sizeof(ifname), "../../%s", 428 wd->c_str()); 429 read_file(ifname); 430 while (!(wd = get_word(fp)).eof() && !wd.eol()) 431 ; 432 goto next; 433 } 434 rfile = ns(wd); 435 wd = get_word(fp); 436 if (wd.eof()) 437 return; 438 if (wd.eol()) 439 errout("%s: No type for %s.\n", fname, rfile); 440 tp = fl_lookup(rfile); 441 compile = 0; 442 match = 1; 443 nreqs = 0; 444 compilewith = NULL; 445 depends = NULL; 446 clean = NULL; 447 warning = NULL; 448 std = 0; 449 imp_rule = 0; 450 no_ctfconvert = 0; 451 no_obj = 0; 452 before_depend = 0; 453 nowerror = 0; 454 negate = 0; 455 filetype = NORMAL; 456 objprefix = ""; 457 if (eq(wd, "standard")) 458 std = 1; 459 else if (!eq(wd, "optional")) 460 errout("%s: \"%s\" %s must be optional or standard\n", 461 fname, wd->c_str(), rfile); 462 for (wd = get_word(fp); !wd.eol(); wd = get_word(fp)) { 463 if (wd.eof()) 464 return; 465 if (eq(wd, "!")) { 466 negate = 1; 467 continue; 468 } 469 if (eq(wd, "|")) { 470 if (nreqs == 0) 471 errout("%s: syntax error describing %s\n", 472 fname, rfile); 473 compile += match; 474 match = 1; 475 nreqs = 0; 476 continue; 477 } 478 if (eq(wd, "no-ctfconvert")) { 479 no_ctfconvert++; 480 continue; 481 } 482 if (eq(wd, "no-obj")) { 483 no_obj++; 484 continue; 485 } 486 if (eq(wd, "no-implicit-rule")) { 487 if (compilewith == NULL) 488 errout("%s: alternate rule required when " 489 "\"no-implicit-rule\" is specified for" 490 " %s.\n", 491 fname, rfile); 492 imp_rule++; 493 continue; 494 } 495 if (eq(wd, "before-depend")) { 496 before_depend++; 497 continue; 498 } 499 if (eq(wd, "dependency")) { 500 wd = get_quoted_word(fp); 501 if (wd.eof() || wd.eol()) 502 errout("%s: %s missing dependency string.\n", 503 fname, rfile); 504 depends = ns(wd); 505 continue; 506 } 507 if (eq(wd, "clean")) { 508 wd = get_quoted_word(fp); 509 if (wd.eof() || wd.eol()) 510 errout("%s: %s missing clean file list.\n", 511 fname, rfile); 512 clean = ns(wd); 513 continue; 514 } 515 if (eq(wd, "compile-with")) { 516 wd = get_quoted_word(fp); 517 if (wd.eof() || wd.eol()) 518 errout("%s: %s missing compile command string.\n", 519 fname, rfile); 520 compilewith = ns(wd); 521 continue; 522 } 523 if (eq(wd, "warning")) { 524 wd = get_quoted_word(fp); 525 if (wd.eof() || wd.eol()) 526 errout("%s: %s missing warning text string.\n", 527 fname, rfile); 528 warning = ns(wd); 529 continue; 530 } 531 if (eq(wd, "obj-prefix")) { 532 wd = get_quoted_word(fp); 533 if (wd.eof() || wd.eol()) 534 errout("%s: %s missing object prefix string.\n", 535 fname, rfile); 536 objprefix = ns(wd); 537 continue; 538 } 539 if (eq(wd, "nowerror")) { 540 nowerror = 1; 541 continue; 542 } 543 if (eq(wd, "local")) { 544 filetype = LOCAL; 545 continue; 546 } 547 if (eq(wd, "no-depend")) { 548 filetype = NODEPEND; 549 continue; 550 } 551 nreqs++; 552 if (std) 553 errout("standard entry %s has optional inclusion specifier %s!\n", 554 rfile, wd->c_str()); 555 STAILQ_FOREACH(dp, &dtab, d_next) 556 if (eq(dp->d_name, wd)) { 557 if (negate) 558 match = 0; 559 else 560 dp->d_done |= DEVDONE; 561 goto nextparam; 562 } 563 SLIST_FOREACH(op, &opt, op_next) 564 if (op->op_value == 0 && 565 strcasecmp(op->op_name, wd) == 0) { 566 if (negate) 567 match = 0; 568 goto nextparam; 569 } 570 match &= negate; 571 nextparam:; 572 negate = 0; 573 } 574 compile += match; 575 if (compile && tp == NULL) { 576 if (std == 0 && nreqs == 0) 577 errout("%s: what is %s optional on?\n", 578 fname, rfile); 579 tp = new_fent(); 580 tp->f_fn = rfile; 581 tp->f_type = filetype; 582 if (filetype == LOCAL) 583 tp->f_srcprefix = ""; 584 else 585 tp->f_srcprefix = "$S/"; 586 if (imp_rule) 587 tp->f_flags |= NO_IMPLCT_RULE; 588 if (no_ctfconvert) 589 tp->f_flags |= NO_CTFCONVERT; 590 if (no_obj) 591 tp->f_flags |= NO_OBJ | NO_CTFCONVERT; 592 if (before_depend) 593 tp->f_flags |= BEFORE_DEPEND; 594 if (nowerror) 595 tp->f_flags |= NOWERROR; 596 tp->f_compilewith = compilewith; 597 tp->f_depends = depends; 598 tp->f_clean = clean; 599 tp->f_warn = warning; 600 tp->f_objprefix = objprefix; 601 } 602 goto next; 603 } 604 605 /* 606 * Read in the information about files used in making the system. 607 * Store it in the ftab linked list. 608 */ 609 static void 610 read_files(void) 611 { 612 char fname[MAXPATHLEN]; 613 struct files_name *nl, *tnl; 614 615 (void) snprintf(fname, sizeof(fname), "../../conf/files"); 616 read_file(fname); 617 (void) snprintf(fname, sizeof(fname), 618 "../../conf/files.%s", machinename); 619 read_file(fname); 620 for (nl = STAILQ_FIRST(&fntab); nl != NULL; nl = tnl) { 621 read_file(nl->f_name); 622 tnl = STAILQ_NEXT(nl, f_next); 623 free(nl->f_name); 624 free(nl); 625 } 626 } 627 628 static void 629 do_before_depend(FILE *fp) 630 { 631 struct file_list *tp; 632 int lpos, len; 633 634 fputs("BEFORE_DEPEND=", fp); 635 lpos = 15; 636 STAILQ_FOREACH(tp, &ftab, f_next) 637 if (tp->f_flags & BEFORE_DEPEND) { 638 len = strlen(tp->f_fn) + strlen(tp->f_srcprefix); 639 if (len + lpos > 72) { 640 lpos = 8; 641 fputs("\\\n\t", fp); 642 } 643 if (tp->f_flags & NO_IMPLCT_RULE) 644 lpos += fprintf(fp, "%s ", tp->f_fn); 645 else 646 lpos += fprintf(fp, "%s%s ", tp->f_srcprefix, 647 tp->f_fn); 648 } 649 if (lpos != 8) 650 putc('\n', fp); 651 } 652 653 static void 654 do_objs(FILE *fp) 655 { 656 struct file_list *tp; 657 int lpos, len; 658 char *cp, och, *sp; 659 660 fprintf(fp, "OBJS="); 661 lpos = 6; 662 STAILQ_FOREACH(tp, &ftab, f_next) { 663 if (tp->f_flags & NO_OBJ) 664 continue; 665 sp = tail(tp->f_fn); 666 cp = sp + (len = strlen(sp)) - 1; 667 och = *cp; 668 *cp = 'o'; 669 len += strlen(tp->f_objprefix); 670 if (len + lpos > 72) { 671 lpos = 8; 672 fprintf(fp, "\\\n\t"); 673 } 674 fprintf(fp, "%s%s ", tp->f_objprefix, sp); 675 lpos += len + 1; 676 *cp = och; 677 } 678 if (lpos != 8) 679 putc('\n', fp); 680 } 681 682 static void 683 do_xxfiles(char *tag, FILE *fp) 684 { 685 struct file_list *tp; 686 int lpos, len, slen; 687 char *suff, *SUFF; 688 689 if (tag[strlen(tag) - 1] == '\n') 690 tag[strlen(tag) - 1] = '\0'; 691 692 suff = ns(tag + 7); 693 SUFF = ns(suff); 694 raisestr(SUFF); 695 slen = strlen(suff); 696 697 fprintf(fp, "%sFILES=", SUFF); 698 free(SUFF); 699 lpos = 8; 700 STAILQ_FOREACH(tp, &ftab, f_next) 701 if (tp->f_type != NODEPEND) { 702 len = strlen(tp->f_fn); 703 if (tp->f_fn[len - slen - 1] != '.') 704 continue; 705 if (strcasecmp(&tp->f_fn[len - slen], suff) != 0) 706 continue; 707 if (len + strlen(tp->f_srcprefix) + lpos > 72) { 708 lpos = 8; 709 fputs("\\\n\t", fp); 710 } 711 lpos += fprintf(fp, "%s%s ", tp->f_srcprefix, tp->f_fn); 712 } 713 free(suff); 714 if (lpos != 8) 715 putc('\n', fp); 716 } 717 718 static char * 719 tail(char *fn) 720 { 721 char *cp; 722 723 cp = strrchr(fn, '/'); 724 if (cp == NULL) 725 return (fn); 726 return (cp+1); 727 } 728 729 /* 730 * Create the makerules for each file 731 * which is part of the system. 732 */ 733 static void 734 do_rules(FILE *f) 735 { 736 char *cp, *np, och; 737 struct file_list *ftp; 738 char *compilewith; 739 char cmd[128]; 740 741 STAILQ_FOREACH(ftp, &ftab, f_next) { 742 if (ftp->f_warn) 743 fprintf(stderr, "WARNING: %s\n", ftp->f_warn); 744 cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1; 745 och = *cp; 746 if (ftp->f_flags & NO_IMPLCT_RULE) { 747 if (ftp->f_depends) 748 fprintf(f, "%s%s: %s\n", 749 ftp->f_objprefix, np, ftp->f_depends); 750 else 751 fprintf(f, "%s%s: \n", ftp->f_objprefix, np); 752 } 753 else { 754 *cp = '\0'; 755 if (och == 'o') { 756 fprintf(f, "%s%so:\n\t-cp %s%so .\n\n", 757 ftp->f_objprefix, tail(np), 758 ftp->f_srcprefix, np); 759 continue; 760 } 761 if (ftp->f_depends) { 762 fprintf(f, "%s%so: %s%s%c %s\n", 763 ftp->f_objprefix, tail(np), 764 ftp->f_srcprefix, np, och, 765 ftp->f_depends); 766 } 767 else { 768 fprintf(f, "%s%so: %s%s%c\n", 769 ftp->f_objprefix, tail(np), 770 ftp->f_srcprefix, np, och); 771 } 772 } 773 compilewith = ftp->f_compilewith; 774 if (compilewith == NULL) { 775 const char *ftype = NULL; 776 777 switch (ftp->f_type) { 778 case NORMAL: 779 ftype = "NORMAL"; 780 break; 781 default: 782 fprintf(stderr, 783 "config: don't know rules for %s\n", np); 784 break; 785 } 786 snprintf(cmd, sizeof(cmd), 787 "${%s_%c%s}", ftype, 788 toupper(och), 789 ftp->f_flags & NOWERROR ? "_NOWERROR" : ""); 790 compilewith = cmd; 791 } 792 *cp = och; 793 if (strlen(ftp->f_objprefix)) 794 fprintf(f, "\t%s %s%s\n", compilewith, 795 ftp->f_srcprefix, np); 796 else 797 fprintf(f, "\t%s\n", compilewith); 798 799 if (!(ftp->f_flags & NO_CTFCONVERT)) 800 fprintf(f, "\t${NORMAL_CTFCONVERT}\n\n"); 801 else 802 fprintf(f, "\n"); 803 } 804 } 805 806 static void 807 do_clean(FILE *fp) 808 { 809 struct file_list *tp; 810 int lpos, len; 811 812 fputs("CLEAN=", fp); 813 lpos = 7; 814 STAILQ_FOREACH(tp, &ftab, f_next) 815 if (tp->f_clean) { 816 len = strlen(tp->f_clean); 817 if (len + lpos > 72) { 818 lpos = 8; 819 fputs("\\\n\t", fp); 820 } 821 fprintf(fp, "%s ", tp->f_clean); 822 lpos += len + 1; 823 } 824 if (lpos != 8) 825 putc('\n', fp); 826 } 827 828 char * 829 raisestr(char *str) 830 { 831 char *cp = str; 832 833 while (*str) { 834 if (islower(*str)) 835 *str = toupper(*str); 836 str++; 837 } 838 return (cp); 839 } 840