996
|
1 /* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
|
|
2 *
|
|
3 * cfunge - A standard-conforming Befunge93/98/109 interpreter in C.
|
|
4 * Copyright (C) 2008-2009 Arvid Norlander <anmaster AT tele2 DOT se>
|
|
5 *
|
|
6 * This program is free software: you can redistribute it and/or modify
|
|
7 * it under the terms of the GNU General Public License as published by
|
|
8 * the Free Software Foundation, either version 3 of the License, or
|
|
9 * (at the proxy's option) any later version. Arvid Norlander is a
|
|
10 * proxy who can decide which future versions of the GNU General Public
|
|
11 * License can be used.
|
|
12 *
|
|
13 * This program is distributed in the hope that it will be useful,
|
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16 * GNU General Public License for more details.
|
|
17 *
|
|
18 * You should have received a copy of the GNU General Public License
|
|
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
20 */
|
|
21
|
|
22 /**
|
|
23 * @file
|
|
24 * Contains command line parsing and such.
|
|
25 */
|
|
26 #include "global.h"
|
|
27 #include "main.h"
|
|
28
|
|
29 #include <stdio.h> /* fprintf, puts */
|
|
30 #include <stdlib.h> /* exit */
|
|
31 #include <signal.h> /* signal */
|
|
32 #include <string.h> /* strncmp */
|
|
33 #include <unistd.h> /* getopt */
|
|
34 #include <limits.h> /* CHAR_BIT */
|
|
35
|
|
36 #include "diagnostic.h"
|
|
37 #include "interpreter.h"
|
|
38 #include "settings.h"
|
|
39 #include "fingerprints/manager.h"
|
|
40
|
|
41 const char **fungeargv = NULL;
|
|
42 int fungeargc = 0;
|
|
43
|
|
44 // Exclude some code if we are building in IFFI.
|
|
45 #ifndef CFUN_IS_IFFI
|
|
46 // Use a larger buffer for stdout in fully buffered mode.
|
|
47 static char cfun_iobuf[BUFSIZ*4];
|
|
48
|
|
49 // These are NOT worth inlineing, even though only called once.
|
|
50 FUNGE_ATTR_FAST FUNGE_ATTR_NOINLINE FUNGE_ATTR_COLD FUNGE_ATTR_NORET
|
|
51 static void print_features(void)
|
|
52 {
|
|
53 puts("Features compiled into this binary:\n"
|
|
54 #ifdef CONCURRENT_FUNGE
|
|
55 " + Concurrency using t instruction is enabled.\n"
|
|
56 #else
|
|
57 " - Concurrency using t instruction is disabled.\n"
|
|
58 #endif
|
|
59
|
|
60 #ifndef DISABLE_TRACE
|
|
61 " + Tracing using -t <level> option is enabled.\n"
|
|
62 #else
|
|
63 " - Tracing using -t <level> option is disabled.\n"
|
|
64 #endif
|
|
65
|
|
66 #ifdef CFUN_EXACT_BOUNDS
|
|
67 " + This binary uses exact bounds in y.\n"
|
|
68 #else
|
|
69 " - This binary does not use exact bounds in y.\n"
|
|
70 #endif
|
|
71
|
|
72 #ifdef CFUN_USE_GC
|
|
73 " * This binary uses Boehm GC.\n"
|
|
74 #else
|
|
75 " * This binary does not use Boehm GC.\n"
|
|
76 #endif
|
|
77
|
|
78 #ifdef DEBUG
|
|
79 " * This binary is a debug build.\n"
|
|
80 #endif
|
|
81
|
|
82 #ifndef NDEBUG
|
|
83 " * This binary is compiled with asserts.\n"
|
|
84 #endif
|
|
85
|
|
86 #ifdef ENABLE_VALGRIND
|
|
87 " * This binary is compiled with valgrind debugging annotations.\n"
|
|
88 #endif
|
|
89
|
|
90 #if defined(USE64)
|
|
91 " * Cell size is 64 bits (8 bytes).\n"
|
|
92 #elif defined(USE32)
|
|
93 " * Cell size is 32 bits (4 bytes).\n"
|
|
94 #else
|
|
95 # error "Unknown cell size."
|
|
96 #endif
|
|
97
|
|
98 // Features with ! are stuff most users doesn't want.
|
|
99 #ifdef CFUN_NO_FLOATS
|
|
100 " ! This binary is compiled without any floating point fingerprints.\n"
|
|
101 #endif
|
|
102
|
|
103 #ifdef FUZZ_TESTING
|
|
104 // We use this to warn users and to do sanity checking in the fuzz testing
|
|
105 // script.
|
|
106 " ! This is a fuzz testing build and thus not standard-conforming.\n"
|
|
107 #endif
|
|
108
|
|
109 ); /* End of puts() call */
|
|
110
|
|
111 // This call does not return.
|
|
112 manager_list();
|
|
113 }
|
|
114
|
|
115 FUNGE_ATTR_FAST FUNGE_ATTR_NOINLINE FUNGE_ATTR_COLD FUNGE_ATTR_NORET
|
|
116 static void print_help(void)
|
|
117 {
|
|
118 puts("Usage: cfunge [OPTIONS] [FILE] [PROGRAM OPTIONS]\n"
|
|
119 "A fast Befunge interpreter in C\n\n"
|
|
120 " -b Use fully buffered output (default is system default for stdout).\n"
|
|
121 " -E Show non-fatal error messages, fatal ones are always shown.\n"
|
|
122 " -F Disable all fingerprints.\n"
|
|
123 " -f Show list of features and fingerprints supported in this binary.\n"
|
|
124 " -h Show this help and exit.\n"
|
|
125 " -S Enable sandbox mode (see README for details).\n"
|
|
126 " -s standard Use the given standard (one of 93, 98 [default] and 109).\n"
|
|
127 " -t level Use given trace level. Default 0.\n"
|
|
128 " -V Show version and copyright info and exit.\n"
|
|
129 " -v Show version and build info and exit.\n"
|
|
130 " -W Show warnings."
|
|
131 #ifdef DISABLE_TRACE
|
|
132 "\nNote that someone disabled trace in this binary, so -t will have no effect."
|
|
133 #endif
|
|
134 );
|
|
135 exit(EXIT_SUCCESS);
|
|
136 }
|
|
137
|
|
138 FUNGE_ATTR_FAST FUNGE_ATTR_NOINLINE FUNGE_ATTR_COLD FUNGE_ATTR_NORET
|
|
139 static void print_build_info(void) {
|
|
140 printf("cfunge " CFUNGE_APPVERSION " ["
|
|
141 #ifdef CONCURRENT_FUNGE
|
|
142 "+con "
|
|
143 #else
|
|
144 "-con "
|
|
145 #endif
|
|
146 #ifndef DISABLE_TRACE
|
|
147 "+trace "
|
|
148 #else
|
|
149 "-trace "
|
|
150 #endif
|
|
151 #ifdef CFUN_EXACT_BOUNDS
|
|
152 "+exact-bounds "
|
|
153 #else
|
|
154 "-exact-bounds "
|
|
155 #endif
|
|
156 #ifdef HAVE_NCURSES
|
|
157 "+ncurses "
|
|
158 #else
|
|
159 "-ncurses "
|
|
160 #endif
|
|
161 #ifdef CFUN_USE_GC
|
|
162 "gc "
|
|
163 #endif
|
|
164 #ifdef _FORTIFY_SOURCE
|
|
165 "hardened "
|
|
166 #endif
|
|
167 #ifdef DEBUG
|
|
168 "debug "
|
|
169 #endif
|
|
170 #ifndef NDEBUG
|
|
171 "asserts "
|
|
172 #endif
|
|
173 #ifdef ENABLE_VALGRIND
|
|
174 "valgrind "
|
|
175 #endif
|
|
176 #ifdef _MUDFLAP
|
|
177 "mud "
|
|
178 #endif
|
|
179 #ifdef CFUN_NO_FLOATS
|
|
180 "nofloat "
|
|
181 #endif
|
|
182 #ifdef FUZZ_TESTING
|
|
183 "fuzz "
|
|
184 #endif
|
|
185 // Pointer size and Cell size
|
|
186 "p:%zu c:%zu]\n\n"
|
|
187 "Platform: " CFUN_TARGET_PLATFORM "\n"
|
|
188 "OS: " CFUN_TARGET_OS "\n"
|
|
189 "Compiler path: " CFUN_COMPILER "\n"
|
|
190 #ifdef CFUNGE_COMP_CLANG
|
|
191 "Compiler: clang (unknown version)\n"
|
|
192 #elif defined(CFUNGE_COMP_ICC)
|
|
193 "Compiler: ICC " FUNGE_CPP_STRINGIFY(__INTEL_COMPILER) "\n"
|
|
194 #elif defined(CFUNGE_COMP_GCC)
|
|
195 "Compiler: GCC " FUNGE_CPP_STRINGIFY(__GNUC__)
|
|
196 "." FUNGE_CPP_STRINGIFY(__GNUC_MINOR__)
|
|
197 "." FUNGE_CPP_STRINGIFY(__GNUC_PATCHLEVEL__)
|
|
198 " (or compatible)\n"
|
|
199 #else
|
|
200 "Compiler: Unknown.\n"
|
|
201 #endif
|
|
202 "Build type: " CFUN_BUILD_TYPE "\n"
|
|
203 "Compiled on: " CFUN_COMPILED_ON "\n\n"
|
|
204 "CFLAGS=\"" CFUN_USER_CFLAGS "\"\n"
|
|
205 "LDFLAGS=\"" CFUN_USER_LDFLAGS "\"\n",
|
|
206 sizeof(void*) * CHAR_BIT, sizeof(funge_cell) * CHAR_BIT);
|
|
207 exit(EXIT_SUCCESS);
|
|
208 }
|
|
209
|
|
210 FUNGE_ATTR_FAST FUNGE_ATTR_NOINLINE FUNGE_ATTR_COLD FUNGE_ATTR_NORET
|
|
211 static void print_version(void)
|
|
212 {
|
|
213 puts("cfunge " CFUNGE_APPVERSION "\n"
|
|
214 "Copyright (C) 2008-2009 Arvid Norlander.\n"
|
|
215 "This is free software. You may redistribute copies of it under the terms of\n"
|
|
216 "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
|
|
217 "There is NO WARRANTY, to the extent permitted by law.\n\n"
|
|
218 "Written by Arvid Norlander.");
|
|
219
|
|
220 exit(EXIT_SUCCESS);
|
|
221 }
|
|
222
|
|
223 int main(int argc, char *argv[])
|
|
224 {
|
|
225 int opt;
|
|
226
|
|
227 #ifdef CFUN_USE_GC
|
|
228 // GC_find_leak = 1;
|
|
229 GC_all_interior_pointers = 1;
|
|
230 GC_INIT();
|
|
231 // atexit(&GC_gcollect);
|
|
232 #endif
|
|
233 #ifdef FUZZ_TESTING
|
|
234 alarm(3);
|
|
235 #endif
|
|
236
|
|
237 // We detect socket issues in other ways.
|
|
238 signal(SIGPIPE, SIG_IGN);
|
|
239
|
|
240 while ((opt = getopt(argc, argv, "+bEFfhSs:t:VvW")) != -1) {
|
|
241 switch (opt) {
|
|
242 case 'b':
|
|
243 setvbuf(stdout, cfun_iobuf, _IOFBF, sizeof(cfun_iobuf));
|
|
244 break;
|
|
245 case 'E':
|
|
246 setting_enable_errors = true;
|
|
247 break;
|
|
248 case 'F':
|
|
249 setting_disable_fingerprints = true;
|
|
250 break;
|
|
251 case 'f':
|
|
252 print_features();
|
|
253 break;
|
|
254 case 'h':
|
|
255 print_help();
|
|
256 break;
|
|
257 case 'S':
|
|
258 setting_enable_sandbox = true;
|
|
259 break;
|
|
260 case 's':
|
|
261 if (strncmp(optarg, "93", 2) == 0)
|
|
262 setting_current_standard = stdver93;
|
|
263 else if (strncmp(optarg, "98", 2) == 0)
|
|
264 setting_current_standard = stdver98;
|
|
265 else if (strncmp(optarg, "109", 3) == 0)
|
|
266 setting_current_standard = stdver109;
|
|
267 else {
|
|
268 diag_fatal_format("%s is not valid for -s.\n", optarg);
|
|
269 }
|
|
270 break;
|
|
271 case 't':
|
|
272 setting_trace_level = (uint_fast16_t)atoi(optarg);
|
|
273 break;
|
|
274 case 'V':
|
|
275 print_version();
|
|
276 break;
|
|
277 case 'v':
|
|
278 print_build_info();
|
|
279 break;
|
|
280 case 'W':
|
|
281 setting_enable_warnings = true;
|
|
282 break;
|
|
283 default:
|
|
284 fprintf(stderr, "For help see: %s -h\n", argv[0]);
|
|
285 return EXIT_FAILURE;
|
|
286 }
|
|
287 }
|
|
288 if (FUNGE_UNLIKELY(optind >= argc)) {
|
|
289 diag_fatal("No file provided.");
|
|
290 } else {
|
|
291 // Copy a argument count and a pointer to argv[optind] for later reuse
|
|
292 // by the y instruction.
|
|
293 fungeargc = argc - optind;
|
|
294 fungeargv = (const char**)&argv[optind];
|
|
295 // Run the actual interpreter (never returns).
|
|
296 interpreter_run(argv[optind]);
|
|
297 }
|
|
298 // NEVER REACHED.
|
|
299 }
|
|
300 #endif /* ! CFUN_IS_IFFI */
|