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