/*************************************************************************
*	GetRefs.c
*	( if it looks yucky, set tabstops to 4 )
*
*	Program to extract a section of a file.  Primarily for use with the
*	AREXX referencing macro and TxEd Plus, it can also be used as a 
*	standalone program.
*
*	The program takes 1 command line argument.  If any other number
*	is supplied, the program will exit with an error.  The argument is
*	an ascii string that should match one of the entries in the reference
*	file.  
*	The program writes the extracted text to the file ram:extract.txt
*
*	Programmed by John G. Hardie
*	This program is in the public domain, do with it what you will.
*
*	Compiled under Lattice C v4.0 ( lc -v -b -r getrefs )
*	and Blink 7.2 (blink with lc.lib, amiga.lib, SD SC ND)
**************************************************************************/
#include "libraries/dosextens.h"
#include "stdio.h"
#include "string.h"
#include "ctype.h"

/*	Prototypes */
int stringcmp(char *,char *,int *);
void scopynull(char *,char *);

struct Process *HereWeAre;

main(argc,argv)
int argc;
char **argv;
{
	FILE *infile,*outfile;
	char line[256],searchstr[256],*str,found=0,inch,*sarg[5];
	int leng,locate;

	HereWeAre = (struct Process *)FindTask(0);

	if (argc != 2)
	{
		puts("Bad command line - you must supply 1 parameter");
		seterror(50);
		Exit(20);	/* bad command line - go away */
	}
	
	/* we search for the reference file in df1:s df0:s and ram:s */
	/* before we give up and go away							 */
	if (!(infile = fopen("df1:s/txed.refs","r")))
	if (!(infile = fopen("df0:s/txed.refs","r")))
	if (!(infile = fopen("ram:s/txed.refs","r")))
	{
		puts("Error - couldn't open input file");
		seterror(51);
		Exit(20);	/* Huh? where the hell is it? */
	}
	
	/* Try to find the keyword string in the file. */
	leng = strlen(argv[1]);
	while (str = fgets(line,256,infile))
	{
		if (stringcmp(str,argv[1],&locate) == leng)
		{
			/* we want an exact match, no partials e.g 		 */
			/* Open and OpenLibrary don't match in this case */
			if (isspace(*(str+locate+leng)))
			{
				found++;
				break;
			}
		}
	}
	
	/* Did we find the string or run out of input file? */
	if (!found)
	{
		puts("Reference String Not Found");
		fclose(infile);
		seterror(52);
		Exit(20);  /* nope, didn't find it <sigh> */
	}

	/* get the start, stop, and filename from the input line */
	scopynull(line,searchstr);
	if ((leng = strbpl(sarg,6,searchstr)) != 4)
	{
		puts("Bad Line format in ref file");
		fclose(infile);
		seterror(53);
		Exit(20);
	}
	fclose(infile);

	/* Open the search file and commence much looking about */
	if (!(infile = fopen(sarg[2],"r")))
	{
		puts("Error - couldn't open input file");
		seterror(54);
		Exit(20);	/* Huh? where the hell is it? */
	}
	
	/* Try to find the start string in the file. */
	leng = strlen(sarg[3]);
	while (fgets(line,256,infile))
	{
		if (stringcmp(line,sarg[3],&locate) == leng)
		{
			found++;
			break;
		}
	}
	
	/* Did we find the string or run out of input file? */
	if (!found)
	{
		puts("Could not find referenced text");
		fclose(infile);
		seterror(55);
		Exit(20);  /* Ah well, can't have everything (anything?) */
	}

	/* Ok, we found it, now try to open the output file */
	if (!(outfile = fopen("ram:extract.txt","w")))
	{
		puts("Error - Couldn't open the output file");
		fclose(infile);
		seterror(56);
		Exit(20);	/* bad news - something is seriously broke */
	}
	
	/* Write the matching line to the output file, and commence copying */
	fputs(line,outfile);
	found = 0;
	
	/* if stop string is a ^L must read char by char mainly because */
	/* I was too lazy to figure out a more efficient way to do it.  */
	if (!stricmp(sarg[1],"^L"))
	{
		while ((inch = fgetc(infile)) != EOF)
		{
			if (inch == 0xC)
			{
				found++;
				break;
			}
			fputc(inch,outfile);	/* we don't want to write the ^L */
		}							/* it makes reading difficult    */
	}
	else	/* otherwise read a line at a time */
	{
		leng = strlen(sarg[1]);
		while (!found)
		{
			if (!(str = fgets(line,256,infile)))
				break;
			if (stringcmp(str,sarg[1],&locate) == leng)
				found++;
			fputs(line,outfile);
		}
	}

	/* we are (hopefully) done - either EOF or matched, go away anyway */
	fclose(infile);
	fclose(outfile);
	return(0); 	/* keep AREXX happy */
}

/***	little bitty procedure to set the DOS return code if we have   ***/
/***	an error.  If we just do an Exit(20) then ARexx doesn't know   ***/
/***	anything about the error.									   ***/
int seterror(err)
int err;
{
	HereWeAre->pr_Result2 = err;
	return(0);
}

/***********************************************************************
*	stringcmp()
*
*	Unanchored non-destructive string comparison. Written primarily
*	because I couldn't get the lattice pattern matching routines to
*	work, and didn't feel like taking the time to figure out what was
*	wrong.
***********************************************************************/
int stringcmp(s,p,l)
char *s,*p;
int *l;
{
	int len1,len2,i;
	
	len1 = strlen(s);
	len2 = strlen(p);

	/* this can't possibly match so give up immediately */
	if (len1 < len2)
		return(0);
	
	/* no need to go all the way to the end, just stop when target 	*/
	/* can't fit in the remainder of the source						*/
	for (i=0;i<len1-len2;i++)
	{
		if (!strncmp(s,p,len2))  /* I cheated a bit with this call */
		{
			*l = i;				/* want to know where in source we matched */
			return(len2);
		}
		s++;
	}
	*l = len1;
	return(0);	/* no match, sorry */
}


/**********************************************************************
*	scopynull
*
*	This routine copies the first string to the second, skipping
*	whitespace, except if it is enclosed in quotes 
*	the procedure also places a null after each string section 
*	(a string section is a contiguous group of printable ascii chars
*	or several groups and whitespace inside quotes)
*	and adds a null to the end of the resultant string (so that it ends
*	with 2 nulls).  This is meant to be used primarily with the 
*	Lattice function strbpl() which requires a string of this form 
*	as input.
**********************************************************************/
void scopynull(s1,s2)
char *s1,*s2;
{
	int inquote=0,copying=0;

	while (*s1)
	{
		if (*s1 == '\"')	/* is it a quote? yes -> just copy it */
		{
			s1++;
			inquote = 1 - inquote;
		}
		if (inquote)		/* just copy it, like I said */
		{
			copying = 1;
			*s2++ = *s1;
		}
		else
		{
			if (isspace(*s1) || (*s1 == '\n'))	/* whitespace or newline? */
			{
				if (copying)	/* if we are in a string section, then 	  */
				{				/* we found the end of it, so put a NULL  */
					*s2++ = 0;	/* otherwise, just skip it 				  */
					copying = 0;
				}
			}
			else
			{
				copying = 1;	/* just copy the stupid thing already */
				*s2++ = *s1;
			}
		}
		s1++;
	}
	*s2 = 0;
}
