/*
**
** substpat - a string substitution tool using regexp.library
** (c) 1998 by Matthias Bethke, Freeware
**
*/

#include <string.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <exec/memory.h>
#include <dos/rdargs.h>
#include <proto/regexp.h>


/* defines */
#define DEFAULTPROGNAME "substpat"
#define REGEXPNAME "regexp.library"
#define REGEXPVER 38
#define LINELEN 4096

/* protos & dummies */
static ULONG SubstLine(STRPTR,regexp*,STRPTR);
int CXBRK(void) { return 0; }
int _CXBRK(void) { return 0; }
void chkabort(void) {}



/* custom structures */
struct Arguments
{
	STRPTR pat;		// the pattern to look for
	STRPTR subst;	// the string to substitute for it
	LONG stats;		// output statistics
};


/* globals */
struct RegexpBase *RegexpBase;
static UBYTE ProgName[80]={0};
static struct Arguments args={0};
static UBYTE VersionString[] = "\0$VER: substpat V37.1 by M.Bethke "__AMIGADATE__;

LONG main(void)
{
LONG rcode=RETURN_OK;
struct RDArgs *Args;

	if(!GetProgramName(ProgName,sizeof(ProgName))) strcpy(ProgName,DEFAULTPROGNAME);

	if(RegexpBase = (struct RegexpBase*)OpenLibrary(REGEXPNAME,REGEXPVER))
	{
		if(Args = ReadArgs("Pattern/A,SubstString,Stats/S",(LONG*)(&args),NULL))
		{
		regexp *re;

			if(re = RegComp(args.pat))		// compile the expression
			{
			BPTR stdin;
			static UBYTE Line[LINELEN+2];	// 2 more bytes bcoz of an OS V37 bug in FGets()!
			ULONG nmatches=0, lines=0;

				stdin = Input();
				while(FGets(stdin,Line,LINELEN+1))	// iterate through all lines of input
				{
					lines++;
					nmatches += SubstLine(Line,re,args.subst);	// substitute and output line

					if(SetSignal(0,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)	// check for Ctrl-C
					{
						PutStr("*** Break\n");
						args.stats = 0;			// don't output stats
						break;
					}
				}
				if(args.stats) Printf("\n%s: replaced %ld occurences on %ld lines\n",ProgName,nmatches,lines);
				RegFree(re);
			} else
			{
			LONG err;

				err = IoErr();		// get error before doing anything that might alter IoErr()!
				Printf("%s: can't compile pattern \"%s\" - error: %s\n",ProgName,args.pat,RegXlatError(err));
				rcode = RETURN_ERROR;
			}
			FreeArgs(Args);
		} else
		{
			PrintFault(IoErr(),ProgName);
			rcode = RETURN_WARN;
		}
	} else
	{
		Printf("%s: can't open %s V%ld+!\n",ProgName,REGEXPNAME,REGEXPVER);
		rcode = RETURN_FAIL;
	}
	return rcode;
}

static ULONG SubstLine(STRPTR line, regexp *re, STRPTR subst)
{
STRPTR l,o;
static UBYTE OutLine[LINELEN+2];
LONG substlen,preflen;
BOOL HasMatched=FALSE;
ULONG nmatches=0;

	if(!(line && subst && re)) return 0;		// safety thing
	substlen = strlen(subst);						// determine substitute length for later use

	for(l=line,o=OutLine; (*l && o<(OutLine+LINELEN));)	// do until done with line
	{
		if(RegExec(re,l))							  	// check for match
		{
			HasMatched = TRUE;						// remember for later else-branch
			nmatches++;									// increment match counter
			preflen = re->startp[0] - l;			// length of part before first match
			if(o+preflen < OutLine+LINELEN)		// make sure we don't overwrite the
			{												// output buffer
				strncpy(o,l,preflen);				// copy the part before the match
				o += preflen;							// advance output pointer by length
			}
			if(o+substlen < OutLine+LINELEN)		// buffer overflow check again
			{
				strcpy(o,subst);						// write subst string
				o += substlen;							// advance by length of substitute
			}
			l = re->endp[0];							// advance input pointer to first
															// char after match
		} else											// if not matched
		{
			if(HasMatched)								// need to fill output buffer if
			{												// there was a match before
				while(*o++ = *l++) ;					// copy all remaining input to output
			} else										// if no match at all in this line
			{
				PutStr(line);							// just output the enire input
				return 0;								// and be done
			}
		}
	}
	*o = 0;												// make sure output is null-terminated
	PutStr(OutLine);									// write to stdout
	return nmatches;

}
