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

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

#ifdef HEADER

typedef struct SMChlin SMChlin;
struct SMChlin {
   int used;			// Input string used?
   char *freeme;		// To release string
   char *path;			// Path 
   int seq;			// Sequence number
   char *tail;			// Tail ('DEL' or an extended tree-line)
};

typedef struct SMMapch SMMapch;
struct SMMapch {
   char **inp;			// Input string reference
   char *out;			// Output string
   SMChlin aa, bb;		// Input lines (two to detect duplicates and bad sort order)
   SMTLin oo;			// Output line
   int end;			// Reached end?
};

#else

#include "all.h"


//
//	SMMapch
//

SMMapch *
smmapch(char **inp) {
   SMMapch *tt= ALLOC(SMMapch);

   tt->inp= inp;
   tt->aa.used= 1;
   tt->bb.used= 1;
   tt->oo.path= "";

   return tt;
}

#define USED(aa) (aa->used= 1)
#define RET(xx) { tt->out= xx; return 1; }

int 
smmapch_do(SMMapch *tt) {
   SMChlin *aa= &tt->aa;
   SMChlin *bb= &tt->bb;
   SMTLin *oo= &tt->oo;
   char *tmp;
   int len;
   char *p, *q, *nam;

   // Do nothing until our output has been cleared
   if (tt->out) return 0;
   if (tt->end) {
      tt->out= StrDup(SMEOF);
      return 0;
   }

   if (bb->used) {
      if (!*tt->inp) return 0;		// Wait for more data

      if (bb->freeme) free(bb->freeme);
      bb->used= 0;
      bb->freeme= 0;
      bb->path= bb->tail= "";

      if (!isEOF(*tt->inp)) {
	 char *seq;
	 bb->freeme= bb->path= *tt->inp;
	 *tt->inp= 0;

	 // Decode/check local-pc-changes line
	 p= strstr(bb->path, "\t\t");
	 if (!p) error("Bad local-pc-changes format line:\n  %s", bb->path);
	 *p= 0; p += 2;
	 seq= p; p= strchr(p, '\t');
	 if (!p) error("Bad local-pc-changes format line:\n  %s\t\t%s", bb->path, seq);
	 *p++= 0;
	 bb->tail= p;
	 bb->seq= strtol(seq, &p, 10);
	 if (*p) error("Bad sequence number in local-pc-changes line:\n  %s\t\t%s\t", bb->path, seq, bb->tail);
	 if (!starts_with(bb->tail, "Fu\t") &&
	     !starts_with(bb->tail, "Du\t") &&
	     !starts_with(bb->tail, "DEL"))
	    error("Bad local-pc-changes line tail part:\n  %s\t\t%s\t", bb->path, seq, bb->tail);
	 // Change tabs to slashes
	 for (q= bb->path; *q; q++) if (*q == '\t') *q= '/';
      }
   }

   if (aa->used) {
      memcpy(aa, bb, sizeof(*aa));
      memset(bb, 0, sizeof(*bb));
      bb->used= 1;
      return 1;
   }

   // Test ordering and skip dups
   if (aa->freeme && bb->freeme) { 
      int cmp= path_cmp(aa->path, bb->path);	
      if (cmp > 0)
	 error("Out of order paths in local-pc-changes:\n  %s\n  %s", aa->path, bb->path);
      if (cmp == 0) {
	 // Same path, select larger sequence number
	 if (aa->seq < bb->seq)
	    aa->used= 1;
	 else 
	    bb->used= 1;
	 return 1;
      }
   }      

   // Handle ending
   if (!aa->path[0]) {
      if (oo->path[0]) {
	 pathdel(oo);
	 RET(StrDupT("X", 0));
      }
      tt->end= 1;
      RET(StrDupT("END", 0));
   }

   if (!starts_with(aa->path, oo->path)) {
      // Exit directory
      pathdel(oo);
      RET(StrDupT("X", 0));
   }
 
   len= strlen(oo->path);
   p= aa->path + len;
   if (*p++ != '/') {
      // Exit directory (we happen to have found two directories
      // starting with the same string)
      pathdel(oo);
      RET(StrDupT("X", 0));
   }
   nam= p;
   q= strchr(p, '/');
   
   if (q) {
      // Enter a directory, copying mode/etc from target in 'aa'
      *q= 0;	// Temporarily modify aa->path
      pathadd(oo, nam);
      p= strchr(aa->tail, '\t');
      if (p) {
	 char *r= strchr(++p, '\t'); if (!r) DIE;
	 *r= 0; tmp= StrDupT("D", p, nam, 0); *r= '\t';
      } else 
	 tmp= StrDupT("D", "000777/0/0", nam, 0);
      *q= '/';	// Restore aa->path

      // Need to adjust the mode of the directory
      p= strchr(tmp, '/');	// Just after mode
      if (0 == memcmp(p-6, "SYMLNK", 6)) {
	 memcpy(p-6, "000700", 6);
      } else {
	 // Set 'x' bits of anything that has 'r' bit
	 if (isdigit(p[-1]) && (p[-1] & 4)) p[-1] |= 1;
	 if (isdigit(p[-2]) && (p[-2] & 4)) p[-2] |= 1;
	 if (isdigit(p[-3]) && (p[-3] & 4)) p[-3] |= 1;
      }
      RET(tmp);
   }

   // We are in the right directory for 'aa'
   if (starts_with(aa->tail, "DEL")) {
      // All deletions are passed on as a fake "Fd" line (even though
      // this may have been a directory that was deleted)
      USED(aa);
      RET(StrDupT("Fd", "000000/0/0", nam, "0/00000000", 0));
   }
   if (starts_with(aa->tail, "Du")) {
      pathadd(oo, nam);
      USED(aa);
      RET(StrDup(aa->tail));
   }
   if (starts_with(aa->tail, "Fu")) {
      USED(aa);
      RET(StrDup(aa->tail));
   }

   DIE;
}
   
void 
smmapch_del(SMMapch *tt) {
   free(tt->out);
   free(tt->aa.freeme);
   free(tt->bb.freeme);
   smtlin_del(&tt->oo);
   free(tt);
}

#endif

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