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