diff options
Diffstat (limited to 'command_line/CmdLine/Src/OSLib/MacSpecs.c')
-rw-r--r-- | command_line/CmdLine/Src/OSLib/MacSpecs.c | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/command_line/CmdLine/Src/OSLib/MacSpecs.c b/command_line/CmdLine/Src/OSLib/MacSpecs.c index 8648324..defcab1 100644 --- a/command_line/CmdLine/Src/OSLib/MacSpecs.c +++ b/command_line/CmdLine/Src/OSLib/MacSpecs.c @@ -1,25 +1,392 @@ #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; } |