#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
*/
/* cmfld
**
** Code to parse "arbitrary fields."  This function never really
** fails.  When a parse is requested, the current input is scanned
** until a character that is not allowed by the break table is
** encountered.  If no such terminating character is found, an
** incomplete parse is signaled.  Otherwise, the text up to but
** not including that character is returned via the atom buffer.
** Note that the returned text may be empty.  Full completion always
** adds a space unless spaces are allowed by the break table.  Partial
** completion always beeps.
**
** The default break table allows words beginning with a letter
** and consisting of letters, digits, and hyphens.  The standard
** help message reflects this default.
**/

#define	FLDERR			/* cmfld error table allocated here */

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

/* Forward declaration of handler routines */

PASSEDSTATIC int fldcplt ARGS((char *text, int textlen, fdb *fdbp,
	 int full, const char **cplt, int *cpltlen));
PASSEDSTATIC int fldhlp ARGS((char *text, int textlen, fdb *fdbp,
	 int cust, int lines));
PASSEDSTATIC int fldprs ARGS((char *text, int textlen, fdb *fdbp,
	 int *parselen, pval *value));

static brktab fldbrk = {
  {				/* letters only in first position */
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f
  },
  {				/* letters, digits and hyphens here */
    0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x3f,
    0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f
  }
};

ftspec ft_fld = { fldprs, fldhlp, fldcplt, 0, &fldbrk }; /* handler structure */



/* fldprs - Find a terminating character.  If there is one, succeed with
** the text up to the terminator copied to the atom buffer.  Otherwise,
** give incomplete parse.
**/

PASSEDSTATIC int
#if HAVE_STDC
fldprs(char *text, int textlen, fdb *fdbp, int *parselen, pval *value)
#else /* K&R style */
fldprs(text,textlen,fdbp,parselen,value)
char *text;
int textlen,*parselen;
fdb *fdbp;
pval *value;
#endif /* HAVE_STDC */
{
  brktab *btab;				/* break table in effect */
  int fldlen;				/* length of field up to terminator */

  if ((btab = fdbp->_cmbrk) == NULL)	/* get custom break table */
    btab = &fldbrk;			/* or use default */

  for (fldlen = 0; fldlen < textlen; fldlen++) /* loop through data */
    if ((text[fldlen] & CC_QUO) == 0)	/* quoted chars never terminate */
      if (fldlen == 0) {
	int temp = text[fldlen]&CC_CHR;
	if (BREAK1(btab,temp)) {
	  break;			/* found a terminator */
	}
      }
      else {
	int temp = text[fldlen]&CC_CHR;
	if (BREAKR(btab,temp)) {
	  break;			/* found a terminator */
	}
      }

  if (fldlen == textlen && !(fdbp->_cmffl & FLD_WAK)) /* no terminator found */
    return(CMxINC);			/* so incomplete parse */
  if (fdbp->_cmffl & FLD_EMPTY)
      if (fldlen == 0)
	  return(FLDxNM);
  *parselen = fldlen;			/* else set length of field */
  value->_pvstr = cmcsb._cmabp;		/* return string in atom buffer */
  return(CMxOK);			/* good parse */
}



/* fldhlp - Default help assumes a word is being parsed */

PASSEDSTATIC int
#if HAVE_STDC
fldhlp(char *text, int textlen, fdb *fdbp, int cust, int lines)
#else /* K&R style */
fldhlp(text,textlen,fdbp,cust,lines)
char *text;
int textlen,cust;
fdb *fdbp;
int lines;
#endif /* HAVE_STDC */
{
  cmxputs("word");
  return(lines-1);
}



/* fldcplt - Full completion adds a space unless it would be taken as
** part of the field data, partial completion always beeps.
**/

PASSEDSTATIC int
#if HAVE_STDC
fldcplt(char *text, int textlen, fdb *fdbp, int full, const char **cplt, int *cpltlen)
#else /* K&R style */
fldcplt(text,textlen,fdbp,full,cplt,cpltlen)
char *text;
const char **cplt;
int textlen,full,*cpltlen;
fdb *fdbp;
#endif /* HAVE_STDC */
{
  brktab *btab;			/* break table in effect */
  *cplt = NULL;			/* never any completion text */
  if (textlen == 0)
    return(CMP_BEL);		/* beep at no text */
  if (full) {			/* full completion requetsed */
    if ((btab = fdbp->_cmbrk) == NULL) /* get supplied break table */
      btab = &fldbrk;		/* or use default */
    if (BREAK(btab,SPACE,textlen)) /* would a space break here? */
      return(CMP_SPC | CMP_GO);	/* yup, tack on a space and wake up */
    else
      return(CMP_BEL);		/* otherwise beep */
  }
  else
    return(CMP_BEL);		/* partial completion always beeps */
}
