668d8f02ad489782eb1205b1c3bda26219a47482
[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.7 2004/07/07 07:37:04 asmodai 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, Sflag;
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(char ***, char *);
113 static  void    appcstrg(char ***, const char *);
114 static  void    applst(char ***, char *const *);
115 static  void    freelst(char ***);
116 static  char    *concat2(const char *, const char *);
117 static  char    *concat3(const char *, const char *, const char *);
118 static  void    terminate(int);
119 static  const   char *basename(const char *, int);
120 static  void    appdef(char ***, const char *);
121 static  void    usage(void);
122 static  void    fname(const char *, int);
123 static  void    runchild(const char *, char *const *, const char *);
124 static  void    findlibs(char *const *);
125 static  int     rdok(const char *);
126 static  void    lint2(void);
127 static  void    cat(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 [-abceghprvxzHFS] [-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 [-abceghprvzHFS] [-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 __DragonFly__
327         appcstrg(&cppflags, "-D__DragonFly__=" __XSTRING(__DragonFly__));
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:SU: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 'S':
423                         if (tflag)
424                                 usage();
425                         appcstrg(&l1flags, "-S");
426                         Sflag = 1;
427
428                 case 't':
429                         if (sflag)
430                                 usage();
431                         freelst(&lcppflgs);
432                         appcstrg(&lcppflgs, "-traditional");
433                         appstrg(&lcppflgs, concat2("-D", MACHINE));
434 #ifdef MACHINE_ARCH
435                         appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
436 #endif
437                         appcstrg(&l1flags, "-t");
438                         appcstrg(&l2flags, "-t");
439                         tflag = 1;
440                         break;
441
442                 case 'x':
443                         appcstrg(&l2flags, "-x");
444                         break;
445
446                 case 'C':
447                         if (Cflag || oflag || iflag)
448                                 usage();
449                         Cflag = 1;
450                         appstrg(&l2flags, concat2("-C", optarg));
451                         p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
452                         (void)sprintf(p2out, "llib-l%s.ln", optarg);
453                         freelst(&deflibs);
454                         break;
455
456                 case 'D':
457                 case 'I':
458                 case 'U':
459                         (void)sprintf(flgbuf, "-%c", c);
460                         appstrg(&cppflags, concat2(flgbuf, optarg));
461                         break;
462
463                 case 'l':
464                         appcstrg(&libs, optarg);
465                         break;
466
467                 case 'o':
468                         if (Cflag || oflag)
469                                 usage();
470                         oflag = 1;
471                         outputfn = xstrdup(optarg);
472                         break;
473
474                 case 'L':
475                         appcstrg(&libsrchpath, optarg);
476                         break;
477
478                 case 'H':
479                         appcstrg(&l2flags, "-H");
480                         break;
481
482                 case 'V':
483                         Vflag = 1;
484                         break;
485
486                 case '?':
487                         usage();
488                         /* NOTREACHED */
489
490                 case -1:
491                         /* filename */
492                         fname(argv[0], argc == 1);
493                         first = 0;
494                         optind = 1;
495                 }
496
497         }
498
499         if (first)
500                 usage();
501
502         if (iflag)
503                 terminate(0);
504
505         if (!oflag) {
506                 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
507                         s = PATH_LINTLIB;
508                 appcstrg(&libsrchpath, s);
509                 findlibs(libs);
510                 findlibs(deflibs);
511         }
512
513         (void)printf("Lint pass2:\n");
514         lint2();
515
516         if (oflag)
517                 cat(p2in, outputfn);
518
519         if (Cflag)
520                 p2out = NULL;
521
522         terminate(0);
523         /* NOTREACHED */
524         return 0;
525 }
526
527 /*
528  * Read a file name from the command line
529  * and pass it through lint1 if it is a C source.
530  */
531 static void
532 fname(name, last)
533         const   char *name;
534         int     last;
535 {
536         const   char *bn, *suff;
537         char    **args, *ofn, *path;
538         size_t  len;
539
540         bn = basename(name, '/');
541         suff = basename(bn, '.');
542
543         if (strcmp(suff, "ln") == 0) {
544                 /* only for lint2 */
545                 if (!iflag)
546                         appcstrg(&p2in, name);
547                 return;
548         }
549
550         if (strcmp(suff, "c") != 0 &&
551             (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
552                 warnx("unknown file type: %s\n", name);
553                 return;
554         }
555
556         if (!iflag || !first || !last)
557                 (void)printf("%s:\n", Fflag ? name : bn);
558
559         /* build the name of the output file of lint1 */
560         if (oflag) {
561                 ofn = outputfn;
562                 outputfn = NULL;
563                 oflag = 0;
564         } else if (iflag) {
565                 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
566                 len = bn == suff ? strlen(bn) : (suff - 1) - bn;
567                 (void)sprintf(ofn, "%.*s", (int)len, bn);
568                 (void)strcat(ofn, ".ln");
569         } else {
570                 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
571                 (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
572                 if (mktemp(ofn) == NULL) {
573                         warn("can't make temp");
574                         terminate(-1);
575                 }
576         }
577         if (!iflag)
578                 appcstrg(&p1out, ofn);
579
580         args = xcalloc(1, sizeof (char *));
581
582         /* run cpp */
583
584         path = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cpp"));
585         (void)sprintf(path, "%s/cpp", PATH_USRBIN);
586
587         appcstrg(&args, path);
588         applst(&args, cppflags);
589         applst(&args, lcppflgs);
590         appcstrg(&args, name);
591         appcstrg(&args, cppout);
592
593         runchild(path, args, cppout);
594         free(path);
595         freelst(&args);
596
597         /* run lint1 */
598
599         path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
600         (void)sprintf(path, "%s/lint1", PATH_LIBEXEC);
601
602         appcstrg(&args, path);
603         applst(&args, l1flags);
604         appcstrg(&args, cppout);
605         appcstrg(&args, ofn);
606
607         runchild(path, args, ofn);
608         free(path);
609         freelst(&args);
610
611         appcstrg(&p2in, ofn);
612         free(ofn);
613
614         free(args);
615 }
616
617 static void
618 runchild(path, args, crfn)
619         const   char *path, *crfn;
620         char    *const *args;
621 {
622         int     status, rv, signo, i;
623
624         if (Vflag) {
625                 for (i = 0; args[i] != NULL; i++)
626                         (void)printf("%s ", args[i]);
627                 (void)printf("\n");
628         }
629
630         currfn = crfn;
631
632         (void)fflush(stdout);
633
634         switch (fork()) {
635         case -1:
636                 warn("cannot fork");
637                 terminate(-1);
638                 /* NOTREACHED */
639         default:
640                 /* parent */
641                 break;
642         case 0:
643                 /* child */
644                 (void)execv(path, args);
645                 warn("cannot exec %s", path);
646                 exit(1);
647                 /* NOTREACHED */
648         }
649
650         while ((rv = wait(&status)) == -1 && errno == EINTR) ;
651         if (rv == -1) {
652                 warn("wait");
653                 terminate(-1);
654         }
655         if (WIFSIGNALED(status)) {
656                 signo = WTERMSIG(status);
657                 warnx("%s got SIG%s", path, sys_signame[signo]);
658                 terminate(-1);
659         }
660         if (WEXITSTATUS(status) != 0)
661                 terminate(-1);
662         currfn = NULL;
663 }
664
665 static void
666 findlibs(liblst)
667         char    *const *liblst;
668 {
669         int     i, k;
670         const   char *lib, *path;
671         char    *lfn;
672         size_t  len;
673
674         lfn = NULL;
675
676         for (i = 0; (lib = liblst[i]) != NULL; i++) {
677                 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
678                         len = strlen(path) + strlen(lib);
679                         lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
680                         (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
681                         if (rdok(lfn))
682                                 break;
683                         lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
684                         (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
685                         if (rdok(lfn))
686                                 break;
687                 }
688                 if (path != NULL) {
689                         appstrg(&l2libs, concat2("-l", lfn));
690                 } else {
691                         warnx("cannot find llib-l%s.ln", lib);
692                 }
693         }
694
695         free(lfn);
696 }
697
698 static int
699 rdok(path)
700         const   char *path;
701 {
702         struct  stat sbuf;
703
704         if (stat(path, &sbuf) == -1)
705                 return (0);
706         if ((sbuf.st_mode & S_IFMT) != S_IFREG)
707                 return (0);
708         if (access(path, R_OK) == -1)
709                 return (0);
710         return (1);
711 }
712
713 static void
714 lint2()
715 {
716         char    *path, **args;
717
718         args = xcalloc(1, sizeof (char *));
719
720         path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
721         (void)sprintf(path, "%s/lint2", PATH_LIBEXEC);
722         
723         appcstrg(&args, path);
724         applst(&args, l2flags);
725         applst(&args, l2libs);
726         applst(&args, p2in);
727
728         runchild(path, args, p2out);
729         free(path);
730         freelst(&args);
731         free(args);
732 }
733
734 static void
735 cat(srcs, dest)
736         char    *const *srcs;
737         const   char *dest;
738 {
739         int     ifd, ofd, i;
740         char    *src, *buf;
741         ssize_t rlen;
742
743         if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
744                 warn("cannot open %s", dest);
745                 terminate(-1);
746         }
747
748         buf = xmalloc(MBLKSIZ);
749
750         for (i = 0; (src = srcs[i]) != NULL; i++) {
751                 if ((ifd = open(src, O_RDONLY)) == -1) {
752                         free(buf);
753                         warn("cannot open %s", src);
754                         terminate(-1);
755                 }
756                 do {
757                         if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
758                                 free(buf);
759                                 warn("read error on %s", src);
760                                 terminate(-1);
761                         }
762                         if (write(ofd, buf, (size_t)rlen) == -1) {
763                                 free(buf);
764                                 warn("write error on %s", dest);
765                                 terminate(-1);
766                         }
767                 } while (rlen == MBLKSIZ);
768                 (void)close(ifd);
769         }
770         (void)close(ofd);
771         free(buf);
772 }
773