#include "\lattice\h\glfstdio.h"		/*greenleaf  header*/
#include "\lattice\h\dbase.h"
#include "\lattice\h\fcntl.h"		/*Lattice Header*/
#include "\lattice\h\ctype.h"		/*Lattice header*/
#include "\lattice\h\disk.h"		/*Greenleaf header file*/
/*modify the above PATHs for your own system*/

static char *help[]={
"DBASE UTILITIES PROGRAM version 1.0  Lee Mowatt - 10/85",
" To perform a particular function, the command line or the RUN string",
"takes the following generalized form;",
"		CDBUTIL <func#> <.DBF file> [argument list]",
"			   (from DOS)",
"				or",
"		RUN CDBUTIL <func#> <.DBF file> [argument list]",
"			(from inside DBASE III)",
"\n",
"FUNC. #		FUNCTION			ARGUMENT LIST",
"======================================================================",
" 1      Database information       <DBFfile> [NDXfile NDXfile...]",
" 2      Unfiltered record count    <DBFfile>",
" 3      Count to memory variable   <DBFfile>",
" 4      Record listing             <DBFfile> [rec.range]",
" 5      Memo field display         <DBFfile> <rec#> [[+],[-],[-rec#]]",
" 6      memo field searching       <DBFfile> <phrase> [rec. range]",
" 7      memo field from textfile   <DBFfile> <rec#> <textfile> [del]",
" 8      disconnect/connect .DBT    <DBFfile> <0 or 1> ",
"                                              (0=disconnect, 1=connect)",
" 9      Pack a .DBT file           <DBFfile>",
" NOTE: [rec. range] is given in the form start#-end# (i.e. 12-234)",
NULL
};

struct commlist
	{
	int argnum;					/*# of args on commandline excluding  CDBUTIL*/
	char *args[20];				/*in-program argument string pointers*/
	};

/*the following defines help in reading the function source code*/
#define	FUNC		files->args[0]
#define	DBFILE		files->args[1]
#define NDXFILE(x)	files->args[x+1]
#define RECNUM		files->args[2]
#define PHRASE		files->args[2]
#define RANGE		files->args[3]
#define SUBMODE		files->args[2]
#define TXT			files->args[3]

main(argc,argv)

int argc;			/*number of arguments*/
char *argv[];		/*argument string pointers*/
	
{
struct commlist arglist;		/*argument structure*/
int loop,count;					/*general purpose integer variables*/
int function;					/*C2DBASE function number*/
int fnum;						/*DBF file number*/
static struct dbinfo db;		/*DBASE information structure-must be static*/
char *ext=".dbf";				/*DBF file extension*/
char *path;						/*file path name*/
char *stpchr();					/*Lattice function*/

if  ((argc==1)  || (isdigit(argv[1][0]) == 0))
	{
	for (loop=0;help[loop] != NULL;loop++)
		printf("%s\n",help[loop]);
	exit(0);
	}
for (loop=0;loop<argc-1;loop++)
	arglist.args[loop]=argv[loop+1];
arglist.argnum=argc-1; 			/*program name not included in argument list*/

path[0]=NULL;
strcat(path,argv[2]);
if (stpchr(argv[2],'.') == NULL)	/*add DBF extension if not present*/
	strcat(path,ext);
fnum=dbheader(path, &db);       /*fill information structure*/
if (db.error != 0)            		/*check for error*/
        {
        switch (db.error)
                {
                case 1:
                        printf("\7Filename MUST have .DBF extension\n");
                        exit(1); break;
                case 2:
                        printf("\7Cannot open %s\n",path);
                        exit(1); break;
                case 3:
                        printf("\7Not a DBASE .DBF file\n");
                        exit(1); break;
                case 4:
                        printf("\7Cannot open associated .DBT file.\n");
                        exit(1);break;
                default:
                        printf("Unknown error code - %d\n",db.error);
                        exit(1); break;
                }
        }

stcd_i(argv[1],&function);		/*convert decimal string to integer*/
switch (function)
	{
	case 1:
		func1(&db,&arglist);break;
	case 2:
		func2(&db,&arglist);break;
	case 3:
		func3(&db,&arglist);break;
	case 4:
		func4(&db,&arglist);break;
	case 5:
		func5(&db,&arglist);break;
	case 6:
		func6(&db,&arglist);break;
	case 7:
		func7(&db,&arglist);break;
	case 8:
		func8(&db,&arglist);break;
	case 9:
		func9(&db,&arglist);break;
	default:
		printf("\7Unknown CDBUTIL function number\n");break;
	}
dbclose(&db);
}


