/*      Copyright (C) 2001, 2002, 2003, 2004 Stijn van Dongen
 *
 * This file is part of Zoem. You can redistribute and/or modify Zoem under the
 * terms of the GNU General Public License;  either version 2 of the License or
 * (at your option) any later  version.  You should have received a copy of the
 * GPL along with Zoem, in the file COPYING.
*/

#include <stdarg.h>

#include "util.h"

#include "segment.h"
#include "key.h"
#include "ops.h"
#include "source.h"
#include "digest.h"
#include "parse.h"

#include "util/ting.h"
#include "util/err.h"
#include "util/hash.h"
#include "util/types.h"
#include "util/list.h"
#include "util/io.h"


static FILE* fperr = NULL;
static u32 (*tinghash_g)(const void* str) = mcxTingDPhash;

mcxstatus yamHashFie
(  const char* id
)
   {  if (!(tinghash_g = mcxTingHFieByName(id)))
      return STATUS_FAIL
   ;  return STATUS_OK
;  }


mcxHash* yamHashNew
(  int n
)
   {  return mcxHashNew(n, tinghash_g, mcxTingCmp)
;  }


void yamErrorFile
(  FILE* fp
)
   {  fperr = fp
;  }


void yamStats
(  void
)
   {  fprintf(stdout, "Zoem user table stats\n")
   ;  yamKeyStats()
   ;  fprintf(stdout, "Zoem primitive table stats\n")
   ;  yamOpsStats()
   ;  fprintf(stdout, "Scratch lengths\n")
   ;  yamScratchStats()
;  }


void  yam_err_
(  const char  *caller
,  const char  *fmt
,  va_list     *args
)
   {  const char* fname = sourceGetName()
   ;  FILE* fp = fperr ? fperr : stderr
   ;  if (*fname)
      mcxErrf
      (  fp
      ,  "zoem"
      ,  "error around input line <%d> in <%s>"
      ,  sourceGetLc()
      ,  fname
      )
   ;  else
      mcxErrf
      (  fp
      ,  "zoem"
      ,  "error occurred"
      )
   ;  if (key_g->str)
      mcxErrf(fp, NULL, "last key seen is <%s>", key_g->str)

   ;  if (caller)
      fprintf(fp, "___ [%s] ", caller)
   ;  else
      fprintf(fp, "___ ")
   ;  vfprintf(fp, fmt, *args)
   ;  fprintf(fp, "\n")
;  }


void  yamExit
(  const char  *caller
,  const char  *fmt
,  ...
)
   {  va_list  args
   ;  mcxTing* txt

   ;  if (caller)
      {  va_start(args, fmt)
      ;  yam_err_(caller, fmt, &args)
      ;  va_end(args)
   ;  }
      else
      {  txt = mcxTingNew("\\zinsert{stdia}")
      ;  fprintf(stdout, "\n")
      ;  yamOutput(txt, NULL, ZOEM_FILTER_DEFAULT)  
   ;  }

      mcxExit(1)
;  }


void  yamErr
(  const char  *caller
,  const char  *fmt
,  ...
)
   {  va_list  args

   ;  va_start(args, fmt)
   ;  yam_err_(caller, fmt, &args)
   ;  va_end(args)
;  }

void ting_stack_push
(  yamStack*   st
,  char*    str
,  int      len
)
   {  mcxLink* lk = st->sp
   ;  lk    =     lk->next
               ?  lk->next
               :  mcxLinkAfter(lk, NULL)
   ;  lk->val = mcxTingNWrite(lk->val, str, len)   /* fixme (NULL return) */
   ;  st->sp = lk
;  }


const char* ting_stack_pop
(  yamStack*   st
)
   {  const char* str = NULL
   ;  mcxLink* lk = st->sp

   ;  if (lk->prev)
      {  str =  ((mcxTing*) lk->val)->str
      ;  lk = lk->prev
      ;  st->sp = lk
   ;  }
      return str
;  }


void ting_stack_free
(  yamStack** stackp
)
   {  yamStack* stack = *stackp
   ;  mcxLink* lk = stack->sp
   ;  mcxTing* t

   ;  while (lk->next)
      lk = lk->next

   ;  while (lk->prev)
         t = (mcxTing*) lk->val
      ,  mcxTingFree(&t)
      ,  lk = lk->prev

   ;  mcxLinkFree(&lk, NULL)
   ;  mcxFree(stack)
   ;  *stackp = NULL
;  }


yamStack* ting_stack_new
(  int capacity
)
   {  yamStack* stack = mcxAlloc(sizeof(stack), EXIT_ON_FAIL)
   ;  stack->sp = mcxLinkNew(capacity, NULL, MCX_GRIM_ARITHMETIC)
   ;  return stack
;  }


void ting_stack_init
(  yamStack* stack
,  int capacity
)
   {  stack->sp = mcxLinkNew(capacity, NULL, MCX_GRIM_ARITHMETIC)
;  }


