/*///---------------------------------------------------------------------\\\*/
/*// Copyright (c)               (_)/=\~/_(_)         All rights reserved. \\*/
/*/  2005-2006                (_)  /=\  ~/_  (_)        Released under the  \*/
/*\  Jim Peters            (_)    /=\    ~/_    (_)             GNU GPL v2  /*/
/*\\ http://uazu.net    (_) ____ /=\ ____ ~/_ ____ (_)      http://fsf.org //*/
/*\\\---------------------------------------------------------------------///*/

//
//	SMDiff -- see SYMIRR.jot for docs
//   

#ifdef HEADER

typedef struct SMDiff SMDiff;
struct SMDiff {
   char **inp1;			// Input string reference
   char **inp2;			// Input string reference
   char *out;			// Output string
   char *out2;			// Waiting output string
   int acc;			// Accumulating: 'c' copies, 's' skips
   int cnt;			// Count for accumulator
   int lev_aa, lev_bb;		// D/X nesting level on two inputs
   int end;			// Reached end?
};


#else

#include "all.h"


//
//	SMDiff
//

SMDiff *
smdiff(char **inp1, char **inp2) {
   SMDiff *tt= ALLOC(SMDiff);

   tt->inp1= inp1;
   tt->inp2= inp2;

   return tt;
}

#define ADJUST_LEVEL(aa) tt->lev_##aa += (aa[0] == 'X' ? -1 : aa[0] == 'D' ? 1 : 0)
#define PREFIX_ACC if (tt->cnt) { tt->out2= tt->out; tt->out= StrDupF("%c%d", tt->acc, tt->cnt); tt->cnt= 0; }

#define USED(aa) { *p##aa= 0; ADJUST_LEVEL(aa); free(aa); }
#define RET_USED(aa) { *p##aa= 0; ADJUST_LEVEL(aa); tt->out= aa; PREFIX_ACC; return 1; }

#define RET_CS(ch) { \
  if (tt->acc != ch) { \
    if (tt->cnt) { tt->out= StrDupF("%c%d", tt->acc, tt->cnt); tt->cnt= 0; }  \
    tt->acc= ch; }  \
  tt->cnt++; return 1; }


int 
smdiff_do(SMDiff *tt) {
   char **paa, **pbb;
   char *aa, *bb;
   char *p, *q;

   if (tt->out) return 0;		// Nothing to do until our output has been cleared

   // Waiting output line
   if (tt->out2) { tt->out= tt->out2; tt->out2= 0; return 1; }
   if (tt->end) { tt->out= StrDup(SMEOF); return 0; }

   paa= tt->inp1;
   pbb= tt->inp2;
   aa= *paa;
   bb= *pbb;
   if (!aa || !bb) return 0;	// Wait for input
   if (isEOF(aa) || isEOF(bb)) DIE;	// Should have 'END' before EOF

   if (str_eq(bb, "END")) {
      // END is output right away, as itself, closing the diff
      tt->end= 1;
      RET_USED(bb);
   }

   if (tt->lev_aa > tt->lev_bb) {
      // 'aa' is in subdirectories; keep skipping until we get back level
      USED(aa);
      RET_CS('s');
      return 1;
   }
      
   if (tt->lev_bb > tt->lev_aa) {
      // 'bb' is in subdirectories; keep outputting until we get back level
      RET_USED(bb);
   }

   if (str_eq(aa, bb)) {
      // Same string, copy
      USED(aa); USED(bb);
      RET_CS('c');
   }

   // See if we can work through in name order (handles FF/FD/DF/DD)
   p= strchr(aa, '\t'); if (p) p= strchr(p, '\t');
   q= strchr(bb, '\t'); if (q) q= strchr(q, '\t');
   if (p && q) {
      int cmp= strcmp(p, q);
      if (cmp < 0) {
	 USED(aa);
	 RET_CS('s');
      }
      RET_USED(bb);
   }

   // Otherwise just copy out 'bb' and go from there (XF/XD/FX/DX)
   RET_USED(bb);
}
   
void 
smdiff_del(SMDiff *tt) {
   free(tt->out);
   free(tt->out2);
   free(tt);
}

#endif

/*///---------------------------------------------------------------------\\\*/
/*// )`( )()/)(`/\`//\`          (_)/=\~/_(_)           '/\\'/\')(\()( )'( \\*/
/*/ ()(')()\)(/`/\\ `         (_)  /=\  ~/_  (_)          ' //\'\)(/()(`)() \*/
/*\  )`()( )(/'            (_)    /=\    ~/_    (_)             `\)( )()'(  /*/
/*\\  ()()(`)(/         (_) ____ /=\ ____ ~/_ ____ (_)          \)(')()()  //*/
/*\\\---------------------------------------------------------------------///*/