/**********************************************************************/
func1(dbase,files)			/*display file information*/

struct dbinfo *dbase;
struct commlist *files;

{
int loop;
char *stpchr();				/*Lattice function*/
char *string,*temp;			/*general purpose caharacter pointer*/
char *path;					/*pathname*/
char c=0x5c;				/*ascii number for '\'*/
char *ext=".ndx";			/*index extensionto be appended if not present*/

for (loop=3;loop<=files->argnum;loop++)			/*process index files*/
	{
	if ((string=stpchr(DBFILE,c)) != NULL)	/*PATH processing*/
		{
 		while ((temp=stpchr(string,c)) != NULL)
			string=temp+1; 					/*find last '\'*/
		stccpy(path,DBFILE,(string-DBFILE+1));
		}
	strcat(path,NDXFILE(loop-2));
	if (stpchr(path,'.') == NULL)
		strcat(path,ext);
	ndxread(dbase,path);
	/*test for errors*/
	if (dbase->error !=0)
		{
		switch (dbase->error)
			{
			case 1:
				printf("\7Index file must have .NDX extension\n");
				exit(1);break;
			case 2:
				printf("\7Cannot open %s\n",path);
				exit(1);break;
			case 3:
				printf("\7Wrong index file for database being used\n");
				exit(1);break;
			default:
				printf("\7Unknown ndxread error code-%d\n",dbase->error);
				exit(1);break;
			}
		}
	}
dbstat(dbase);			/*display files information*/
}


/**********************************************************************/
func2(dbase,files)					/*unfiltered record count to screen*/

struct dbinfo *dbase;
struct commlist *files;

{
printf("%ld records in %s\n",dbase->info.quan,dbase->filname);
}


/**********************************************************************/
func3(dbase,files)

struct dbinfo *dbase;
struct commlist *files;

{
char count[10];						/*string of record count*/
char c=0x5c;						/*ascii number for '\'*/
char *string,*temp;					/*general purpose string variables*/
char path[35];							/*directory to write .MEM file*/
char *stpchr();						/*Lattice function*/

stci_d(count,(int)(dbase->info.quan),10);	/*convert record number to string*/

if ((string=stpchr(DBFILE,c)) != NULL)	/*PATH processing*/
	{
	while ((temp=stpchr(string,c)) != NULL)
		string=temp+1; 					/*find last '\'*/
	stccpy(path,DBFILE,(string-DBFILE));
	}

pass(count,path);
}


/**********************************************************************/
func4(dbase,files)				/* record listing*/

struct dbinfo *dbase;
struct commlist *files;

{
char *range;
long start,end,strtol();
char *string,*record,*stpchr();
char *temp;

if ((files->argnum < 3) || (isdigit(files->args[2][0]) == 0))  
	{start=1L;	end=dbase->info.quan;}	/*no range specified,do all records*/
  else
	{
	range=files->args[2];
	string=stpchr(range,'-');
	strxlf(record,range,(string-range));
	start=strtol(record,&temp,10);
	strxrt(record,range,strlen(range)-(string-range+1));
	end=strtol(record,&temp,10);
	}

reclist(dbase,start,end);
}


/**********************************************************************/
func5(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
char *memoread();				/*C2DBASE function*/
char *memotext;					/*text pointer*/
char *memoname;					/*name of memo field*/
char *stpchr();					/*Lattice function*/
long rec,start,end;				/*record numbers*/
int fieldspace;					/*length of memo text*/
int count;						/*general purpose integer variable*/
long strtol();					/*Lattice function*/
char *temp,*record;

for (count=0; count<dbase->fieldnum; count++)  /*check that there is a memo field*/
        {
        if (dbase->field[count].type == 'M')
                memoname=dbase->field[count].name;
		}
memoread(dbase,1L);              /*see if this function returns an error*/
if ( (dbase->error == 1) || (dbase->error == 2) ) /*no memo fields to be read*/
        {
        printf("No memo field in this database\n");
        exit(1);
		}
if (stpchr(RECNUM,'+') !=NULL)
	{
	start=strtol(RECNUM,&memotext,10);		/*record specified*/
	end=dbase->info.quan;
	}
  else
	{
	if ((temp=stpchr(RECNUM,'-')) != NULL)
		{
		if (strlen(RECNUM) > (temp-RECNUM+1))				/*range specified*/
			{
			strxlf(record,RECNUM,(RECNUM - temp));
			start=strtol(record,&memotext,10);
			strxrt(record,RECNUM,strlen(RECNUM)-(temp-RECNUM+1));
			end=strtol(record,&memotext,10);
			}
		  else
			{
			start=0L;
			end=strtol(RECNUM,&memotext,10);
			}
		}
	  else
		{
		start=strtol(RECNUM,&memotext,10);
		end=start;
		}
	}
for (rec=start;rec<=end;rec++)
	{
	memotext=memoread(dbase,rec);
	if ((dbase->error == 0) || (dbase->error == 5))
		{
		printf("\n***%s for record %ld***\n",memoname,rec);
		fieldspace=strlen(memotext);
		for (count=0;count<fieldspace;count++)
			bdos(6,memotext[count]);
		printf("\n");
		if (dbase->error == 5)
			printf("Display truncated.Memo text longer than 2048 characters\n");
		}
	  else
		{
		switch (dbase->error)
			{
			case 3:
				printf("no memo text for record %ld\n",rec);break;
			case 4:
				printf("error reading .DBT file\n");break;
			default:
				printf("Unknown memoread error -#%d\n",dbase->error);
				break;
			}
		}
	}
}


