/* 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 names 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);
}
}
}
}