1 /* TinyScheme-based test driver.
3 * Copyright (C) 2016 g10 code GmbH
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <https://www.gnu.org/licenses/>.
27 #include <gpg-error.h>
35 #include "scheme-private.h"
38 #include "../../common/argparse.h"
39 #include "../../common/init.h"
40 #include "../../common/logging.h"
41 #include "../../common/strlist.h"
42 #include "../../common/sysutils.h"
43 #include "../../common/util.h"
45 /* The TinyScheme banner. Unfortunately, it isn't in the header
47 #define ts_banner "TinyScheme 1.41"
53 /* Constants to identify the commands and options. */
54 enum cmd_and_opt_values
60 /* The list of commands and options. */
61 static ARGPARSE_OPTS opts[] =
63 ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
68 size_t scmpath_len = 0;
70 /* Command line parsing. */
72 parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
74 int no_more_options = 0;
76 while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
91 /* Print usage information and and provide strings for help. */
93 my_strusage( int level )
99 case 11: p = "gpgscm (@GNUPG@)";
101 case 13: p = VERSION; break;
102 case 17: p = PRINTABLE_OS_NAME; break;
103 case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
107 p = _("Usage: gpgscm [options] [file] (-h for help)");
110 p = _("Syntax: gpgscm [options] [file]\n"
111 "Execute the given Scheme program, or spawn interactive shell.\n");
114 default: p = NULL; break;
120 /* Load the Scheme program from FILE_NAME. If FILE_NAME is not an
121 absolute path, and LOOKUP_IN_PATH is given, then it is qualified
122 with the values in scmpath until the file is found. */
124 load (scheme *sc, char *file_name,
125 int lookup_in_cwd, int lookup_in_path)
129 const char *directory;
130 char *qualified_name = file_name;
135 lookup_in_path && ! (file_name[0] == '/' || scmpath_len == 0);
137 if (file_name[0] == '/' || lookup_in_cwd || scmpath_len == 0)
139 h = fopen (file_name, "r");
141 err = gpg_error_from_syserror ();
144 if (h == NULL && use_path)
145 for (directory = scmpath, n = scmpath_len; n;
146 directory += strlen (directory) + 1, n--)
148 if (asprintf (&qualified_name, "%s/%s", directory, file_name) < 0)
149 return gpg_error_from_syserror ();
151 h = fopen (qualified_name, "r");
160 free (qualified_name);
161 continue; /* Try again! */
164 err = gpg_error_from_syserror ();
169 /* Failed and no more elements in scmpath to try. */
170 fprintf (stderr, "Could not read %s: %s.\n",
171 qualified_name, gpg_strerror (err));
174 "Consider using GPGSCM_PATH to specify the location "
175 "of the Scheme library.\n");
179 fprintf (stderr, "Loading %s...\n", qualified_name);
180 scheme_load_named_file (sc, h, qualified_name);
183 if (sc->retcode && sc->nesting)
185 fprintf (stderr, "%s: Unbalanced parenthesis\n", qualified_name);
186 err = gpg_error (GPG_ERR_GENERAL);
190 if (file_name != qualified_name)
191 free (qualified_name);
198 main (int argc, char **argv)
213 /* Save argv[0] so that we can re-exec. */
217 if (getenv ("GPGSCM_PATH"))
218 scmpath = getenv ("GPGSCM_PATH");
220 p = scmpath = strdup (scmpath);
228 *p = 0, scmpath_len++;
230 set_strusage (my_strusage);
231 log_set_prefix ("gpgscm", GPGRT_LOG_WITH_PREFIX);
233 /* Make sure that our subsystems are ready. */
235 init_common_subsystems (&argc, &argv);
237 if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
239 fputs ("libgcrypt version mismatch\n", stderr);
243 /* Parse the command line. */
247 parse_arguments (&pargs, opts);
249 if (log_get_errorcount (0))
252 sc = scheme_init_new_custom_alloc (gcry_malloc, gcry_free);
254 fprintf (stderr, "Could not initialize TinyScheme!\n");
257 scheme_set_input_port_file (sc, stdin);
258 scheme_set_output_port_file (sc, stderr);
266 err = load (sc, "init.scm", 0, 1);
268 err = load (sc, "ffi.scm", 0, 1);
270 err = ffi_init (sc, argv0, script ? script : "interactive",
271 argc, (const char **) argv);
273 err = load (sc, "lib.scm", 0, 1);
275 err = load (sc, "repl.scm", 0, 1);
277 err = load (sc, "tests.scm", 0, 1);
280 fprintf (stderr, "Error initializing gpgscm: %s.\n",
287 /* Interactive shell. */
288 fprintf (stderr, "gpgscm/"ts_banner".\n");
289 scheme_load_string (sc, "(interactive-repl)");
293 err = load (sc, script, 1, 1);
295 log_fatal ("%s: %s", script, gpg_strerror (err));
298 retcode = sc->retcode;
299 scheme_load_string (sc, "(*run-atexit-handlers*)");