/* src/sizzle.c - main module
 
  Copyright (C) 1999, 2000 Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
 
  This 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 2, or (at your option)
  any later version.
  
  This software 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 package; see the file COPYING.  If not, write to the
  Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  MA 02111-1307, USA.  */

#if HAVE_CONFIG_H
# include <config.h>
#endif 

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#if HAVE_GETOPT_H
# include <getopt.h>
#endif

#if ENABLE_NLS
# if HAVE_LOCALE_H
#  include <locale.h>
# endif
# include <libintl.h>
# define _(String) gettext(String)
#else
# define _(String) (String)
#endif

#include <version.h>

#include <libsizzle/libsizzle.h>
#include <libsizzle/libpath.h>

char program_name[] = "sizzle";

static char version_string[] = __sizzle_version;

char * program_path = NULL;
static char * script_file_name;
static char * eval_expression;
static int no_init_file;
static int no_system_init_file;
int debug_level;

/*
 * Defining here the struct and #define's for getopt_long() if it
 * is in libiberty.a but could not be found in getopt.h
 */
#if defined(HAVE_GETOPT_LONG) && !defined(DECLARED_GETOPT_LONG)

struct option
{
  const char *name;
  int has_arg;
  int *flag;
  int val;
};

#define no_argument       0
#define required_argument 1
#define optional_argument 2

extern int getopt_long(int argc, 
		       char * const argv[], 
		       const char *optstring,
		       const struct option *longopts, 
		       int *longindex);

extern int optind;
extern char * optarg;
#endif /* DECLARED_GETOPT_LONG */

#ifndef HAVE_GETOPT
char *optarg = NULL;
int optind = 1;
int opterr = 0;
int optopt = 0;

int 
getopt (int argc, char * const argv[], const char *optstring) 
{
  static int current_arg = 1, current_opt = 0;
  int n;

  while (current_arg < argc) 
    {
      if (current_arg != 0 || argv[current_arg][0] == '-') 
        {
          if (current_opt == 0)
            current_opt = 1;
          while (argv[current_arg][current_opt] != '\0')
	    {
	      n = 0;
	      /* go through all option characters */
	      while (optstring[n]) 
		{
		  if (optstring[n] == argv[current_arg][current_opt])
		    {
		      current_opt++;
		      if (optstring[n + 1] == ':') 
			optarg = argv[current_arg + 1];
		      else
			optarg = NULL;
		      if (argv[current_arg][current_opt] == '\0')
			{ 
			  current_arg++;
			  current_opt = 0;
			} 
		      optind = current_arg;
		      return optstring[n];
		    }
		  n++;
		}
            }
	  current_opt++;
	}
      current_arg++;
    }

  current_arg = 1;
  current_opt = 0;
  return EOF;
}
#endif /* not HAVE_GETOPT */

int main_loop (int argc, char * argv[]);

/* Print a usage help message to stderr.  */
static void 
usage (void)
{
#if HAVE_GETOPT_LONG
  printf (_("usage: %s [OPTION]...\n\n\
  -s, --script=FILE         execute FILE as a sizzle script, and exit\n\
  -c, --command=EXPR        evaluate expression EXPR, and exit\n\
  --                        stop scanning arguments, run interactively\n\
\n\
  -l, --load=FILE           load Scheme source code from FILE\n\
  -e, --eval=FUNCTION       after reading script, apply FUNCTION to\n\
                            command line arguments\n\
  -h, --help                display this help and exit\n\
  -v, --version             display version information and exit\n\
  -q, --no-init-file        do not load the user init file\n\
  -n, --no-system-init-file do not load the system init file\n\
  -d, --debug               increase debug level\n\n\
Report bugs to mgrabmue@cs.tu-berlin.de\n"),
	  program_name);
#else /* !HAVE_GETOPT_LONG */
  printf (_("usage: %s [OPTION]...\n\n\
  -s FILE        execute FILE as a sizzle script, and exit\n\
  -c EXPR        evaluate expression EXPR, and exit\n\
  --             stop scanning arguments, run interactively\n\
\n\
  -l FILE        load Scheme source code from FILE\n\
  -e FUNCTION    after reading script, apply FUNCTION to\n\
                 command line arguments\n\
  -h             display this help and exit\n\
  -v             display version information and exit\n\
  -q             do not load the user init file\n\
  -n             do not load the system init file\n\
  -d             increase debug level\n\n\
Report bugs to mgrabmue@cs.tu-berlin.de\n"),
	  program_name);
#endif /* !HAVE_GETOPT_LONG */
}

/* Print version information to stderr.  */
static void 
version (void)
{
  printf ("%s %s\n", program_name, version_string);
}

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

  return_val = zzz_run (main_loop, argc, argv);
  if (debug_level > 0)
    printf(_("Allocated bytes: %d\n"), zzz_allocated_bytes);
  
  return return_val;
}

