#define _PROCESS_0
/*
Remove debugging when we're sure of the module.
#undef DEBUG
#undef DBGLVL
#define DEBUG 0
#define DBGLVL -0x8000
*/

#include "thread/queue.h"
#include "includes.h"
#include "pcoreipc.h"
#include "forker.h"
#include "parseopts.h"
#include "main.h"

/****************** VERSION NUMBER ***********************/

#include "../../version.h"

#define PCORE_VERSION MOOSE_VERSION
#define PCORE_BANNER \
		"pcore " PCORE_VERSION "\n\n" \
		"A Portable Core for MOOSE's OSL.\n" \
		"Copyright (c) " \
		"François-René \"Faré\" Bân RIDEAU \\DD\\a(.ng-V\\u~" " " \
		"1994" "\n" \
		"Please read the README file in the MOOSE distribution.\n"


/******************* HELP STRING *************************/

const char pcore_Banner  [] = { PCORE_BANNER };
const char pcore_Version [] = { PCORE_VERSION };

const char pcore_OptionHelp [] = {
/* Options/environment variables that should be recognized:
   =======================================================
*/
       /* OSL commands in command line */
       " -e	 --exec		parse all following parameters as OSL tokens\n"
       " -c xxx	 --command xxx	parse following single parameter as OSL text\n"
/*
       "*-s	 --stdin	parse standard input\n"
       "*-i	 --interactive	use MOOSE as an interactive shell\n"
       "*-l	 --login	read login configuration files\n"
*/
/*
Detailed behavior:
=================
 * argv[0] is first read so that if it begins by '-', --login option is
   assumed.
 * if no arguments (but unclear options),
   use -i if connected to a tty, else -s behavior.
 * -i by default sources the resource files
 * -s by default does not source the resource files
 * if arguments given, remaining parameters are a file to parse and execute
   as any unix interpreter, with arguments to give to it. do not read resource
   files unless explicitly specified.
 That's the standard behavior for a unix shell or interpreter.
*/

       /* startup configuration file: */
       " -n	 --norc		do not read configuration files.\n"
       " -f	 --rcfile	read given configuration file.\n"

       /* general behavior: */
/*
       " -q	 --quit		kill self after executing given commands.\n"
       " -s#	 --server #	stay as server on optionally given socket.\n"
       " -ox,y,z --other x,y,z	cooperate with given other servers.\n"
       " -C	 --cooperate	cooperate with any connecting client.\n"
       " -Afile	 --auth file	use file for connection authorization.\n"
*/
       /* sizes: */
/*
       " -M#	 --coremem #	total size of core memory (instead of 16 MB)\n"
       " -S#	 --sharedmem #	total size of shared memory (256 KB)\n"
       " -T#	 --thrstack #	default size for threads' stacks (16 KB)\n"
       " -G#	 --sigstack #	default size for the signal stack (32 KB)\n"
*/
       /* Debugging: */
/*
       " -x	 --trace	turns on parse debugging\n"
       " -Dopts	 --debug opts	specify debugging modes\n"
*/
       /* miscellaneous options: */
       " -0	 --reset	reset all options to defaults\n"
       " -V	 --version	just ask version number\n"
       " -h,-?	 --help		print this help message\n"

/* -0 is used to override options given by an alias */

/*
 Some remaining of the command line should be given to process (2) under
 some form or another...

 Currently: none

 Completely unoptimized, as the shorter time using "C", the better for
 mental sanity.

*/
};


/**************** Help for Option actions ******************/

static char * concat (char*a,char* b) {
 /* malloc string containing concatenation of the previous */
   char * new = malloc (strlen(a)+strlen(b)) ;
   if (!new) { 
     DBGMSG(0,"malloc failed while concatening strings !\n") ;
     exit (100) ;
   }
   strcpy (new,a) ;
   strcat (new,b) ;
   return new ;
}


/****************************** Options ********************************/
char *	pcore_config_file ;
int	pcore_opt_must_print_banner ;
int	pcore_opt_long_prog_name ;
int	pcore_arg_meaning ;
int	pcore_argc ;
char ** pcore_argv ;
Queue   pcore_command_queue ;

/******************** Option actions ***********************/

static void PrintHelp (void) {

  char * progname ;
  if (pcore_opt_long_prog_name) { 
	progname=po_argv[0] ;
  } else {
    for ( progname=po_argv[0] + strlen(po_argv[0]) ;
	  (progname!=po_argv[0]) && (*(progname-1)!='/') ;
	  progname-- ) ;
  }

  printf     ( "%s\n"  "%s [options] files\n"  "options:\n"  "%s\n",
	       pcore_Banner, progname, pcore_OptionHelp);
  exit(0);
}

static void PrintVersion (void) {
  printf     ( "MOOSE OSL Portable Core, version " PCORE_VERSION "\n" ) ;
  exit(0);
}

static void SetExec (void) {
  pcore_arg_meaning = pcore_argv_is_tokens ;
}

static void QueueString (Queue *queue) {
 ___(10,"Queueing argument\n") ;
  q_insert (*queue,po_Parse_String_Arg(NULL)) ;
 ___(20,"Done queueing argument\n") ;
}

static po_option pcore_options [] = {
  {'e', "exec",		(po_action) SetExec,		NULL},
  {'c', "command",	(po_action) QueueString,	&pcore_command_queue},
  {'n', "norc",		(po_action) po_SetNULL,		&pcore_config_file},
  {'f', "rcfile",	(po_action) po_Parse_String_Arg,&pcore_config_file},
  {'h',	"help",		(po_action) PrintHelp,		NULL},
  {'?',	"",		(po_action) PrintHelp,		NULL},
  {'V',	"version",	(po_action) PrintVersion,	NULL},
  {'_',	"nop",		(po_action) Nop,		NULL},
};



/**************************** Main functions ********************************/

static void Init_Options (void) {

  ___(95,"Initializing options\n") ;

  pcore_config_file = concat(getenv("HOME"),"/.oslrc") ;
  pcore_opt_must_print_banner = 1 ;
  pcore_opt_long_prog_name = 0 ;
  pcore_arg_meaning = pcore_argv_is_file_and_args ;
  pcore_command_queue = q_create () ;
}

void  Adjust_Options (void) {
}

void  Show_Banner (void) {
  if (pcore_opt_must_print_banner) puts (pcore_Banner) ;
}



/************************* And here is main (), *************************
 **************** the standard entry point for C programs **************/

void main (int argc, char **argv) {

 ___(100,"Parsing the command line !\n") ;

  Init_Options () ;				/* get options */

  Parse_Options (&argc,argv,pcore_options) ;	/* do parse the command line */
    pcore_argv = argv ;
    pcore_argc = argc ;

  Adjust_Options () ;				/* verify option sensibility */

 ___(100,"Launching the run-time process !\n") ;

  Show_Banner () ;				/* show our banner */

  pcore_init_ipc () ;				/* init IPC */

  pcore_do_fork () ;				/* let's go working */
  
 ___(100,"You should never have reached this point !!!\n") ;
}
