/***************************************************************************
 * GFindXXX.c
 *
 * GFindXXX, Copyright ©1995 Lee Kindness.
 *
 */

/* All our includes are in this file */
#include "gst.c"

#include "GFindXXX_rev.h"

#define PROGNAME "GFindXXX"

/* Libraries used, don't auto open them SAS/C :) */
struct Library *GotchaLibBase = NULL;

/* The differnet types of search fields */
enum STypes { ST_SYSTEM, ST_SYSOP, ST_PLACE, ST_PHONE };
#define STS_SYSTEM "system"
#define STS_SYSOP  "sysop"
#define STS_PLACE  "place"
#define STS_PHONE  "phone"

LONG NLSearch(struct gl_context *nl, STRPTR pat, STRPTR npat, enum STypes stype,
              BOOL full, BOOL points, BOOL cutdash, BOOL verbatim, STRPTR lformat);

const char *vtag = VERSTAG;

/***************************************************************************
 * LFormat() -- Print out node details, when LFORMAT is selected.
 */

#define SPEC        '%'
#define S_NL        'n'
#define S_TAB       't'
#define S_RETURN    'r'
#define S_VTAB      'v'
#define S_DQUOTE    'q'
#define S_ALERT     'a'
#define S_BSPACE    'b'
#define S_SYSTEM    'S'
#define S_ADDRESS   'A'
#define S_ADDRESS4D '4'
#define S_LOCATION  'l'
#define S_SYSOP     's'
#define S_TYPE      'T'
#define S_PHONE     'P'
#define S_BAUD      'B'
#define S_COST      'c'
#define S_FLAGS     'f'
#define S_PASSWORD  'w'
#define S_ZONE      'z'
#define S_NET       'e'
#define S_NODE      'N'
#define S_POINT     'p'
#define S_DOMAIN    'd'
#define S_REGION    'R'
#define S_HUB       'h'

#define FT_SHORT "%A %S, %l, %s, %P"
#define FT_FULL  "Node %A, \"%S\" is in %l\n" \
                 "Operated by %s\n" \
                 "Region %R, Hub %h\n" \
                 "Phone %P, Cost %c\n" \
                 "Flags %f\n" \
                 "Password %w\n"

#define STATE_NONE 0
#define STATE_SPEC 1

void LFormat(struct gl_nodeinfo *nd, STRPTR format, BOOL verbatim)
{
	STRPTR s;
	LONG state = STATE_NONE;
	BPTR fh = Output();
	
	for( s = format; *s != '\000'; ++s )
	{
		switch( state )
		{
			case STATE_NONE:
				if( *s == SPEC )
					state = STATE_SPEC;
				else
					FPutC(fh, *s);
				break;
			case STATE_SPEC:
				switch( *s )
				{
					case SPEC:
						FPutC(fh, SPEC);
						break;
					case S_NL:
						FPutC(fh, '\n');
						break;
					case S_TAB:
						FPutC(fh, '\t');
						break;
					case S_RETURN:
						FPutC(fh, '\r');
						break;
					case S_VTAB:
						FPutC(fh, '\v');
						break;
					case S_DQUOTE:
						FPutC(fh, '\"');
						break;
					case S_ALERT:
						FPutC(fh, '\a');
						break;
					case S_BSPACE:
						FPutC(fh, '\b');
						break;
					case S_SYSTEM:
						FPuts(fh, nd->name);
						break;
					case S_ADDRESS4D:
						FPrintf(fh, "%ld:%ld/%ld.%ld", nd->zone, nd->net,
						       nd->node, nd->point);
						break;
					case S_ADDRESS:
						FPrintf(fh, "%ld:%ld/%ld.%ld@%s", nd->zone, nd->net,
						       nd->node, nd->point, nd->domain);
						break;
					case S_LOCATION:
						FPuts(fh, nd->location);
						break;
					case S_SYSOP:
						FPuts(fh, nd->sysop);
						break;
					case S_TYPE: /* Gotchlib does not support this... */
						FPuts(fh, "unknown");
						break;
					case S_PHONE:
						if( verbatim )
							FPuts(fh, nd->phone);
						else
							FPuts(fh, nd->tphone);
						break;
					case S_BAUD:
						FPuts(fh, nd->baud);
						break;
					case S_COST:
						if(nd->cost != -1)
							FPrintf(fh, "%01ld.%02ld", nd->cost/100, nd->cost%100);
						else
							FPrintf(fh, "undialable");
						break;
					case S_FLAGS:
						FPuts(fh, nd->flags);
						break;
					case S_PASSWORD:
						FPuts(fh, (STRPTR)nd->password[0] ? (STRPTR)nd->password : (STRPTR)"none");
						break;
					case S_ZONE:
						FPrintf(fh, "%ld", nd->zone);
						break;
					case S_NET:
						FPrintf(fh, "%ld", nd->net);
						break;
					case S_NODE:
						FPrintf(fh, "%ld", nd->node);
						break;
					case S_POINT:
						FPrintf(fh, "%ld", nd->point);
						break;
					case S_DOMAIN: /*DING*/
						FPuts(fh, nd->domain);
						break;
					case S_REGION:
						FPrintf(fh, "%ld", nd->region);
						break;
					case S_HUB:
						FPrintf(fh, "%ld", nd->hub);
						break;
				}
				state = STATE_NONE;
				break;
		}	
	}
	FPutC(fh, '\n');
}

