#include <xfbuf.h>
#include <ascii.h>

char *strip_path();

#define same(s1,s2) (strcmp(s1,s2)==0)
#define NULL 0

/*

	J <command> <filespec>

	Tom Jennings
	1 Nov 91
*/

#define RO 0x01		/* Read only attribute. */
#define HI 0x02		/* Hidden attribute, */
#define SY 0x04		/* System attribute, */
#define VO 0x08		/* Volume ID */
#define DI 0x10		/* directory */
#define AR 0x20		/* Archive, */
#define TG1 0x40	/* Tag #1 */
#define TG2 0x80	/* Tag #2 */

#define MAXFOUND 10
char names[MAXFOUND][80]; /* list of found names */
int found = 0;		/* how many */
int item = -1;		/* -1 none found;
			   0 - (MAXFOUND - 1) picked item;
			   -2 ESCape, Control-C abort */

char no_action;		/* 1 == don't execute anything */
char no_extention;	/* 1 == strip extention */
char no_chdir;		/* 1 == do from current directory */

char progname[80];	/* program to exec */
char filename[80];	/* globally searched for filename */
int level;		/* how deep we are, */
unsigned _stack = 8000;

char _months[13][4] = {
	"Eh?",
	"Jan",
	"Feb",
	"Mar",
	"Apr",
	"May",
	"Jun",
	"Jul",
	"Aug",
	"Sep",
	"Oct",
	"Nov",
	"Dec"
};

main(argc,argv)
int argc;
char *argv[];
{
char *p,buff[80];
int i;

	i= 1;
	p= argv[1];				/* check 1st arg for options */
	if (*p == '/') {
		for (; *p; ++p) {
			switch (*p) {
				case 'e': case 'E':	no_extention= 1; break;
				case 'p': case 'P':	no_chdir= 1; break;
				case 't': case 'T': 	no_action= 1; break;
			}	
		}
		i= 2;				/* 2nd arg is program */
		--argc;
	}
	if (argc > 2) {				/* required filename */
		cpyarg(progname,argv[i++]);	/* program to execute */
		cpyarg(filename,strip_path(buff,argv[i])); /* filename to find */

	} else {
		printf("J/e/p/t <program> <filespec>                5 Nov 91\r\n");
		printf("\r\n");
		printf("Search the entire disk for a file, and if a match is found, CHDIR's to the\r\n");
		printf("directory it was found in (see /P), execute a program, passing the \r\n");
		printf("complete found filename (see /E) as an argument. \r\n");
		printf("\r\n");
		printf("If there is more than one filename, you are prompted to select one. Note that\r\n");
		printf("you can select one \"on the fly\" by entering it's number 1 - 9, or ESCape\r\n");
		printf("to abort.\r\n");
		printf("\r\n");
		printf("/T prevents any action from being taken; useful for seeing what would\r\n");
		printf("   happen (shows resulting equivelent commands).\r\n");
		printf("/P prevents the CHDIR, and passes the full pathname to the program as \r\n");
		printf("   the argument.\r\n");
		printf("/E strips the found filename extention from the passed argument.\r\n");
		printf(" \r\n");
		printf("<filespec> is expanded as follows:\r\n");
		printf("\r\n");
		printf("    FILE  is equiv. to FILE*.*            .EXT is equiv. to *.EXT\r\n");
		printf("    FILE. is equiv. to FILE.              FILE*. is equiv. to FILE*.\r\n");
		printf("\r\n");
		printf("Tom Jennings / World Power Systems / Box 77731 / San Francisco CA 94107 USA\r\n");
		exit(1);
	}
	fixdir(filename);			/* fixup directory names */
	if ((*filename == '.') && (strlen(filename) <= 4)) {
		strcpy(buff,"*");		/* turn extention-only  (.EXE) */
		strcat(buff,filename);		/* into full filename (*.EXE) */
		strcpy(filename,buff);
	}
	for (p= filename; *p; ++p) {		/* if no extention given (FILE) */
		if (*p == '.') break;
	}
	if (*p != '.') strcat(filename,"*.*");	/* make it wild (FILE*.*) */
	dir("\\");				/* start at the root */

/* May have been manually aborted (ESCape, Control-C) or simply no file found.
We come back here also when we have to ask for a selection (see below). */

check_it:
	if (item == -2) {			/* manually aborted */
		printf("ABORTED\r\n");
		exit(2);
	}
	if (found == 0) {			/* nothing found */
		printf("Nothing found matching \"%s\"\r\n",filename);
		exit(1);
	}

/* If only one item, it's easy -- just do it. If more than one, it may have 
been selected on the fly (item > -1). Otherwise, ask which one. */

	if (found == 1) item= 0;		/* one file, select it */
	else if (item < 0) {			/* else must ask */
		printf("Which one? (0-%d): ",found);
		while (! check_for_item());	/* get answer */
		printf("\r\n");
		goto check_it;			/* re-process new input */
	}
	if (no_chdir) {				/* if no CHDIR, */
		cpyarg(filename,names[item]);	/*   use complete pathname */

	} else {				/* CHDIR there, use filename only */
		cpyarg(filename,strip_path(buff,names[item])); /* filename & path */
		i= strlen(buff);		/* if not root dir, */
		if (i > 1) buff[i - 1]= NUL;	/* remove trailing slash */
		printf("cd %s\r\n",buff);	/* say it */	
		if (! no_action) chdir(buff);	/* do it (maybe) */
	}
	if (no_extention) {			/* if no extention */
		for (p= filename; *p; ++p)
			if (*p == '.') *p= NUL;	/* zap it */
	}
	printf("%s %s\r\n",progname,filename);	/* say it */
	if (! no_action) execlp(progname,progname,filename,NULL); /* do it (maybe) */
	exit(0);
}

