#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
*/

/*
 * cmmisc
 *
 * miscellaneous parsing routines.
 */

#include "ccmdlib.h"
#include "cmfncs.h"

static pval parseval;
static fdb *used;

static void cmnohist ARGS((void));

/*
 * simple confirm routine
 */

void
confirm(VOID)
{
  static fdb cfmfdb = { _CMCFM, 0, NULL, NULL, NULL, NULL, NULL };

  parse(&cfmfdb,&parseval,&used);
}

/*
 * simple noise routine
 */
void
#if HAVE_STDC
noise(const char *nw)
#else /* K&R style */
noise(nw)
const char *nw;
#endif /* HAVE_STDC */
{
  static fdb noifdb = { _CMNOI, 0, NULL, NULL, NULL, NULL, NULL };

  noifdb._cmdat = (pdat) nw;
  parse(&noifdb,&parseval,&used);
  cmxflsh();
}


/*
 * general take command
 * accepts routine to recur on.
 * resets cmcsb descriptors, continues parsing, and then
 * restores descriptors.
 * expects to be returned to on eof.
 * sets eof on plain take command, if in inferior take.
 */

void
#if HAVE_STDC
cmtake(int (*proutine) ARGS((void)))
#else /* K&R style */
cmtake(proutine)
int (*proutine) ARGS((void));
#endif /* HAVE_STDC */
{
  FILE *in,*out,*err,*oldin,*oldout,*olderr; /* input and output streams */
  char ifname[200],ofname[200],efname[200];
  static int level = 0;
  static fdb cmdfdb = { _CMFIL, FIL_NODIR, NULL, NULL, NULL, NULL, NULL};
  static fdb cfm1fdb = { _CMCFM, CM_SDH, &cmdfdb, NULL,
			 "Confirm to end current command level", NULL, NULL};
  static fdb logfdb = { _CMFIL, FIL_PO, NULL, NULL, NULL, NULL, NULL };
  static fdb cfmfdb = { _CMCFM, 0, &logfdb, NULL, NULL, NULL, NULL};
  int useoj=0,useej=0;
  int history;

  noise("commands from");		/* give noise */
  parse(&cfm1fdb,&parseval,&used);	/* parse for filename or confirm */
  if (used == &cfm1fdb) {		/* if a confirm */
    if (level != 0)			/* if not top level parse, */
      cmcsb._cmerr = CMxEOF;		/* set eof to pop back */
    else
      cmcsb._cmerr = CMxOK;		/* otherwise, no error */
    longjmp(cmerjb,1);			/* and then jump back to error catch */
  }
  strcpy(ifname,*parseval._pvfil);	/* a filename...copy it */
  noise("logging output on");		/* try to parse a log file */
  parse(&cfmfdb, &parseval, &used);
  if (used == &cfmfdb) {		/* just a confirm? */
    useoj = useej = 0;
  }
  else {
    useoj = 1;
    strcpy(ofname,cmcsb._cmabp);	/* copy output filename */
    noise("and errors on");		/* try to parse an error file */
    parse(&cfmfdb, &parseval, &used);
    if (used == &cfmfdb) {		/* just a confirm? */
      useej = 0;
    }
    else {
      useej = 1;
      strcpy(efname,cmcsb._cmabp);	/* copy output filename */
      confirm();
    }
  }
  in = fopen(ifname,"r");		/* try to open input file */
  if (in == NULL) {
    cmxputs("?Unable to open input file\n");
    return;
  }
  if (useoj) {
    out = fopen(ofname,"a");		/* try to open output file */
    if (out == NULL) {
      cmxerr("?Unable to open logfile\n");
      fclose(in);			/* clean up */
      return;
    }
  }
  else
    out = NULL;
  if (useej) {
    err = fopen(efname,"a");
    if (err == NULL) {
      cmxerr("?Unable to open error file\n");
      fclose(in);
      fclose(out);
      return;
    }
  }
  else
    err = cmcsb._cmej;
  oldin = cmcsb._cmij;			/* save old Files */
  oldout = cmcsb._cmoj;
  olderr = cmcsb._cmej;
  if (useej) {
    cmseti(in,out,err);
  }
  else
    cmseti(in,out,cmcsb._cmej);
  level++;				/* note the recursion */
  if (cmcsb._cmhist) {
      history = cmcsb._cmhist->enabled;
      cmhst_disable();
  }
  (void)(*proutine)();				/* call the parser */
  if (cmcsb._cmhist) {
      cmcsb._cmhist->enabled = history;
  }
  level--;				/* back from the recursion */
  fclose(in);				/* close up private files */
  cmxflsh();
  if (out != NULL)
    fclose(out);
  cmcsb._cmerr = CMxOK;
  if (useej)
    if (err != NULL)
      fclose(err);
  cmseti(oldin,oldout,olderr);		/* restore old FILES */
  return;
}


/*
 * simple command line arg handler.
 * just make cmd line appear as imput.
 * returns TRUE if there were cmd line args.
 * returns FALSE on any but the first call.
 */
