#include "Replace.h"

STXT VersTag[]		= "$VER: " VSTR;
STXT CompileNo[]	= "Compiled on " __DATE__ " at " __TIME__;
STXT Copyright[]	= "Copyright © 1994,95 Klaus Alexander Seistrup @ Magnetic Ink";
STXT EMail[]		= "E-mail: kas@mink.ping.dk";

STXT LFFmt[]		= "%s\n";

CFG	 GlobCFG;

TEXT RBuf[RBUFSIZE];


Prototype LONG	 stricmp(TEXT *,TEXT *);
//
LONG
stricmp(s1,s2)
TEXT *s1,*s2;
{
	return (Strnicmp(s1,s2));
}


Prototype LONG	 strnicmp(TEXT *,TEXT *,LONG);
//
LONG
strnicmp(s1,s2,n)
TEXT *s1,*s2;
LONG n;
{
	return (Strnicmp(s1,s2,n));
}


Prototype VOID	 BadFile(TEXT *,TEXT *,TEXT *);
//
VOID
BadFile(pgm,typ,fil)
TEXT *pgm,*typ,*fil;
{
	extern volatile int errno;

	int err = errno;

	fprintf(stderr,"›33m%s:›0m Couldn't open %sput file ›3m%s›0m\n",pgm,typ,fil);
	fprintf(stderr,"Error %ld: %s\n",err,strerror(err));
	exit(10);
}


Prototype VOID	 BadParm(TEXT *,TEXT *);
//
VOID
BadParm(pgm,parm)
TEXT *pgm,*parm;
{
	fprintf(stderr,"›33m%s:›0m Mandatory ›3m%s›0m parameter missing!\n",pgm,parm);
	exit(10);
}



Prototype VOID	 About(VOID);
//
VOID
About(VOID)
{
	fprintf(stderr,LFFmt,VersTag+6);
	fprintf(stderr,LFFmt,CompileNo);
	fprintf(stderr,LFFmt,Copyright);
	fprintf(stderr,LFFmt,EMail);
}


Prototype VOID	 Usage(TEXT *);
//
VOID
Usage(pgm)
TEXT *pgm;
{
	fprintf(stderr, \
"›33mUSAGE:›0m ›1m%s›0m ›2m[›0m-i›3minFile›0m›2m] [›0m-o›3moutFile›0m›2m] <›0m-s›3msearchStr›0m›2m> <›0m-r›3mreplaceStr›0m›2m> [›0m-0›3mzeroAlias›0m›2m] [›0m-c›2m] [›0m-v›2m]›0m\n" \
"\n" \
"\t-›1mi›0m Optional ›3minput›0m file (default: stdin)\n" \
"\t-›1mo›0m Optional ›3moutput›0m file (default: stdout)\n" \
"\t-›1ms›0m Mandatory ›3msearch›0m string\n" \
"\t-›1mr›0m Mandatory ›3mreplace›0m string\n" \
"\t-›1m0›0m Set ASCII zero alias for search/replace (not yet implemented)\n" \
"\t-›1mc›0m Use case-sensitive search routine (default: case-insensitive)\n" \
"\t-›1mv›0m Verbose (report number of successful search/replace)\n",pgm);

}


Prototype TEXT	*transmogrify(TEXT *);
//
TEXT *
transmogrify(src)
TEXT *src;
{
	TEXT *dst = src;
	TEXT *ptr = dst;

	if (src)
	{
		BOOL flg = 0;
		long len = 2;

		while (*ptr)
		{
			if (*ptr == 0x5C)	// BackSlash
				flg = 1;

			++ptr;
			++len;
		}

		if (flg)
		{
			TEXT c;

			dst = malloc(len);

			if (dst == NULL)
			{
				fputs("Not enough memory!\n",stderr);
				exit(20);
			}
			ptr = dst;

			while (c = *src)
			{
				if (c == 0x5C)
				{
					TEXT *tail;
					long v;

					++src;

					switch (*src)
					{
						case 0x5C:
							*ptr = c;
							break;
						case 0x00:
							--src;
							break;
						default:
							v = strtol(src,&tail,0);
							
							if (v == 0)
							{
								fputs("Conversion error - check escaped chars!\n",stderr);
								exit(10);
							}
							*ptr = (TEXT) (v & 0x00FFL);
							src  = tail;
							--src;
					}
				}
				else
					*ptr = c;

				++src;
				++ptr;
			}
			*ptr = 0;
		}
	}
	return (dst);
}