int
main_loop (int argc, char * argv[])
{
  zzz_scm_t result;
  zzz_scm_t load_files = NULL, * load_filesp = &load_files;
  char * apply_func = NULL, * eval_string = NULL;
  int arg;
  int index;
  int exit_code;
  char home_init_file[512];

#if HAVE_GETOPT_LONG
  static struct option command_line_options[] =
  {
    {"script", required_argument, NULL, 's'},
    {"command", required_argument, NULL, 'c'},
    {"load", required_argument, NULL, 'l'},
    {"eval", required_argument, NULL, 'e'},
    {"help", no_argument, NULL, 'h'},
    {"version", no_argument, NULL, 'v'},
    {"no-init-file", no_argument, NULL, 'q'},
    {"no-system-init-file", no_argument, NULL, 'n'},
    {"debug", no_argument, NULL, 'd'},
    {NULL, 0, NULL, 0}
  };
#endif /* HAVE_GETOPT_LONG */


#if ENABLE_NLS
  setlocale (LC_ALL, "");
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);
#endif /* ENABLE_NLS */

  program_path = argv[0];

#if HAVE_GETOPT_LONG
  while ((arg = getopt_long (argc, argv, "+hvs:c:l:e:qnd",
			     command_line_options, &index)) != EOF)
#else /* !HAVE_GETOPT_LONG */
  while ((arg = getopt (argc, argv, "hvs:c:l:e:qnd")) != EOF)
#endif /* !HAVE_GETOPT_LONG */
    {
      switch (arg)
	{
	case 'h':
	  usage ();
	  exit (0);
	  break;

	case 'v':
	  version ();
	  exit (0);
	  break;

	case 's':
	  script_file_name = optarg;
	  goto parsing_end;
	  break;

	case 'c':
	  eval_expression = optarg;
	  goto parsing_end;
	  break;

	case 'l':
	  *load_filesp = zzz_cons (zzz_make_string (optarg, -1), NULL);
	  load_filesp = cdr_addr (*load_filesp);
	  break;

	case 'e':
	  apply_func = optarg;
	  break;

	case 'q':
	  no_init_file = 1;
	  break;

	case 'n':
	  no_system_init_file = 1;
	  break;

	case 'd':
	  debug_level++;
	  break;

	default:
	  usage ();
	  exit (1);
	  break;
	}
    }
 parsing_end:

  zzz_set_arguments (argc - optind, argv[0], argv + optind);

  if (!no_system_init_file)
    {
      if (zzz_evaluate_file (zzz_library_environment,
			     LIBRARY_DIR "/core/init.scm") != 0)
	{
	  fprintf (stderr, "sizzle: cannot load system init file\n");
	}
    } 
  if (!no_init_file)
    {
      if (getenv ("HOME") &&
	  strlen (getenv ("HOME")) < (sizeof (home_init_file) - 32))
	{
	  strcpy (home_init_file, getenv ("HOME"));
	  strcat (home_init_file, "/.sizzle");
	  /* -2 means error while loading.  */
	  if (zzz_evaluate_file (zzz_interaction_environment,
				 home_init_file) == -2)
	    {
	      fprintf (stderr, "sizzle: cannot load user init file\n");
	    }
	}
    }
  while (cons_p (load_files))
 
    {
      exit_code = zzz_evaluate_file (zzz_interaction_environment,
				     string_val (car (load_files)));
      if (exit_code == -1)
	{
	  fprintf (stderr, "sizzle: file not found: %s\n",
		   string_val (car (load_files)));
	  return 1;
	}
      else if (exit_code)
	return exit_code;
      load_files = cdr (load_files);
    }
  if (apply_func)
    {
      eval_string = zzz_malloc (strlen (apply_func) + 64);
      strcpy (eval_string, "(apply ");
      strcat (eval_string, apply_func);
      strcat (eval_string, " (command-line))");
    }
  if (script_file_name)
    {
      exit_code = zzz_evaluate_file (zzz_interaction_environment,
				     script_file_name);
      if (exit_code == -1)
	{
	  if (apply_func)
	    zzz_free (eval_string, strlen (apply_func) + 64);
	  fprintf (stderr, "sizzle: file not found: %s\n",
		   script_file_name);
	  return 1;
	}
      if (apply_func)
	exit_code = zzz_evaluate_string (zzz_interaction_environment,
					 eval_string);
    }
  else if (eval_expression)
    {
      exit_code = zzz_evaluate_string (zzz_interaction_environment,
				       eval_expression);
      if (apply_func)
	exit_code = zzz_evaluate_string (zzz_interaction_environment,
					 eval_string);
    }
  else
    exit_code = zzz_read_eval_print ();

  if (apply_func)
    zzz_free (eval_string, strlen (apply_func) + 64);

#if 0
  /* This code shows how to detect the presence of the glibc.  */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
  printf ("i need my own getopt\n");
#else
  printf ("i get my getopt from libc\n");
#endif
#endif /* 0 */
  return exit_code;
}