/**********************************************************************/
func6(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
char *memoread();
long rec,start,end;				/*record numbers*/
char *temp,*string,*record;		/*general purpose string variable*/
char *stpchr();
long strtol();					/*Lattice function*/
int find,found=FALSE;			/*find status of textfind function*/
int loop,count;

memoread(dbase,1L);              /*see if this function returns an error*/
if ( (dbase->error == 1) || (dbase->error == 2) ) /*no memo fields to be read*/
        {
        printf("No memo field in this database\n");
        exit(1);
		}

count=strlen(PHRASE);
for (loop=0;loop<count;loop++)
	{
	if (PHRASE[loop] == '_')
		PHRASE[loop] = 0x20;
	}

if ((files->argnum < 4) || (isdigit(RANGE[0]) == 0)) 	/*no range specified*/
	{start=1L;	end=dbase->info.quan;}
  else
	{													/*range given*/
	string=stpchr(RANGE,'-');
	strxlf(record,RANGE,(string-RANGE));
	start=strtol(record,&temp,10);
	strxrt(record,RANGE,strlen(RANGE)-(string-RANGE+1));
	end=strtol(record,&temp,10);
	}

printf("search for %s\n",PHRASE);
for (rec=start;rec<=end;rec++)
	{
	find=textfind(dbase,rec,PHRASE);
	switch (find)
		{
		case 1:
			found=TRUE;
			printf("\nRecord %ld ",rec);
			break;
		case 0:
			printf(".");break;
		case -1:
			if (dbase->error == 2)
				{
				printf("Error- search string is NULL\n");
				exit(1);
				}
			  else
				{
				if (dbase->error == 3)
					printf("Error reading .DBT file.\n");
				}
			break;
		default:
			printf("Unknown error\n"); break;
		}
	}
printf("\n");
}


/**********************************************************************/
func7(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
unsigned memoadd();				/*C2DBASE function*/
static long rec;				/*record number*/
long strtol();					/*Lattice function*/
char *stpchr();					/*Lattice function*/
struct DISKTABLE text;			/*structure for Greenleaf function 'dos2delete*/
								/*found in disk.h header*/

rec=strtol(RECNUM);
if (stpchr(TXT,'.') ==NULL)		/* test for proper arguments*/
	{printf("\7Command line error\n");	exit(1);}

if (memoadd(dbase,rec,TXT) == -1)
	{
	switch (dbase->error)
		{
		case 0:
			break;
		case 1:
			printf("\7Record does not have a memo field.\n");	break;
		case 2:
			printf("\7Cannot open %s\n",TXT);	break;
		case 3:
			printf("\7Cannot re-open .DBT file\n");	break;
		default:
			printf("\7Unknown error\n");	break;
		}
	}
  else
	{
	if ((files->args[4] == "del") || (files->args[4]=="DEL"))
		{
		text.string=TXT;
		dos2delete(&text);			/*delete text file*/
		}
	}
}


/**********************************************************************/
func8(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
onoffdbt(dbase,SUBMODE);
}


/**********************************************************************/
func9(dbase,files)

struct dbinfo *dbase;
struct commlist *files;
{
if (dbtpack(dbase) != 0)
	{
	switch (dbase->error)
		{
		case 1:
			printf("\7Database has no .DBT file\n");	break;
		case 2:
			printf("\7Cannot open original .DBT file\n");	break;
		case 3:
			printf("\7Cannot create new .DBT file\n");	break;
		case 4:
			Printf("\7Error writing to new .DBT file\n");	break;
		case 5:
			printf("\7Error updating .DBF file\n");		break;
		default:
			printf("\7Unknown DBTPACK error code\n");	break;
		}
	}
}
        	
