Initial import of binutils 2.22 on the new vendor branch
[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.12 2006/10/02 13:26:40 corecode 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(char ***lstp, char *s)
135 {
136         char    **lst, **olst;
137         int     i;
138
139         olst = *lstp;
140         for (i = 0; olst[i] != NULL; i++) ;
141         lst = xmalloc((i + 2) * sizeof (char *));
142         memcpy(lst, olst, i * sizeof (char *));
143         lst[i] = s;
144         lst[i + 1] = NULL;
145         *lstp = lst;
146 }
147
148 static void
149 appcstrg(char ***lstp, const char *s)
150 {
151         appstrg(lstp, xstrdup(s));
152 }
153
154 static void
155 applst(char ***destp, char *const *src)
156 {
157         int     i, k;
158         char    **dest, **odest;
159
160         odest = *destp;
161         for (i = 0; odest[i] != NULL; i++) ;
162         for (k = 0; src[k] != NULL; k++) ;
163         dest = xmalloc((i + k + 1) * sizeof (char *));
164         memcpy(dest, odest, i * sizeof (char *));
165         for (k = 0; src[k] != NULL; k++)
166                 dest[i + k] = xstrdup(src[k]);
167         dest[i + k] = NULL;
168         *destp = dest;
169         free(odest);
170 }
171
172 static void
173 freelst(char ***lstp)
174 {
175         char    *s;
176         int     i;
177
178         for (i = 0; (*lstp)[i] != NULL; i++) ;
179         while (i-- > 0) {
180                 s = (*lstp)[i];
181                 (*lstp)[i] = NULL;
182                 free(s);
183         }
184 }
185
186 static char *
187 concat2(const char *s1, const char *s2)
188 {
189         char    *s;
190
191         s = xmalloc(strlen(s1) + strlen(s2) + 1);
192         strcpy(s, s1);
193         strcat(s, s2);
194
195         return (s);
196 }
197
198 static char *
199 concat3(const char *s1, const char *s2, const char *s3)
200 {
201         char    *s;
202
203         s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
204         strcpy(s, s1);
205         strcat(s, s2);
206         strcat(s, s3);
207
208         return (s);
209 }
210
211 /*
212  * Clean up after a signal.
213  */
214 static void
215 terminate(int signo)
216 {
217         int     i;
218
219         if (cppout != NULL)
220                 remove(cppout);
221
222         if (p1out != NULL) {
223                 for (i = 0; p1out[i] != NULL; i++)
224                         remove(p1out[i]);
225         }
226
227         if (p2out != NULL)
228                 remove(p2out);
229
230         if (currfn != NULL)
231                 remove(currfn);
232
233         exit(signo != 0 ? 1 : 0);
234 }
235
236 /*
237  * Returns a pointer to the last component of strg after delim.
238  * Returns strg if the string does not contain delim.
239  */
240 static const char *
241 basename(const char *strg, int delim)
242 {
243         const   char *cp, *cp1, *cp2;
244
245         cp = cp1 = cp2 = strg;
246         while (*cp != '\0') {
247                 if (*cp++ == delim) {
248                         cp2 = cp1;
249                         cp1 = cp;
250                 }
251         }
252         return (*cp1 == '\0' ? cp2 : cp1);
253 }
254
255 static void
256 appdef(char ***lstp, const char *def)
257 {
258         appstrg(lstp, concat2("-D__", def));
259         appstrg(lstp, concat3("-D__", def, "__"));
260 }
261
262 static void
263 usage(void)
264 {
265         printf("lint [-abceghprvxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n");
266         printf("     [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n");
267         printf("\n");
268         printf("lint [-abceghprvzHFS] [-s|-t] -Clibrary [-Dname[=def]]\n");
269         printf("     [-Idirectory] [-Uname] file ...\n");
270         terminate(-1);
271 }
272
273 int
274 main(int argc, char **argv)
275 {
276         int     c, fd;
277         char    flgbuf[3], *tmp, *s;
278         size_t  len;
279         struct  utsname un;
280
281         if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
282                 tmpdir = xstrdup(_PATH_TMP);
283         } else {
284                 s = xmalloc(len + 2);
285                 sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
286                 tmpdir = s;
287         }
288
289         cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
290         sprintf(cppout, "%slint0.XXXXXX", tmpdir);
291
292         fd = mkstemp(cppout);
293         if (fd == -1) {
294                 err(1, "could not make a temporary file");
295                 close(fd);
296                 terminate(-1);
297         }
298         close (fd);
299
300         p1out = xcalloc(1, sizeof (char *));
301         p2in = xcalloc(1, sizeof (char *));
302         cppflags = xcalloc(1, sizeof (char *));
303         lcppflgs = xcalloc(1, sizeof (char *));
304         l1flags = xcalloc(1, sizeof (char *));
305         l2flags = xcalloc(1, sizeof (char *));
306         l2libs = xcalloc(1, sizeof (char *));
307         deflibs = xcalloc(1, sizeof (char *));
308         libs = xcalloc(1, sizeof (char *));
309         libsrchpath = xcalloc(1, sizeof (char *));
310
311         appcstrg(&cppflags, "-x");
312         appcstrg(&cppflags, "c");
313         appcstrg(&cppflags, "-undef");
314         /* even with -undef cpp still identifies as GNUC */
315         appcstrg(&cppflags, "-U__GNUC__");
316 #if defined(__GNUC__)
317 #if __GNUC__ < 3
318         appcstrg(&cppflags, "-$");
319         appcstrg(&cppflags, "-C");
320 #else
321         appcstrg(&cppflags, "-CC");
322 #endif
323 #endif
324         appcstrg(&cppflags, "-Wcomment");
325 #ifdef __DragonFly__
326         appcstrg(&cppflags, "-D__DragonFly__=" __XSTRING(__DragonFly__));
327 #else
328 #       error "This ain't NetBSD.  You lose!"
329         appcstrg(&cppflags, "-D__NetBSD__");
330 #endif
331         appcstrg(&cppflags, "-Dlint");          /* XXX don't def. with -s */
332         appdef(&cppflags, "lint");
333         appdef(&cppflags, "unix");
334
335         appcstrg(&lcppflgs, "-Wtraditional");
336
337         if (uname(&un) == -1)
338                 err(1, "uname");
339         appdef(&cppflags, un.machine);
340         appstrg(&lcppflgs, concat2("-D", un.machine));
341
342 #ifdef MACHINE_ARCH
343         if (strcmp(un.machine, MACHINE_ARCH) != 0) {
344                 appdef(&cppflags, MACHINE_ARCH);
345                 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
346         }
347 #endif
348
349         appcstrg(&deflibs, "c");
350
351         if (signal(SIGHUP, terminate) == SIG_IGN)
352                 signal(SIGHUP, SIG_IGN);
353         signal(SIGINT, terminate);
354         signal(SIGQUIT, terminate);
355         signal(SIGTERM, terminate);
356
357         while (argc > optind) {
358
359                 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:SU:V");
360
361                 switch (c) {
362
363                 case 'a':
364                 case 'b':
365                 case 'c':
366                 case 'e':
367                 case 'g':
368                 case 'r':
369                 case 'v':
370                 case 'z':
371                         sprintf(flgbuf, "-%c", c);
372                         appcstrg(&l1flags, flgbuf);
373                         break;
374
375                 case 'F':
376                         Fflag = 1;
377                         /* FALLTHROUGH */
378                 case 'u':
379                 case 'h':
380                         sprintf(flgbuf, "-%c", c);
381                         appcstrg(&l1flags, flgbuf);
382                         appcstrg(&l2flags, flgbuf);
383                         break;
384
385                 case 'i':
386                         if (Cflag)
387                                 usage();
388                         iflag = 1;
389                         break;
390
391                 case 'n':
392                         freelst(&deflibs);
393                         break;
394
395                 case 'p':
396                         appcstrg(&l1flags, "-p");
397                         appcstrg(&l2flags, "-p");
398                         if (*deflibs != NULL) {
399                                 freelst(&deflibs);
400                                 appcstrg(&deflibs, "c");
401                         }
402                         break;
403
404                 case 's':
405                         if (tflag)
406                                 usage();
407                         freelst(&lcppflgs);
408                         appcstrg(&lcppflgs, "-trigraphs");
409                         appcstrg(&lcppflgs, "-Wtrigraphs");
410                         appcstrg(&lcppflgs, "-pedantic");
411                         appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
412                         appcstrg(&l1flags, "-s");
413                         appcstrg(&l2flags, "-s");
414                         sflag = 1;
415                         break;
416
417                 case 'S':
418                         if (tflag)
419                                 usage();
420                         appcstrg(&l1flags, "-S");
421                         Sflag = 1;
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                         sprintf(p2out, "llib-l%s.ln", optarg);
448                         freelst(&deflibs);
449                         break;
450
451                 case 'D':
452                 case 'I':
453                 case 'U':
454                         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[optind], argc == optind + 1);
488                         first = 0;
489
490                         argc -= optind;
491                         argv += optind;
492                         optreset = optind = 1;
493                 }
494         }
495
496         if (first)
497                 usage();
498
499         if (iflag)
500                 terminate(0);
501
502         if (!oflag) {
503                 if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
504                         s = PATH_LINTLIB;
505                 appcstrg(&libsrchpath, s);
506                 findlibs(libs);
507                 findlibs(deflibs);
508         }
509
510         printf("Lint pass2:\n");
511         lint2();
512
513         if (oflag)
514                 cat(p2in, outputfn);
515
516         if (Cflag)
517                 p2out = NULL;
518
519         terminate(0);
520         /* NOTREACHED */
521         return 0;
522 }
523
524 /*
525  * Read a file name from the command line
526  * and pass it through lint1 if it is a C source.
527  */
528 static void
529 fname(const char *name, int last)
530 {
531         const   char *bn, *suff;
532         char    **args, *ofn, *path;
533         size_t  len;
534         int fd;
535
536         bn = basename(name, '/');
537         suff = basename(bn, '.');
538
539         if (strcmp(suff, "ln") == 0) {
540                 /* only for lint2 */
541                 if (!iflag)
542                         appcstrg(&p2in, name);
543                 return;
544         }
545
546         if (strcmp(suff, "c") != 0 &&
547             (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
548                 warnx("unknown file type: %s\n", name);
549                 return;
550         }
551
552         if (!iflag || !first || !last)
553                 printf("%s:\n", Fflag ? name : bn);
554
555         /* build the name of the output file of lint1 */
556         if (oflag) {
557                 ofn = outputfn;
558                 outputfn = NULL;
559                 oflag = 0;
560         } else if (iflag) {
561                 ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
562                 len = bn == suff ? strlen(bn) : (suff - 1) - bn;
563                 sprintf(ofn, "%.*s", (int)len, bn);
564                 strcat(ofn, ".ln");
565         } else {
566                 ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
567                 sprintf(ofn, "%slint1.XXXXXX", tmpdir);
568                 fd = mkstemp(ofn);
569                 if (fd == -1) {
570                         err(1, "could not make a temporary file");
571                         close(fd);
572                         terminate(-1);
573                 }
574                 close (fd);
575         }
576         if (!iflag)
577                 appcstrg(&p1out, ofn);
578
579         args = xcalloc(1, sizeof (char *));
580
581         /* run cpp */
582
583         path = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cpp"));
584         sprintf(path, "%s/cpp", PATH_USRBIN);
585
586         appcstrg(&args, path);
587         applst(&args, cppflags);
588         applst(&args, lcppflgs);
589         appcstrg(&args, name);
590         appcstrg(&args, cppout);
591
592         runchild(path, args, cppout);
593         free(path);
594         freelst(&args);
595
596         /* run lint1 */
597
598         path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
599         sprintf(path, "%s/lint1", PATH_LIBEXEC);
600
601         appcstrg(&args, path);
602         applst(&args, l1flags);
603         appcstrg(&args, cppout);
604         appcstrg(&args, ofn);
605
606         runchild(path, args, ofn);
607         free(path);
608         freelst(&args);
609
610         appcstrg(&p2in, ofn);
611         free(ofn);
612
613         free(args);
614 }
615
616 static void
617 runchild(const char *path, char *const *args, const char *crfn)
618 {
619         int     status, rv, signo, i;
620
621         if (Vflag) {
622                 for (i = 0; args[i] != NULL; i++)
623                         printf("%s ", args[i]);
624                 printf("\n");
625         }
626
627         currfn = crfn;
628
629         fflush(stdout);
630
631         switch (fork()) {
632         case -1:
633                 warn("cannot fork");
634                 terminate(-1);
635                 /* NOTREACHED */
636         default:
637                 /* parent */
638                 break;
639         case 0:
640                 /* child */
641                 execv(path, args);
642                 warn("cannot exec %s", path);
643                 exit(1);
644                 /* NOTREACHED */
645         }
646
647         while ((rv = wait(&status)) == -1 && errno == EINTR) ;
648         if (rv == -1) {
649                 warn("wait");
650                 terminate(-1);
651         }
652         if (WIFSIGNALED(status)) {
653                 signo = WTERMSIG(status);
654                 warnx("%s got SIG%s", path, sys_signame[signo]);
655                 terminate(-1);
656         }
657         if (WEXITSTATUS(status) != 0)
658                 terminate(-1);
659         currfn = NULL;
660 }
661
662 static void
663 findlibs(char *const *liblst)
664 {
665         int     i, k;
666         const   char *lib, *path;
667         char    *lfn;
668         size_t  len;
669
670         lfn = NULL;
671
672         for (i = 0; (lib = liblst[i]) != NULL; i++) {
673                 for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
674                         len = strlen(path) + strlen(lib);
675                         lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
676                         sprintf(lfn, "%s/llib-l%s.ln", path, lib);
677                         if (rdok(lfn))
678                                 break;
679                         lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
680                         sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
681                         if (rdok(lfn))
682                                 break;
683                 }
684                 if (path != NULL) {
685                         appstrg(&l2libs, concat2("-l", lfn));
686                 } else {
687                         warnx("cannot find llib-l%s.ln", lib);
688                 }
689         }
690
691         free(lfn);
692 }
693
694 static int
695 rdok(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(void)
710 {
711         char    *path, **args;
712
713         args = xcalloc(1, sizeof (char *));
714
715         path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
716         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(char *const *srcs, const char *dest)
731 {
732         int     ifd, ofd, i;
733         char    *src, *buf;
734         ssize_t rlen;
735
736         if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
737                 warn("cannot open %s", dest);
738                 terminate(-1);
739         }
740
741         buf = xmalloc(MBLKSIZ);
742
743         for (i = 0; (src = srcs[i]) != NULL; i++) {
744                 if ((ifd = open(src, O_RDONLY)) == -1) {
745                         free(buf);
746                         warn("cannot open %s", src);
747                         terminate(-1);
748                 }
749                 do {
750                         if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
751                                 free(buf);
752                                 warn("read error on %s", src);
753                                 terminate(-1);
754                         }
755                         if (write(ofd, buf, (size_t)rlen) == -1) {
756                                 free(buf);
757                                 warn("write error on %s", dest);
758                                 terminate(-1);
759                         }
760                 } while (rlen == MBLKSIZ);
761                 close(ifd);
762         }
763         close(ofd);
764         free(buf);
765 }
766