#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: Andrew Lowry
*/
/* cmtad
**
** This module contains routines for parsing time and date specifications.
** Parsing is performed by means of the dtparse routine from the datime
** module.  Flags from FDB field _cmffl are passed on to this routine
** to control the parse.
**
** If the parse is incomplete and the dtparse routine supplies a
** completion text, full completion evokes that text along with a
** trailing space, while partial completion gives the text up to
** the first punctuation.
**
** Help gives a message that depends only on whether the date or time
** have been suppressed from the parse.
**
** The break table has no bearing on the parse, and is set to break on
** everything so that CM_WKF parsing will work.
**/

#define TADERR			/* time/date error table allocated here */

#include "ccmdlib.h"		/* get standard symbols */
#include "cmfncs.h"		/* and internal symbols */

/* Forward declaration of handler routines */

PASSEDSTATIC int tadcplt ARGS((char *text, int textlen, fdb *fdbp,
	 int full, const char **cplt, int *cpltlen));
PASSEDSTATIC int tadhlp ARGS((char *text, int textlen, fdb *fdbp,
	 int cust, int lines));
PASSEDSTATIC int tadprs ARGS((char *text, int textlen, fdb *fdbp,
	 int *parselen, pval *value));

#define tadbrk cmallbk		/* std break table breaks on everything */

ftspec ft_tad = { tadprs, tadhlp, tadcplt, 0, &tadbrk }; /* handler structure */

/* Global variable to hold completion text from parse attempt in
** case a completion request is forthcoming.
**/

static const char *tadcmp;



/* tadprs - Invoke the dtparse routine to attempt to parse the current
** input as a date/time specification.  Propagate an incomplete parse,
** and translate any other failing parse into an error codes that
** depends on flags passed for the parse.  Otherwise, the date/time info
** is returned via the _pvtad component of the value.  As stated in the
** comments for the dtparse routine, if the DTP_NTI flag is specified,
** indicating that no time should be parsed, the time info is set to one
** second past midnight, with local timezone and dst settings.  If the
** DTP_NDA flag is set, so no date is input, the current date is filled
** in.
**
**	* * * W A R N I N G -- S T R A N G E   C O D E * * *
**
** Something strange is done with the `fail' flag here.  Specifically,
** in order to pass the input off to the dtparse routine, we need to
** strip all the quote flags from the characters.  If this parse fails,
** that could affect other alternative parse functions from the FDB
** chain.  Thus before returning a failure code, the input text has
** to be rebuilt.  Thus, when a match fails, we set our local failure
** flag and return CMxAGN, which cause the ccmd routines to rebuild
** the input and call us again.  At that point we return the real
** error code and reset our local flag.  (Yuck!)
**/

PASSEDSTATIC int
#if HAVE_STDC
tadprs(char *text, int textlen, fdb *fdbp, int *parselen, pval *value)
#else /* K&R style */
tadprs(text,textlen,fdbp,parselen,value)
char *text;
int textlen;
fdb *fdbp;
int *parselen;
pval *value;
#endif /* HAVE_STDC */
{
  static int fail=FALSE;		/* TRUE after text rebuild */
  int inc,i;				/* TRUE after incomplete parse */
  int tadflg = fdbp->_cmffl;		/* get parse flags */
  datime *rettad = &value->_pvtad;	/* point to result datime block */

  if (fail) {				/* called again after rebuild? */
    fail = FALSE;			/* yup, reset local flag */
    if (tadflg & DTP_NTI)		/* and return appropriate error */
      return(TADxDAT);
    else if (tadflg & DTP_NDA)
      return(TADxTIM);
    else
      return(TADxDT);
  }

  if (tadflg & DTP_NDA)			/* check exclusions from parse */
    if (tadflg & DTP_NTI)
      return(TADxNTD);			/* cant exclude both time and date */

  for (i = 0; i < textlen; i++)		/* clear quote flags... */
    text[i] &= CC_CHR;			/*  cuz dtparse wants normal chars */

					/* attempt a parse */
  if (!dtparse(tadflg,text,textlen,rettad,parselen,&tadcmp,&inc))
    if (inc)				/* reached end of input? */
      return(CMxINC);			/* then ask for more */
    else {
      fail = TRUE;			/* otherwise set up for failure */
      return(CMxAGN);			/* after they rebuild the input */
    }
  else
    return(CMxOK);			/* success!! */
}



/* tadcplt - The tadcmp global variable should still be set according
** the the incomplete parse that caused this action, so we just make
** use of that string without going through the entire matching process
** again.  If the completion text is empty, we beep.  If the first
** character is a space, we return an empty completion and add a space
** and a wakeup for full completion.  Otherwise, the given completion
** text is returned with no wakeup for full completion, and stopping after
** punctuation for partial completion.
**/

PASSEDSTATIC int
#if HAVE_STDC
tadcplt(char *text, int textlen, fdb *fdbp, int full, const char **cplt, int *cpltlen)
#else /* K&R style */
tadcplt(text,textlen,fdbp,full,cplt,cpltlen)
char *text;
const char **cplt;
int textlen,full,*cpltlen;
fdb *fdbp;
#endif /* HAVE_STDC */
{
  *cplt = NULL;				/* assume no completion */
  if (tadcmp == NULL)
    return(CMP_BEL);			/* beep if nothing available */
  else if (*tadcmp == SPACE)
    if (full)
      return(CMP_SPC | CMP_GO);		/* wakeup for space on full */
    else
      return(CMP_BEL);			/* but beep with partial */
  else {
    *cplt = tadcmp;			/* real completion - fill it in */
    *cpltlen = -1;			/* complete to end of string */
    if (full)
      return(CMP_SPC);			/* include space, no wakeup if full */
    else
      return(CMP_PNC);			/* only up to punctuaion on partial */
  }
}



/* tadhlp - Prints a set message selected according to the flags specified
** in the call.
**/

PASSEDSTATIC int
#if HAVE_STDC
tadhlp(char *text, int textlen, fdb *fdbp, int cust, int lines)
#else /* K&R style */
tadhlp(text,textlen,fdbp,cust,lines)
char *text;
int textlen,cust;
fdb *fdbp;
int lines;
#endif /* HAVE_STDC */
{
  int tadflg = fdbp->_cmffl;		/* get flags from FDB */

  if (tadflg & DTP_NDA)			/* check exclusions */
    if (tadflg & DTP_NTI)
      cmxputs("date and time (but both are suppressed?)"); /* strange */
    else
      cmxputs("time");			/* only date suppressed */
  else
    if (tadflg & DTP_NTI)
      cmxputs("date");			/* only time suppressed */
    else
      cmxputs("date and time");		/* neither suppressed */

  return(lines-1);
}
