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