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