/*
          EnTab - Replace blanks with TABs whenever possible.

          Based on the entab program by Gary Brant found on <>< 179.
          ARP and Resident support by Fabio Rossetti.

          (c) 1989 by Fabio Rossetti

          To compile under Lattice C v5.0x use:

		lc -O -v -cus entab
		blink lib:cres.o entab.o to entab lib lib:a.lib lib:lc.lib sd nd

*/

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/arpbase.h>
#include <arpfunctions.h>

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

struct ArpBase *ArpBase=NULL;
struct Process *Pr;
LONG argc;

#define NARGS 3
#define BFSIZE 256	
#define FROM	argv[0]
#define TO	argv[1]
#define TAB	argv[2]

STRPTR argv[NARGS];

struct UserAnchor {
	struct	AnchorPath	ua_AP;
	BYTE	moremem[255];	/* extension */
};
struct	UserAnchor *Anchor=NULL;

/* Trick to keep code down to size */
VOID MemCleanup()
{
}

/* shutdown routine */
VOID Cleanup(r1,r2,msg)
LONG r1,r2;
STRPTR msg;
{
	if (msg) Puts(msg);
	if (ArpBase) CloseLibrary((struct Library *)ArpBase);
	Pr->pr_Result2 = r2;
	exit(r1);
}

#define MAXLINE 256

char tabarray[MAXLINE];


VOID _main(Line)
STRPTR Line;

{

   int i = 0, j, k, l, ntabs = 0, tabstop = 8;
   int argtabs[99];
   char ch;
   char **Argv;
	BPTR fh,ofh;



	Pr = (struct Process*)FindTask(NULL);
	
	if(!(ArpBase = (struct ArpBase*)OpenLibrary(ArpName,ArpVersion)))
			Cleanup(RETURN_FAIL,ERROR_INVALID_RESIDENT_LIBRARY,NULL);
	
	/* parse command line */
	for (argc=0;argc < NARGS ;++argc)
		argv[argc] = (STRPTR) NULL;

	while(*Line > ' ')
		++Line;

	if((argc = GADS(++Line,
		strlen(Line),
		"Usage: EnTab [FROM Pattern] [TO Filename] [TAB tabsize [tabsize ..] ]",
		argv,
		"FROM,TO,TAB/..." )) < 0)
			Cleanup(RETURN_WARN,NULL,FROM);


   /* decode tabstop arguments */
   Argv = (char **)TAB;
   while ((Argv[i] != NULL)) {
      j = 0;
      tabstop = 0;
      while ((ch = (char)Argv[i++][j++]) != '\0') {
     if (ch >= '0' && ch <= '9') {
        tabstop *= 10;
        tabstop += ch - '0';
     } else
        Cleanup(RETURN_WARN,NULL,"Bad args");
      }
      argtabs[ntabs++] = tabstop;
   }

   /* fill tabarray with \1 for each tabstop position */
   for (k = 0; k < MAXLINE; k++)
      tabarray[k] = '\0';
   if (ntabs > 1)
      for (k = 0; k < ntabs; k++)
     if ((l = argtabs[k]-1) < MAXLINE)
        tabarray[l] = '\001';
     else
        Cleanup(RETURN_WARN,NULL,"Bad tab specification");
   else if ((tabstop > 0) && (tabstop < MAXLINE))
      for (k = tabstop; k < MAXLINE; k += tabstop)
     tabarray[k] = '\001';
   else Cleanup(RETURN_WARN,NULL,"Bad tab specification");


	if ( Anchor = (struct UserAnchor *)ArpAlloc( (ULONG)sizeof( *Anchor )) )
	{
		Anchor->ua_AP.ap_Length = 255;	/* Want full path built */
		
	}
	else Cleanup(RETURN_FAIL,ERROR_NO_FREE_STORE,"Error:No memory");
	
	if (FROM)  {

	if (!(FindFirst(FROM,(struct AnchorPath*) Anchor)))
		if (Anchor->ua_AP.ap_Info.fib_DirEntryType < 0) {
			if(!(fh=ArpOpen(Anchor->ua_AP.ap_Buf,MODE_OLDFILE))) {
				Printf("Can't open %s\n",FROM);
				Cleanup(RETURN_ERROR,ERROR_OBJECT_NOT_FOUND,NULL);
				}
			}
		else {
			Printf("%s is a directory !\n",TO);
			Cleanup(RETURN_ERROR,ERROR_OBJECT_WRONG_TYPE,NULL);
			}
		else {
			Printf("Can't find %s\n",FROM);
			Cleanup(RETURN_ERROR,ERROR_OBJECT_NOT_FOUND,NULL);
			}
		}
	else fh = Input();

	if(TO) {
			if(!(ofh=ArpOpen(TO,MODE_NEWFILE))) {
				Printf("Can't open %s\n",TO);
				Cleanup(RETURN_ERROR,ERROR_OBJECT_NOT_FOUND,NULL);
				}
			}
	else ofh = Output();

        entab (fh,ofh);

	Cleanup(NULL,NULL,NULL);

}

/* entab - remove the tabs from one file */

entab (ifile,ofile)
BPTR ifile,ofile;
{
   int n;
   char inline[MAXLINE],Buf[MAXLINE], outline[MAXLINE];

register int count, obp=0;
register char *il = inline;

/* read lines */
for (;;) {
if (!obp) if (!(count = Read(ifile,Buf,BFSIZE))) {		
			return(0);
			}

if (*(Buf + obp) == '\n') {
		++obp;
		*il = '\0';
		il = inline;

		if (SetSignal(0,0) & SIGBREAKF_CTRL_C) 
		Cleanup(RETURN_WARN,NULL,"***Break");


      n = strlen (inline);
      while (--n >= 0)            /* back over white space */
     if (inline[n] != ' ' && inline[n] != '\t' &&
        inline[n] != '\n') break;
      inline[n+1] = '\0';
      compress (inline, outline, MAXLINE);
      FPrintf(ofile,"%s\n",outline);
   }
else {
	if (((char *)il - (char *)inline) > MAXLINE) 
			Cleanup(RETURN_FAIL,NULL,"Buffer overflow");
	*il++ = *(Buf + obp++);
	}
if (obp == count) obp = 0;
}
}



/* compress - compress one line, replacing strings of blanks with tabs    *
 * to tab stops specified on command line or default            */

compress (in, out, lim)
char in[], out[];
int  lim;
{
   register int i = 0, j = 0;
   register char ch;

   while (((ch = in[i++]) != '\0') && (i < lim)) {
      if (ch == ' ') {
     register int k = i, tc;
     while (((tc = tabarray[k]) == '\0') && (in[k] == ' ') && (k < lim))
        k++;
     if ((tc == '\001') && (k > i))
        out[j++] = '\t';
     else            /* avoid running through this again next trip */
        while (i++ <= k)
           out[j++] = ch;
     i = k;
      } else if (ch == '\042' || ch == '\047') {
     register int tc;        /* avoid tabbing quoted strings */
     out[j++] = ch;
     while (((tc = in[i++]) != ch) && (i < lim)) {
        if (tc == '\134') {     /* possible protected quote */
           out[j++] = tc;
           tc = in[i++];
           if (i == lim) break;
        }
        out[j++] = tc;
     }
     out[j++] = ch;
      } else
     out[j++] = ch;
   }
   out[j] = ch;
}

