/*
 * entab.c - add tabs to a text file
 * by Bruce Momjian (root@candle.uucp)
 * ANSIfied and Amigaized by
 * Jörgen Grahn
 * Amiga version 1.0 1994-02-20
 * Below follows original code by Momjian,
 * modified as required.
 *
 */

/*
**	entab.c		- add tabs to a text file
**	by Bruce Momjian (root@candle.uucp)
**
**  version 0.9
**
**	tabsize = 4
**
*/

#include <exec/types.h>
#include <dos/rdargs.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/utility_protos.h>

#ifdef LATTICE
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/utility.h>
#endif

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUL		'\0'

#ifndef TRUE
#define	TRUE 	1
#endif
#ifndef FALSE
#define FALSE	0
#endif

extern struct SysBase		* SysBase;
extern struct DosLibrary	* DOSBase;
extern struct Library		* UtilityBase;

static char template[] =
	"NOTRAIL/S,DETAB/S,QUOTE/S,MINSPACE/N/K,TABSIZE/N/K,FILES/M";

static LONG	minspace = 2;
static LONG	tabsize = 8;

static char	* defaultnames[] = {NULL};

static LONG result[6] =
	{(LONG)FALSE, (LONG)FALSE, (LONG)FALSE,
		(LONG)&minspace, (LONG)&tabsize, (LONG)NULL};

static const char versionstring[] =	"$VER: entab 1.0 (20.2.94) "
									"Bruce Momjian/Jörgen Grahn";

int main(int argc, char **argv)
{
	int	tab_size,
		min_spaces,
		protect_quotes,
		del_tabs,
		clip_lines;

int		prv_spaces,
		col_in_tab,
		escaped,
		nxt_spaces;
	char in_line[BUFSIZ],
		 out_line[BUFSIZ],
		 *src,
		 *dst,
		 quote_char,
		 *cp;
	FILE	*in_file;

	struct RDArgs	 * anchor;
	char			** name;

	if(DOSBase->dl_lib.lib_Version < 36)
	{	exit(20);
	}

	UtilityBase = OpenLibrary("utility.library", 36);
	if(UtilityBase==NULL)
	{	exit(20);
	}

	cp = FilePart(argv[0]);

	if(Stricmp(cp,"detab")==0)
	{	result[1] = (LONG)TRUE;
	}
														 		 
	anchor = ReadArgs(template, result, NULL);
	if(anchor==NULL)
	{	CloseLibrary(UtilityBase);
		exit(10);
	}

#ifdef DEBUG
	printf("tab_size %ld, min_spaces %ld, protect_quotes %ld, del_tabs %ld, clip_lines %ld\n",
		*(LONG *)result[4], *(LONG *)result[3], result[2], result[1], result[0]);
#endif

	tab_size = *(LONG *)result[4],
	min_spaces = *(LONG *)result[3],
	protect_quotes = result[2],
	del_tabs = result[1],
	clip_lines = result[0];
	name = (char **)result[5];

	do
	{
		if(result[5]==0)
		{	in_file = stdin;
		}
		else
		{	if((in_file=fopen(*name,"r")) == NULL)
			{	fprintf(stderr, "Error: Can not open file %s\n", *name);
				name++;
				continue;
			}
			else
			{	name++;
			}
		}

		escaped = FALSE;

		while(fgets(in_line, BUFSIZ, in_file) != NULL)
		{
			col_in_tab = 0;
			prv_spaces = 0;
			src = in_line;		/* points to current processed char */
			dst = out_line;		/* points to next unallocated char */
			if(!escaped)
				quote_char = ' ';
			escaped = FALSE;
			while(*src != NUL)
			{
				col_in_tab++;
				if (*src == ' ' || *src == '\t')
				{
					if (*src == '\t')
					{
						prv_spaces = prv_spaces + tab_size - col_in_tab + 1;
						col_in_tab = tab_size;
					}
					else
						prv_spaces++;

					if (col_in_tab == tab_size)
					{
						/* Is the next character going to be a tab?
						   Needed to do tab replacement in current spot if
						   next char is going to be a tab, ignoring
						   min_spaces */
						nxt_spaces = 0;
						while (1)
						{
							if ( *(src+nxt_spaces+1) == NUL ||
							    (*(src+nxt_spaces+1) != ' ' &&
							     *(src+nxt_spaces+1) != '\t'))
								break;
							if (*(src+nxt_spaces+1) == ' ')
								++nxt_spaces;
							if (*(src+nxt_spaces+1) == '\t' || 
	 						    nxt_spaces == tab_size)
							{
								nxt_spaces = tab_size;
								break;
							}
						}
						if ((prv_spaces >= min_spaces || nxt_spaces == tab_size) &&
							 quote_char == ' ' &&
							 !del_tabs)
						{
							*(dst++) = '\t';
							prv_spaces = 0;
						}
						else
						{
							for (; prv_spaces > 0; prv_spaces--)
								*(dst++) = ' ';
						}
					}
				}
				else
				{
					for (; prv_spaces > 0; prv_spaces--)
						*(dst++) = ' ';
					if (*src == '\b')
						col_in_tab -= 2;
					if (!escaped && protect_quotes)
					{
						if (*src == '\\')
							escaped = TRUE;
						if (*src == '"' || *src == '\'')
							if (quote_char == ' ')
									quote_char = *src;
							else if (*src == quote_char)
									quote_char = ' ';
					}
					else
						if (*src != '\r' && *src != '\n')
							escaped = FALSE;
							
					if (( *src == '\r' || *src == '\n') &&
						clip_lines && !escaped)
					{
						while (dst > out_line &&
							  (*(dst-1) == ' ' || *(dst-1) == '\t'))
									dst--;
						prv_spaces = 0;
					}
					*(dst++) = *src;
				}
				col_in_tab %= tab_size;
				++src;
			}
			/* for cases where the last line of file has no newline */
			if (clip_lines && !escaped)
			{
				while (dst > out_line &&
					  (*(dst-1) == ' ' || *(dst-1) == '\t'))
							dst--;
				prv_spaces = 0;
			}
			for (; prv_spaces > 0; prv_spaces--)
				*(dst++) = ' ';
			*dst = NUL;
			if(fputs(out_line,stdout) == EOF)
				fprintf(stderr, "Error writing output.\n");
		}
	}while(name!=NULL && *name!=NULL);

	FreeArgs(anchor);
	CloseLibrary(UtilityBase);

	exit(0);
}
