#include "config.h"
/*
 * Copyright (c) 1986, 2014 by The Trustees of Columbia University in
 * the City of New York.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  + Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *  + Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 *  + Neither the name of Columbia University nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.

 Author: Howie Kaye
*/

static const char *Version = "Skel Version 1.0 of Sun Apr  5 02:37:41 1987";

#include "ccmdlib.h"			/* get ccmd symbols */

#if HAVE_STDC
#include <string.h>
#endif

/*
 * forward declare parse routines.
 */
static int toplevel ARGS((void));
static void c_bug_report ARGS((int helpflg));
static void c_exit ARGS((int helpflg));
static void c_help ARGS((int helpflg));
static void c_take ARGS((int helpflg));
static void c_version ARGS((int helpflg));
static void dohelp ARGS((int (*f )(int)));
static void execute ARGS((int (*f ) (int)));

/*
 * set up the top level keyword table
 * This will be used by the help command also.
 */

static keywrd cmds[] = {
  { "bug-report", KEY_INV, (keyval) c_bug_report },
  { "exit",	0,	(keyval) c_exit },
  { "help",	0,	(keyval) c_help },
  { "quit",	KEY_INV,(keyval) c_exit },
  { "take",	0,	(keyval) c_take },
  { "version",	KEY_INV,(keyval) c_version },
};

/*
 * the actual keyword table type has a length in it.
 */
static keytab cmdtab = { (sizeof(cmds)/sizeof(keywrd)), cmds };

static int argc;
static char **argv;

int
#if HAVE_STDC
main(int Argc, char **Argv)
#else /* K&R style */
main(Argc,Argv)
int Argc;
char **Argv;
#endif /* HAVE_STDC */
{
  argc = Argc;
  argv = Argv;

  (void)cmini();			/* initialize ccmd */
  cmxprintf("Skeleton program Version 1.0\n"); /* display version info */
  cmxprintf("%s\n",cm_version());	/* and CCMD version as well. */
  toplevel();				/* top level cmd parser. */
  cmdone();				/* restore terminal, etc */
  return(0);
}

static int done = FALSE;		/* exit flag */

static int
toplevel(VOID)
{
  pval parseval;
  fdb *used;
					/* FDB for top level commands */
  static fdb cmdfdb = { _CMKEY, 0, NULL, (pdat) &(cmdtab), "Command, ",
			  NULL, NULL };
  while (!done) {
    cmseter();				/* set error trap */
					/* control will come here in the */
					/* case of a parse error. */
    if (cmcsb._cmerr == CMxEOF)		/* exit on EOF -- this is useful */
      break;				/* for take's */
    if (cmargs(argc,argv))		/* check for command line args */
      done = TRUE;
    else
      prompt("Skel> ");			/* prompt */
    cmsetrp();				/* set reparse trap */
					/* control will come here in the */
					/* case of a reparse. */
    parse(&cmdfdb,&parseval,&used);	/* parse a command */
    execute((int(*) ARGS((int)))parseval._pvkey);	/* execute it. */
  }
  return (0);
}

/*
 * execute a command.
 * call the function, with the help flag off.
 */

static void
#if HAVE_STDC
execute(int (*f) ARGS((int)))
#else /* K&R style */
execute(f)
int (*f) ARGS((int));
#endif /* HAVE_STDC */
{
  (*f)(FALSE);				/* call function with help flag off */
}

/*
 * call a command function with the help flag on
 */
static void
#if HAVE_STDC
dohelp(int (*f) ARGS((int)))
#else /* K&R style */
dohelp(f)
int (*f) ARGS((int));
#endif /* HAVE_STDC */
{
  (*f)(TRUE);				/* call function with help flag on */
}



/*
 * top level commands.
 * all of these take the form
 * command(helpflag) {
 *   if (helpflag) print a help string
 *   else { parse and execute }
 *
 * this style is encouraged, as the documentation for each command
 * resides inside the command itself.  This leads to self documenting
 * parses, and documentation which is consistant with the code.
 */

/*
 * the exit command
 */
static void
#if HAVE_STDC
c_exit(int helpflg)
#else /* K&R style */
c_exit(helpflg) int helpflg;
#endif /* HAVE_STDC */
{
  if (helpflg) {
    cmxprintf("\
Exit from this program.  The invisible quit command is a synonym for it.\n");
  }
  else {
    noise("this program");
    confirm();
    done = TRUE;			/* just set the global exitflg */
  }
}

/*
 * give help.
 */
