text: /*************************************************************************/
  /*                                                                       */
  /*                  Language Technologies Institute                      */
  /*                     Carnegie Mellon University                        */
  /*                       Copyright (c) 1999-2007                         */
  /*                        All Rights Reserved.                           */
  /*                                                                       */
  /*  Permission is hereby granted, free of charge, to use and distribute  */
  /*  this software and its documentation without restriction, including   */
  /*  without limitation the rights to use, copy, modify, merge, publish,  */
  /*  distribute, sublicense, and/or sell copies of this work, and to      */
  /*  permit persons to whom this work is furnished to do so, subject to   */
  /*  the following conditions:                                            */
  /*   1. The code must retain the above copyright notice, this list of    */
  /*      conditions and the following disclaimer.                         */
  /*   2. Any modifications must be clearly marked as such.                */
  /*   3. Original authors' names are not deleted.                         */
  /*   4. The authors' names are not used to endorse or promote products   */
  /*      derived from this software without specific prior written        */
  /*      permission.                                                      */
  /*                                                                       */
  /*  CARNEGIE MELLON UNIVERSITY AND THE CONTRIBUTORS TO THIS WORK         */
  /*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
  /*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
  /*  SHALL CARNEGIE MELLON UNIVERSITY NOR THE CONTRIBUTORS BE LIABLE      */
  /*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
  /*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
  /*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
  /*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
  /*  THIS SOFTWARE.                                                       */
  /*                                                                       */
  /*************************************************************************/
  /*             Author:  Alan W Black (awb@cs.cmu.edu)                    */
  /*               Date:  April 2000                                       */
  /*************************************************************************/
  /*                                                                       */
  /*  Item features and paths                                              */
  /*                                                                       */
  /*************************************************************************/
  #include "include/cst_alloc.h"
  #include "include/cst_item.h"
  #include "include/cst_relation.h"
  #include "include/cst_utterance.h"
  #include "include/cst_tokenstream.h"
  
  CST_VAL_REGISTER_FUNCPTR(ffunc,cst_ffunction)
  
  DEF_STATIC_CONST_VAL_STRING(ffeature_default_val,"0");
  
  static const void *internal_ff(const cst_item *item,
  			       const char *featpath,int type);
  
  const char *ffeature_string(const cst_item *item,const char *featpath)
  {
      return val_string(ffeature(item,featpath));
  }
  int ffeature_int(const cst_item *item,const char *featpath)
  {
      return val_int(ffeature(item,featpath));
  }
  float ffeature_float(const cst_item *item,const char *featpath)
  {
      return val_float(ffeature(item,featpath));
  }
  
  cst_item* path_to_item(const cst_item *item,const char *featpath)
  {
      return (cst_item *)internal_ff(item,featpath,1);
  }
  
  const cst_val *ffeature(const cst_item *item,const char *featpath)
  {
      return (cst_val *)internal_ff(item,featpath,0);
  }
  
  static const void *internal_ff(const cst_item *item,
  			       const char *featpath,int type)
  {
      const char *tk, *relation;
      cst_utterance *utt;
      const cst_item *pitem;
      void *void_v;
      const cst_val *ff;
      cst_ffunction ffunc;
      char tokenstring[200]; /* we don't seem to have featpaths longer than 72 */
      char *tokens[100];
      int i,j;
  
      /* This used to use cst_tokenstream but that was too slow */
      for (i=0; i<199 && featpath[i]; i++)
          tokenstring[i] = featpath[i];
      tokenstring[i]='\0';
      tokens[0] = tokenstring;
      for (i=0,j=1; tokenstring[i]; i++)
      {
          if (strchr(":.",tokenstring[i]))
          {
              tokenstring[i] = '\0';
              tokens[j] = &tokenstring[i+1];
              j++;
          }
      }
      tokens[j] = NULL;
      j=0;
      for (tk = tokens[j], pitem=item;
  	 pitem && 
  	     (((type == 0) && tokens[j+1]) ||
  	      ((type == 1) && tk));
  	 j++, tk = tokens[j])
      {
  	if (cst_streq(tk,"n"))
  	    pitem = item_next(pitem);
  	else if (cst_streq(tk,"p"))
  	    pitem = item_prev(pitem);
  	else if (cst_streq(tk,"pp"))
  	{
  	    if (item_prev(pitem))
  		pitem = item_prev(item_prev(pitem));
  	    else
  		pitem = NULL;
  	}
  	else if (cst_streq(tk,"nn"))
  	{
  	    if (item_next(pitem))
  		pitem = item_next(item_next(pitem));
  	    else
  		pitem = NULL;
  	}
  	else if (cst_streq(tk,"parent"))
  	    pitem = item_parent(pitem);
  	else if ((cst_streq(tk,"daughter")) ||
  		 (cst_streq(tk,"daughter1")))
  	    pitem = item_daughter(pitem);
  	else if (cst_streq(tk,"daughtern"))
  	    pitem = item_last_daughter(pitem);
  	else if (cst_streq(tk,"first"))
  	    pitem = item_first(pitem);
  	else if (cst_streq(tk,"last"))
  	    pitem = item_last(pitem);
  	else if (cst_streq(tk,"R"))
  	{
  	    /* A relation move */
              j++;
  	    relation = tokens[j];
  	    pitem = item_as(pitem,relation);
  	}
  	else
  	{
  	    cst_errmsg("ffeature: unknown directive \"%s\" ignored\n",tk);
  	    return NULL;
  	}
      }
  
      if (type == 0)
      {
  	if (pitem && (utt = item_utt(pitem)))
  	    ff = feat_val(utt->ffunctions,tk);
  	else
  	    ff = NULL;
  	void_v = NULL;
  	if (!ff)
  	    void_v = (void *)item_feat(pitem,tk);
  	else if (pitem)
  	{
  	    ffunc = val_ffunc(ff);
  	    void_v = (void *)(*ffunc)(pitem);
  	}
  	if (void_v == NULL)
          {
  #if 0
              if (pitem)
                  printf("awb_debug didn't find %s in %s\n",tk,
                         get_param_string(pitem->contents->features,"name","noname"));
              else
              {
                  if (cst_streq("gpos",tk))
                      printf("awb_debug2\n");
                  printf("awb_debug didn't find %s %s\n",tk,featpath);
              }
  #endif
  	    void_v = (void *)&ffeature_default_val;
          }
      }
      else
  	void_v = (void *)pitem;
  
      return void_v;
  }
  
  void ff_register(cst_features *ffunctions, const char *name, cst_ffunction f)
  {
      /* Register features functions */
  
  #if 0
      if (feat_present(ffunctions, name))
  	cst_errmsg("warning: ffunction %s redefined\n", name);
  #endif
      feat_set(ffunctions, name, ffunc_val(f));
  }
  
  void ff_unregister(cst_features *ffunctions, const char *name)
  {
      feat_remove(ffunctions, name);
  }
  