/* 7 PROCEEDURES IN COMMON*/
static Boolean WildMatch(char pat[], char name[]);
static void SplitDot(char name[], char ext[]);
static void SplitColon(char path[], char spec[]);
static Boolean SpecMatch(char spec[], char name[]);
static long GetDirID(short index, short volNo, long dirID, char name[], char *attrib);
static short GetVolNo(short index, short volNo, char name[], long *freeBytes);
static short GetSpec(char line[], char path[], char spec[], long dirID, short volNo);
				
Boolean WildMatch(char pat[], char name[]) {
	/* compares each non-wildcard pattern character to
		the name character in equivalent position unless
		name ends during the process, in which case the
		remaining pattern characters would be compared
		to name’s terminating null character, guaranteeing
		false if remaining pattern characters are not wild.
		The NAME LARGER THAN PATTERN test follows the
		above because a pattern with ‘*’ can be smaller than name.
		*/
	short x, y = 0; // POSITIONS IN PAT AND NAME CHARACTER ARRAYS
	short nameLen;
	nameLen = strlen(name);
	for (x = 0; pat[x] != '\0'; x++) {
		if (pat[x] != '?') { // CHECK THIS CHARACTER?
			if (pat[x] == '*') // ACCEPT REMAINING CHARACTERS?
				 return true;
			if (toupper(pat[x]) != toupper(name[y])) // MISMATCH?
				return false;
			}
		if (x < nameLen) // PATTERN POSITION WITHIN NAME?
			y += 1; // NEXT POSITION IN NAME
		}
	if (nameLen > x) // NAME LARGER THAN PATTERN?
		return false;
	return true;
	}																
			
static void SplitDot(char name[], char ext[]) {
	/* splits name at first dot into base name and extension */
	char *dotPos;
	dotPos = (char *)strchr(name, '.');
	if (dotPos) { // NAME HAS DOT?
		strcpy(ext, dotPos);
		*dotPos = '\0'; // TRUNCATE NAME
		}
	else // NAME HAS NO DOT
		*ext = '\0'; // NULLIFY EXTENSION
	}
																	

static void SplitColon(char path[], char spec[]) {
	short	lastColon, x;
	lastColon = 0;
	for (x = 0; path[x] != '\0'; x++)
		if (path[x] == ':') lastColon = x; // COLON?
	if (lastColon) {
		strcpy(spec, &path[lastColon +1]);
		path[lastColon + 1] = '\0';
		}
	else {
		strcpy(spec,path);
		*path = '\0';
		}
	}
			
							
Boolean SpecMatch(char spec[], char name[]) {
	/* splits spec and name into their base and extension
		then compares spec base to name base and
		spec extension to name extension.  If everything
		matches, true is returned.  If the name extension
		is empty and the spec extension is “.*” some 
		special handling is required.
		*/
	Boolean baseMatch, extMatch;
	char dotStarStr[3] = {'.', '*', '\0'};
	char nameBase[256], nameExt[256];
	char specBase[256], specExt[256];
		
	strcpy(nameBase, name);
	strcpy(specBase, spec);
	SplitDot(specBase, specExt);		
	SplitDot(nameBase, nameExt);
	baseMatch = WildMatch(specBase, nameBase);
	extMatch = WildMatch(specExt, nameExt);
	if (*nameExt == '\0') // NAME EXT EMPTY?
		if (!strncmp(specExt, dotStarStr, 2)) // SPEC EXT DOTSTAR?
			extMatch = true; // EXCEPTION MATCH!		
	return (baseMatch && extMatch);
	}	

static long GetDirID(index, volNo, dirID, name, attrib)
	short index;
	short volNo;
	long dirID;
	char name[];
	char *attrib;
	{
	char pString[256];			
	HFileInfo pBlock;
	
	pBlock.ioFDirIndex = index;
	pBlock.ioVRefNum = volNo;
	pBlock.ioDirID = dirID;
	pBlock.ioNamePtr = pString; // RESERVE STRING MEMORY		
	strcpy(pBlock.ioNamePtr, name);
	c2pstr(pBlock.ioNamePtr);
	if (PBGetCatInfo((CInfoPBPtr)&pBlock, false) == noErr) {
		p2cstr(pBlock.ioNamePtr);
		strcpy(name, pBlock.ioNamePtr);			
		*attrib =  pBlock.ioFlAttrib & 0x10; //  A DIRECTORY?
		return pBlock.ioDirID;
		}
	else
		return 0L;
	}
		
										
static short GetVolNo(short index, short volNo, char name[], long *freeBytes) {
	char pString[256];		
	HVolumeParam pBlock3;
	
	pBlock3.ioVolIndex = index;		
	pBlock3.ioVRefNum = volNo;
	pBlock3.ioNamePtr = pString; // RESERVE STRING MEMORY
	strcpy(pBlock3.ioNamePtr, name);
	c2pstr(pBlock3.ioNamePtr);
	if (PBHGetVInfo((HParmBlkPtr)&pBlock3, false) == noErr) {
		p2cstr(pBlock3.ioNamePtr);
		strcpy(name, pBlock3.ioNamePtr);	
		*freeBytes = 100; // KRW!!!! pBlock3.ioVFrBlk * pBlock3.ioVAlBlkSiz;
		return pBlock3.ioVRefNum;
		}
	else
		return 0;
	}
																
	
static short GetSpec(line, path, spec, dirID, volNo)
	char line[];
	char path[];
	char spec[];
	long *dirID;
	short *volNo;
	{
	/* GetSpec takes line and returns the remaining arguments.
		"line" is split at the last colon into the path and file spec
		by SplitColon. If the path includes the root name, 
		its volume number is needed to find the directory ID; 
		otherwise, the default volume will be searched.  Likewise, with
		an empty or partial path, the default directory is assumed.  
		If the file spec is a directory, its name is appended to 
		the path and *.* is the file spec. */
	char attrib;		
	char colonStr[2] = {':','\0'};
	char root[256];
	char StrDotStr[4] = {'*','.','*','\0'};
	long fileNum;
	long freeBytes;
	
	*dirID = 0; // ASSUME DEFAULT DIRECTORY
	strcpy(path, line);
	SplitColon(path, spec);
	
	/* FIGURE VOLUME REFERENCE*/
	if (*path == '\0' || *path == ':')  // PATH EMPTY OR PARTIAL?
		*volNo = 0; // USE DEFAULT VOLUME
	else { // EXPLICIT VOL NAME!
		*volNo = -32768; // USE TO FIND VOLNO FROM VOLNAME EXCLUSIVE
		strcpy(root, path);
		*volNo = GetVolNo(-1, *volNo, root, &freeBytes);
		if (*volNo == 0) return 1; // INVALID VOLUME ERROR?
		}
	
	/* FIGURE DIRECTORY ID*/
	if (*path != '\0') { // PATH NOT EMPTY?
		*dirID = GetDirID(0, *volNo, *dirID, path, &attrib);
		if (*dirID == 0) return 2; // INVALID DIRECTORY?
		}
		
	/* FIGURE FILESPEC */
	if (*spec == '\0') // FILESPEC EMPTY?
		strcpy(spec, StrDotStr);
	else { // CHECK WHETHER IT'S A DIRECTORY
		fileNum = GetDirID(0, *volNo, *dirID, spec, &attrib);
		if (fileNum) { // FOUND EXACT MATCH?
			if (attrib) { // IS IT A DIRECTORY?
				*dirID = fileNum;
				strcat(path, spec);				
				strcpy(spec, StrDotStr);
				}
			}
		}
	}