Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.bin / xlint / xlint / xlint.c
1 /*      $NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $    */
2
3 /*
4  * Copyright (c) 1994, 1995 Jochen Pohl
5  * All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Jochen Pohl for
18  *      The NetBSD Project.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * $FreeBSD: src/usr.bin/xlint/xlint/xlint.c,v 1.8 2000/01/14 09:25:31 sheldonh Exp $
34  * $DragonFly: src/usr.bin/xlint/xlint/xlint.c,v 1.2 2003/06/17 04:29:34 dillon Exp $
35  */
36
37 #include <sys/param.h>
38 #include <sys/wait.h>
39 #include <sys/stat.h>
40 #include <sys/utsname.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <signal.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <paths.h>
50
51 #include "lint.h"
52 #include "pathnames.h"
53
54 /* directory for temporary files */
55 static  const   char *tmpdir;
56
57 /* path name for cpp output */
58 static  char    *cppout;
59
60 /* files created by 1st pass */
61 static  char    **p1out;
62
63 /* input files for 2nd pass (without libraries) */
64 static  char    **p2in;
65
66 /* library which will be created by 2nd pass */
67 static  char    *p2out;
68
69 /* flags always passed to cpp */
70 static  char    **cppflags;
71
72 /* flags for cpp, controled by sflag/tflag */
73 static  char    **lcppflgs;
74
75 /* flags for lint1 */
76 static  char    **l1flags;
77
78 /* flags for lint2 */
79 static  char    **l2flags;
80
81 /* libraries for lint2 */
82 static  char    **l2libs;
83
84 /* default libraries */
85 static  char    **deflibs;
86
87 /* additional libraries */
88 static  char    **libs;
89
90 /* search path for libraries */
91 static  char    **libsrchpath;
92
93 /* flags */
94 static  int     iflag, oflag, Cflag, sflag, tflag, Fflag;
95
96 /* print the commands executed to run the stages of compilation */
97 static  int     Vflag;
98
99 /* filename for oflag */
100 static  char    *outputfn;
101
102 /* reset after first .c source has been processed */
103 static  int     first = 1;
104
105 /*
106  * name of a file which is currently written by a child and should
107  * be removed after abnormal termination of the child
108  */
109 static  const   char *currfn;
110
111
112 static  void    appstrg __P((char ***, char *));
113 static  void    appcstrg __P((char ***, const char *));
114 static  void    applst __P((char ***, char *const *));
115 static  void    freelst __P((char ***));
116 static  char    *concat2 __P((const char *, const char *));
117 static  char    *concat3 __P((const char *, const char *, const char *));
118 static  void    terminate __P((int));
119 static  const   char *basename __P((const char *, int));
120 static  void    appdef __P((char ***, const char *));
121 static  void    usage __P((void));
122 static  void    fname __P((const char *, int));
123 static  void    runchild __P((const char *, char *const *, const char *));
124 static  void    findlibs __P((char *const *));
125 static  int     rdok __P((const char *));
126 static  void    lint2 __P((void));
127 static  void    cat __P((char *const *, const char *));
128
129 /*
130  * Some functions to deal with lists of strings.
131  * Take care that we get no surprises in case of asyncron signals.
132  */
133 static void
134 appstrg(lstp, s)
135         char    ***lstp, *s;
136 {
137         char    **lst, **olst;
138         int     i;
139
140         olst = *lstp;
141         for (i = 0; olst[i] != NULL; i++) ;
142         lst = xmalloc((i + 2) * sizeof (char *));
143         (void)memcpy(lst, olst, i * sizeof (char *));
144         lst[i] = s;
145         lst[i + 1] = NULL;
146         *lstp = lst;
147 }       
148
149 static void
150 appcstrg(lstp, s)
151         char    ***lstp;
152         const   char *s;
153 {
154         appstrg(lstp, xstrdup(s));
155 }
156
157 static void
158 applst(destp, src)
159         char    ***destp;
160         char    *const *src;
161 {
162         int     i, k;
163         char    **dest, **odest;
164
165         odest = *destp;
166         for (i = 0; odest[i] != NULL; i++) ;
167         for (k = 0; src[k] != NULL; k++) ;
168         dest = xmalloc((i + k + 1) * sizeof (char *));
169         (void)memcpy(dest, odest, i * sizeof (char *));
170         for (k = 0; src[k] != NULL; k++)
171                 dest[i + k] = xstrdup(src[k]);
172         dest[i + k] = NULL;
173         *destp = dest;
174         free(odest);
175 }
176
177 static void
178 freelst(lstp)
179         char    ***lstp;
180 {
181         char    *s;
182         int     i;
183
184         for (i = 0; (*lstp)[i] != NULL; i++) ;
185         while (i-- > 0) {
186                 s = (*lstp)[i];
187                 (*lstp)[i] = NULL;
188                 free(s);
189         }
190 }
191
192 static char *
193 concat2(s1, s2)
194         const   char *s1, *s2;
195 {
196         char    *s;
197
198         s = xmalloc(strlen(s1) + strlen(s2) + 1);
199         (void)strcpy(s, s1);
200         (void)strcat(s, s2);
201
202         return (s);
203 }
204
205 static char *
206 concat3(s1, s2, s3)
207         const   char *s1, *s2, *s3;
208 {
209         char    *s;
210
211         s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
212         (void)strcpy(s, s1);
213         (void)strcat(s, s2);
214         (void)strcat(s, s3);
215
216         return (s);
217 }
218
219 /*
220  * Clean up after a signal.
221  */
222 static void
223 terminate(signo)
224         int     signo;
225 {
226         int     i;
227
228         if (cppout != NULL)
229                 (void)remove(cppout);
230
231         if (p1out != NULL) {
232                 for (i = 0; p1out[i] != NULL; i++)
233                         (void)remove(p1out[i]);
234         }
235
236         if (p2out != NULL)
237                 (void)remove(p2out);
238
239         if (currfn != NULL)
240                 (void)remove(currfn);
241
242         exit(signo != 0 ? 1 : 0);
243 }
244
245 /*
246  * Returns a pointer to the last component of strg after delim.
247  * Returns strg if the string does not contain delim.
248  */
249 static const char *
250 basename(strg, delim)
251         const   char *strg;
252         int     delim;
253 {
254         const   char *cp, *cp1, *cp2;
255
256         cp = cp1 = cp2 = strg;
257         while (*cp != '\0') {
258                 if (*cp++ == delim) {
259                         cp2 = cp1;
260                         cp1 = cp;
261                 }
262         }
263         return (*cp1 == '\0' ? cp2 : cp1);
264 }
265
266 static void
267 appdef(lstp, def)
268         char    ***lstp;
269         const   char *def;
270 {
271         appstrg(lstp, concat2("-D__", def));
272         appstrg(lstp, concat3("-D__", def, "__"));
273 }
274
275 static void
276 usage()
277 {
278         (void)printf("lint [-abceghprvxzHF] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n");
279         (void)printf("     [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n");
280         (void)printf("\n");
281         (void)printf("lint [-abceghprvzHF] [-s|-t] -Clibrary [-Dname[=def]]\n");
282         (void)printf("     [-Idirectory] [-Uname] file ...\n");
283         terminate(-1);
284 }
285
286 int
287 main(argc, argv)
288         int     argc;
289         char    *argv[];
290 {
291         int     c;
292         char    flgbuf[3], *tmp, *s;
293         size_t  len;
294         struct  utsname un;
295
296         if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
297                 tmpdir = xstrdup(_PATH_TMP);
298         } else {
299                 s = xmalloc(len + 2);
300                 (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
301                 tmpdir = s;
302         }
303
304         cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
305         (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
306         if (mktemp(cppout) == NULL) {
307                 warn("can't make temp");
308                 terminate(-1);
309         }
310
311         p1out = xcalloc(1, sizeof (char *));
312         p2in = xcalloc(1, sizeof (char *));
313         cppflags = xcalloc(1, sizeof (char *));
314         lcppflgs = xcalloc(1, sizeof (char *));
315         l1flags = xcalloc(1, sizeof (char *));
316         l2flags = xcalloc(1, sizeof (char *));
317         l2libs = xcalloc(1, sizeof (char *));
318         deflibs = xcalloc(1, sizeof (char *));
319         libs = xcalloc(1, sizeof (char *));
320         libsrchpath = xcalloc(1, sizeof (char *));
321
322         appcstrg(&cppflags, "-lang-c");
323         appcstrg(&cppflags, "-$");
324         appcstrg(&cppflags, "-C");
325         appcstrg(&cppflags, "-Wcomment");
326 #ifdef __FreeBSD__
327         appcstrg(&cppflags, "-D__FreeBSD__=" __XSTRING(__FreeBSD__));
328 #else
329 #       error "This ain't NetBSD.  You lose!"
330         appcstrg(&cppflags, "-D__NetBSD__");
331 #endif
332         appcstrg(&cppflags, "-Dlint");          /* XXX don't def. with -s */
333         appdef(&cppflags, "lint");
334         appdef(&cppflags, "unix");
335
336         appcstrg(&lcppflgs, "-Wtraditional");
337
338         if (uname(&un) == -1)
339                 err(1, "uname");
340         appdef(&cppflags, un.machine);
341         appstrg(&lcppflgs, concat2("-D", un.machine));
342
343 #ifdef MACHINE_ARCH
344         if (strcmp(un.machine, MACHINE_ARCH) != 0) {
345                 appdef(&cppflags, MACHINE_ARCH);
346                 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
347         }
348 #endif
349         
350         appcstrg(&deflibs, "c");
351
352         if (signal(SIGHUP, terminate) == SIG_IGN)
353                 (void)signal(SIGHUP, SIG_IGN);
354         (void)signal(SIGINT, terminate);
355         (void)signal(SIGQUIT, terminate);
356         (void)signal(SIGTERM, terminate);
357
358         while (argc > optind) {
359
360                 argc -= optind;
361                 argv += optind;
362                 optind = 0;
363
364                 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:U:V");
365
366                 switch (c) {
367
368                 case 'a':
369                 case 'b':
370                 case 'c':
371                 case 'e':
372                 case 'g':
373                 case 'r':
374                 case 'v':
375                 case 'z':
376                         (void)sprintf(flgbuf, "-%c", c);
377                         appcstrg(&l1flags, flgbuf);
378                         break;
379
380                 case 'F':
381                         Fflag = 1;
382                         /* FALLTHROUGH */
383                 case 'u':
384                 case 'h':
385                         (void)sprintf(flgbuf, "-%c", c);
386                         appcstrg(&l1flags, flgbuf);
387                         appcstrg(&l2flags, flgbuf);
388                         break;
389
390                 case 'i':
391                         if (Cflag)
392                                 usage();
393                         iflag = 1;
394                         break;
395
396                 case 'n':
397                         freelst(&deflibs);
398                         break;
399
400                 case 'p':
401                         appcstrg(&l1flags, "-p");
402                         appcstrg(&l2flags, "-p");
403                         if (*deflibs != NULL) {
404                                 freelst(&deflibs);
405                                 appcstrg(&deflibs, "c");
406                         }
407                         break;
408
409                 case 's':
410                         if (tflag)
411                                 usage();
412                         freelst(&lcppflgs);
413                         appcstrg(&lcppflgs, "-trigraphs");
414                         appcstrg(&lcppflgs, "-Wtrigraphs");
415                         appcstrg(&lcppflgs, "-pedantic");
416                         appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
417                         appcstrg(&l1flags, "-s");
418                         appcstrg(&l2flags, "-s");
419                         sflag = 1;
420                         break;
421
422                 case 't':
423                         if (sflag)
424                                 usage();
425                         freelst(&lcppflgs);
426                         appcstrg(&lcppflgs, "-traditional");
427                         appstrg(&lcppflgs, concat2("-D", MACHINE));
428 #ifdef MACHINE_ARCH
429                         appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
430 #endif
431                         appcstrg(&l1flags, "-t");
432                         appcstrg(&l2flags, "-t");
433                         tflag = 1;
434                         break;
435
436                 case 'x':
437                         appcstrg(&l2flags, "-x");
438                         break;
439
440                 case 'C':
441                         if (Cflag || oflag || iflag)
442                                 usage();
443                         Cflag = 1;
444                         appstrg(&l2flags, concat2("-C", optarg));
445                         p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
446                         (void)sprintf(p2out, "llib-l%s.ln", optarg);
447                         freelst(&deflibs);
448                         break;
449
450                 case 'D':
451                 case 'I':
452                 case 'U':
453                         (void)sprintf(flgbuf, "-%c", c);
454                         appstrg(&cppflags, concat2(flgbuf, optarg));
455                         break;
456
457                 case 'l':
458                         appcstrg(&libs, optarg);
459                         break;
460
461                 case 'o':
462                         if (Cflag || oflag)
463                                 usage();
464                         oflag = 1;
465                         outputfn = xstrdup(optarg);
466                         break;
467
468                 case 'L':
469                         appcstrg(&libsrchpath, optarg);
470                         break;
471
472                 case 'H':
473                         appcstrg(&l2flags, "-H");
474                         break;
475
476                 case 'V':
477                         Vflag = 1;
478                         break;
479
480                 case '?':
481                         usage();
482                         /* NOTREACHED */
483
484                 case -1:
485                         /* filename */
486                         fname(argv[0], argc == 1);
487                         first = 0;
488                         optind = 1;
489                 }
490
491         }
492
493         if (first)
494                 usage();
495
496         if (iflag)
497                 terminate(0);
498
499         if (!oflag) {
500                 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
501                         s = PATH_LINTLIB;
502                 appcstrg(&libsrchpath, s);
503                 findlibs(libs);
504                 findlibs(deflibs);
505         }
506
507         (void)printf("Lint pass2:\n");
508         lint2();
509
510         if (oflag)
511                 cat(p2in, outputfn);
512
513         if (Cflag)
514                 p2out = NULL;
515
516         terminate(0);
517         /* NOTREACHED */
518         return 0;
519 }
520
521 /*
522  * Read a file name from the command line
523  * and pass it through lint1 if it is a C source.
524  */
525 static void
526 fname(name, last)
527         const   char *name;
528         int     last;
529 {
530         const   char *bn, *suff;
531         char    **args, *ofn, *path;
532         size_t  len;
533
534         bn = basename(name, '/');
535         suff = basename(bn, '.');
536
537         if (strcmp(suff, "ln") == 0) {
538                 /* only for lint2 */
539                 if (!iflag)
540                         appcstrg(&p2in, name);
541                 return;
542         }
543
544         if (strcmp(suff, "c") != 0 &&
545             (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
546                 warnx("unknown file type: %s\n", name);
547                 return;
548         }
549
550         if (!iflag || !first || !last)
551                 (void)printf("%s:\n", Fflag ? name : bn);
552
553         /* build the name of the output file of lint1 */
554         if (oflag) {
555                 ofn = outputfn;
556                 outputfn = NULL;
557                 oflag = 0;
558         } else if (iflag) {
559                 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
560                 len = bn == suff ? strlen(bn) : (suff - 1) - bn;
561                 (void)sprintf(ofn, "%.*s", (int)len, bn);
562                 (void)strcat(ofn, ".ln");
563         } else {
564                 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
565                 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
566                 if (mktemp(ofn) == NULL) {
567                         warn("can't make temp");
568                         terminate(-1);
569                 }
570         }
571         if (!iflag)
572                 appcstrg(&p1out, ofn);
573
574         args = xcalloc(1, sizeof (char *));
575
576         /* run cpp */
577
578         path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/cpp"));
579         (void)sprintf(path, "%s/cpp", PATH_LIBEXEC);
580
581         appcstrg(&args, path);
582         applst(&args, cppflags);
583         applst(&args, lcppflgs);
584         appcstrg(&args, name);
585         appcstrg(&args, cppout);
586
587         runchild(path, args, cppout);
588         free(path);
589         freelst(&args);
590
591         /* run lint1 */
592
593         path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
594         (void)sprintf(path, "%s/lint1", PATH_LIBEXEC);
595
596         appcstrg(&args, path);
597         applst(&args, l1flags);
598         appcstrg(&args, cppout);
599         appcstrg(&args, ofn);
600
601         runchild(path, args, ofn);
602         free(path);
603         freelst(&args);
604
605         appcstrg(&p2in, ofn);
606         free(ofn);
607
608         free(args);
609 }
610
611 static void
612 runchild(path, args, crfn)
613         const   char *path, *crfn;
614         char    *const *args;
615 {
616         int     status, rv, signo, i;
617
618         if (Vflag) {
619                 for (i = 0; args[i] != NULL; i++)
620                         (void)printf("%s ", args[i]);
621                 (void)printf("\n");
622         }
623
624         currfn = crfn;
625
626         (void)fflush(stdout);
627
628         switch (fork()) {
629         case -1:
630                 warn("cannot fork");
631                 terminate(-1);
632                 /* NOTREACHED */
633         default:
634                 /* parent */
635                 break;
636         case 0:
637                 /* child */
638                 (void)execv(path, args);
639                 warn("cannot exec %s", path);
640                 exit(1);
641                 /* NOTREACHED */
642         }
643
644         while ((rv = wait(&status)) == -1 && errno == EINTR) ;
645         if (rv == -1) {
646                 warn("wait");
647                 terminate(-1);
648         }
649         if (WIFSIGNALED(status)) {
650                 signo = WTERMSIG(status);
651                 warnx("%s got SIG%s", path, sys_signame[signo]);
652                 terminate(-1);
653         }
654         if (WEXITSTATUS(status) != 0)
655                 terminate(-1);
656         currfn = NULL;
657 }
658
659 static void
660 findlibs(liblst)
661         char    *const *liblst;
662 {
663         int     i, k;
664         const   char *lib, *path;
665         char    *lfn;
666         size_t  len;
667
668         lfn = NULL;
669
670         for (i = 0; (lib = liblst[i]) != NULL; i++) {
671                 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
672                         len = strlen(path) + strlen(lib);
673                         lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
674                         (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
675                         if (rdok(lfn))
676                                 break;
677                         lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
678                         (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
679                         if (rdok(lfn))
680                                 break;
681                 }
682                 if (path != NULL) {
683                         appstrg(&l2libs, concat2("-l", lfn));
684                 } else {
685                         warnx("cannot find llib-l%s.ln", lib);
686                 }
687         }
688
689         free(lfn);
690 }
691
692 static int
693 rdok(path)
694         const   char *path;
695 {
696         struct  stat sbuf;
697
698         if (stat(path, &sbuf) == -1)
699                 return (0);
700         if ((sbuf.st_mode & S_IFMT) != S_IFREG)
701                 return (0);
702         if (access(path, R_OK) == -1)
703                 return (0);
704         return (1);
705 }
706
707 static void
708 lint2()
709 {
710         char    *path, **args;
711
712         args = xcalloc(1, sizeof (char *));
713
714         path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
715         (void)sprintf(path, "%s/lint2", PATH_LIBEXEC);
716         
717         appcstrg(&args, path);
718         applst(&args, l2flags);
719         applst(&args, l2libs);
720         applst(&args, p2in);
721
722         runchild(path, args, p2out);
723         free(path);
724         freelst(&args);
725         free(args);
726 }
727
728 static void
729 cat(srcs, dest)
730         char    *const *srcs;
731         const   char *dest;
732 {
733         int     ifd, ofd, i;
734         char    *src, *buf;
735         ssize_t rlen;
736
737         if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
738                 warn("cannot open %s", dest);
739                 terminate(-1);
740         }
741
742         buf = xmalloc(MBLKSIZ);
743
744         for (i = 0; (src = srcs[i]) != NULL; i++) {
745                 if ((ifd = open(src, O_RDONLY)) == -1) {
746                         free(buf);
747                         warn("cannot open %s", src);
748                         terminate(-1);
749                 }
750                 do {
751                         if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
752                                 free(buf);
753                                 warn("read error on %s", src);
754                                 terminate(-1);
755                         }
756                         if (write(ofd, buf, (size_t)rlen) == -1) {
757                                 free(buf);
758                                 warn("write error on %s", dest);
759                                 terminate(-1);
760                         }
761                 } while (rlen == MBLKSIZ);
762                 (void)close(ifd);
763         }
764         (void)close(ofd);
765         free(buf);
766 }
767