int
#if HAVE_STDC
cmargs(int argc, char **argv)
#else /* K&R style */
cmargs(argc,argv)
int argc;
char **argv;
#endif /* HAVE_STDC */
{
  static int first = TRUE;

  if (argc <= 1)
    return(FALSE);			/* no args to stuff */
  if (first) {
    FILE *oin,*oout,*oerr;
    oin = cmcsb._cmij;
    oout = cmcsb._cmoj;
    oerr = cmcsb._cmej;
    cmseti(NULL,NULL,NULL);
    prompt("");				/* issue an empty prompt */
    argc--;
    while (argc-- > 0) {
      cmsti(*(++argv),0);		/* stuff each arg */
      if (argc > 0) {
        cmsti1(SPACE,0);		/* separated by spaces */
      }
    }
    cmsti1(NEWLINE,0);			/* and finished with a newline */
    cmcsb._cmflg |= CM_CFM;		/* mark buffer as confirmed */
    cmcsb._cmbkc = NEWLINE;		/* and this is the confirm char */
    first = FALSE;
    cmseti(oin,oout,oerr);
    return(TRUE);
  }
  else
    return(FALSE);
}


/*
 * make sure hstact() won't do anything next time.
 * for use after parsing a password, etc.
 */
static void
cmnohist(VOID) {
  cmcsb._cmcnt += cmcsb._cmptr - cmcsb._cmbfp;
  cmcsb._cmhst = cmcsb._cmptr = cmcsb._cmbfp ;
/*  cmcsb._cmflg2 |= CM_CRT; */  /* XXX */
}

/*
 * set up break mask with * in it.
 */
static brktab passbrk = {
  {
    0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0x00, 0x3f,
    0x80, 0x00, 0x00, 0x17, 0x80, 0x00, 0x00, 0x1f
  },
  {
    0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0x00, 0x3f,
    0x80, 0x00, 0x00, 0x17, 0x80, 0x00, 0x00, 0x1f
  }
};
static fdb passfdb = { _CMFLD, CM_SDH, NULL, NULL, "Password", NULL, &passbrk};
static fdb qpassfdb = { _CMCFM, CM_SDH, &passfdb, NULL, NULL, NULL, NULL };

char *
#if HAVE_STDC
cmpasswd(const char *prmpt)
#else /* K&R style */
cmpasswd(prmpt)
const char * prmpt;
#endif /* HAVE_STDC */
{
  static char password[50];

  prompt(prmpt);			/* prompt */
  setjmp(cmerjb);
  cmcsb._cmerh = (int (*) ARGS((int,...)))cmerjnp; /* error handler */
  if (cmcsb._cmerr != CMxOK) {
    cmxputc('\n');
    cmecho(TRUE);
    cmnohist();				/* clean up the buffers */
    return(NULL);
  }
  cmsetrp();				/* set reparse handler */
  cmecho(FALSE);			/* turn off echoing */
  parse(&qpassfdb,&parseval,&used);	/* parse a field */
  if (used == &passfdb) {
    strcpy(password,cmcsb._cmabp);	/* copy it into a local buffer */
    confirm();				/* confirm */
  }
  else password[0] = '\0';
  cmxputc('\n');			/* and display the confirm*/
  cmecho(TRUE);				/* turn back on echoing */
  cmnohist();				/* clean up the buffers */
  return(password);
}

int
#if HAVE_STDC
cmsystem(const char *cmd)
#else /* K&R style */
cmsystem(cmd)
const char *cmd;
#endif /* HAVE_STDC */
{
  int r;
  cmtend();
  r = system(cmd);
  cmtset();
  return(r);
}

char *
cmini(VOID) {
  static int cmdbuf[200];
  static char atmbuf[200];
  static char wrkbuf[200];

  cmbufs(cmdbuf,200,atmbuf,200,wrkbuf,200); /* set up our buffers */
  cmseti(stdin, stdout, stderr);
  return(atmbuf);
}

/*
 * convert a datime struct into a long time(2) value.
 */
long
#if HAVE_STDC
datime_to_time(datime *dt) {
#else /* K&R style */
datime_to_time(dt) datime *dt; {
#endif /* HAVE_STDC */
  long t;
  int i;
  static int months[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
  int isaleap;

#if 0
  t = dt->_dtyr - 2000;			/* num years */
  isaleap = ((!(t%4) && t%100) || !(t%400));
  t = t/4 + t*365 - t/100 + t/400;	/* num days */
  t += 30*365 + 30/4;			/* subtract num of days in 1900-1970 */
#else
  t = dt->_dtyr - 1970;			/* num years */
  isaleap = ((!(dt->_dtyr%4) && dt->_dtyr%100) || !(dt->_dtyr%400));
  t = t*365 + (t+1)/4;			/* num days */
#endif
  for ( i = 0; i < dt->_dtmon; i++)
    t += months[i];
  t += dt->_dtday;
  if (dt->_dtmon >= 2 && isaleap) t += 1; /* add feb 29 (leap day) */
  t *= 24;				/* to hours */
  t += dt->_dthr;
  t *= 60;				/* to minutes */
  t += dt->_dtmin + dt->_dttz + dt->_dtdst;
  t *= 60;
  t += dt->_dtsec;		       	/* to seconds. */
  return(t);
}

void
#if HAVE_STDC
cm_set_ind(int flag)
#else /* K&R style */
cm_set_ind(flag)
int flag;
#endif /* HAVE_STDC */
{
    if (!flag)
	cmcsb._cmflg2 |= CM_NIN;
    else
	cmcsb._cmflg2 &= ~CM_NIN;
}
