1/*	$NetBSD: main1.c,v 1.83 2024/05/12 18:00:58 rillig 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#if HAVE_NBTOOL_CONFIG_H
35#include "nbtool_config.h"
36#endif
37
38#include <sys/cdefs.h>
39#if defined(__RCSID)
40__RCSID("$NetBSD: main1.c,v 1.83 2024/05/12 18:00:58 rillig Exp $");
41#endif
42
43#include <sys/types.h>
44#include <locale.h>
45#include <signal.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50
51#include "lint1.h"
52
53int aflag;
54bool bflag;
55bool cflag;
56bool eflag;
57bool Fflag;
58bool hflag;
59bool Pflag;
60bool pflag;
61bool rflag;
62bool Tflag;
63bool vflag;
64bool wflag;
65bool yflag;
66bool zflag;
67
68/*
69 * The default language level is the one that checks for compatibility
70 * between traditional C and C90.  As of 2022, this default is no longer
71 * useful since most traditional C code has already been migrated.
72 */
73bool allow_trad = true;
74bool allow_c90 = true;
75bool allow_c99;
76bool allow_c11;
77bool allow_c23;
78bool allow_gcc;
79
80sig_atomic_t fpe;
81
82static void usage(void);
83
84static FILE *
85gcc_builtins(void)
86{
87	/* https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html */
88	static const char builtins[] =
89	    "typedef typeof(sizeof(0)) __lint_size_t;\n"
90
91	    "void *alloca(__lint_size_t);\n"
92	    "void *__builtin_alloca(__lint_size_t);\n"
93	    "void *__builtin_alloca_with_align"
94		"(__lint_size_t, __lint_size_t);\n"
95	    "void *__builtin_alloca_with_align_and_max"
96		"(__lint_size_t, __lint_size_t, __lint_size_t);\n"
97
98	    "int __builtin_isinf(long double);\n"
99	    "int __builtin_isnan(long double);\n"
100	    "int __builtin_copysign(long double, long double);\n";
101	size_t builtins_len = sizeof(builtins) - 1;
102
103#if HAVE_NBTOOL_CONFIG_H
104	char template[] = "/tmp/lint.XXXXXX";
105	int fd;
106	FILE *fp;
107	if ((fd = mkstemp(template)) == -1)
108		return NULL;
109	(void)unlink(template);
110	if ((fp = fdopen(fd, "r+")) == NULL) {
111		(void)close(fd);
112		return NULL;
113	}
114	if (fwrite(builtins, 1, builtins_len, fp) != builtins_len) {
115		(void)fclose(fp);
116		return NULL;
117	}
118	rewind(fp);
119	return fp;
120#else
121	return fmemopen(__UNCONST(builtins), builtins_len, "r");
122#endif
123}
124
125/*ARGSUSED*/
126static void
127sigfpe(int s)
128{
129	fpe = 1;
130}
131
132int
133main(int argc, char *argv[])
134{
135	int c;
136
137	setlocale(LC_ALL, "");
138	setprogname(argv[0]);
139
140	while ((c = getopt(argc, argv, "abceghpq:rstvwyzA:FPR:STX:")) != -1) {
141		switch (c) {
142		case 'a':	aflag++;	break;
143		case 'b':	bflag = true;	break;
144		case 'c':	cflag = true;	break;
145		case 'e':	eflag = true;	break;
146		case 'F':	Fflag = true;	break;
147		case 'g':	allow_gcc = true;	break;
148		case 'h':	hflag = true;	break;
149		case 'p':	pflag = true;	break;
150		case 'P':	Pflag = true;	break;
151		case 'q':	enable_queries(optarg);	break;
152		case 'r':	rflag = true;	break;
153		case 's':
154			allow_trad = false;
155			allow_c90 = true;
156			allow_c99 = false;
157			allow_c11 = false;
158			allow_c23 = false;
159			break;
160		case 'S':
161			allow_trad = false;
162			allow_c90 = true;
163			allow_c99 = true;
164			allow_c11 = false;
165			allow_c23 = false;
166			break;
167		case 'T':	Tflag = true;	break;
168		case 't':
169			allow_trad = true;
170			allow_c90 = false;
171			allow_c99 = false;
172			allow_c11 = false;
173			allow_c23 = false;
174			break;
175		case 'w':	wflag = true;	break;
176		case 'v':	vflag = true;	break;
177		case 'y':	yflag = true;	break;
178		case 'z':	zflag = true;	break;
179
180		case 'A':
181			if (strcmp(optarg, "c23") == 0) {
182				allow_trad = false;
183				allow_c90 = true;
184				allow_c99 = true;
185				allow_c11 = true;
186				allow_c23 = true;
187			} else if (strcmp(optarg, "c11") == 0) {
188				allow_trad = false;
189				allow_c90 = true;
190				allow_c99 = true;
191				allow_c11 = true;
192				allow_c23 = false;
193			} else
194				usage();
195			break;
196
197		case 'R':
198			add_directory_replacement(optarg);
199			break;
200
201		case 'X':
202			suppress_messages(optarg);
203			break;
204		default:
205			usage();
206		}
207	}
208	argc -= optind;
209	argv += optind;
210
211	if (argc != 2)
212		usage();
213
214	/* initialize output */
215	outopen(argv[1]);
216
217#ifdef DEBUG
218	setvbuf(stdout, NULL, _IONBF, 0);
219#endif
220#if YYDEBUG
221	if (yflag)
222		yydebug = 1;
223#endif
224
225	(void)signal(SIGFPE, sigfpe);
226	init_decl();
227	init_lex();
228
229	if (allow_gcc && allow_c90) {
230		if ((yyin = gcc_builtins()) == NULL)
231			err(1, "cannot open builtins");
232		curr_pos.p_file = "<gcc-builtins>";
233		curr_pos.p_line = 0;
234		lex_next_line();
235		yyparse();
236		(void)fclose(yyin);
237	}
238
239	/* open the input file */
240	if ((yyin = fopen(argv[0], "r")) == NULL)
241		err(1, "cannot open '%s'", argv[0]);
242	curr_pos.p_file = argv[0];
243	curr_pos.p_line = 0;
244	lex_next_line();
245	yyparse();
246	(void)fclose(yyin);
247
248	/* Following warnings cannot be suppressed by LINTED */
249	lwarn = LWARN_ALL;
250	debug_step("main lwarn = %d", lwarn);
251
252	end_translation_unit();
253
254	outclose();
255
256	return seen_error || (wflag && seen_warning) ? 1 : 0;
257}
258
259static void __dead
260usage(void)
261{
262	(void)fprintf(stderr,
263	    "usage: %s [-abceghmprstvwyzFPST] [-Alevel] [-d directory] "
264	    "[-R old=new]\n"
265	    "       %*s [-X id,...] [-q id,...] src dest\n",
266	    getprogname(), (int)strlen(getprogname()), "");
267	exit(1);
268}
269
270void __dead
271norecover(void)
272{
273	/* cannot recover from previous errors */
274	error(224);
275	exit(1);
276}
277