/* Recursively find each directory, and execute all the weird options. Returns
the number of bytes tallied. */

dir(s) 
char *s;
{
int i;
struct _xfbuf xfbuf;
char path[80];
char zfound;

	if (found >= MAXFOUND) return;			/* stop early if too many */
	if (check_for_item()) return;			/* check for typeahead */

	++level;
	strcpy(path,s);					/* build full search path */
	strcat(path,"*.*"); 
	i= 0;						/* _find flag, file count */
	zfound= 0;
	xfbuf.s_attrib= 0;				/* not hidden, system, etc */

	while (_find(path,i++,&xfbuf)) {
		if (check_for_item()) return;		/* check for typeahead */
		if (xfbuf.f_attrib & VO) continue;	/* ignore volume ID */
		if (*xfbuf.name == '.') continue;	/* ignore . and .. */
		if (fmatch("Stopfile.Z",xfbuf.name))	/* if we find a stopfile */
			zfound= 1;			/* flag for later */

		if (fmatch(filename,xfbuf.name)) {	/* if matches our pattern */
			if (found < MAXFOUND) {
				fileinfo(s,&xfbuf);	/* display it */
				strcpy(names[found],s);	/* build complete name */
				strcat(names[found],xfbuf.name);
				++found;

			} else {
				printf("[...]\r\n");
				return;			/* too many! */
			}
		}
	}

/* Now search for all subdirectories within this directory. */

	strcpy(path,s);					/* start here, */
	strcat(path,"*.*");				/* all subdirs */
	i= 0;						/* _find flag, file count */
	xfbuf.s_attrib= DI;

	if (! zfound) while (_find(path,i++,&xfbuf)) {
		if ((xfbuf.f_attrib & DI) == 0) continue; /* only dirs */
		if (*xfbuf.name == '.') continue;	/* ignore . and .. */

		strcpy(path,s);				/* build full pathname */
		strcat(path,xfbuf.name);
		strcat(path,"\\");
		dir(path);				/* do it, */
	}
	if (level) --level;				/* pop up one level */
}

/* Check the keyboard for a select on what we've displayed so far. */

check_for_item() {
char c;

	if (item < 0) switch (c= bdos(6,0xff)) {
		case ESC:
		case ETX:
			item= -2;		/* flag abort */
			break;

		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			c -= '0';			/* convert to index */
			if (c < found) 			/* if in range, */
				item= c; 		/* select item */
			break;
	}
	return(item != -1);
}

/* Display stuff for this file. */

fileinfo(path,xfbuf)
char *path;			/* pathname */
struct _xfbuf *xfbuf;		/* file info structure */
{
char buff[80];
int i;
	strcpy(buff,path);				/* build full pathname */
	strcat(buff,xfbuf-> name);
	if (xfbuf-> f_attrib & DI) stoupper(buff);	/* dirs in upper case */
	else stolower(buff);				/* files in lower case */

	printf("%2d: %s",found,buff);			/* filename text */
	for (i= strlen(buff); i < 40; i++) {		/* generate leaders */
		printf(i & 1 ? " " : ".");		/* dot or space */
	}
	if (xfbuf-> f_attrib & DI) printf("  <dir>  ");
	else printf("%10lu ",xfbuf-> fsize);

	printf(" %2u ",xfbuf-> date & 0x1f);			/* day */
	printf("%s ",_months[(xfbuf-> date >> 5) & 0x0f]);	/* month */
	printf("%2u",((xfbuf-> date >> 9) & 0x3f) + 80);	/* year */
	printf("  %2u:%02u",xfbuf-> time >> 11,(xfbuf-> time >> 5) & 0x3f);
	printf("\r\n");
}

