Some trivial changes from FreeBSD that allow to use kgdb on /dev/fwmem0.0.
[dragonfly.git] / usr.bin / xlint / xlint / xlint.c
blob5c37fa3626a89fc9fa014c0df74c7940dd09b568
1 /* $NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $ */
3 /*
4 * Copyright (c) 1994, 1995 Jochen Pohl
5 * All Rights Reserved.
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.
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.
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 $
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>
51 #include "lint.h"
52 #include "pathnames.h"
54 /* directory for temporary files */
55 static const char *tmpdir;
57 /* path name for cpp output */
58 static char *cppout;
60 /* files created by 1st pass */
61 static char **p1out;
63 /* input files for 2nd pass (without libraries) */
64 static char **p2in;
66 /* library which will be created by 2nd pass */
67 static char *p2out;
69 /* flags always passed to cpp */
70 static char **cppflags;
72 /* flags for cpp, controled by sflag/tflag */
73 static char **lcppflgs;
75 /* flags for lint1 */
76 static char **l1flags;
78 /* flags for lint2 */
79 static char **l2flags;
81 /* libraries for lint2 */
82 static char **l2libs;
84 /* default libraries */
85 static char **deflibs;
87 /* additional libraries */
88 static char **libs;
90 /* search path for libraries */
91 static char **libsrchpath;
93 /* flags */
94 static int iflag, oflag, Cflag, sflag, tflag, Fflag, Sflag;
96 /* print the commands executed to run the stages of compilation */
97 static int Vflag;
99 /* filename for oflag */
100 static char *outputfn;
102 /* reset after first .c source has been processed */
103 static int first = 1;
106 * name of a file which is currently written by a child and should
107 * be removed after abnormal termination of the child
109 static const char *currfn;
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 *);
130 * Some functions to deal with lists of strings.
131 * Take care that we get no surprises in case of asyncron signals.
133 static void
134 appstrg(char ***lstp, char *s)
136 char **lst, **olst;
137 int i;
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;
148 static void
149 appcstrg(char ***lstp, const char *s)
151 appstrg(lstp, xstrdup(s));
154 static void
155 applst(char ***destp, char *const *src)
157 int i, k;
158 char **dest, **odest;
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);
172 static void
173 freelst(char ***lstp)
175 char *s;
176 int i;
178 for (i = 0; (*lstp)[i] != NULL; i++) ;
179 while (i-- > 0) {
180 s = (*lstp)[i];
181 (*lstp)[i] = NULL;
182 free(s);
186 static char *
187 concat2(const char *s1, const char *s2)
189 char *s;
191 s = xmalloc(strlen(s1) + strlen(s2) + 1);
192 strcpy(s, s1);
193 strcat(s, s2);
195 return (s);
198 static char *
199 concat3(const char *s1, const char *s2, const char *s3)
201 char *s;
203 s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
204 strcpy(s, s1);
205 strcat(s, s2);
206 strcat(s, s3);
208 return (s);
212 * Clean up after a signal.
214 static void
215 terminate(int signo)
217 int i;
219 if (cppout != NULL)
220 remove(cppout);
222 if (p1out != NULL) {
223 for (i = 0; p1out[i] != NULL; i++)
224 remove(p1out[i]);
227 if (p2out != NULL)
228 remove(p2out);
230 if (currfn != NULL)
231 remove(currfn);
233 exit(signo != 0 ? 1 : 0);
237 * Returns a pointer to the last component of strg after delim.
238 * Returns strg if the string does not contain delim.
240 static const char *
241 basename(const char *strg, int delim)
243 const char *cp, *cp1, *cp2;
245 cp = cp1 = cp2 = strg;
246 while (*cp != '\0') {
247 if (*cp++ == delim) {
248 cp2 = cp1;
249 cp1 = cp;
252 return (*cp1 == '\0' ? cp2 : cp1);
255 static void
256 appdef(char ***lstp, const char *def)
258 appstrg(lstp, concat2("-D__", def));
259 appstrg(lstp, concat3("-D__", def, "__"));
262 static void
263 usage(void)
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);
274 main(int argc, char **argv)
276 int c, fd;
277 char flgbuf[3], *tmp, *s;
278 size_t len;
279 struct utsname un;
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;
289 cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
290 sprintf(cppout, "%slint0.XXXXXX", tmpdir);
292 fd = mkstemp(cppout);
293 if (fd == -1) {
294 err(1, "could not make a temporary file");
295 close(fd);
296 terminate(-1);
298 close (fd);
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 *));
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");
335 appcstrg(&lcppflgs, "-Wtraditional");
337 if (uname(&un) == -1)
338 err(1, "uname");
339 appdef(&cppflags, un.machine);
340 appstrg(&lcppflgs, concat2("-D", un.machine));
342 #ifdef MACHINE_ARCH
343 if (strcmp(un.machine, MACHINE_ARCH) != 0) {
344 appdef(&cppflags, MACHINE_ARCH);
345 appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
347 #endif
349 appcstrg(&deflibs, "c");
351 if (signal(SIGHUP, terminate) == SIG_IGN)
352 signal(SIGHUP, SIG_IGN);
353 signal(SIGINT, terminate);
354 signal(SIGQUIT, terminate);
355 signal(SIGTERM, terminate);
357 while (argc > optind) {
359 c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:SU:V");
361 switch (c) {
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;
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;
385 case 'i':
386 if (Cflag)
387 usage();
388 iflag = 1;
389 break;
391 case 'n':
392 freelst(&deflibs);
393 break;
395 case 'p':
396 appcstrg(&l1flags, "-p");
397 appcstrg(&l2flags, "-p");
398 if (*deflibs != NULL) {
399 freelst(&deflibs);
400 appcstrg(&deflibs, "c");
402 break;
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;
417 case 'S':
418 if (tflag)
419 usage();
420 appcstrg(&l1flags, "-S");
421 Sflag = 1;
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;
437 case 'x':
438 appcstrg(&l2flags, "-x");
439 break;
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;
451 case 'D':
452 case 'I':
453 case 'U':
454 sprintf(flgbuf, "-%c", c);
455 appstrg(&cppflags, concat2(flgbuf, optarg));
456 break;
458 case 'l':
459 appcstrg(&libs, optarg);
460 break;
462 case 'o':
463 if (Cflag || oflag)
464 usage();
465 oflag = 1;
466 outputfn = xstrdup(optarg);
467 break;
469 case 'L':
470 appcstrg(&libsrchpath, optarg);
471 break;
473 case 'H':
474 appcstrg(&l2flags, "-H");
475 break;
477 case 'V':
478 Vflag = 1;
479 break;
481 case '?':
482 usage();
483 /* NOTREACHED */
485 case -1:
486 /* filename */
487 fname(argv[optind], argc == optind + 1);
488 first = 0;
490 argc -= optind;
491 argv += optind;
492 optreset = optind = 1;
496 if (first)
497 usage();
499 if (iflag)
500 terminate(0);
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);
510 printf("Lint pass2:\n");
511 lint2();
513 if (oflag)
514 cat(p2in, outputfn);
516 if (Cflag)
517 p2out = NULL;
519 terminate(0);
520 /* NOTREACHED */
521 return 0;
525 * Read a file name from the command line
526 * and pass it through lint1 if it is a C source.
528 static void
529 fname(const char *name, int last)
531 const char *bn, *suff;
532 char **args, *ofn, *path;
533 size_t len;
534 int fd;
536 bn = basename(name, '/');
537 suff = basename(bn, '.');
539 if (strcmp(suff, "ln") == 0) {
540 /* only for lint2 */
541 if (!iflag)
542 appcstrg(&p2in, name);
543 return;
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;
552 if (!iflag || !first || !last)
553 printf("%s:\n", Fflag ? name : bn);
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);
574 close (fd);
576 if (!iflag)
577 appcstrg(&p1out, ofn);
579 args = xcalloc(1, sizeof (char *));
581 /* run cpp */
583 path = xmalloc(strlen(PATH_USRBIN) + sizeof ("/cpp"));
584 sprintf(path, "%s/cpp", PATH_USRBIN);
586 appcstrg(&args, path);
587 applst(&args, cppflags);
588 applst(&args, lcppflgs);
589 appcstrg(&args, name);
590 appcstrg(&args, cppout);
592 runchild(path, args, cppout);
593 free(path);
594 freelst(&args);
596 /* run lint1 */
598 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
599 sprintf(path, "%s/lint1", PATH_LIBEXEC);
601 appcstrg(&args, path);
602 applst(&args, l1flags);
603 appcstrg(&args, cppout);
604 appcstrg(&args, ofn);
606 runchild(path, args, ofn);
607 free(path);
608 freelst(&args);
610 appcstrg(&p2in, ofn);
611 free(ofn);
613 free(args);
616 static void
617 runchild(const char *path, char *const *args, const char *crfn)
619 int status, rv, signo, i;
621 if (Vflag) {
622 for (i = 0; args[i] != NULL; i++)
623 printf("%s ", args[i]);
624 printf("\n");
627 currfn = crfn;
629 fflush(stdout);
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 */
647 while ((rv = wait(&status)) == -1 && errno == EINTR) ;
648 if (rv == -1) {
649 warn("wait");
650 terminate(-1);
652 if (WIFSIGNALED(status)) {
653 signo = WTERMSIG(status);
654 warnx("%s got SIG%s", path, sys_signame[signo]);
655 terminate(-1);
657 if (WEXITSTATUS(status) != 0)
658 terminate(-1);
659 currfn = NULL;
662 static void
663 findlibs(char *const *liblst)
665 int i, k;
666 const char *lib, *path;
667 char *lfn;
668 size_t len;
670 lfn = NULL;
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;
684 if (path != NULL) {
685 appstrg(&l2libs, concat2("-l", lfn));
686 } else {
687 warnx("cannot find llib-l%s.ln", lib);
691 free(lfn);
694 static int
695 rdok(const char *path)
697 struct stat sbuf;
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);
708 static void
709 lint2(void)
711 char *path, **args;
713 args = xcalloc(1, sizeof (char *));
715 path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
716 sprintf(path, "%s/lint2", PATH_LIBEXEC);
718 appcstrg(&args, path);
719 applst(&args, l2flags);
720 applst(&args, l2libs);
721 applst(&args, p2in);
723 runchild(path, args, p2out);
724 free(path);
725 freelst(&args);
726 free(args);
729 static void
730 cat(char *const *srcs, const char *dest)
732 int ifd, ofd, i;
733 char *src, *buf;
734 ssize_t rlen;
736 if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
737 warn("cannot open %s", dest);
738 terminate(-1);
741 buf = xmalloc(MBLKSIZ);
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);
749 do {
750 if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
751 free(buf);
752 warn("read error on %s", src);
753 terminate(-1);
755 if (write(ofd, buf, (size_t)rlen) == -1) {
756 free(buf);
757 warn("write error on %s", dest);
758 terminate(-1);
760 } while (rlen == MBLKSIZ);
761 close(ifd);
763 close(ofd);
764 free(buf);