
/******** rep.c by Dimitri C. Keletsekis - 28 November 1996 ************

This code compiles into 820 bytes of executable re-entrant CLI command
for replacing strings in files. It can be compiled with SAS C 6.50+. 
The SCOPTIONS file is included. Just do <sc rep link> to produce it.

It's may not be the best, it may not be the fastest, but it works..

It uses the NOSTARTUP compiler option which means that it compiles
without *any* start-up code from the compiler. It's one function with
no global variables.

*************************************************************************/

#include <exec/exec.h>
#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/rdargs.h>
#include <dos/dostags.h>

#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <dos.h>

#include <proto/dos.h>
#include <proto/exec.h>


int rep(void)
{
struct DosLibrary  *DOSBase=NULL;
struct RDArgs *rdargs = NULL;
unsigned char *file, *str, *repstr, dest[256];
long rc;
long args[4];
struct FileInfoBlock *fib=NULL;
unsigned char *buff=NULL;
BPTR fp;
LONG buffsize, sz;
int err = 0;
register unsigned char *p, *d, *t;
unsigned char *endfile;
BOOL flag = 0;

rc = 10;   /* return code */

if (!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 36L)))
{ Write (Output(), "Need newer OS\n", 14);
  goto endprog;
}

memset((char *)args, 0, sizeof(args));
rdargs = ReadArgs("FILE/A,STRING/A,NEWSTRING/A,NEWFILE", args, NULL);
if (!rdargs)
{ Write (Output(), "Wrong arguments\n", 16);
  goto endprog;
}

file   = (char *)args[0];
str    = (char *)args[1];
repstr = (char *)args[2];
if (args[3])
    strcpy (dest, (char *)args[3]);
else
    strcpy (dest, (char *)args[0]);

/*------------------------------ read file ------------------------*/

if (!(fp = Open (file, MODE_OLDFILE))) 
{  Write (Output(), "Could not open file\n", 20);
   goto endprog;
}

if (fib = (struct FileInfoBlock *)AllocVec(sizeof(struct FileInfoBlock), MEMF_CLEAR))
{   if (ExamineFH(fp, fib))
    {   buffsize = fib->fib_Size;
        if (buff = (unsigned char *)AllocVec(buffsize + 32, MEMF_CLEAR))
        {   sz = Read (fp, buff, buffsize);
	    if (sz != buffsize) ++err;
            endfile = &buff[sz];
        }
    }
    FreeVec (fib);
}
Close (fp);

if (err)
{  Write (Output(), "Error reading file\n", 19);
   goto endprog;
}
else if (!buff)
{  Write (Output(), "No memory!\n", 11);
   goto endprog;
}

/*---------------------------- do replace ---------------------*/

if (!(fp = Open (dest, MODE_NEWFILE)))
{  Write (Output(), "Error writing file\n", 19);
   goto endprog;
}
p = buff;

while (p < endfile)
{
   if (*p == *str)
   {   t = p;
       d = str;
       while ((*d) && (*t) && (*d == *t)) { ++t; ++d; }
       if (*d == 0) 
       {   --t;
           p = t;
           if (EOF == (int)(FPuts (fp, repstr))) goto endflag;
       }
       else
           if (EOF == (int)(FPutC (fp, *p))) goto endflag;
    }
    else
       if (EOF == (int)(FPutC (fp, *p))) goto endflag;

    ++p;
}

rc = 0;
goto endnoflag;  /* i.e. skip error report */

endflag:
Write (Output(), "Error writing file\n", 19);

endnoflag:
Close (fp);

endprog :
if (rdargs)  FreeArgs (rdargs);
if (buff)    FreeVec (buff);
if (DOSBase) CloseLibrary((struct Library *)DOSBase);
return (rc);
}

