kernel - Reduce lwp_signotify() latency
[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. 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  * @(#)mkmakefile.c     8.1 (Berkeley) 6/6/93
30  * $FreeBSD: src/usr.sbin/config/mkmakefile.c,v 1.51.2.3 2001/01/23 00:09:32 peter Exp $
31  */
32
33 /*
34  * Build the makefile for the system, from
35  * the information in the 'files' files and the
36  * additional files for the machine being compiled to.
37  */
38
39 #include <ctype.h>
40 #include <err.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <sys/param.h>
44 #include "y.tab.h"
45 #include "config.h"
46 #include "configvers.h"
47
48 #define next_word(fp, wd)                                               \
49         {                                                               \
50                 char *word;                                             \
51                                                                         \
52                 word = get_word(fp);                                    \
53                 if (word == (char *)EOF)                                \
54                         return;                                         \
55                 else                                                    \
56                         wd = word;                                      \
57         }
58 #define next_quoted_word(fp, wd)                                        \
59         {                                                               \
60                 char *word;                                             \
61                                                                         \
62                 word = get_quoted_word(fp);                             \
63                 if (word == (char *)EOF)                                \
64                         return;                                         \
65                 else                                                    \
66                         wd = word;                                      \
67         }
68
69 static struct file_list *fcur;
70
71 static char *tail(char *);
72 static void do_clean(FILE *);
73 static void do_rules(FILE *);
74 static void do_sfiles(FILE *);
75 static void do_mfiles(FILE *);
76 static void do_cfiles(FILE *);
77 static void do_objs(FILE *);
78 static void do_before_depend(FILE *);
79 static int opteq(char *, char *);
80 static void read_files(void);
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         for (fp = ftab; fp != NULL; fp = fp->f_next) {
91                 if (strcmp(fp->f_fn, file) == 0)
92                         return(fp);
93         }
94         return(0);
95 }
96
97 /*
98  * Lookup a file, by final component name.
99  */
100 static struct file_list *
101 fltail_lookup(char *file)
102 {
103         struct file_list *fp;
104
105         for (fp = ftab; fp != NULL; fp = fp->f_next) {
106                 if (strcmp(tail(fp->f_fn), tail(file)) == 0)
107                         return(fp);
108         }
109         return(0);
110 }
111
112 /*
113  * Make a new file list entry
114  */
115 static struct file_list *
116 new_fent(void)
117 {
118         struct file_list *fp;
119
120         fp = malloc(sizeof(*fp));
121         bzero(fp, sizeof(*fp));
122         if (fcur == NULL)
123                 fcur = ftab = fp;
124         else
125                 fcur->f_next = fp;
126         fcur = fp;
127         return(fp);
128 }
129
130 /*
131  * Build the makefile from the skeleton
132  */
133 void
134 makefile(void)
135 {
136         FILE *ifp, *ofp;
137         char line[BUFSIZ];
138         struct opt *op;
139         int versreq;
140
141         read_files();
142         snprintf(line, sizeof(line), "../platform/%s/conf/Makefile",
143                  platformname);
144         ifp = fopen(line, "r");
145         if (ifp == NULL) {
146                 snprintf(line, sizeof(line), "Makefile.%s", platformname);
147                 ifp = fopen(line, "r");
148         }
149         if (ifp == NULL)
150                 err(1, "%s", line);
151         ofp = fopen(path("Makefile.new"), "w");
152         if (ofp == NULL)
153                 err(1, "%s", path("Makefile.new"));
154         fprintf(ofp, "KERN_IDENT=%s\n", raisestr(ident));
155         fprintf(ofp, "MACHINE_PLATFORM=%s\n", platformname);
156         fprintf(ofp, "MACHINE=%s\n", machinename);
157         fprintf(ofp, "MACHINE_ARCH=%s\n", machinearchname);
158         fprintf(ofp, ".export MACHINE_PLATFORM\n");
159         fprintf(ofp, ".export MACHINE\n");
160         fprintf(ofp, ".export MACHINE_ARCH\n");
161         fprintf(ofp, "IDENT=");
162         if (profiling) {
163                 /* Don't compile kernel profiling code for vkernel */
164                 if (strncmp(platformname, "vkernel", 6) != 0)
165                         fprintf(ofp, " -DGPROF");
166         }
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, nowerror, 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                             "../platform/%s/conf/files",
271                             platformname);
272                         fp = fopen(fname, "r");
273                         if (fp != NULL)
274                                 goto next;
275                         snprintf(fname, sizeof(fname),
276                             "files.%s", platformname);
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 == NULL)
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 == NULL) {
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 = NULL;
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         nowerror = 0;
330         filetype = NORMAL;
331         if (strcmp(wd, "standard") == 0) {
332                 std = 1;
333         } else if (strcmp(wd, "mandatory") == 0) {
334                 /*
335                  * If an entry is marked "mandatory", config will abort if 
336                  * it's not called by a configuration line in the config
337                  * file.  Apart from this, the device is handled like one
338                  * marked "optional".
339                  */
340                 mandatory = 1;
341         } else if (strcmp(wd, "nonoptional") == 0) {
342                 nonoptional = 1;
343         } else if (strcmp(wd, "optional") == 0) {
344                 /* don't need to do anything */
345         } else {
346                 printf("%s: %s must be optional, mandatory or standard\n",
347                        fname, this);
348                 printf("Alternatively, your version of config(8) may be out of sync with your\nkernel source.\n");
349                 exit(1);
350         }
351 nextparam:
352         next_word(fp, wd);
353         if (wd == NULL)
354                 goto doneparam;
355         if (strcmp(wd, "config-dependent") == 0) {
356                 configdep++;
357                 goto nextparam;
358         }
359         if (strcmp(wd, "no-obj") == 0) {
360                 no_obj++;
361                 goto nextparam;
362         }
363         if (strcmp(wd, "no-implicit-rule") == 0) {
364                 if (special == NULL) {
365                         printf("%s: alternate rule required when "
366                                "\"no-implicit-rule\" is specified.\n",
367                                fname);
368                 }
369                 imp_rule++;
370                 goto nextparam;
371         }
372         if (strcmp(wd, "before-depend") == 0) {
373                 before_depend++;
374                 goto nextparam;
375         }
376         if (strcmp(wd, "dependency") == 0) {
377                 next_quoted_word(fp, wd);
378                 if (wd == NULL) {
379                         printf("%s: %s missing compile command string.\n",
380                                fname, this);
381                         exit(1);
382                 }
383                 depends = strdup(wd);
384                 goto nextparam;
385         }
386         if (strcmp(wd, "clean") == 0) {
387                 next_quoted_word(fp, wd);
388                 if (wd == NULL) {
389                         printf("%s: %s missing clean file list.\n",
390                                fname, this);
391                         exit(1);
392                 }
393                 clean = strdup(wd);
394                 goto nextparam;
395         }
396         if (strcmp(wd, "compile-with") == 0) {
397                 next_quoted_word(fp, wd);
398                 if (wd == NULL) {
399                         printf("%s: %s missing compile command string.\n",
400                                fname, this);
401                         exit(1);
402                 }
403                 special = strdup(wd);
404                 goto nextparam;
405         }
406         if (strcmp(wd, "nowerror") == 0) {
407                 nowerror++;
408                 goto nextparam;
409         }
410         if (strcmp(wd, "warning") == 0) {
411                 next_quoted_word(fp, wd);
412                 if (wd == NULL) {
413                         printf("%s: %s missing warning text string.\n",
414                                 fname, this);
415                         exit(1);
416                 }
417                 warning = strdup(wd);
418                 goto nextparam;
419         }
420         nreqs++;
421         if (strcmp(wd, "local") == 0) {
422                 filetype = LOCAL;
423                 goto nextparam;
424         }
425         if (strcmp(wd, "no-depend") == 0) {
426                 filetype = NODEPEND;
427                 goto nextparam;
428         }
429         if (strcmp(wd, "device-driver") == 0) {
430                 printf("%s: `device-driver' flag obsolete.\n", fname);
431                 exit(1);
432         }
433         if (strcmp(wd, "profiling-routine") == 0) {
434                 filetype = PROFILING;
435                 goto nextparam;
436         }
437         if (needs == NULL && nreqs == 1)
438                 needs = strdup(wd);
439         if (isdup)
440                 goto invis;
441         for (dp = dtab; dp != NULL; save_dp = dp, dp = dp->d_next)
442                 if (strcmp(dp->d_name, wd) == 0) {
443                         if (std && dp->d_type == PSEUDO_DEVICE &&
444                             dp->d_count <= 0)
445                                 dp->d_count = 1;
446                         goto nextparam;
447                 }
448         if (mandatory) {
449                 printf("%s: mandatory device \"%s\" not found\n",
450                        fname, wd);
451                 exit(1);
452         }
453         if (std) {
454                 dp = malloc(sizeof(*dp));
455                 bzero(dp, sizeof(*dp));
456                 init_dev(dp);
457                 dp->d_name = strdup(wd);
458                 dp->d_type = PSEUDO_DEVICE;
459                 dp->d_count = 1;
460                 save_dp->d_next = dp;
461                 goto nextparam;
462         }
463         for (op = opt; op != NULL; op = op->op_next) {
464                 if (op->op_value == 0 && opteq(op->op_name, wd)) {
465                         if (nreqs == 1) {
466                                 free(needs);
467                                 needs = NULL;
468                         }
469                         goto nextparam;
470                 }
471         }
472         if (nonoptional) {
473                 printf("%s: the option \"%s\" MUST be specified\n",
474                         fname, wd);
475                 exit(1);
476         }
477 invis:
478         while ((wd = get_word(fp)) != NULL)
479                 ;
480         if (tp == NULL)
481                 tp = new_fent();
482         tp->f_fn = this;
483         tp->f_type = INVISIBLE;
484         tp->f_needs = needs;
485         tp->f_flags = isdup;
486         tp->f_special = special;
487         tp->f_depends = depends;
488         tp->f_clean = clean;
489         tp->f_warn = warning;
490         goto next;
491
492 doneparam:
493         if (std == 0 && nreqs == 0) {
494                 printf("%s: what is %s optional on?\n",
495                     fname, this);
496                 exit(1);
497         }
498
499         if (wd != NULL) {
500                 printf("%s: syntax error describing %s\n",
501                     fname, this);
502                 exit(1);
503         }
504         if (filetype == PROFILING && profiling == 0)
505                 goto next;
506         if (tp == NULL)
507                 tp = new_fent();
508         tp->f_fn = this;
509         tp->f_type = filetype;
510         tp->f_flags = 0;
511         if (configdep)
512                 tp->f_flags |= CONFIGDEP;
513         if (imp_rule)
514                 tp->f_flags |= NO_IMPLCT_RULE;
515         if (no_obj)
516                 tp->f_flags |= NO_OBJ;
517         if (before_depend)
518                 tp->f_flags |= BEFORE_DEPEND;
519         if (nowerror)
520                 tp->f_flags |= NOWERROR;
521         if (imp_rule)
522                 tp->f_flags |= NO_IMPLCT_RULE;
523         if (no_obj)
524                 tp->f_flags |= NO_OBJ;
525         tp->f_needs = needs;
526         tp->f_special = special;
527         tp->f_depends = depends;
528         tp->f_clean = clean;
529         tp->f_warn = warning;
530         if (pf && pf->f_type == INVISIBLE)
531                 pf->f_flags = 1;                /* mark as duplicate */
532         goto next;
533 }
534
535 static int
536 opteq(char *cp, char *dp)
537 {
538         char c, d;
539
540         for (;; cp++, dp++) {
541                 if (*cp != *dp) {
542                         c = isupper(*cp) ? tolower(*cp) : *cp;
543                         d = isupper(*dp) ? tolower(*dp) : *dp;
544                         if (c != d)
545                                 return(0);
546                 }
547                 if (*cp == 0)
548                         return(1);
549         }
550 }
551
552 static void
553 do_before_depend(FILE *fp)
554 {
555         struct file_list *tp;
556         int lpos, len;
557
558         fputs("BEFORE_DEPEND=", fp);
559         lpos = 15;
560         for (tp = ftab; tp != NULL; tp = tp->f_next)
561                 if (tp->f_flags & BEFORE_DEPEND) {
562                         len = strlen(tp->f_fn);
563                         if ((len = 3 + len) + lpos > 72) {
564                                 lpos = 8;
565                                 fputs("\\\n\t", fp);
566                         }
567                         if (tp->f_flags & NO_IMPLCT_RULE)
568                                 fprintf(fp, "%s ", tp->f_fn);
569                         else
570                                 fprintf(fp, "$S/%s ", tp->f_fn);
571                         lpos += len + 1;
572                 }
573         if (lpos != 8)
574                 putc('\n', fp);
575 }
576
577 static void
578 do_objs(FILE *fp)
579 {
580         struct file_list *tp;
581         int lpos, len;
582         char *cp, och, *sp;
583
584         fprintf(fp, "OBJS=");
585         lpos = 6;
586         for (tp = ftab; tp != NULL; tp = tp->f_next) {
587                 if (tp->f_type == INVISIBLE || tp->f_flags & NO_OBJ)
588                         continue;
589                 sp = tail(tp->f_fn);
590                 cp = sp + (len = strlen(sp)) - 1;
591                 och = *cp;
592                 *cp = 'o';
593                 if (len + lpos > 72) {
594                         lpos = 8;
595                         fprintf(fp, "\\\n\t");
596                 }
597                 fprintf(fp, "%s ", sp);
598                 lpos += len + 1;
599                 *cp = och;
600         }
601         if (lpos != 8)
602                 putc('\n', fp);
603 }
604
605 static void
606 do_cfiles(FILE *fp)
607 {
608         struct file_list *tp;
609         int lpos, len;
610
611         fputs("CFILES=", fp);
612         lpos = 8;
613         for (tp = ftab; tp != NULL; tp = tp->f_next)
614                 if (tp->f_type != INVISIBLE && tp->f_type != NODEPEND) {
615                         len = strlen(tp->f_fn);
616                         if (tp->f_fn[len - 1] != 'c')
617                                 continue;
618                         if ((len = 3 + len) + lpos > 72) {
619                                 lpos = 8;
620                                 fputs("\\\n\t", fp);
621                         }
622                         if (tp->f_type != LOCAL)
623                                 fprintf(fp, "$S/%s ", tp->f_fn);
624                         else
625                                 fprintf(fp, "%s ", tp->f_fn);
626
627                         lpos += len + 1;
628                 }
629         if (lpos != 8)
630                 putc('\n', fp);
631 }
632
633 static void
634 do_mfiles(FILE *fp)
635 {
636         struct file_list *tp;
637         int lpos, len;
638
639         fputs("MFILES=", fp);
640         lpos = 8;
641         for (tp = ftab; tp != NULL; tp = tp->f_next)
642                 if (tp->f_type != INVISIBLE) {
643                         len = strlen(tp->f_fn);
644                         if (tp->f_fn[len - 1] != 'm' || tp->f_fn[len - 2] != '.')
645                                 continue;
646                         if ((len = 3 + len) + lpos > 72) {
647                                 lpos = 8;
648                                 fputs("\\\n\t", fp);
649                         }
650                         fprintf(fp, "$S/%s ", tp->f_fn);
651                         lpos += len + 1;
652                 }
653         if (lpos != 8)
654                 putc('\n', fp);
655 }
656
657 static void
658 do_sfiles(FILE *fp)
659 {
660         struct file_list *tp;
661         int lpos, len;
662
663         fputs("SFILES=", fp);
664         lpos = 8;
665         for (tp = ftab; tp != NULL; tp = tp->f_next)
666                 if (tp->f_type != INVISIBLE) {
667                         len = strlen(tp->f_fn);
668                         if (tp->f_fn[len - 1] != 'S' && tp->f_fn[len - 1] != 's')
669                                 continue;
670                         if ((len = 3 + len) + lpos > 72) {
671                                 lpos = 8;
672                                 fputs("\\\n\t", fp);
673                         }
674                         fprintf(fp, "$S/%s ", tp->f_fn);
675                         lpos += len + 1;
676                 }
677         if (lpos != 8)
678                 putc('\n', fp);
679 }
680
681
682 static char *
683 tail(char *fn)
684 {
685         char *cp;
686
687         cp = strrchr(fn, '/');
688         if (cp == NULL)
689                 return(fn);
690         return(cp + 1);
691 }
692
693 /*
694  * Create the makerules for each file
695  * which is part of the system.
696  * Devices are processed with the special c2 option -i
697  * which avoids any problem areas with i/o addressing
698  * (e.g. for the VAX); assembler files are processed by as.
699  */
700 static void
701 do_rules(FILE *f)
702 {
703         char *cp, *np, och;
704         struct file_list *ftp;
705         char *special;
706
707         for (ftp = ftab; ftp != NULL; ftp = ftp->f_next) {
708                 if (ftp->f_type == INVISIBLE)
709                         continue;
710                 if (ftp->f_warn != NULL)
711                         printf("WARNING: %s\n", ftp->f_warn);
712                 cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1;
713                 och = *cp;
714                 if (ftp->f_flags & NO_IMPLCT_RULE) {
715                         if (ftp->f_depends)
716                                 fprintf(f, "%s: %s\n", np, ftp->f_depends);
717                         else
718                                 fprintf(f, "%s: \n", np);
719                 }
720                 else {
721                         *cp = '\0';
722                         if (och == 'o') {
723                                 fprintf(f, "%so:\n\t-cp $S/%so .\n\n",
724                                         tail(np), np);
725                                 continue;
726                         }
727                         if (ftp->f_depends)
728                                 fprintf(f, "%so: $S/%s%c %s\n", tail(np),
729                                         np, och, ftp->f_depends);
730                         else
731                                 fprintf(f, "%so: $S/%s%c\n", tail(np),
732                                         np, och);
733                 }
734                 special = ftp->f_special;
735                 if (special == NULL) {
736                         const char *ftype = NULL;
737                         static char cmd[128];
738
739                         switch (ftp->f_type) {
740
741                         case NORMAL:
742                                 ftype = "NORMAL";
743                                 break;
744
745                         case PROFILING:
746                                 if (!profiling)
747                                         continue;
748                                 ftype = "PROFILE";
749                                 break;
750
751                         default:
752                                 printf("config: don't know rules for %s\n", np);
753                                 break;
754                         }
755                         snprintf(cmd, sizeof(cmd), "${%s_%c%s}%s",
756                             ftype, toupper(och),
757                             ftp->f_flags & CONFIGDEP ? "_C" : "",
758                             ftp->f_flags & NOWERROR ? "" : " ${WERROR}");
759                         special = cmd;
760                 }
761                 *cp = och;
762                 fprintf(f, "\t%s\n\n", special);
763         }
764 }
765
766 static void
767 do_clean(FILE *fp)
768 {
769         struct file_list *tp;
770         int lpos, len;
771
772         fputs("CLEAN=", fp);
773         lpos = 7;
774         for (tp = ftab; tp != NULL; tp = tp->f_next)
775                 if (tp->f_clean) {
776                         len = strlen(tp->f_clean);
777                         if (len + lpos > 72) {
778                                 lpos = 8;
779                                 fputs("\\\n\t", fp);
780                         }
781                         fprintf(fp, "%s ", tp->f_clean);
782                         lpos += len + 1;
783                 }
784         if (lpos != 8)
785                 putc('\n', fp);
786 }
787
788 char *
789 raisestr(char *str)
790 {
791         char *cp = str;
792
793         while (*str) {
794                 if (islower(*str))
795                         *str = toupper(*str);
796                 str++;
797         }
798         return(cp);
799 }