/***************************************************************************
 * PrintNode() -- Print out node details.
 */

void PrintNode(struct gl_nodeinfo *nd, BOOL full, BOOL verbatim, STRPTR lformat)
{
	if( lformat )
		LFormat(nd, lformat, verbatim);
	else if( full )
		LFormat(nd, FT_FULL, verbatim);
	else
		LFormat(nd, FT_SHORT, verbatim);
}


/***************************************************************************
 * NLSearch() -- Called for each search...
 */

LONG NLSearch(struct gl_context *nl, STRPTR pat, STRPTR npat, enum STypes stype,
              BOOL full, BOOL points, BOOL cutdash, BOOL verbatim, STRPTR lformat)
{
	LONG ret = 0;
	struct gl_address *ad = NULL;
	struct gl_nodeinfo *nd = NULL;
	struct gl_pattern *pt = NULL;
	
	if( (ad = AllocVec(sizeof(struct gl_address), MEMF_CLEAR)) &&
	    (nd = AllocVec(sizeof(struct gl_nodeinfo), MEMF_CLEAR)) &&
	    (pt = AllocVec(sizeof(struct gl_pattern), MEMF_CLEAR)) )
	{
		STRPTR s = NULL;
		ULONG sig = 0;
		
		/* convert */
		GL_XtractInfos(ad, npat);
		
		switch( stype )
		{
			case ST_SYSTEM:
				s = nd->name;
				break;
			
			case ST_SYSOP:
				s = nd->sysop;
				break;
			
			case ST_PLACE:
				s = nd->location;
				break;
			
			case ST_PHONE:
				if( !cutdash )
				{
					if( verbatim )
						s = nd->phone;
					else
						s = nd->tphone;
				} else
					s = (STRPTR)-1;
		}
	
		if( s && GL_FindNodeFirst(ad, nl, nd, pt) )
			do
			{
				if( !(points && ad->point) )
				{
					STRPTR ss;
					if( s == (STRPTR)-1 )
					{
						STRPTR src;
						
						if( verbatim )
							src = nd->phone;
						else
							src = nd->tphone;
						
						/* Strip out dashes */
						if( ss = AllocVec(strlen(src)+1, MEMF_CLEAR) )
						{
							STRPTR s2, s3;
							s3 = ss;
							for( s2 = src ; *s2 != '\0'; s2++ )
							{
								if( *s2 != '-' )
								{
									*s3 = *s2;
									s3++;
								}
							}	
						}
					} else
						ss = s;
					
					if( MatchPatternNoCase(pat, ss) )
					{
						++ret;
						PrintNode(nd, full, verbatim, lformat);
					}
					
					if( s == (STRPTR)-1 )
						FreeVec(ss);
				}
			} while( (GL_FindNodeNext(ad, nl, nd, pt)) && (!(sig = CheckSignal(SIGBREAKF_CTRL_C))) );
			if( sig )
				PrintFault(ERROR_BREAK, "# " PROGNAME);
	}
	if( pt )
		FreeVec(pt);
	if( nd )
		FreeVec(nd);
	if( ad )
		FreeVec(ad);
	
	return ret;
}


