Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -1,22 +1,27 @@ +CPPFLAGS := -I. -DUSE_TCL_STUBS=1 +CFLAGS := -fPIC -g3 -ggdb3 -Wall +LDFLAGS := +LIBS := -ltclstub8.6 + all: example.so example.c: $(shell find example -type f) $(shell find lib -type f) xvfs.c.rvt xvfs-create Makefile ./xvfs-create --directory example --name example > example.c.new mv example.c.new example.c example.o: example.c xvfs-core.h Makefile - cc -fPIC -Wall -I. -o example.o -c example.c + $(CC) $(CPPFLAGS) $(CFLAGS) -o example.o -c example.c xvfs-core.o: xvfs-core.c xvfs-core.h Makefile - cc -fPIC -Wall -I. -o xvfs-core.o -c xvfs-core.c + $(CC) $(CPPFLAGS) $(CFLAGS) -o xvfs-core.o -c xvfs-core.c example.so: example.o xvfs-core.o Makefile - cc -fPIC -shared -o example.so example.o xvfs-core.o + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o example.so example.o xvfs-core.o $(LIBS) test: example.so - echo 'load ./example.so Xvfs_example; puts OK' | tclsh | grep '^OK$$' + echo 'if {[catch { load ./example.so Xvfs_example; source //xvfs:/main.tcl }]} { puts stderr $$::errorInfo; exit 1 }; exit 0' | tclsh clean: rm -f example.so example.o example.c distclean: clean Index: xvfs-core.c ================================================================== --- xvfs-core.c +++ xvfs-core.c @@ -1,7 +1,19 @@ #include #include + +static int xvfs_tclvfs_standalone_pathInFilesystem(Tcl_Obj *path, ClientData *dataPtr) { + return(TCL_ERROR); +} + +static int xvfs_tclvfs_normalizePath(Tcl_Interp *interp, Tcl_Obj *path, int nextCheckpoint) { + return(TCL_ERROR); +} + +static Tcl_Obj *xvfs_tclvfs_listVolumes() { + return(NULL); +} /* * There are three (3) modes of operation for Xvfs_Register: * 1. standalone -- We register our own Tcl_Filesystem * and handle requests under `//xvfs:/` @@ -12,13 +24,75 @@ * 3. flexible -- Attempts to find a core Xvfs instance for the * process at runtime, if found do #2, otherwise * fallback to #1 * */ -static int Xvfs_Register_Standalone(Tcl_Interp *interp, const char *fsName, int protocolVersion, xvfs_proc_getChildren_t getChildrenProc, xvfs_proc_getData_t getDataProc) { - Tcl_SetResult(interp, "Not implemented", NULL); - return(TCL_ERROR); +static int xvfs_standalone_register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) { + Tcl_Filesystem *xvfsInfo; + int tcl_ret; + + /* + * In standalone mode, we only support the same protocol we are + * compiling for. + */ + if (fsInfo->protocolVersion != XVFS_PROTOCOL_VERSION) { + if (interp) { + Tcl_SetResult(interp, "Protocol mismatch", NULL); + } + return(TCL_ERROR); + } + + xvfsInfo = (Tcl_Filesystem *) Tcl_AttemptAlloc(sizeof(*xvfsInfo)); + if (!xvfsInfo) { + if (interp) { + Tcl_SetResult(interp, "Unable to allocate Tcl_Filesystem object", NULL); + } + return(TCL_ERROR); + } + + xvfsInfo->typeName = "xvfs"; + xvfsInfo->structureLength = sizeof(*xvfsInfo); + xvfsInfo->version = TCL_FILESYSTEM_VERSION_1; + xvfsInfo->pathInFilesystemProc = xvfs_tclvfs_standalone_pathInFilesystem; + xvfsInfo->dupInternalRepProc = NULL; + xvfsInfo->freeInternalRepProc = NULL; + xvfsInfo->internalToNormalizedProc = NULL; + xvfsInfo->createInternalRepProc = NULL; + xvfsInfo->normalizePathProc = xvfs_tclvfs_normalizePath; + xvfsInfo->filesystemPathTypeProc = NULL; + xvfsInfo->filesystemSeparatorProc = NULL; + xvfsInfo->statProc = NULL; + xvfsInfo->accessProc = NULL; + xvfsInfo->openFileChannelProc = NULL; + xvfsInfo->matchInDirectoryProc = NULL; + xvfsInfo->utimeProc = NULL; + xvfsInfo->linkProc = NULL; + xvfsInfo->listVolumesProc = xvfs_tclvfs_listVolumes; + xvfsInfo->fileAttrStringsProc = NULL; + xvfsInfo->fileAttrsGetProc = NULL; + xvfsInfo->fileAttrsSetProc = NULL; + xvfsInfo->createDirectoryProc = NULL; + xvfsInfo->removeDirectoryProc = NULL; + xvfsInfo->deleteFileProc = NULL; + xvfsInfo->copyFileProc = NULL; + xvfsInfo->renameFileProc = NULL; + xvfsInfo->copyDirectoryProc = NULL; + xvfsInfo->lstatProc = NULL; + xvfsInfo->loadFileProc = NULL; + xvfsInfo->getCwdProc = NULL; + xvfsInfo->chdirProc = NULL; + + tcl_ret = Tcl_FSRegister(NULL, xvfsInfo); + if (tcl_ret != TCL_OK) { + if (interp) { + Tcl_SetResult(interp, "Tcl_FSRegister() failed", NULL); + } + + return(tcl_ret); + } + + return(TCL_OK); } -int Xvfs_Register(Tcl_Interp *interp, const char *fsName, int protocolVersion, xvfs_proc_getChildren_t getChildrenProc, xvfs_proc_getData_t getDataProc) { - return(Xvfs_Register_Standalone(interp, fsName, protocolVersion, getChildrenProc, getDataProc)); +int Xvfs_Register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo) { + return(xvfs_standalone_register(interp, fsInfo)); } Index: xvfs-core.h ================================================================== --- xvfs-core.h +++ xvfs-core.h @@ -6,8 +6,15 @@ #define XVFS_PROTOCOL_VERSION 1 typedef const char **(*xvfs_proc_getChildren_t)(const char *path, Tcl_WideInt *count); typedef const unsigned char *(*xvfs_proc_getData_t)(const char *path, Tcl_WideInt start, Tcl_WideInt *length); -int Xvfs_Register(Tcl_Interp *interp, const char *fsName, int protocolVersion, xvfs_proc_getChildren_t getChildrenProc, xvfs_proc_getData_t getDataProc); +struct Xvfs_FSInfo { + int protocolVersion; + const char *fsName; + xvfs_proc_getChildren_t getChildrenProc; + xvfs_proc_getData_t getDataProc; +}; + +int Xvfs_Register(Tcl_Interp *interp, struct Xvfs_FSInfo *fsInfo); #endif Index: xvfs.c.rvt ================================================================== --- xvfs.c.rvt +++ xvfs.c.rvt @@ -131,15 +131,28 @@ */ return(fileInfo->data.fileContents + start); } int Xvfs__Init(Tcl_Interp *interp) { + struct Xvfs_FSInfo fsInfo = { + .protocolVersion = XVFS_PROTOCOL_VERSION, + .fsName = "", + .getChildrenProc = xvfs__getChildren, + .getDataProc = xvfs__getData + }; int register_ret; - - /* XXX:TODO: Stubs */ + +#ifdef USE_TCL_STUBS + const char *tclInitStubs_ret; + /* Initialize Stubs */ + tclInitStubs_ret = Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0); + if (!tclInitStubs_ret) { + return(TCL_ERROR); + } +#endif - register_ret = Xvfs_Register(interp, "", XVFS_PROTOCOL_VERSION, xvfs__getChildren, xvfs__getData); + register_ret = Xvfs_Register(interp, &fsInfo); if (register_ret != TCL_OK) { return(register_ret); } return(TCL_OK);