view interps/cfunge/cfunge-src/src/main.c @ 12518:2d8fe55c6e65 draft default tip

<int-e> learn The password of the month is release incident pilot.
author HackEso <hackeso@esolangs.org>
date Sun, 03 Nov 2024 00:31:02 +0000
parents 859f9b4339e6
children
line wrap: on
line source

/* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
 *
 * cfunge - A standard-conforming Befunge93/98/109 interpreter in C.
 * Copyright (C) 2008-2009 Arvid Norlander <anmaster AT tele2 DOT se>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at the proxy's option) any later version. Arvid Norlander is a
 * proxy who can decide which future versions of the GNU General Public
 * License can be used.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file
 * Contains command line parsing and such.
 */
#include "global.h"
#include "main.h"

#include <stdio.h>  /* fprintf, puts */
#include <stdlib.h> /* exit */
#include <signal.h> /* signal */
#include <string.h> /* strncmp */
#include <unistd.h> /* getopt */
#include <limits.h> /* CHAR_BIT */

#include "diagnostic.h"
#include "interpreter.h"
#include "settings.h"
#include "fingerprints/manager.h"

const char **fungeargv = NULL;
int fungeargc = 0;

// Exclude some code if we are building in IFFI.
#ifndef CFUN_IS_IFFI
// Use a larger buffer for stdout in fully buffered mode.
static char cfun_iobuf[BUFSIZ*4];

// These are NOT worth inlineing, even though only called once.
FUNGE_ATTR_FAST FUNGE_ATTR_NOINLINE FUNGE_ATTR_COLD FUNGE_ATTR_NORET
static void print_features(void)
{
	puts("Features compiled into this binary:\n"
#ifdef CONCURRENT_FUNGE
	     " + Concurrency using t instruction is enabled.\n"
#else
	     " - Concurrency using t instruction is disabled.\n"
#endif

#ifndef DISABLE_TRACE
	     " + Tracing using -t <level> option is enabled.\n"
#else
	     " - Tracing using -t <level> option is disabled.\n"
#endif

#ifdef CFUN_EXACT_BOUNDS
	     " + This binary uses exact bounds in y.\n"
#else
	     " - This binary does not use exact bounds in y.\n"
#endif

#ifdef CFUN_USE_GC
	     " * This binary uses Boehm GC.\n"
#else
	     " * This binary does not use Boehm GC.\n"
#endif

#ifdef DEBUG
	     " * This binary is a debug build.\n"
#endif

#ifndef NDEBUG
	     " * This binary is compiled with asserts.\n"
#endif

#ifdef ENABLE_VALGRIND
	     " * This binary is compiled with valgrind debugging annotations.\n"
#endif

#if defined(USE64)
	     " * Cell size is 64 bits (8 bytes).\n"
#elif defined(USE32)
	     " * Cell size is 32 bits (4 bytes).\n"
#else
#  error "Unknown cell size."
#endif

	// Features with ! are stuff most users doesn't want.
#ifdef CFUN_NO_FLOATS
	     " ! This binary is compiled without any floating point fingerprints.\n"
#endif

#ifdef FUZZ_TESTING
	// We use this to warn users and to do sanity checking in the fuzz testing
	// script.
	     " ! This is a fuzz testing build and thus not standard-conforming.\n"
#endif

	); /* End of puts() call */

	// This call does not return.
	manager_list();
}

FUNGE_ATTR_FAST FUNGE_ATTR_NOINLINE FUNGE_ATTR_COLD FUNGE_ATTR_NORET
static void print_help(void)
{
	puts("Usage: cfunge [OPTIONS] [FILE] [PROGRAM OPTIONS]\n"
	     "A fast Befunge interpreter in C\n\n"
	     " -b           Use fully buffered output (default is system default for stdout).\n"
	     " -E           Show non-fatal error messages, fatal ones are always shown.\n"
	     " -F           Disable all fingerprints.\n"
	     " -f           Show list of features and fingerprints supported in this binary.\n"
	     " -h           Show this help and exit.\n"
	     " -S           Enable sandbox mode (see README for details).\n"
	     " -s standard  Use the given standard (one of 93, 98 [default] and 109).\n"
	     " -t level     Use given trace level. Default 0.\n"
	     " -V           Show version and copyright info and exit.\n"
	     " -v           Show version and build info and exit.\n"
	     " -W           Show warnings."
#ifdef DISABLE_TRACE
	     "\nNote that someone disabled trace in this binary, so -t will have no effect."
#endif
	     );
	exit(EXIT_SUCCESS);
}

