/*
 *
 * a r g v . c			-- Argc/Argv management
 *
 * Copyright (C) 1993,1994,1995 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
 * 
 *
 * Permission to use, copy, and/or distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that both the above copyright notice and this permission notice appear in
 * all copies and derived works.  Fees for distribution or use of this
 * software or derived works may only be charged with express written
 * permission of the copyright holder.  
 * This software is provided ``as is'' without express or implied warranty.
 *
 * This software is a derivative work of other copyrighted softwares; the
 * copyright notices of these softwares are placed in the file COPYRIGHTS
 *
 *
 *           Author: Erick Gallesio [eg@kaolin.unice.fr]
 *    Creation date: 30-Aug-1994 15:38
 * Last file update: 13-Jul-1995 10:26
 */

#include "stk.h"

/* Previous versions of Stk use the TkArgv mechanism for managing argc/argv.
 * Here is an ad hoc version for argc/argv hich is simpler than the original
 * one and which can be used when NO_TK is defined
 */

#ifdef USE_TK
char *STk_arg_Xdisplay 	  = NULL;
char *STk_arg_geometry 	  = NULL;
char *STk_arg_name 	  = NULL;
int   STk_arg_sync	  = 0;
int   STk_arg_no_tk	  = 0;
#endif
char *STk_arg_file	  = NULL;
char *STk_arg_load	  = NULL;
char *STk_arg_image	  = NULL;
char *STk_arg_cells	  = NULL;
int   STk_arg_interactive = 0;

static struct arguments{
  char *key, *help;
} Table[] = {
#ifdef USE_TK
  {"-geometry",    "Initial geometry for window"},
  {"-display", 	   "Display to use"},
  {"-name",	   "\tName to use for application"},
  {"-sync", 	   "\tUse synchronous mode for display server"},
  {"-no-tk",       "\tDon't initialize Tk"},
#endif
  {"-file", 	   "\tFile from which to read commands"},
  {"-load",        "\tFile to load after all the initializations are done"},
  {"-cells",	   "\tDefault size for heap"},
  {"-image",       "\tUse  previously created image"},
  {"-interactive", "Interactive mode"},
  {"-help",    	   "\tPrint summary of command-line options and abort"},
  {"", ""}};

#define NEXTARG() ((argc--,*++argv) ? *argv : (need_argument(p->key), (char*) NULL))

static void need_argument(char *opt)
{
  fprintf(stderr, "\"%s\"  option requires an additional argument\n", opt);
  exit(1);
}

static void usage(void)
{
  struct arguments *p;
  
  for (p = Table; *(p->key); p++) 
    fprintf(stderr, "%s\t%s\n", p->key, p->help);
  exit(1);
}

static void reset_flags_defaults(void)
{
#ifdef USE_TK
  STk_arg_Xdisplay = STk_arg_geometry = STk_arg_name = NULL;
  STk_arg_sync     = STk_arg_no_tk    = 0;
#endif
  STk_arg_file = STk_arg_load = STk_arg_image = STk_arg_cells = NULL;
}

char ** STk_process_argc_argv(int argc, char **argv)
{
  struct arguments *p;
  char **new_argv;
  int i = 0;
  
  reset_flags_defaults();
  new_argv = (char**) must_malloc(argc * sizeof(char*));
  STk_whence(*argv, STk_Argv0);

  while (--argc) {
    char *arg = *++argv;
    int found = FALSE;

    for (p = Table; *(p->key); p++) {
      if (strstr(p->key, arg)== p->key) {
	found = TRUE;
#ifdef USE_TK
	if (!strcmp(p->key, "-geometry"))  {STk_arg_geometry    = NEXTARG(); break;}
	if (!strcmp(p->key, "-display"))   {STk_arg_Xdisplay    = NEXTARG(); break;}
	if (!strcmp(p->key, "-name"))      {STk_arg_name        = NEXTARG(); break;}
	if (!strcmp(p->key, "-sync"))      {STk_arg_sync        = TRUE;      break;}
	if (!strcmp(p->key, "-no-tk"))     {STk_arg_no_tk       = TRUE;      break;}
#endif
	if (!strcmp(p->key, "-file"))      {STk_arg_file        = NEXTARG(); break;}
	if (!strcmp(p->key, "-load"))      {STk_arg_load        = NEXTARG(); break;}
	if (!strcmp(p->key, "-cells"))     {STk_arg_cells       = NEXTARG(); break;}
	if (!strcmp(p->key, "-image"))     {STk_arg_image       = NEXTARG(); break;}
	if (!strcmp(p->key,"-interactive")){STk_arg_interactive = TRUE;      break;}
	if (!strcmp(p->key, "-help"))      {usage(); 		 	     break;}
      }
    }
    if (!found) new_argv[i++] = arg;
  }
  new_argv[i] = NULL;
  return new_argv;
}