/***************************************************************************
 * main() --
 */
int main(int argc, char **argv)
{
	int ret = RETURN_FAIL;
	
	/* Open libraries */
	if( (GotchaLibBase = OpenLibrary("gotcha.library", 1)) &&
	    (DOSBase->dl_lib.lib_Version >= 36) ) 
	{
		/* Parse arguments */
		struct RDArgs *rda;
		#define DEF_NODELIST "Nodelist:"
		#define DEF_NPAT "*"
		#define DEF_STYPE STS_SYSTEM
		#define TEMPLATE "PATTERN/M/A,N=NPAT/K,S=STYPE/K,FULL/S,POINTS/S,VERBATIM/S,STRIPDASHES/S,LFORMAT/K,NODELIST/K"
		#define OPT_PATTERN 0
		#define OPT_NPAT 1
		#define OPT_STYPE 2
		#define OPT_FULL 3
		#define OPT_POINTS 4
		#define OPT_VERBATIM 5
		#define OPT_STRIPDASHES 6
		#define OPT_LFORMAT 7
		#define OPT_NODELIST 8
		#define OPT_MAX 9
		STRPTR args[OPT_MAX] = {0, DEF_NPAT, DEF_STYPE, 0, 0, 0, 0, 0, DEF_NODELIST};

		if( rda = ReadArgs(TEMPLATE, (LONG *)&args, NULL) ) 
		{
			STRPTR s;
			
			struct gl_context *nl;

			/* Open nodelist */
			if( nl = GL_OpenNL(args[OPT_NODELIST]) )
			{
				STRPTR *pata;
				LONG n = 0;
				LONG matches = 0;
				enum STypes st;
				
				if( stricmp(args[OPT_STYPE], STS_SYSOP) == 0 )
					st = ST_SYSOP;
				else if( stricmp(args[OPT_STYPE], STS_PLACE) == 0 )
					st = ST_PLACE;
				else if( stricmp(args[OPT_STYPE], STS_PHONE) == 0 )
					st = ST_PHONE;
				else
					st = ST_SYSTEM;
				
				pata = (void *) args[OPT_PATTERN];
				
				ret = RETURN_OK;
				
				while( (s = pata[n]) && !ret ) 
				{
					STRPTR pattern;
					/* Act on the pattern */
				
					/* Alloc buffer for tokenized widcard */
					if( pattern = AllocVec(strlen(s)*3, MEMF_CLEAR) )
					{
						/* Parse wildcard */
						if( ParsePatternNoCase(s, pattern, strlen(s)*3) != -1 )
						{
						
							LONG num;
							
							/* CallFunc! */
							
							if( (num = NLSearch(nl,
							                    pattern,
							                    args[OPT_NPAT],
							                    st,
                                  (BOOL)args[OPT_FULL],
                                  (BOOL)args[OPT_POINTS],
                                  (BOOL)args[OPT_STRIPDASHES],
                                  (BOOL)args[OPT_VERBATIM],
                                  args[OPT_LFORMAT])) == -1 )
							{
								PrintFault(IoErr(), "# " PROGNAME);
								ret = RETURN_FAIL;
							} else if( num == 0 )
								Printf("# No matches for \"%s\"\n", s);
							else
								matches += num;

						}
						FreeVec(pattern);
					}
					n++;
				}
				
				if( matches )
					Printf("# %ld %s found.\n",
					       matches,
					       ((matches == 1) ? "match" : "matches"));
				else
					Printf("# No matches\n");
				Printf("# " VERS " (" DATE ")\n"
				       "# Copyright (c)Lee Kindness, 2:250/366.34\n");
				GL_CloseNL(nl);
			}
			FreeArgs(rda);
		} else
			PrintFault(IoErr(), "# " PROGNAME);
		CloseLibrary(GotchaLibBase);
	}
	return ret;
}
