MWCC/command_line/CmdLine/Src/OSLib/MacSpecs.c

393 lines
8.2 KiB
C

#include "oslib.h"
#include <errno.h>
extern char STSbuf[256];
#define OPTION_ASSERT(cond) do { if (!(cond)) { printf("%s:%u: failed assertion\n", __FILE__, __LINE__); abort(); } } while(0)
typedef struct DirNode {
char *name;
unsigned int dirID;
union {
struct DirNode *parent;
struct VolNode *volume;
} p;
struct DirNode *list;
struct DirNode *next;
} DirNode;
typedef struct VolNode {
UInt16 vRefNum;
DirNode root;
struct VolNode *next;
} VolNode;
static unsigned int lastDirID = 3;
static unsigned int lastVolRef = 2;
static char stname[256];
static char stpath[256];
static char stdir[256];
static char stvol[8];
static unsigned int dirMapRows;
static DirNode **dirIDMap[256];
static VolNode *vols;
static int AddDirMapEntry(DirNode *node) {
unsigned int row;
unsigned int col;
row = node->dirID >> 8;
col = node->dirID & 0xFF;
while (row >= dirMapRows) {
if (row >= 256) {
fprintf(stderr, "Fatal error: too many directories referenced, out of memory\n");
return 0;
}
dirIDMap[row] = calloc(sizeof(DirNode *), 256);
if (!dirIDMap[row])
return 0;
dirMapRows++;
}
dirIDMap[row][col] = node;
return 1;
}
static VolNode *FindOrAddVolRef(VolNode **list, char *name) {
int sz;
VolNode *vn;
while (*list) {
if (OS_EqualPath(name, (*list)->root.name))
return *list;
list = &(*list)->next;
}
if (lastVolRef >= 256)
return 0;
vn = malloc(sizeof(VolNode));
if (!vn)
return 0;
vn->next = 0;
vn->vRefNum = lastVolRef++;
sz = strlen(name) + 1;
vn->root.name = malloc(sz);
if (!vn->root.name)
return 0;
strcpy(vn->root.name, name);
vn->root.dirID = 2;
vn->root.p.volume = vn;
vn->root.list = 0;
vn->root.next = 0;
*list = vn;
return vn;
}
static DirNode *FindDirMapEntry(unsigned int dirID) {
unsigned int row;
unsigned int col;
row = dirID >> 8;
col = dirID & 0xFF;
#line 166
OPTION_ASSERT(dirID != 2);
if (row >= dirMapRows)
return 0;
else
return dirIDMap[row][col];
}
static DirNode *FindOrAddDirRef(DirNode *parent, char *name) {
int sz;
DirNode *dn;
DirNode **list;
list = &parent->list;
while (*list) {
if (OS_EqualPath(name, (*list)->name))
return *list;
list = &(*list)->next;
}
if (lastDirID >= 0x10000)
return 0;
sz = strlen(name) + 1;
dn = malloc(sizeof(DirNode));
if (!dn)
return 0;
dn->name = malloc(sz);
if (!dn->name)
return 0;
strcpy(dn->name, name);
dn->list = 0;
dn->next = 0;
dn->dirID = lastDirID++;
if (!AddDirMapEntry(dn))
return 0;
dn->p.parent = parent;
*list = dn;
return dn;
}
static int FindOrAdd(const OSPathSpec *path, unsigned int *vRefNum, unsigned int *dirID) {
VolNode *vol;
DirNode *level;
char pb[256];
char voln[8];
char pathbuf[256];
char *ptr;
char *st;
char ch;
if (!OS_PathSpecToString(path, pathbuf, 256))
return 0;
if (!pathbuf[0])
return 0;
ptr = OS_GetDirPtr(pathbuf);
strncpy(voln, pathbuf, ptr - pathbuf);
voln[ptr - pathbuf] = 0;
strcpy(pb, ptr);
vol = FindOrAddVolRef(&vols, voln);
if (!vol)
return 0;
*vRefNum = vol->vRefNum;
level = &vol->root;
ptr = &pb[1];
#line 267
OPTION_ASSERT(*pb == OS_PATHSEP);
while (*ptr) {
st = ptr;
while ((ch = *ptr) && *ptr != OS_PATHSEP) {
++ptr;
}
*ptr = 0;
level = FindOrAddDirRef(level, st);
if (!ch)
break;
++ptr;
if (!level)
return 0;
}
*dirID = level->dirID;
return 1;
}
static void StepVolDir(unsigned int *vRefNum, unsigned int *dirID, DirNode **node) {
VolNode *step;
if (*vRefNum == 1) {
*node = 0;
return;
}
if (*dirID == 2) {
step = vols;
while (step && step->vRefNum != *vRefNum)
step = step->next;
if (step) {
*node = &step->root;
*vRefNum = 1;
*dirID = 1;
} else {
*node = 0;
}
} else {
*node = FindDirMapEntry(*dirID);
if (*node)
*dirID = (*node)->p.parent->dirID;
}
}
static int ResolvePath(const OSPathSpec *path, unsigned int *vRefNum, unsigned int *dirID) {
if (FindOrAdd(path, vRefNum, dirID)) {
*vRefNum = -*vRefNum;
return 1;
} else {
*vRefNum = 0;
*dirID = 0;
return 0;
}
}
static int ResolveVolDir(unsigned int vRefNum, unsigned int dirID, char *vol, char *dir) {
DirNode *nodes[256];
DirNode *cur;
int idx;
int len;
char *dptr;
vRefNum = -vRefNum;
idx = 0;
do {
StepVolDir(&vRefNum, &dirID, &cur);
if (cur)
nodes[idx++] = cur;
} while (cur);
if (idx) {
strcpy(vol, nodes[--idx]->name);
} else {
vol[0] = 0;
dir[0] = 0;
return 0;
}
dptr = dir;
*(dptr++) = OS_PATHSEP;
while (idx--) {
len = strlen(nodes[idx]->name);
if ((dptr - dir) + len + 1 > 256) {
*dptr = 0;
return 0;
} else {
memcpy(dptr, nodes[idx]->name, len);
dptr += len;
*(dptr++) = OS_PATHSEP;
}
}
*dptr = 0;
return 1;
}
int OS_OSPathSpec_To_VolDir(const OSPathSpec *spec, SInt16 *vRefNum, SInt32 *dirID) {
unsigned int vol;
unsigned int dir;
if (ResolvePath(spec, &vol, &dir)) {
*vRefNum = vol;
*dirID = dir;
return 0;
} else {
*vRefNum = 0;
*dirID = 0;
return ENOENT;
}
}
int OS_OSSpec_To_FSSpec(const OSSpec *spec, FSSpec *fss) {
int err;
SInt16 vRefNum;
SInt32 dirID;
char *s;
err = OS_OSPathSpec_To_VolDir(&spec->path, &vRefNum, &dirID);
fss->vRefNum = vRefNum;
fss->parID = dirID;
if (err) return err;
s = OS_NameSpecToString(&spec->name, STSbuf, sizeof(STSbuf));
if (!s || strlen(s) >= 256)
return ENAMETOOLONG;
c2pstrcpy(fss->name, s);
return 0;
}
int OS_VolDir_To_OSNameSpec(SInt16 vRefNum, SInt32 dirID, OSNameSpec *spec, SInt32 *parID) {
unsigned int cv;
unsigned int cd;
DirNode *node;
cv = -vRefNum;
cd = dirID;
StepVolDir(&cv, &cd, &node);
if (!node)
return ENOENT;
*parID = cd;
return OS_MakeNameSpec(node->name, spec);
}
int OS_VolDir_To_OSPathSpec(SInt16 vRefNum, SInt32 dirID, OSPathSpec *spec) {
int err;
int vlen;
int dlen;
if (!vRefNum || !dirID) {
err = OS_GetCWD(spec);
if (err)
return err;
} else {
if (!ResolveVolDir(vRefNum, dirID, stvol, stdir))
return ENOENT;
vlen = strlen(stvol);
dlen = strlen(stdir);
if (vlen + dlen < 256) {
memcpy(spec->s, stvol, vlen);
memcpy(spec->s + vlen, stdir, dlen + 1);
}
}
return 0;
}
int OS_FSSpec_To_OSSpec(const FSSpec *fss, OSSpec *spec) {
int err;
err = OS_VolDir_To_OSPathSpec(fss->vRefNum, fss->parID, &spec->path);
if (err)
return err;
p2cstrcpy(stname, fss->name);
err = OS_MakeNameSpec(stname, &spec->name);
if (err)
return err;
return err;
}
int OS_GetRsrcOSSpec(const OSSpec *spec, OSSpec *rspec, Boolean create) {
char dbuffer[256];
int err;
OS_PathSpecToString(&spec->path, dbuffer, sizeof(dbuffer));
err = OS_MakeSpec2(dbuffer, "resource.frk", rspec);
if (err)
return err;
err = OS_Status(rspec);
if (err) {
if (create) {
err = OS_Mkdir(rspec);
if (err)
return err;
// Windows version has a call to SetFileAttributes here
} else {
return err;
}
err = OS_MakeSpec2(dbuffer, "resource.frk", rspec);
if (err)
return err;
} else if (OS_IsFile(rspec)) {
return ENOTDIR;
}
err = OS_MakeNameSpec(OS_NameSpecToString(&spec->name, STSbuf, sizeof(STSbuf)), &rspec->name);
if (err)
return err;
return 0;
}