static void
#if HAVE_STDC
c_help(int helpflg)
#else /* K&R style */
c_help(helpflg)
int helpflg;
#endif /* HAVE_STDC */
{
  static fdb cmdfdb = { _CMKEY, 0, NULL, (pdat) &(cmdtab), "Command, ",
			  NULL, NULL };
  static fdb hlpfdb = { _CMCFM, 0, &cmdfdb, NULL, NULL, NULL, NULL };
  pval parseval;
  fdb *used;

  if (helpflg) {
    cmxprintf("The help command gives help.\n");
  }
  else {
    noise("me with");
    parse(&hlpfdb,&parseval,&used);	/* parse a command */
    if (used == &hlpfdb) {
      cmxprintf("This is a skeleton CCMD program.\n");
    }
    else {
      confirm();
      dohelp((int (*) ARGS((int)))parseval._pvkey); /* help on a subject. */
    }
  }
}

/*
 * the take command
 * takes commands from another file.
 */

static void
#if HAVE_STDC
c_take(int helpflg)
#else /* K&R style */
c_take(helpflg)
int helpflg;
#endif /* HAVE_STDC */
{
  if (helpflg) {
    cmxprintf("Take commands from another file.\n");
  }
  else {
    cmtake(toplevel);
  }
}


static void
#if HAVE_STDC
c_version(int helpflg)
#else /* K&R style */
c_version(helpflg)
int helpflg;
#endif /* HAVE_STDC */
{
  if (helpflg) {
    cmxprintf("Display the current version of ccmd\n");
  }
  else {
    noise("of this program");
    confirm();
    cmxprintf("%s\n%s\n", Version,cm_version());
  }
}

static void
#if HAVE_STDC
c_bug_report(int helpflg)
#else /* K&R style */
c_bug_report(helpflg)
int helpflg;
#endif /* HAVE_STDC */
{
  static const char *bug_address = "SY.Howie@CU20B.Columbia.EDU";
  static const char *mail_program = "/usr/ucb/mail";
  static const char *mail_args = "-s 'CCMD bug'";
  if (helpflg) {
    cmxprintf("Report a CCMD bug.  This will execute the command:\n\
   %s %s %s\n\
to send out a bug report.  If this is not valid for your site, get the\n\
person locally responsible for CCMD to change the file: skel.c to have\n\
the appropriate program and/or address.\n",
	      mail_program, mail_args, bug_address);

  }
  else {
    static const char *msg = NULL;
    static char *cmd = NULL;
    static para_data pd = { NULL, NULL };
    static fdb parafdb = { _CMPARA, 0, NULL, NULL, NULL, NULL, NULL };
    FILE *mypipe;
    pval parseval;
    fdb *used;

    noise("on CCMD to send off");
    parafdb._cmdat = (pdat) &pd;
    confirm();
    cmcls();
    cmxputs(" Message (CTRL/D to send,\n\
  Use CTRL/B to insert a file, CTRL/E to enter editor, CTRL/K to redisplay\n\
  message, CTRL/L to clear screen and redisplay, CTRL/N to abort.):\n");
    parse(&parafdb,&parseval,&used);
    msg = parseval._pvpara;
    if (msg == NULL) {
      cmxprintf("Aborted!\n");
    }
    else {
      cmd = (char*)malloc(strlen(bug_address)+sizeof(" ")+
			  strlen(mail_args)+sizeof(" ")+
			  strlen(mail_program)+1);
      sprintf(cmd,"%s %s %s",mail_program,mail_args,bug_address);
#ifndef MSDOS
      if ((mypipe = (FILE*)popen(cmd,"w")) == NULL) {
	cmxeprintf("?Could not run %s",mail_program);
	perror("");
      }
      else {
	fprintf(mypipe,"Bug report in %s\n\n",cm_version());
	fprintf(mypipe,"%s",msg);
	pclose(mypipe);
	cmxprintf("Sent to %s\n", bug_address);
      }
#else
      cmxprintf("Sorry, but i don't know how to send mail from an MSDOS\n\
machine.  I will save your message in the file CCMD.BUG  -- please try to\n\
find another way to send it out.\n");
      if ((mypipe = fopen("CCMD.BUG", "w")) == NULL) {
	cmxeprintf("Could not open CCMD.BUG");
	perror("");
      }
      else {
	fprintf(mypipe, "%s\n\n",cmd);
	fprintf(mypipe,"Bug report in %s\n\n",cm_version());
	fprintf(mypipe,"%s",msg);
	fclose(mypipe);
      }
#endif
    }
  }
}
