
#include "ops-xtag.h"

#include <ctype.h>

#include "util.h"
#include "segment.h"
#include "digest.h"

#include "util/types.h"
#include "util/ding.h"
#include "util/list.h"


yamSeg* yamXtag
(  yamSeg*  seg
,  mcxTing* dev      /* if dev->len == 0, implicit closing tag */
,  mcxTing* arg
)
   {  mcxTing* txt = mcxTingEmpty(NULL, 80)
   ;  char* me =  arg ? "\\<>#2" : "\\<>#1"
   ;  mcxbool ok = TRUE
   ;  mcxbits flags = 0
   ;  yamStack* xmlStack = currentXmlStack()

   ;  if (yamDigest(dev,dev, seg))
      ok = FALSE

   ;  if (ok && arg && yamDigest(arg, arg, seg))
      ok = FALSE

   ;  if (!ok)
      ;
            /*  we interpret, but keep syntax as is, so that the thing
             *  will pass again through this routine in OUTPUT mode.
            
             *  Why? because otherwise everything is stuffed in \@{<..>} scope
             *  (and invisible to (repeated) interpretation).
             *  Perhaps it'd be better to stuff it in \@{<} .. \@{>} scope.
            */
      else if (seg->flags & SEGMENT_DIGEST)
      {  if (arg)
         mcxTingPrint(txt, "\\<%s>{%s}", dev->str, arg->str)
      ;  else
         mcxTingPrint(txt, "\\<%s>", dev->str)
      ;  flags |= SEGMENT_CONSTANT
   ;  }
      else
      while(1)
      {  ok = FALSE
                      /*  if branch: close tag, either explicit or implicit
                      */
      ;  if (*(dev->str) == '/' || !dev->len)
         {  const char* otag = NULL

         ;  if (arg)
            {  yamErr(me, "No arguments allowed with closing tag")
            ;  break
         ;  }

            if (!(otag = ting_stack_pop(xmlStack)))
            {  yamErr
               (  me
               ,  "XML syntactic sugar stack underflow at tag </%s>"
               ,  dev->len ? dev->str+1 : ""
               )
            ;  break
         ;  }

            if (dev->len && strcmp(dev->str+1, otag))
            {  yamErr(me, "tag </%s> closes <%s>", dev->str+1, otag)
            ;  break
         ;  }
            mcxTingPrint(txt, "\\@{\\N\\J</%s>\\N}", otag)
      ;  }

           /*  open tag.
           */
         else
         {  char* p           =  mcxStrChrIs(dev->str, isspace, -1)
         ;  int taglen        =  p ? p - dev->str : dev->len
         ;  int devlen        =  dev->len
         ;  char z            =  *(dev->str+dev->len-1)
         ;  mcxbool closing   =  z == '/' || z == '!' 
         ;  mcxbool opening   =  !arg && !closing

         ;  if (z == '!')     /* this makes \<br!> work */
            devlen -= 1

         ;  if (closing && arg)               
            {  yamErr(me, "no args allowed with closing syntax <%s>", dev->str)
            ;  break
         ;  }

            if (opening)
            ting_stack_push(xmlStack, dev->str, taglen)
               /* fixme check (alloc) error */

         ;  txt =
            arg
            ?  mcxTingPrint
               (  txt
               ,  "\\@{<%s>}%s\\@{</%.*s>}"
               ,  dev->str
               ,  arg->str
               ,  taglen
               ,  dev->str
               )
            :  opening
               ?  mcxTingPrint
                  (  txt
                  ,  "\\@{\\N<%.*s>\\N\\I}"
                  ,  devlen
                  ,  dev->str
                  )
               :  mcxTingPrint
                  (  txt
                  ,  "\\@{<%.*s>}"
                  ,  devlen
                  ,  dev->str
                  )
            ;
         }
         ok = TRUE
      ;  break
   ;  }

      seg_check_ok(ok, seg)

   ;  mcxTingFree(&dev)
   ;  mcxTingFree(&arg)

   ;  return yamSegPushx(seg, txt, flags)
;  }


void mod_xtag_exit
(  void
)
   {
;  }

void mod_xtag_init
(  void
)
   {
;  }