/******************************************************************************
 *
 * Unix environment saving
 *
 * 	The two following function permit to save/restore the argc/argv/envp
 * in a file. They are used upon image restauration.
 *
 ******************************************************************************/
void STk_save_unix_args_and_environment(int argc, char **argv)
{
  FILE *f;
  char **env;
  char filename[50];
  extern char **environ;

  /* Open a file in which we will save argc/argv/envp */
  sprintf(filename, "/usr/tmp/STktmp%d", getpid());
  if ((f = fopen(filename, "w")) == NULL) {
    fprintf(stderr, "Cannot save environment in %s.\n ABORT.\n", filename);
    exit(1);
  }

  /* print argc */
  fprintf(f, "%d\n", argc);

  /* print argv */
  for ( ; argc; argc-=1, argv+=1) {
    fprintf(f, "%d %s\n", strlen(*argv), *argv);
  }

  /* print environment */
  for (env=environ; *env; env++) {};
  fprintf(f, "%d\n", env-environ);

  for (env=environ; *env; env++) {
    fprintf(f, "%d %s\n", strlen(*env), *env);
  }

  /* Close file */
  fclose(f);
}

void STk_restore_unix_args_and_environment(int *argc, char ***argv)
{
  FILE *f;
  int i, l, Argc, env_len;
  char **Argv, **Env;
  char filename[50];
  extern char **environ;

  /* Open a file in which we have saved argc/argv/envp */
  sprintf(filename, "/usr/tmp/STktmp%d", getpid());
  if ((f = fopen(filename, "r")) == NULL) {
    fprintf(stderr, "Cannot re-open environment in %s.\n ABORT.\n", filename);
    exit(1);
  }

  /* Read argc */
  fscanf(f, "%d", &Argc); getc(f);

  /* Read argv */
  Argv = must_malloc((Argc+1) * sizeof(char *));

  for (i=0; i<Argc; i++) {
    fscanf(f, "%d", &l); getc(f);
    Argv[i] = must_malloc(l+1);
    fread(Argv[i], 1, l, f);
    Argv[i][l] = '\0';
  }
  Argv[Argc] = NULL;

  /* Read environment */
  fscanf(f, "%d", &env_len); getc(f);
  Env = must_malloc((env_len+1) * sizeof(char *));
  for (i=0; i<env_len; i++) {
    fscanf(f, "%d", &l); getc(f);
    Env[i] = must_malloc(l+1);
    fread(Env[i], 1, l, f);
    Env[i][l] = '\0';
  }
  Env[i]= NULL;

  /* Save read values in global variables */
  *argc   = Argc;
  *argv   = Argv;
  environ = Env;
  
  /* close & delete temporary file */
  fclose(f);
  unlink(filename);
}

void STk_initialize_scheme_args(char **argv)
{
  SCM l;

  for (l = NIL; *argv; argv++)
    l = Cons(STk_makestring(*argv), l);
  
  VCELL(Intern(ARGV))      = Reverse(l);
  VCELL(Intern(PROG_NAME)) = STk_makestring(STk_Argv0);
}
