LCOV - code coverage report
Current view: top level - tests/gpgscm - main.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 80 119 67.2 %
Date: 2016-09-12 12:29:17 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /* TinyScheme-based test driver.
       2             :  *
       3             :  * Copyright (C) 2016 g10 code GmbH
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       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.
      11             :  *
      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.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #include <assert.h>
      24             : #include <ctype.h>
      25             : #include <errno.h>
      26             : #include <gcrypt.h>
      27             : #include <gpg-error.h>
      28             : #include <stdio.h>
      29             : #include <stdlib.h>
      30             : #include <string.h>
      31             : #include <unistd.h>
      32             : 
      33             : #include "private.h"
      34             : #include "scheme.h"
      35             : #include "scheme-private.h"
      36             : #include "ffi.h"
      37             : #include "i18n.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"
      44             : 
      45             : /* The TinyScheme banner.  Unfortunately, it isn't in the header
      46             :    file.  */
      47             : #define ts_banner "TinyScheme 1.41"
      48             : 
      49             : int verbose;
      50             : 
      51             : 
      52             : 
      53             : /* Constants to identify the commands and options. */
      54             : enum cmd_and_opt_values
      55             :   {
      56             :     aNull       = 0,
      57             :     oVerbose    = 'v',
      58             :   };
      59             : 
      60             : /* The list of commands and options. */
      61             : static ARGPARSE_OPTS opts[] =
      62             :   {
      63             :     ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
      64             :     ARGPARSE_end (),
      65             :   };
      66             : 
      67             : char *scmpath = "";
      68             : size_t scmpath_len = 0;
      69             : 
      70             : /* Command line parsing.  */
      71             : static void
      72         129 : parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
      73             : {
      74         129 :   int no_more_options = 0;
      75             : 
      76         258 :   while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
      77             :     {
      78           0 :       switch (pargs->r_opt)
      79             :         {
      80             :         case oVerbose:
      81           0 :           verbose++;
      82           0 :           break;
      83             : 
      84             :         default:
      85           0 :           pargs->err = 2;
      86           0 :           break;
      87             :         }
      88             :     }
      89         129 : }
      90             : 
      91             : /* Print usage information and and provide strings for help. */
      92             : static const char *
      93           0 : my_strusage( int level )
      94             : {
      95             :   const char *p;
      96             : 
      97           0 :   switch (level)
      98             :     {
      99           0 :     case 11: p = "gpgscm (@GNUPG@)";
     100           0 :       break;
     101           0 :     case 13: p = VERSION; break;
     102           0 :     case 17: p = PRINTABLE_OS_NAME; break;
     103           0 :     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
     104             : 
     105             :     case 1:
     106             :     case 40:
     107           0 :       p = _("Usage: gpgscm [options] [file] (-h for help)");
     108           0 :       break;
     109             :     case 41:
     110           0 :       p = _("Syntax: gpgscm [options] [file]\n"
     111             :             "Execute the given Scheme program, or spawn interactive shell.\n");
     112           0 :       break;
     113             : 
     114           0 :     default: p = NULL; break;
     115             :     }
     116           0 :   return p;
     117             : }
     118             : 
     119             : 
     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.  */
     123             : static gpg_error_t
     124         774 : load (scheme *sc, char *file_name,
     125             :       int lookup_in_cwd, int lookup_in_path)
     126             : {
     127         774 :   gpg_error_t err = 0;
     128             :   size_t n;
     129             :   const char *directory;
     130         774 :   char *qualified_name = file_name;
     131             :   int use_path;
     132         774 :   FILE *h = NULL;
     133             : 
     134         774 :   use_path =
     135         774 :     lookup_in_path && ! (file_name[0] == '/' || scmpath_len == 0);
     136             : 
     137         774 :   if (file_name[0] == '/' || lookup_in_cwd || scmpath_len == 0)
     138             :     {
     139         129 :       h = fopen (file_name, "r");
     140         129 :       if (! h)
     141           1 :         err = gpg_error_from_syserror ();
     142             :     }
     143             : 
     144         774 :   if (h == NULL && use_path)
     145        1293 :     for (directory = scmpath, n = scmpath_len; n;
     146           1 :          directory += strlen (directory) + 1, n--)
     147             :       {
     148         647 :         if (asprintf (&qualified_name, "%s/%s", directory, file_name) < 0)
     149           0 :           return gpg_error_from_syserror ();
     150             : 
     151         647 :         h = fopen (qualified_name, "r");
     152         647 :         if (h)
     153         646 :           break;
     154             : 
     155           1 :         if (n > 1)
     156             :           {
     157           1 :             free (qualified_name);
     158           1 :             continue;   /* Try again!  */
     159             :           }
     160             : 
     161           0 :         err = gpg_error_from_syserror ();
     162             :       }
     163             : 
     164         774 :   if (h == NULL)
     165             :     {
     166             :       /* Failed and no more elements in scmpath to try.  */
     167           0 :       fprintf (stderr, "Could not read %s: %s.\n",
     168             :                qualified_name, gpg_strerror (err));
     169           0 :       if (lookup_in_path)
     170           0 :         fprintf (stderr,
     171             :                  "Consider using GPGSCM_PATH to specify the location "
     172             :                  "of the Scheme library.\n");
     173           0 :       return err;
     174             :     }
     175         774 :   if (verbose > 1)
     176           0 :     fprintf (stderr, "Loading %s...\n", qualified_name);
     177         774 :   scheme_load_named_file (sc, h, qualified_name);
     178         773 :   fclose (h);
     179             : 
     180         773 :   if (sc->retcode)
     181             :     {
     182           0 :       if (sc->nesting)
     183           0 :         fprintf (stderr, "%s: Unbalanced parenthesis\n", qualified_name);
     184           0 :       return gpg_error (GPG_ERR_GENERAL);
     185             :     }
     186             : 
     187         773 :   if (file_name != qualified_name)
     188         645 :     free (qualified_name);
     189         773 :   return 0;
     190             : }
     191             : 
     192             : 
     193             : 
     194             : int
     195         129 : main (int argc, char **argv)
     196             : {
     197             :   gpg_error_t err;
     198             :   char *argv0;
     199             :   ARGPARSE_ARGS pargs;
     200             :   scheme *sc;
     201             :   char *p;
     202             : #if _WIN32
     203             :   char pathsep = ';';
     204             : #else
     205         129 :   char pathsep = ':';
     206             : #endif
     207         129 :   char *script = NULL;
     208             : 
     209             :   /* Save argv[0] so that we can re-exec.  */
     210         129 :   argv0 = argv[0];
     211             : 
     212             :   /* Parse path.  */
     213         129 :   if (getenv ("GPGSCM_PATH"))
     214         129 :     scmpath = getenv ("GPGSCM_PATH");
     215             : 
     216         129 :   p = scmpath = strdup (scmpath);
     217         129 :   if (p == NULL)
     218           0 :     return 2;
     219             : 
     220         129 :   if (*p)
     221         129 :     scmpath_len++;
     222       12291 :   for (; *p; p++)
     223       12162 :     if (*p == pathsep)
     224         128 :       *p = 0, scmpath_len++;
     225             : 
     226         129 :   set_strusage (my_strusage);
     227         129 :   log_set_prefix ("gpgscm", GPGRT_LOG_WITH_PREFIX);
     228             : 
     229             :   /* Make sure that our subsystems are ready.  */
     230         129 :   i18n_init ();
     231         129 :   init_common_subsystems (&argc, &argv);
     232             : 
     233         129 :   if (!gcry_check_version (GCRYPT_VERSION))
     234             :     {
     235           0 :       fputs ("libgcrypt version mismatch\n", stderr);
     236           0 :       exit (2);
     237             :     }
     238             : 
     239             :   /* Parse the command line. */
     240         129 :   pargs.argc  = &argc;
     241         129 :   pargs.argv  = &argv;
     242         129 :   pargs.flags = 0;
     243         129 :   parse_arguments (&pargs, opts);
     244             : 
     245         129 :   if (log_get_errorcount (0))
     246           0 :     exit (2);
     247             : 
     248         129 :   sc = scheme_init_new_custom_alloc (gcry_malloc, gcry_free);
     249         129 :   if (! sc) {
     250           0 :     fprintf (stderr, "Could not initialize TinyScheme!\n");
     251           0 :     return 2;
     252             :   }
     253         129 :   scheme_set_input_port_file (sc, stdin);
     254         129 :   scheme_set_output_port_file (sc, stderr);
     255             : 
     256         129 :   if (argc)
     257             :     {
     258         129 :       script = argv[0];
     259         129 :       argc--, argv++;
     260             :     }
     261             : 
     262         129 :   err = load (sc, "init.scm", 0, 1);
     263         129 :   if (! err)
     264         129 :     err = load (sc, "ffi.scm", 0, 1);
     265         129 :   if (! err)
     266         129 :     err = ffi_init (sc, argv0, argc, (const char **) argv);
     267         129 :   if (! err)
     268         129 :     err = load (sc, "lib.scm", 0, 1);
     269         129 :   if (! err)
     270         129 :     err = load (sc, "repl.scm", 0, 1);
     271         129 :   if (! err)
     272         129 :     err = load (sc, "tests.scm", 0, 1);
     273         129 :   if (err)
     274             :     {
     275           0 :       fprintf (stderr, "Error initializing gpgscm: %s.\n",
     276             :                gpg_strerror (err));
     277           0 :       exit (2);
     278             :     }
     279             : 
     280         129 :   if (script == NULL)
     281             :     {
     282             :       /* Interactive shell.  */
     283           0 :       fprintf (stderr, "gpgscm/"ts_banner".\n");
     284           0 :       scheme_load_string (sc, "(interactive-repl)");
     285             :     }
     286             :   else
     287             :     {
     288         129 :       err = load (sc, script, 1, 1);
     289         128 :       if (err)
     290           0 :         log_fatal ("%s: %s", script, gpg_strerror (err));
     291             :     }
     292             : 
     293         128 :   scheme_deinit (sc);
     294         128 :   xfree (sc);
     295         128 :   return EXIT_SUCCESS;
     296             : }

Generated by: LCOV version 1.11