Prototype CFG	*InitCFG(LONG,TEXT **);
//
CFG *
InitCFG(argc,argv)
LONG argc;
TEXT **argv;
{
	CFG  *cfg = &GlobCFG;
	TEXT *pgmName = FilePart(argv[0]);

	bzero(cfg,sizeof(*cfg));

	cfg->cfg_fi = stdin;
	cfg->cfg_fo = stdout;
	cfg->cfg_fe = freopen("Console:","w+",stderr);

	if (cfg->cfg_fe)
	{
		int i;

		if (argv[1][0] == '?')
		{
			Usage(pgmName);
			exit(1);
		}

		for (i = 1 ; i < argc ; ++i)
		{
			TEXT *ptr = argv[i];

			if (*ptr == '-')
			{
				ptr += 2;

				switch (ToLower(ptr[-1]))
				{
					case 'c':
						cfg->cfg_case = TRUE;
						break;
					case 'i':
						if (*ptr)
							cfg->cfg_in = ptr;
						else
							cfg->cfg_in = argv[++i];
						break;
					case 'o':
						if (*ptr)
							cfg->cfg_out = ptr;
						else
							cfg->cfg_out = argv[++i];
						break;
					case 'r':
						if (*ptr)
							cfg->cfg_replace = ptr;
						else
							cfg->cfg_replace = argv[++i];
						break;
					case 's':
						if (*ptr)
							cfg->cfg_search = ptr;
						else
							cfg->cfg_search = argv[++i];
						break;
					case '0':
					case 'z':
					case 'n':	// Zero-alias not yet implemented...
						break;
					case 'v':
						cfg->cfg_verbose = TRUE;
						break;
					case 'a':
						About();
						exit(1);
					case '?':
					case 'h':
						Usage(pgmName);
						exit(1);
					default:
						fprintf(cfg->cfg_fe,"›33m%s:›0m Unrecognized option ›1m%c›0m\n",pgmName,ptr[-1]);
						Usage(pgmName);
						exit(5);
				}
			}
		}

		if (cfg->cfg_in && cfg->cfg_out)
		{
			if ((Stricmp(cfg->cfg_in,cfg->cfg_out) == 0) || (Stricmp(cfg->cfg_out,"-") == 0))
			{
				long  len = strlen(cfg->cfg_in) + 3L;
				char *new = malloc(len);

				if (new == NULL)
				{
					fprintf(cfg->cfg_fe,"›33m%s:›0m Insufficient memory!\n",pgmName);
					exit(20);
				}
				sprintf(new,"%s~",cfg->cfg_in);

				if (Rename(cfg->cfg_in,new) == 0)
				{
					(VOID) DeleteFile(new);

					if (Rename(cfg->cfg_in,new) == 0)
					{
						fprintf(cfg->cfg_fe,"›33m%s:›0m Can't rename ›3m%s›0m as ›3m%s›0m!\n",pgmName,cfg->cfg_in,new);
						exit(20);
					}
				}
				cfg->cfg_out = cfg->cfg_in;
				cfg->cfg_in	 = new;
			}
		}

		if (cfg->cfg_in)
			if ((cfg->cfg_fi = freopen(cfg->cfg_in,"r",stdin)) == NULL)
				BadFile(pgmName,"in",cfg->cfg_in);

		if (cfg->cfg_out)
			if ((cfg->cfg_fo = freopen(cfg->cfg_out,"w",stdout)) == NULL)
				BadFile(pgmName,"out",cfg->cfg_out);

		if (cfg->cfg_search == NULL)
			BadParm(pgmName,"search");

		cfg->cfg_search	= transmogrify(cfg->cfg_search);
		cfg->cfg_slen	= strlen(cfg->cfg_search);

		if (cfg->cfg_replace == NULL)
			BadParm(pgmName,"replace");

		cfg->cfg_replace = transmogrify(cfg->cfg_replace);
		cfg->cfg_rlen	 = strlen(cfg->cfg_replace);

		if (cfg->cfg_case)
			cfg->cfg_comp = strncmp;
		else
			cfg->cfg_comp = strnicmp;

		return (cfg);
	}
	fprintf(cfg->cfg_fo,"›33m%s:›0m Error stream wouldn't open...\n",pgmName);
	exit(20);
}


/*
**	USAGE: Replace [-iinFile] [-ooutFile] <-ssearchStr> <-rreplaceStr> [-c] [-v]
*/
void
main(ac,av)
int ac;
char **av;
{
	CFG *cfg = InitCFG((LONG)ac,(TEXT **)av);
	LONG  bsiz = RBUFSIZE-1;
	TEXT *rbuf = RBuf;
	TEXT *ptr;

	while (ptr = fgets(rbuf,bsiz,cfg->cfg_fi))
	{
		int slen = strlen(ptr);			
		int ccnt = 0;

		while (ccnt < slen)
		{
			if (cfg->cfg_comp(cfg->cfg_search,&ptr[ccnt],cfg->cfg_slen) != 0)
			{
				fputc(ptr[ccnt],cfg->cfg_fo);
				++ccnt;
			}
			else
			{
				fwrite(cfg->cfg_replace,1,cfg->cfg_rlen,cfg->cfg_fo);
				++(cfg->cfg_count);
				ccnt += cfg->cfg_slen;
			}
		}
	}

	if (cfg->cfg_verbose)
	{
		if (cfg->cfg_count)
			fprintf(cfg->cfg_fe,"Replaced %ld occurrances of ›3m%s›0m with ›3m%s›0m\n",cfg->cfg_count,cfg->cfg_search,cfg->cfg_replace);
		else
			fprintf(cfg->cfg_fe,"No matches found...\n");
	}
	exit(0);
}


/*
**	EOF
*/