FUNGE_ATTR_FAST FUNGE_ATTR_NOINLINE FUNGE_ATTR_COLD FUNGE_ATTR_NORET
static void print_build_info(void) {
	printf("cfunge " CFUNGE_APPVERSION " ["
#ifdef CONCURRENT_FUNGE
	       "+con "
#else
	       "-con "
#endif
#ifndef DISABLE_TRACE
	       "+trace "
#else
	       "-trace "
#endif
#ifdef CFUN_EXACT_BOUNDS
	       "+exact-bounds "
#else
	       "-exact-bounds "
#endif
#ifdef HAVE_NCURSES
	       "+ncurses "
#else
	       "-ncurses "
#endif
#ifdef CFUN_USE_GC
	       "gc "
#endif
#ifdef _FORTIFY_SOURCE
	       "hardened "
#endif
#ifdef DEBUG
	       "debug "
#endif
#ifndef NDEBUG
	       "asserts "
#endif
#ifdef ENABLE_VALGRIND
	       "valgrind "
#endif
#ifdef _MUDFLAP
	       "mud "
#endif
#ifdef CFUN_NO_FLOATS
	       "nofloat "
#endif
#ifdef FUZZ_TESTING
	       "fuzz "
#endif
	// Pointer size and Cell size
	       "p:%zu c:%zu]\n\n"
           "Platform:      " CFUN_TARGET_PLATFORM "\n"
	       "OS:            " CFUN_TARGET_OS "\n"
	       "Compiler path: " CFUN_COMPILER "\n"
#ifdef CFUNGE_COMP_CLANG
	       "Compiler:      clang (unknown version)\n"
#elif defined(CFUNGE_COMP_ICC)
	       "Compiler:      ICC " FUNGE_CPP_STRINGIFY(__INTEL_COMPILER) "\n"
#elif defined(CFUNGE_COMP_GCC)
	       "Compiler:      GCC " FUNGE_CPP_STRINGIFY(__GNUC__)
	       "." FUNGE_CPP_STRINGIFY(__GNUC_MINOR__)
	       "." FUNGE_CPP_STRINGIFY(__GNUC_PATCHLEVEL__)
	       " (or compatible)\n"
#else
	       "Compiler:      Unknown.\n"
#endif
	       "Build type:    " CFUN_BUILD_TYPE "\n"
	       "Compiled on:   " CFUN_COMPILED_ON "\n\n"
	       "CFLAGS=\"" CFUN_USER_CFLAGS "\"\n"
	       "LDFLAGS=\"" CFUN_USER_LDFLAGS "\"\n",
	       sizeof(void*) * CHAR_BIT, sizeof(funge_cell) * CHAR_BIT);
	exit(EXIT_SUCCESS);
}

FUNGE_ATTR_FAST FUNGE_ATTR_NOINLINE FUNGE_ATTR_COLD FUNGE_ATTR_NORET
static void print_version(void)
{
	puts("cfunge " CFUNGE_APPVERSION "\n"
	     "Copyright (C) 2008-2009 Arvid Norlander.\n"
	     "This is free software.  You may redistribute copies of it under the terms of\n"
	     "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
	     "There is NO WARRANTY, to the extent permitted by law.\n\n"
	     "Written by Arvid Norlander.");

	exit(EXIT_SUCCESS);
}

int main(int argc, char *argv[])
{
	int opt;

#ifdef CFUN_USE_GC
//	GC_find_leak = 1;
	GC_all_interior_pointers = 1;
	GC_INIT();
//	atexit(&GC_gcollect);
#endif
#ifdef FUZZ_TESTING
	alarm(3);
#endif

	// We detect socket issues in other ways.
	signal(SIGPIPE, SIG_IGN);

	while ((opt = getopt(argc, argv, "+bEFfhSs:t:VvW")) != -1) {
		switch (opt) {
			case 'b':
				setvbuf(stdout, cfun_iobuf, _IOFBF, sizeof(cfun_iobuf));
				break;
			case 'E':
				setting_enable_errors = true;
				break;
			case 'F':
				setting_disable_fingerprints = true;
				break;
			case 'f':
				print_features();
				break;
			case 'h':
				print_help();
				break;
			case 'S':
				setting_enable_sandbox = true;
				break;
			case 's':
				if (strncmp(optarg, "93", 2) == 0)
					setting_current_standard = stdver93;
				else if (strncmp(optarg, "98", 2) == 0)
					setting_current_standard = stdver98;
				else if (strncmp(optarg, "109", 3) == 0)
					setting_current_standard = stdver109;
				else {
					diag_fatal_format("%s is not valid for -s.\n", optarg);
				}
				break;
			case 't':
				setting_trace_level = (uint_fast16_t)atoi(optarg);
				break;
			case 'V':
				print_version();
				break;
			case 'v':
				print_build_info();
				break;
			case 'W':
				setting_enable_warnings = true;
				break;
			default:
				fprintf(stderr, "For help see: %s -h\n", argv[0]);
				return EXIT_FAILURE;
		}
	}
	if (FUNGE_UNLIKELY(optind >= argc)) {
		diag_fatal("No file provided.");
	} else {
		// Copy a argument count and a pointer to argv[optind] for later reuse
		// by the y instruction.
		fungeargc = argc - optind;
		fungeargv = (const char**)&argv[optind];
		// Run the actual interpreter (never returns).
		interpreter_run(argv[optind]);
	}
	// NEVER REACHED.
}
#endif /* ! CFUN_IS_IFFI */