From cba93f7fceb074b8e40e15bc2aed8a76b8a3e915 Mon Sep 17 00:00:00 2001 From: Meep-Eep Date: Wed, 3 Jan 2007 16:58:59 +0000 Subject: [PATCH] uio cleanups, documentation path fixes, improvements Fixes bugs 738, 907 git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2641 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/ChangeLog | 6 + sc2/doc/devel/netplay/todo | 3 + sc2/src/config_unix.h.in | 4 +- sc2/src/config_win.h.in | 4 +- sc2/src/options.c | 2 +- sc2/src/port.h | 32 ++- sc2/src/sc2code/libs/file.h | 16 +- sc2/src/sc2code/libs/file/dirs.c | 221 +++++++++++++-- sc2/src/sc2code/libs/resource/direct.c | 6 +- sc2/src/sc2code/libs/uio/debug.c | 2 +- sc2/src/sc2code/libs/uio/doc/todo | 4 +- sc2/src/sc2code/libs/uio/fileblock.c | 8 +- sc2/src/sc2code/libs/uio/fstypes.c | 9 +- sc2/src/sc2code/libs/uio/io.c | 22 +- sc2/src/sc2code/libs/uio/io.h | 2 +- sc2/src/sc2code/libs/uio/ioaux.c | 99 +++++-- sc2/src/sc2code/libs/uio/mem.h | 9 + sc2/src/sc2code/libs/uio/mount.c | 14 +- sc2/src/sc2code/libs/uio/mounttree.c | 152 ++--------- sc2/src/sc2code/libs/uio/mounttree.h | 24 +- sc2/src/sc2code/libs/uio/paths.c | 359 ++++++++++++++++++++++++- sc2/src/sc2code/libs/uio/paths.h | 53 +++- sc2/src/sc2code/libs/uio/stdio/stdio.c | 33 ++- sc2/src/sc2code/libs/uio/stdio/stdio.h | 8 - sc2/src/sc2code/libs/uio/uioutils.c | 34 ++- sc2/src/sc2code/ships/orz/orz.c | 138 +++++----- 26 files changed, 908 insertions(+), 356 deletions(-) diff --git a/sc2/ChangeLog b/sc2/ChangeLog index 9860be3f8..c4d731449 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,10 @@ Changes towards version 0.7: +- uio cleanups, documentation - SvdB +- uio path parsing fixes/improvements - SvdB + - Windows UNC path support (#907) + - Windows drive-relative paths ("D:path" without a path seperator) + - treat multiple consecutive path seperators as one (like POSIX) +- config dir no longer needs trailing path seperator (bug #738)- SvdB - Simplification of uio Stream functions. No more internal seeks. - SvdB Changes towards version 0.6: diff --git a/sc2/doc/devel/netplay/todo b/sc2/doc/devel/netplay/todo index f4717cf7e..844128b61 100644 --- a/sc2/doc/devel/netplay/todo +++ b/sc2/doc/devel/netplay/todo @@ -89,6 +89,9 @@ Bugs: button won't be updated. - If one side is computer-controlled, sync loss will occur, because the AI uses the RNG. It needs its own RNG context. +- Pressing F10 to exit the supermelee setup when a connection is active + will cause an attempt to draw a NULL frame. (possibly the disconnect + feedback) Final actions: diff --git a/sc2/src/config_unix.h.in b/sc2/src/config_unix.h.in index 6932bd3f4..7c7158939 100644 --- a/sc2/src/config_unix.h.in +++ b/sc2/src/config_unix.h.in @@ -20,10 +20,10 @@ #define CONFIGDIR USERDIR /* Directory where supermelee teams will be stored */ -#define MELEEDIR "${UQM_CONFIG_DIR}teams/" +#define MELEEDIR "${UQM_CONFIG_DIR}/teams/" /* Directory where save games will be stored */ -#define SAVEDIR "${UQM_CONFIG_DIR}save/" +#define SAVEDIR "${UQM_CONFIG_DIR}/save/" /* Defined if words are stored with the most significant byte first */ @WORDS_BIGENDIAN@ diff --git a/sc2/src/config_win.h.in b/sc2/src/config_win.h.in index 127714a78..734486bd2 100644 --- a/sc2/src/config_win.h.in +++ b/sc2/src/config_win.h.in @@ -21,10 +21,10 @@ #define CONFIGDIR USERDIR /* Directory where supermelee teams will be stored */ -#define MELEEDIR "%UQM_CONFIG_DIR%teams/" +#define MELEEDIR "%UQM_CONFIG_DIR/%teams/" /* Directory where save games will be stored */ -#define SAVEDIR "%UQM_CONFIG_DIR%save/" +#define SAVEDIR "%UQM_CONFIG_DIR/%save/" /* Defined if words are stored with the most significant byte first */ @WORDS_BIGENDIAN@ diff --git a/sc2/src/options.c b/sc2/src/options.c index afa11a381..8891856f4 100644 --- a/sc2/src/options.c +++ b/sc2/src/options.c @@ -401,6 +401,6 @@ mountDirZips (uio_MountHandle *contentHandle, uio_DirHandle *dirHandle) } } } - uio_freeDirList (dirList); + uio_DirList_free (dirList); } diff --git a/sc2/src/port.h b/sc2/src/port.h index e95b698d4..5fbe75bbf 100644 --- a/sc2/src/port.h +++ b/sc2/src/port.h @@ -19,6 +19,26 @@ # endif #endif + +// Compilation related +#ifdef _MSC_VER +# define inline __inline +#else +# define inline __inline__ +# ifdef __MINGW32__ + // For when including Microsoft Windows header files. +# define _inline inline +# endif +#endif + +// Compilation warnings: +// UQM uses a lot of functions that can be used unsafely, but it uses them +// in a safe way. The warnings about these functions however may drown out +// serious warnings, so we turn them off. +#ifdef _MSC_VER +# define _CRT_SECURE_NO_DEPRECATE +#endif + #ifdef _MSC_VER # include #else @@ -40,18 +60,6 @@ char *strupr (char *str); int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); #endif - -// Compilation related -#ifdef _MSC_VER -# define inline __inline -#else -# define inline __inline__ -# ifdef __MINGW32__ - // For when including Microsoft Windows header files. -# define _inline inline -# endif -#endif - // Directories #ifdef WIN32 # include diff --git a/sc2/src/sc2code/libs/file.h b/sc2/src/sc2code/libs/file.h index a7e3d309e..b1a996df2 100644 --- a/sc2/src/sc2code/libs/file.h +++ b/sc2/src/sc2code/libs/file.h @@ -49,15 +49,20 @@ int expandPath (char *dest, size_t len, const char *src, int what); // Process ".." and "." #define EP_SLASHES 16 // Consider backslashes as path component separators. - // They will be replaced by slashes. -#define EP_ALL (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | EP_SLASHES) + // They will be replaced by slashes. Windows UNC paths will always + // start with "\\server\share", with backslashes. +#define EP_SINGLESEP 32 + // Replace multiple consecutive path separators by a single one. +#define EP_ALL (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | EP_SLASHES \ + EP_SINGLESEP) // Everything // Everything except Windows style backslashes on Unix Systems: #ifdef WIN32 # define EP_ALL_SYSTEM (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | \ - EP_SLASHES) + EP_SLASHES | EP_SINGLESEP) #else -# define EP_ALL_SYSTEM (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS) +# define EP_ALL_SYSTEM (EP_HOME | EP_ENVVARS | EP_ABSOLUTE | EP_DOTS | \ + EP_SINGLESEP) #endif // from files.h @@ -65,6 +70,9 @@ int copyFile (uio_DirHandle *srcDir, const char *srcName, uio_DirHandle *dstDir, const char *newName); bool fileExists (const char *name); bool fileExists2(uio_DirHandle *dir, const char *fileName); +#ifdef WIN32 +size_t skipUNCServerShare(const char *inPath); +#endif #ifdef WIN32 static inline int isDriveLetter(int c) diff --git a/sc2/src/sc2code/libs/file/dirs.c b/sc2/src/sc2code/libs/file/dirs.c index a0166df51..d1a2f8563 100644 --- a/sc2/src/sc2code/libs/file/dirs.c +++ b/sc2/src/sc2code/libs/file/dirs.c @@ -42,8 +42,8 @@ #define APPDATA_FALLBACK -static char *expandPathAbsolute (char *dest, size_t destLen, - const char *src, int what); +static char *expandPathAbsolute (char *dest, size_t destLen, const char *src, + size_t *skipSrc, int what); static char *strrchr2(const char *start, int c, const char *end); @@ -73,19 +73,56 @@ mkdirhier (const char *path) pathstart = path; #ifdef WIN32 - // driveletter + semicolon on Windows. if (isDriveLetter(pathstart[0]) && pathstart[1] == ':') { + // Driveletter + semicolon on Windows. + // Copy as is; don't try to create directories for it. *(ptr++) = *(pathstart++); *(ptr++) = *(pathstart++); + + ptr[0] = '/'; + ptr[1] = '\0'; + if (stat (buf, &statbuf) == -1) + { + log_add (log_Error, "Can't stat \"%s\": %s", buf, strerror (errno)); + return -1; + } + } else if (pathstart[0] == '\\' && pathstart[1] == '\\') { + // Windows UNC path. (\\server\share\...) + // Copy the server part as is; don't try to create directories for + // it, or stat it. Don't create a dir for the share either. + *(ptr++) = *(pathstart++); + *(ptr++) = *(pathstart++); + + // Copy the server part + while (*pathstart != '\0' && *pathstart != '\\' && *pathstart != '/') + *(ptr++) = *(pathstart++); + + if (*pathstart == '\0') + { + log_add (log_Error, "Incomplete UNC path \"%s\"", pathstart); + return -1; + } + + // Copy the path seperator. + *(ptr++) = *(pathstart++); + + // Copy the share part + while (*pathstart != '\0' && *pathstart != '\\' && *pathstart != '/') + *(ptr++) = *(pathstart++); + + ptr[0] = '/'; + ptr[1] = '\0'; + if (stat (buf, &statbuf) == -1) + { + log_add (log_Error, "Can't stat \"%s\": %s", buf, strerror (errno)); + return -1; + } } #endif - if (*pathstart == '/') { - *ptr = '/'; - ptr++; - pathstart++; - } + if (*pathstart == '/') + *(ptr++) = *(pathstart++); if (*pathstart == '\0') { // path exists completely, nothing more to do @@ -106,7 +143,7 @@ mkdirhier (const char *path) { if (errno != ENOENT) { - log_add (log_Error, "Can't stat %s: %s", buf, + log_add (log_Error, "Can't stat \"%s\": %s", buf, strerror (errno)); return -1; } @@ -194,6 +231,8 @@ getHomeDir (void) // EP_DOTS - Process ".." and "." // EP_SLASHES - Consider backslashes as path component separators. // They will be replaced by slashes. +// EP_SINGLESEP - Replace multiple consecutive path seperators (which POSIX +// considers equivalent to a single one) by a single one. // Additionally, there's EP_ALL, which indicates all of the above, // and EP_SYSTEM_ALL, which does the same as EP_ALL, with the exception // of EP_SLASHES, which will only be included if the operating system @@ -396,13 +435,15 @@ expandPath (char *dest, size_t len, const char *src, int what) homelen = strlen (home); if (what & EP_ABSOLUTE) { + size_t skip; destptr = expandPathAbsolute (dest, destend - dest, - home, what); + home, &skip, what); if (destptr == NULL) { // errno is set return -1; } + home += skip; what &= ~EP_ABSOLUTE; // The part after the '~' should not be seen // as absolute. @@ -417,13 +458,15 @@ expandPath (char *dest, size_t len, const char *src, int what) if (what & EP_ABSOLUTE) { + size_t skip; destptr = expandPathAbsolute (destptr, destend - destptr, src, - what); + &skip, what); if (destptr == NULL) { // errno is set return -1; } + src += skip; } CHECKLEN (dest, srcend - src); @@ -435,6 +478,20 @@ expandPath (char *dest, size_t len, const char *src, int what) { /* Replacing backslashes in path by slashes. */ destptr = dest; +#ifdef WIN32 + { + // A Windows UNC path should always start with two backslashes + // and have a backslash in between the server and share part. + size_t skip = skipUNCServerShare (destptr); + if (skip != 0) + { + char *slash = (char *) memchr (destptr + 2, '/', skip - 2); + if (slash) + *slash = '\\'; + destptr += skip; + } + } +#endif while (*destptr != '\0') { if (*destptr == '\\') @@ -456,8 +513,15 @@ expandPath (char *dest, size_t len, const char *src, int what) pathStart = dest; #ifdef WIN32 - if (isDriveLetter(src[0]) && (src[1] == ':')) + if (isDriveLetter(pathStart[0]) && (pathStart[1] == ':')) + { pathStart += 2; + } + else + { + // Test for a UNC path. + pathStart += skipUNCServerShare(pathStart); + } #endif if (pathStart[0] == '/') pathStart++; @@ -517,34 +581,113 @@ expandPath (char *dest, size_t len, const char *src, int what) *destptr = '\0'; } + if (what & EP_SINGLESEP) + { + char *srcptr; + srcptr = dest; + destptr = dest; + while (*srcptr != '\0') + { + char ch = *srcptr; + *(destptr++) = *(srcptr++); + if (ch == '/') + { + while (*srcptr == '/') + srcptr++; + } + } + *destptr = '\0'; + } + return 0; } +#ifdef WIN32 +// letter is 0 based: 0 = A, 1 = B, ... +bool +driveLetterExists(int letter) +{ + unsigned long drives; + + drives = _getdrives (); + + return ((drives >> letter) & 1) != 0; +} +#endif + // helper for expandPath, expanding an absolute path // returns a pointer to the end of the filled in part of dest. static char * -expandPathAbsolute (char *dest, size_t destLen, const char *src, int what) +expandPathAbsolute (char *dest, size_t destLen, const char *src, + size_t *skipSrc, int what) { - if (src[0] == '/' || ((what & EP_SLASHES) && src[0] == '\\') -#ifdef WIN32 - || (isDriveLetter(src[0]) && (src[1] == ':')) -#endif - ) { + const char *orgSrc; + + if (src[0] == '/' || ((what & EP_SLASHES) && src[0] == '\\')) + { // Path is already absolute; nothing to do + *skipSrc = 0; return dest; } - // Path is not already absolute; we've got work to do. - if (getcwd (dest, destLen) == NULL) + orgSrc = src; +#ifdef WIN32 + if (isDriveLetter(src[0]) && (src[1] == ':')) { - // errno is set - return NULL; + int letter; + + if (src[2] == '/' || src[2] == '\\') + { + // Path is already absolute (of the form "d:/"); nothing to do + *skipSrc = 0; + return dest; + } + + // Path is of the form "d:path", without a (back)slash after the + // semicolon. + + letter = tolower(src[0]) - 'a'; + + // _getdcwd() should only be called on drives that exist. + // This is weird though, because it means a race condition + // in between the existance check and the call to _getdcwd() + // cannot be avoided, unless a drive still exists for Windows + // when the physical drive is removed. + if (!driveLetterExists(letter)) + { + errno = ENOENT; + return NULL; + } + + // Get the working directory for a specific drive. + if (_getdcwd (letter + 1, dest, destLen) == NULL) + { + // errno is set + return NULL; + } + + src += 2; + } + else +#endif + { + // Relative dir + if (getcwd (dest, destLen) == NULL) + { + // errno is set + return NULL; + } } { size_t tempLen; tempLen = strlen (dest); - assert (tempLen > 0); + if (tempLen == 0) + { + // getcwd() or _getdcwd() returned a 0-length string. + errno = ENOENT; + return NULL; + } dest += tempLen; destLen -= tempLen; } @@ -561,6 +704,8 @@ expandPathAbsolute (char *dest, size_t destLen, const char *src, int what) dest++; destLen--; } + + *skipSrc = (size_t) (src - orgSrc); return dest; } @@ -576,4 +721,34 @@ strrchr2(const char *start, int c, const char *end) { } } +#ifdef WIN32 +// returns 0 if the path is not a valid UNC path. +// Does not skip trailing slashes. +size_t +skipUNCServerShare(const char *inPath) { + const char *path = inPath; + + // Skip the initial two backslashes. + if (path[0] != '\\' || path[1] != '\\') + return (size_t) 0; + path += 2; + + // Skip the server part. + while (*path != '\\' && *path != '/') { + if (*path == '\0') + return (size_t) 0; + path++; + } + + // Skip the seperator. + path++; + + // Skip the share part. + while (*path != '\0' && *path != '\\' && *path != '/') + path++; + + return (size_t) (path - inPath); +} +#endif + diff --git a/sc2/src/sc2code/libs/resource/direct.c b/sc2/src/sc2code/libs/resource/direct.c index 0e28f2c29..b99b98b36 100644 --- a/sc2/src/sc2code/libs/resource/direct.c +++ b/sc2/src/sc2code/libs/resource/direct.c @@ -68,7 +68,7 @@ LoadDirEntryTable (uio_DirHandle *dirHandle, const char *path, uio_closeDir (dir); if (num_entries == 0) { - uio_freeDirList(dirList); + uio_DirList_free(dirList); *pnum_entries = 0; return ((DIRENTRY_REF) 0); } @@ -80,7 +80,7 @@ LoadDirEntryTable (uio_DirHandle *dirHandle, const char *path, if (lpST == 0) { FreeStringTable (StringTable); - uio_freeDirList(dirList); + uio_DirList_free(dirList); *pnum_entries = 0; return ((DIRENTRY_REF) 0); } @@ -101,7 +101,7 @@ LoadDirEntryTable (uio_DirHandle *dirHandle, const char *path, lpStr += size; } - uio_freeDirList(dirList); + uio_DirList_free(dirList); *pnum_entries = num_entries; UnlockStringTable (StringTable); return ((DIRENTRY_REF) StringTable); diff --git a/sc2/src/sc2code/libs/uio/debug.c b/sc2/src/sc2code/libs/uio/debug.c index 0618af5ef..96ddcd4a3 100644 --- a/sc2/src/sc2code/libs/uio/debug.c +++ b/sc2/src/sc2code/libs/uio/debug.c @@ -712,7 +712,7 @@ listOneDir(DebugContext *debugContext, const char *arg) { } for (i = 0; i < dirList->numNames; i++) fprintf(debugContext->out, "%s\n", dirList->names[i]); - uio_freeDirList(dirList); + uio_DirList_free(dirList); return 0; } diff --git a/sc2/src/sc2code/libs/uio/doc/todo b/sc2/src/sc2code/libs/uio/doc/todo index 12b6dddeb..4240ca12e 100644 --- a/sc2/src/sc2code/libs/uio/doc/todo +++ b/sc2/src/sc2code/libs/uio/doc/todo @@ -12,7 +12,7 @@ Documentation: - It would be (theoretically) possible to add HTTP and FTP support for remote file systems. - on adding extra file system types: -- open, mkdir, rmdir, and unlink should themselves make sure that + open, mkdir, rmdir, and unlink should themselves make sure that the physical structure is kept up to date when an entry is removed or added. - stream stuff is not thread safe @@ -36,7 +36,7 @@ Bugs: in the dirHandle, which will cause problems. - 'openDirRelative(repository, "/")' causes segfaults later on - uio_rename() doesn't work on directories - uio_getPhysicalAccess() needs to be changed so that it works the same on +- uio_getPhysicalAccess() needs to be changed so that it works the same on dirs as on files. stat() can be cleaned up too then. - uio_getPhysicalAccess() will not return ENOENT when (only) the last component does not exist, even when O_RDONLY is used. diff --git a/sc2/src/sc2code/libs/uio/fileblock.c b/sc2/src/sc2code/libs/uio/fileblock.c index 7b824335c..78ea4b82f 100644 --- a/sc2/src/sc2code/libs/uio/fileblock.c +++ b/sc2/src/sc2code/libs/uio/fileblock.c @@ -27,7 +27,7 @@ static uio_FileBlock *uio_FileBlock_new(uio_Handle *handle, int flags, off_t offset, size_t blockSize, char *buffer, size_t bufSize); static inline uio_FileBlock *uio_FileBlock_alloc(void); -static void uio_freeFileBlock(uio_FileBlock *block); +static void uio_FileBlock_free(uio_FileBlock *block); uio_FileBlock * @@ -150,11 +150,11 @@ uio_closeFileBlock(uio_FileBlock *block) { uio_free(block->buffer); } uio_Handle_unref(block->handle); - uio_freeFileBlock(block); + uio_FileBlock_free(block); return 0; } -// caller should uio_refHandle(handle) (unless it doesn't need it's own +// caller should uio_Handle_ref(handle) (unless it doesn't need it's own // reference anymore). static uio_FileBlock * uio_FileBlock_new(uio_Handle *handle, int flags, off_t offset, @@ -177,7 +177,7 @@ uio_FileBlock_alloc(void) { } static void -uio_freeFileBlock(uio_FileBlock *block) { +uio_FileBlock_free(uio_FileBlock *block) { uio_free(block); } diff --git a/sc2/src/sc2code/libs/uio/fstypes.c b/sc2/src/sc2code/libs/uio/fstypes.c index 43702cab0..d940e8fb5 100644 --- a/sc2/src/sc2code/libs/uio/fstypes.c +++ b/sc2/src/sc2code/libs/uio/fstypes.c @@ -38,7 +38,8 @@ static uio_FileSystemInfo **uio_getFileSystemInfoPtr(uio_FileSystemID id); static inline uio_FileSystemInfo *uio_FileSystemInfo_alloc(void); -static inline void uio_freeFileSystemInfo(uio_FileSystemInfo *fileSystemInfo); +static inline void uio_FileSystemInfo_free( + uio_FileSystemInfo *fileSystemInfo); uio_FileSystemInfo *uio_fileSystems = NULL; @@ -173,9 +174,9 @@ uio_unRegisterFileSystem(uio_FileSystemID id) { temp = *ptr; *ptr = (*ptr)->next; -// uio_unrefFileSystemHandler(temp->handler); +// uio_FileSystemHandler_unref(temp->handler); uio_free(temp->name); - uio_freeFileSystemInfo(temp); + uio_FileSystemInfo_free(temp); return 0; } @@ -261,7 +262,7 @@ uio_FileSystemInfo_alloc(void) { // *** Deallocators *** static inline void -uio_freeFileSystemInfo(uio_FileSystemInfo *fileSystemInfo) { +uio_FileSystemInfo_free(uio_FileSystemInfo *fileSystemInfo) { #ifdef uio_MEM_DEBUG uio_MemDebug_debugFree(uio_FileSystemInfo, (void *) fileSystemInfo); #endif diff --git a/sc2/src/sc2code/libs/uio/io.c b/sc2/src/sc2code/libs/uio/io.c index f4f12804a..0e6c9ecd2 100644 --- a/sc2/src/sc2code/libs/uio/io.c +++ b/sc2/src/sc2code/libs/uio/io.c @@ -311,7 +311,7 @@ uio_unmountDir(uio_MountHandle *mountHandle) { uio_repositoryRemoveMount(mountHandle->repository, mountHandle->mountInfo); - uio_deleteMountInfo(mountHandle->mountInfo); + uio_MountInfo_delete(mountHandle->mountInfo); uio_MountHandle_delete(mountHandle); uio_PRoot_unrefMount(pRoot); @@ -643,7 +643,7 @@ uio_open(uio_DirHandle *dir, const char *path, int flags, mode_t mode) { uio_DirHandle * uio_openDir(uio_Repository *repository, const char *path, int flags) { uio_DirHandle *dirHandle; - const char * const rootStr = "/"; + const char * const rootStr = ""; dirHandle = uio_DirHandle_new(repository, unconst(rootStr), unconst(rootStr)); @@ -1009,8 +1009,8 @@ typedef struct uio_DirBufferLink { } uio_DirBufferLink; static int strPtrCmp(const char * const *ptr1, const char * const *ptr2); -static void uio_freeDirBufferLink(uio_DirBufferLink *sdbl); -static void uio_freeDirBufferChain(uio_DirBufferLink *dirBufferLink); +static void uio_DirBufferLink_free(uio_DirBufferLink *sdbl); +static void uio_DirBufferChain_free(uio_DirBufferLink *dirBufferLink); static uio_DirList *uio_getDirListMulti(uio_PDirHandle **pDirHandles, int numPDirHandles, const char *pattern, match_MatchType matchType); static uio_DirList *uio_makeDirList(const char **newNames, @@ -1037,7 +1037,7 @@ static inline void uio_EntriesContext_free(uio_EntriesContext // The caller may modify the elements of dirHandle->names, but // dirHandle->names itself, and the rest of the elements of dirHandle -// should be left alone, so that they will be freed by uio_freeDirList(). +// should be left alone, so that they will be freed by uio_DirList_free(). uio_DirList * uio_getDirList(uio_DirHandle *dirHandle, const char *path, const char *pattern, match_MatchType matchType) { @@ -1182,7 +1182,7 @@ uio_getDirListMulti(uio_PDirHandle **pDirHandles, // free the old junk for (pDirI = 0; pDirI < numPDirHandles; pDirI++) - uio_freeDirBufferChain(links[pDirI]); + uio_DirBufferChain_free(links[pDirI]); uio_free(links); uio_free(numNames); @@ -1252,7 +1252,7 @@ uio_collectDirEntries(uio_PDirHandle *pDirHandle, uio_DirBufferLink **linkPtr, if (numRead == 0) { fprintf(stderr, "Warning: uio_DIR_BUFFER_SIZE is too small to " "hold a certain large entry on its own!\n"); - uio_freeDirBufferLink(*linkEndPtr); + uio_DirBufferLink_free(*linkEndPtr); break; } totalEntries += numRead; @@ -1356,18 +1356,18 @@ uio_EntriesContext_free(uio_EntriesContext *entriesContext) { } static void -uio_freeDirBufferLink(uio_DirBufferLink *dirBufferLink) { +uio_DirBufferLink_free(uio_DirBufferLink *dirBufferLink) { uio_free(dirBufferLink->buffer); uio_free(dirBufferLink); } static void -uio_freeDirBufferChain(uio_DirBufferLink *dirBufferLink) { +uio_DirBufferChain_free(uio_DirBufferLink *dirBufferLink) { uio_DirBufferLink *next; while (dirBufferLink != NULL) { next = dirBufferLink->next; - uio_freeDirBufferLink(dirBufferLink); + uio_DirBufferLink_free(dirBufferLink); dirBufferLink = next; } } @@ -1389,7 +1389,7 @@ uio_DirList_alloc(void) { } void -uio_freeDirList(uio_DirList *dirList) { +uio_DirList_free(uio_DirList *dirList) { if (dirList->buffer) uio_free(dirList->buffer); if (dirList->names) diff --git a/sc2/src/sc2code/libs/uio/io.h b/sc2/src/sc2code/libs/uio/io.h index db66796d1..9269071d8 100644 --- a/sc2/src/sc2code/libs/uio/io.h +++ b/sc2/src/sc2code/libs/uio/io.h @@ -135,7 +135,7 @@ int uio_closeDir(uio_DirHandle *dirHandle); uio_DirList *uio_getDirList(uio_DirHandle *dirHandle, const char *path, const char *pattern, match_MatchType matchType); -void uio_freeDirList(uio_DirList *dirList); +void uio_DirList_free(uio_DirList *dirList); // For debugging purposes void uio_DirHandle_print(const uio_DirHandle *dirHandle, FILE *out); diff --git a/sc2/src/sc2code/libs/uio/ioaux.c b/sc2/src/sc2code/libs/uio/ioaux.c index d6d6fac4d..411a81b35 100644 --- a/sc2/src/sc2code/libs/uio/ioaux.c +++ b/sc2/src/sc2code/libs/uio/ioaux.c @@ -33,17 +33,30 @@ static int copyError(int error, uio_FileSystemHandler *toHandler, uio_Handle *toHandle, uio_PDirHandle *toDir, const char *toName, char *buf); -/* - * Follow a path starting from a specified physical dir as long as possible. - * When you can get no further, 'endPDirHandle' will be filled in with a - * reference to the dir where you ended up, and 'pathRest' will point into - * the original path to the beginning of the part that was not matched. - * It is allowed to have endPDirHandle point to pDirHandle and/or restPath - * point to path when calling this function. Just take care to keep a - * reference to the original so you can decrement the ref counter. - * returns: 0 if the complete path was matched - * ENOENT if some component (the next one) didn't exists - * ENODIR if a component (the next one) exists but isn't a dir +/** + * Follow a path starting from a specified physical dir for as long as + * possible. + * + * @param[in] startPDirHandle The physical dir to start from. + * @param[in] path The path to follow, relative to + * 'startPDirHandle'. + * @param[in] pathLen The string length of 'path'. + * @param[out] endPDirHandle The physical dir where you end up after + * following 'path' for as long as possible. Unmodified if an error + * occurs. + * @param[out] pathRest '*pathRest' will point into 'path' to the + * start the part that was not matched. Unmodified if an error occurs. + * + * @retval 0 if the complete path was matched + * @retval ENOENT if some component (the next one in '*pathRest') didn't + * exist. + * @retval ENODIR if a component (the next one in '*pathRest') did exist, + * but wasn't a dir. + * + * @note It is allowed to have 'endPDirHandle' point to pDirHandle, but + * care should be taken to keep a reference to the original so its + * reference counter can be decremented. + * @note It is allowed to have 'pathRest' point to 'path'. */ int uio_walkPhysicalPath(uio_PDirHandle *startPDirHandle, const char *path, @@ -61,7 +74,7 @@ uio_walkPhysicalPath(uio_PDirHandle *startPDirHandle, const char *path, tempBuf = uio_alloca(strlen(path) + 1); pathEnd = path + pathLen; getFirstPathComponent(path, pathEnd, &partStart, &partEnd); - while (1) { + for (;;) { if (partStart == pathEnd) { retVal = 0; break; @@ -89,7 +102,19 @@ uio_walkPhysicalPath(uio_PDirHandle *startPDirHandle, const char *path, return retVal; } -// Make a all directory components of a path, inside a physical directory. +/** + * Create a directory inside a physical directory. All non-existant + * parent directories will be created as well. + * + * @param[in] pDirHandle The physical directory to which 'path' is relative + * @param[in] path The path to the directory to create, relative to + * 'pDirHandle' + * @param[in] pathLen The string length of 'path'. + * @param[in] mode The access mode for the newly created directories. + * + * @returns the new (physical) directory, or NULL if an error occurs, in + * which case #errno will be set. + */ uio_PDirHandle * uio_makePath(uio_PDirHandle *pDirHandle, const char *path, size_t pathLen, mode_t mode) { @@ -136,12 +161,23 @@ uio_makePath(uio_PDirHandle *pDirHandle, const char *path, size_t pathLen, return pDirHandle; } -/* - * permissions should already have been checked + +/** + * Copy a file from one physical directory to another. + * The copy will have the same file permissions as the original. * - * The new file will have the same permissions as the old. - * If an error occurs during copying, an attempt will be made to - * remove the copy. + * @param[in] fromDir The physical directory where the file to copy is + * located. + * @param[in] fromName The name of the file to copy. + * @param[in] toDir The physical directory where to put the copy. + * @param[in] toName The name to use for the copy. + * + * @note It is up to the caller to make any relevant permissions checks. + * + * @note This function will fail if a file with the name in 'toName' already + * exists, leaving the original file intact. If an error occurs during + * copying, an attempt is made to remove the file that was to be the + * copy. */ int uio_copyFilePhysical(uio_PDirHandle *fromDir, const char *fromName, @@ -683,7 +719,7 @@ uio_verifyPath(uio_DirHandle *dirHandle, const char *path, return 0; } - // try all the MountInfo structures in effect for this MountTree + // Try all the MountInfo structures in effect for this MountTree. for (item = tree->pLocs; item != NULL; item = item->next) { const char *pRootPath; uio_PDirHandle *pDirHandle; @@ -695,7 +731,7 @@ uio_verifyPath(uio_DirHandle *dirHandle, const char *path, uio_PDirHandle_unref(pDirHandle); switch (retVal) { case 0: - // complete match. We're done. + // Complete match. We're done. return 0; case ENOTDIR: // A component is matched, but not as a dir. Failed. @@ -703,7 +739,7 @@ uio_verifyPath(uio_DirHandle *dirHandle, const char *path, errno = ENOTDIR; return -1; case ENOENT: - // no match; try next pLoc + // No match; try the next pLoc. continue; default: // Unknown error. Let's bail out just to be safe. @@ -723,12 +759,21 @@ uio_verifyPath(uio_DirHandle *dirHandle, const char *path, return -1; } -// Get the absolute path pointed to by 'path' relative to 'dirHandle' -// The new path will be put in '*destPath', which will be newly allocated. -// It will be \0-terminated, and will not have a '/' as first or last -// character. -// The length of '*destPath' will be returned. -// On error, -1 will be returned, and errno will be set. +/** + * Determine the absolute path given a path relative to a given directory. + * + * @param[in] dirHandle The directory to which 'path' is relative. + * @param[in] path The path, relative to 'dirHandle', to make + * absolute. + * @param[in] pathLen The string length of 'path'. + * @param[out] destPath Filled with a newly allocated string containing + * the sought absolute path. It will not contain a '/' as the first + * or last character. It should be freed with uio_free(). + * Unmodified if an error occurs. + * + * @returns the length of '*destPath', or -1 if an error occurs, in which + * case #errno will be set. + */ ssize_t uio_resolvePath(uio_DirHandle *dirHandle, const char *path, size_t pathLen, char **destPath) { diff --git a/sc2/src/sc2code/libs/uio/mem.h b/sc2/src/sc2code/libs/uio/mem.h index 4bf264e40..6fff349e7 100644 --- a/sc2/src/sc2code/libs/uio/mem.h +++ b/sc2/src/sc2code/libs/uio/mem.h @@ -48,6 +48,15 @@ uio_strdup(const char *s) { # define uio_strdup strdup #endif +// Allocates new memory, copies 'len' characters from 'src', and adds a '\0'. +static inline char * +uio_memdup0(const char *src, size_t len) { + char *dst = uio_malloc(len + 1); + memcpy(dst, src, len); + dst[len] = '\0'; + return dst; +} + #endif diff --git a/sc2/src/sc2code/libs/uio/mount.c b/sc2/src/sc2code/libs/uio/mount.c index 623106c6f..1bde4d7f4 100644 --- a/sc2/src/sc2code/libs/uio/mount.c +++ b/sc2/src/sc2code/libs/uio/mount.c @@ -31,9 +31,9 @@ # include "memdebug.h" #endif -static void uio_deleteRepository(uio_Repository *repository); +static void uio_Repository_delete(uio_Repository *repository); static uio_Repository *uio_Repository_alloc(void); -static void uio_freeRepository(uio_Repository *repository); +static void uio_Repository_free(uio_Repository *repository); void @@ -137,7 +137,7 @@ uio_Repository_unref(uio_Repository *repository) { assert(repository->ref > 0); repository->ref--; if (repository->ref == 0) - uio_deleteRepository(repository); + uio_Repository_delete(repository); } static uio_Repository * @@ -150,15 +150,15 @@ uio_Repository_alloc(void) { } static void -uio_deleteRepository(uio_Repository *repository) { +uio_Repository_delete(uio_Repository *repository) { assert(repository->numMounts == 0); uio_free(repository->mounts); - uio_deleteMountTree(repository->mountTree); - uio_freeRepository(repository); + uio_MountTree_delete(repository->mountTree); + uio_Repository_free(repository); } static void -uio_freeRepository(uio_Repository *repository) { +uio_Repository_free(uio_Repository *repository) { #ifdef uio_MEM_DEBUG uio_MemDebug_debugFree(uio_Repository, (void *) repository); #endif diff --git a/sc2/src/sc2code/libs/uio/mounttree.c b/sc2/src/sc2code/libs/uio/mounttree.c index dc69ac33e..eb5bdec77 100644 --- a/sc2/src/sc2code/libs/uio/mounttree.c +++ b/sc2/src/sc2code/libs/uio/mounttree.c @@ -63,10 +63,6 @@ static uio_MountTree * uio_splitMountTree(uio_MountTree **tree, uio_PathComp *lastComp, int depth); static void uio_mountTreeRemoveMountInfoRec(uio_MountTree *mountTree, uio_MountInfo *mountInfo); -static int uio_countPathComps(const uio_PathComp *comp); -static uio_PathComp *uio_lastPathComp(uio_PathComp *comp); -static uio_PathComp *uio_makePathComps(const char *path, - uio_PathComp *upComp); static void uio_printMount(FILE *outStream, const uio_MountInfo *mountInfo); static inline uio_MountTree * uio_MountTree_new(uio_MountTree *subTrees, @@ -74,21 +70,16 @@ static inline uio_MountTree * uio_MountTree_new(uio_MountTree *subTrees, *comps, uio_PathComp *lastComp, uio_MountTree *next); static inline uio_MountTreeItem *uio_MountTree_newItem( uio_MountInfo *mountInfo, int depth, uio_MountTreeItem *next); -static inline uio_PathComp *uio_PathComp_new(char *name, size_t nameLen, - uio_PathComp *upComp); -static inline void uio_deleteMountTreeItem(uio_MountTreeItem *item); -static inline void uio_deletePathComp(uio_PathComp *pathComp); +static inline void uio_MountTreeItem_delete(uio_MountTreeItem *item); static inline uio_MountTree *uio_MountTree_alloc(void); static inline uio_MountTreeItem *uio_MountTreeItem_alloc(void); static inline uio_MountInfo *uio_MountInfo_alloc(void); -static inline uio_PathComp *uio_PathComp_alloc(void); -static inline void uio_freeMountTree(uio_MountTree *mountTree); -static inline void uio_freeMountTreeItem(uio_MountTreeItem *mountTreeItem); -static inline void uio_freeMountInfo(uio_MountInfo *mountInfo); -static inline void uio_freePathComp(uio_PathComp *pathComp); +static inline void uio_MountTree_free(uio_MountTree *mountTree); +static inline void uio_MountTreeItem_free(uio_MountTreeItem *mountTreeItem); +static inline void uio_MountInfo_free(uio_MountInfo *mountInfo); // make the root mount Tree @@ -409,7 +400,7 @@ uio_mountTreeRemoveMountInfo(uio_Repository *repository, upTree = mountTree->upTree; // Remove the tree itself. - uio_deleteMountTree(mountTree); + uio_MountTree_delete(mountTree); // The upTree itself could have become unnecessary now. // This is the case when upTree now only has one subTree, and upTree @@ -453,7 +444,7 @@ uio_mountTreeRemoveMountInfo(uio_Repository *repository, // Now delete the tree itself upTree->subTrees = NULL; upTree->comps = NULL; - uio_deleteMountTree(upTree); + uio_MountTree_delete(upTree); } // pre: mountInfo exists in mountTree->pLocs (and hence in pLocs for @@ -484,28 +475,7 @@ uio_mountTreeRemoveMountInfoRec(uio_MountTree *mountTree, item = *itemPtr; *itemPtr = item->next; - uio_deleteMountTreeItem(item); -} - -// Count the number of path components that 'comp' leads to. -static int -uio_countPathComps(const uio_PathComp *comp) { - int count; - - count = 0; - for (; comp != NULL; comp = comp->next) - count++; - return count; -} - -static uio_PathComp * -uio_lastPathComp(uio_PathComp *comp) { - if (comp == NULL) - return NULL; - - while (comp->next != NULL) - comp = comp->next; - return comp; + uio_MountTreeItem_delete(item); } // Count the number of pLocs in a tree that leads to. @@ -520,30 +490,6 @@ uio_mountTreeCountPLocs(const uio_MountTree *tree) { return count; } -// make a list of uio_PathComps from a path string -static uio_PathComp * -uio_makePathComps(const char *path, uio_PathComp *upComp) { - const char *start, *end; - char *str; - uio_PathComp *result; - uio_PathComp **compPtr; // Where to put the next PathComp - - compPtr = &result; - getFirstPath0Component(path, &start, &end); - while (*start != '\0') { - str = uio_malloc(end - start + 1); - memcpy(str, start, end - start); - str[end - start] = '\0'; - - *compPtr = uio_PathComp_new(str, end - start, upComp); - upComp = *compPtr; - compPtr = &(*compPtr)->next; - getNextPath0Component(&start, &end); - } - *compPtr = NULL; - return result; -} - // resTree may point to top // pPath may point to path void @@ -691,20 +637,6 @@ uio_printPathToMountTree(FILE *outStream, const uio_MountTree *tree) { uio_printPathToComp(outStream, tree->lastComp); } -void -uio_printPathComp(FILE *outStream, const uio_PathComp *comp) { - fprintf(outStream, "%s", comp->name); -} - -void -uio_printPathToComp(FILE *outStream, const uio_PathComp *comp) { - if (comp == NULL) - return; - uio_printPathToComp(outStream, comp->up); - fprintf(outStream, "/"); - uio_printPathComp(outStream, comp); -} - void uio_printMountInfo(FILE *outStream, const uio_MountInfo *mountInfo) { uio_FileSystemInfo *fsInfo; @@ -757,28 +689,28 @@ uio_MountTree_new(uio_MountTree *subTrees, uio_MountTreeItem *pLocs, } void -uio_deleteMountTree(uio_MountTree *tree) { +uio_MountTree_delete(uio_MountTree *tree) { uio_MountTree *subTree, *nextTree; uio_MountTreeItem *item, *nextItem; subTree = tree->subTrees; while (subTree != NULL) { nextTree = subTree->next; - uio_deleteMountTree(subTree); + uio_MountTree_delete(subTree); subTree = nextTree; } item = tree->pLocs; while (item != NULL) { nextItem = item->next; - uio_deleteMountTreeItem(item); + uio_MountTreeItem_delete(item); item = nextItem; } if (tree->comps != NULL) - uio_deletePathComp(tree->comps); + uio_PathComp_delete(tree->comps); - uio_freeMountTree(tree); + uio_MountTree_free(tree); } static inline uio_MountTree * @@ -791,7 +723,7 @@ uio_MountTree_alloc(void) { } static inline void -uio_freeMountTree(uio_MountTree *mountTree) { +uio_MountTree_free(uio_MountTree *mountTree) { #ifdef uio_MEM_DEBUG uio_MemDebug_debugFree(uio_MountTree, (void *) mountTree); #endif @@ -814,8 +746,8 @@ uio_MountTree_newItem(uio_MountInfo *mountInfo, int depth, } static inline void -uio_deleteMountTreeItem(uio_MountTreeItem *item) { - uio_freeMountTreeItem(item); +uio_MountTreeItem_delete(uio_MountTreeItem *item) { + uio_MountTreeItem_free(item); } static inline uio_MountTreeItem * @@ -828,7 +760,7 @@ uio_MountTreeItem_alloc(void) { } static inline void -uio_freeMountTreeItem(uio_MountTreeItem *mountTreeItem) { +uio_MountTreeItem_free(uio_MountTreeItem *mountTreeItem) { #ifdef uio_MEM_DEBUG uio_MemDebug_debugFree(uio_MountTreeItem, (void *) mountTreeItem); #endif @@ -856,10 +788,10 @@ uio_MountInfo_new(uio_FileSystemID fsID, uio_MountTree *mountTree, } void -uio_deleteMountInfo(uio_MountInfo *mountInfo) { +uio_MountInfo_delete(uio_MountInfo *mountInfo) { uio_free(mountInfo->dirName); uio_PDirHandle_unref(mountInfo->pDirHandle); - uio_freeMountInfo(mountInfo); + uio_MountInfo_free(mountInfo); } static inline uio_MountInfo * @@ -872,7 +804,7 @@ uio_MountInfo_alloc(void) { } static inline void -uio_freeMountInfo(uio_MountInfo *mountInfo) { +uio_MountInfo_free(uio_MountInfo *mountInfo) { #ifdef uio_MEM_DEBUG uio_MemDebug_debugFree(uio_MountInfo, (void *) mountInfo); #endif @@ -880,49 +812,3 @@ uio_freeMountInfo(uio_MountInfo *mountInfo) { } -// *** uio_PathComp *** // - -// 'name' should be a null terminated string. It is stored in the PathComp, -// no copy is made. -// 'namelen' should be the length of 'name' -static inline uio_PathComp * -uio_PathComp_new(char *name, size_t nameLen, uio_PathComp *upComp) { - uio_PathComp *result; - - result = uio_PathComp_alloc(); - result->name = name; - result->nameLen = nameLen; - result->up = upComp; - return result; -} - -static inline void -uio_deletePathComp(uio_PathComp *pathComp) { - uio_PathComp *next; - - while (pathComp != NULL) { - next = pathComp->next; - uio_free(pathComp->name); - uio_freePathComp(pathComp); - pathComp = next; - } -} - -static inline uio_PathComp * -uio_PathComp_alloc(void) { - uio_PathComp *result = uio_malloc(sizeof (uio_PathComp)); -#ifdef uio_MEM_DEBUG - uio_MemDebug_debugAlloc(uio_PathComp, (void *) result); -#endif - return result; -} - -static inline void -uio_freePathComp(uio_PathComp *pathComp) { -#ifdef uio_MEM_DEBUG - uio_MemDebug_debugFree(uio_PathComp, (void *) pathComp); -#endif - uio_free(pathComp); -} - - diff --git a/sc2/src/sc2code/libs/uio/mounttree.h b/sc2/src/sc2code/libs/uio/mounttree.h index f2c2eaf18..04c5586fc 100644 --- a/sc2/src/sc2code/libs/uio/mounttree.h +++ b/sc2/src/sc2code/libs/uio/mounttree.h @@ -33,12 +33,12 @@ void uio_printMounts(FILE *outStream, const uio_Repository *repository); typedef struct uio_MountTreeItem uio_MountTreeItem; typedef struct uio_MountTree uio_MountTree; -typedef struct uio_PathComp uio_PathComp; typedef struct uio_MountInfo uio_MountInfo; #include "physical.h" #include "types.h" #include "uioport.h" +#include "paths.h" /* @@ -69,19 +69,6 @@ struct uio_MountTreeItem { // The next MountTreeItem in a MountTree }; -struct uio_PathComp { - char *name; - // The name of this path component, 0-terminated - size_t nameLen; - // The length of the 'name' field, for fast lookups. - struct uio_PathComp *next; - // The next path component leading to a MountTree - // If this is NULL, then this was the last component - // until the MountTree that - struct uio_PathComp *up; - // Links to the directory -}; - struct uio_MountTree { struct uio_MountTree *subTrees; // Trees for subdirs in this MountTree @@ -183,7 +170,7 @@ struct uio_MountInfo { */ uio_MountTree *uio_makeRootMountTree(void); -void uio_deleteMountTree(uio_MountTree *tree); +void uio_MountTree_delete(uio_MountTree *tree); uio_MountTree *uio_mountTreeAddMountInfo(uio_Repository *repository, uio_MountTree *mountTree, uio_MountInfo *mountInfo, const char *path, uio_MountLocation location, const uio_MountInfo *relative); @@ -198,13 +185,12 @@ uio_MountInfo *uio_MountInfo_new(uio_FileSystemID fsID, uio_MountTree *mountTree, uio_PDirHandle *pDirHandle, char *dirName, uio_AutoMount **autoMount, uio_MountHandle *mountHandle, int flags); -void uio_deleteMountInfo(uio_MountInfo *mountInfo); -void uio_printMountTree(FILE *outStream, const uio_MountTree *tree, int indent); +void uio_MountInfo_delete(uio_MountInfo *mountInfo); +void uio_printMountTree(FILE *outStream, const uio_MountTree *tree, + int indent); void uio_printMountTreeItem(FILE *outStream, const uio_MountTreeItem *item); void uio_printMountTreeItems(FILE *outStream, const uio_MountTreeItem *item); void uio_printPathToMountTree(FILE *outStream, const uio_MountTree *tree); -void uio_printPathComp(FILE *outStream, const uio_PathComp *comp); -void uio_printPathToComp(FILE *outStream, const uio_PathComp *comp); void uio_printMountInfo(FILE *outStream, const uio_MountInfo *mountInfo); static inline uio_bool diff --git a/sc2/src/sc2code/libs/uio/paths.c b/sc2/src/sc2code/libs/uio/paths.c index c053dedaa..144794740 100644 --- a/sc2/src/sc2code/libs/uio/paths.c +++ b/sc2/src/sc2code/libs/uio/paths.c @@ -18,14 +18,18 @@ * */ -#include #include +#include +#include #include #include "paths.h" #include "uioport.h" #include "mem.h" +static inline uio_PathComp *uio_PathComp_alloc(void); +static inline void uio_PathComp_free(uio_PathComp *pathComp); + // gets the first dir component of a path // sets '*start' to the start of the first component // sets '*end' to the end of the first component @@ -236,4 +240,357 @@ validPathName(const char *path, size_t len) { return true; } +// returns 0 if the path is not a valid UNC path. +// Does not skip trailing slashes. +size_t +uio_skipUNCServerShare(const char *inPath) { + const char *path = inPath; + + // Skip the initial two backslashes. + if (path[0] != '\\' || path[1] != '\\') + return (size_t) 0; + path += 2; + + // Skip the server part. + while (*path != '\\' && *path != '/') { + if (*path == '\0') + return (size_t) 0; + path++; + } + + // Skip the seperator. + path++; + + // Skip the share part. + while (*path != '\0' && *path != '\\' && *path != '/') + path++; + + return (size_t) (path - inPath); +} + +/** + * Find the server and share part of a Windows "Universal Naming Convention" + * path (a path of the form '\\server\share\path\file'). + * The path must contain at least a server and share path to be valid. + * The initial two slashes must be backslashes, the other slashes may each + * be either a forward slash or a backslash. + * + * @param[in] inPath The path to parse. + * @param[out] outPath Will contain a newly allocated string (to be + * freed using uio_free(), containing the server and share part + * of inPath, separated by a backslash, or NULL if 'inPath' was + * not a valid UNC path. + * @param[out] outLen If not NULL on entry, it will contain the string + * length of '*outPath', or 0 if 'inPath' was not a valid UNC path. + * + * @returns The number of characters to add to 'inPath' to get to the first + * path component past the server and share part, or 0 if 'inPath' + * was not a valid UNC path. + */ +size_t +uio_getUNCServerShare(const char *inPath, char **outPath, size_t *outLen) { + const char *ptr; + const char *server; + const char *serverEnd; + const char *share; + const char *shareEnd; + char *name; + char *nameEnd; + size_t nameLen; + + ptr = inPath; + + if (ptr[0] != '\\' || ptr[1] != '\\') + goto noMatch; + + // Parse the server part. + server = ptr + 2; + serverEnd = server; + for (;;) { + if (*serverEnd == '\0') + goto noMatch; + if (isPathDelimiter(*serverEnd)) + break; + serverEnd++; + } + if (serverEnd == server) + goto noMatch; + + // Parse the share part. + share = serverEnd + 1; + shareEnd = share; + while (*shareEnd != '\0') { + if (isPathDelimiter(*shareEnd)) + break; + serverEnd++; + } + + // Skip any trailing path delimiters. + ptr = shareEnd; + while (isPathDelimiter(*ptr)) + ptr++; + + // Allocate a new string and fill it. + nameLen = (serverEnd - server) + (shareEnd - share) + 3; + name = uio_malloc(nameLen + 1); + nameEnd = name; + *(nameEnd++) = '\\'; + *(nameEnd++) = '\\'; + memcpy(nameEnd, server, serverEnd - server); + *(nameEnd++) = '\\'; + memcpy(nameEnd, share, shareEnd - share); + *nameEnd = '\0'; + + *outPath = name; + if (outLen != NULL) + *outLen = nameLen; + return (size_t) (ptr - inPath); + +noMatch: + *outPath = NULL; + if (outLen != NULL) + *outLen = 0; + return (size_t) 0; +} + +// Decomposes a path into its components. +// If isAbsolute is not NULL, *isAbsolute will be set to true +// iff the path is absolute. +// As POSIX considers multiple consecutive slashes to be equivalent to +// a single slash, so will uio (but not in the "\\MACHINE\share" part +// of a Windows UNC path). +int +decomposePath(const char *path, uio_PathComp **pathComp, + uio_bool *isAbsolute) { + uio_PathComp *result; + uio_PathComp *last; + uio_PathComp **endResult = &result; + uio_bool absolute = false; + char *name; +#ifdef WIN32 + size_t nameLen; +#endif + + if (path[0] == '\0') { + errno = ENOENT; + return -1; + } + + last = NULL; +#ifdef WIN32 + path += uio_getUNCServerShare(path, &name, &nameLen); + if (name != NULL) { + // UNC path + *endResult = uio_PathComp_new(name, nameLen, last); + last = *endResult; + endResult = &last->next; + + absolute = true; + } else if (isDriveLetter(path[0]) && path[1] == ':') { + // DOS/Windows drive letter. + if (path[2] != '\0' && !isPathDelimiter(path[2])) { + errno = ENOENT; + return -1; + } + name = uio_memdup0(path, 2); + *endResult = uio_PathComp_new(name, 2, last); + last = *endResult; + endResult = &last->next; + absolute = true; + } else +#endif + { + if (isPathDelimiter(*path)) { + absolute = true; + do { + path++; + } while (isPathDelimiter(*path)); + } + } + + while (*path != '\0') { + const char *start = path; + while (*path != '\0' && !isPathDelimiter(*path)) + path++; + + name = uio_memdup0(path, path - start); + *endResult = uio_PathComp_new(name, path - start, last); + last = *endResult; + endResult = &last->next; + + while (isPathDelimiter(*path)) + path++; + } + + *endResult = NULL; + *pathComp = result; + if (isAbsolute != NULL) + *isAbsolute = absolute; + return 0; +} + +// Pre: pathComp forms a valid path for the platform. +void +composePath(const uio_PathComp *pathComp, uio_bool absolute, + char **path, size_t *pathLen) { + size_t len; + const uio_PathComp *ptr; + char *result; + char *pathPtr; + + assert(pathComp != NULL); + + // First determine how much space is required. + len = 0; + if (absolute) + len++; + ptr = pathComp; + while (ptr != NULL) { + len += ptr->nameLen; + ptr = ptr->next; + } + + // Allocate the required space. + result = (char *) uio_malloc(len + 1); + + // Fill the path. + pathPtr = result; + ptr = pathComp; + if (absolute) { +#ifdef WIN32 + if (ptr->name[0] == '\\') { + // UNC path + assert(ptr->name[1] == '\\'); + // Nothing to do. + } else if (ptr->nameLen == 2 && ptr->name[1] == ':' + && isDriveLetter(ptr->name[0])) { + // Nothing to do. + } + else +#endif + { + *(pathPtr++) = '/'; + } + } + + for (;;) { + memcpy(pathPtr, ptr->name, ptr->nameLen); + pathPtr += ptr->nameLen; + + ptr = ptr->next; + if (ptr == NULL) + break; + + *(pathPtr++) = '/'; + } + + *path = result; + *pathLen = len; +} + + +// *** uio_PathComp *** // + +static inline uio_PathComp * +uio_PathComp_alloc(void) { + uio_PathComp *result = uio_malloc(sizeof (uio_PathComp)); +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugAlloc(uio_PathComp, (void *) result); +#endif + return result; +} + +static inline void +uio_PathComp_free(uio_PathComp *pathComp) { +#ifdef uio_MEM_DEBUG + uio_MemDebug_debugFree(uio_PathComp, (void *) pathComp); +#endif + uio_free(pathComp); +} + +// 'name' should be a null terminated string. It is stored in the PathComp, +// no copy is made. +// 'namelen' should be the length of 'name' +uio_PathComp * +uio_PathComp_new(char *name, size_t nameLen, uio_PathComp *upComp) { + uio_PathComp *result; + + result = uio_PathComp_alloc(); + result->name = name; + result->nameLen = nameLen; + result->up = upComp; + return result; +} + +void +uio_PathComp_delete(uio_PathComp *pathComp) { + uio_PathComp *next; + + while (pathComp != NULL) { + next = pathComp->next; + uio_free(pathComp->name); + uio_PathComp_free(pathComp); + pathComp = next; + } +} + +// Count the number of path components that 'comp' leads to. +int +uio_countPathComps(const uio_PathComp *comp) { + int count; + + count = 0; + for (; comp != NULL; comp = comp->next) + count++; + return count; +} + +uio_PathComp * +uio_lastPathComp(uio_PathComp *comp) { + if (comp == NULL) + return NULL; + + while (comp->next != NULL) + comp = comp->next; + return comp; +} + +// make a list of uio_PathComps from a path string +uio_PathComp * +uio_makePathComps(const char *path, uio_PathComp *upComp) { + const char *start, *end; + char *str; + uio_PathComp *result; + uio_PathComp **compPtr; // Where to put the next PathComp + + compPtr = &result; + getFirstPath0Component(path, &start, &end); + while (*start != '\0') { + str = uio_malloc(end - start + 1); + memcpy(str, start, end - start); + str[end - start] = '\0'; + + *compPtr = uio_PathComp_new(str, end - start, upComp); + upComp = *compPtr; + compPtr = &(*compPtr)->next; + getNextPath0Component(&start, &end); + } + *compPtr = NULL; + return result; +} + +void +uio_printPathComp(FILE *outStream, const uio_PathComp *comp) { + fprintf(outStream, "%s", comp->name); +} + +void +uio_printPathToComp(FILE *outStream, const uio_PathComp *comp) { + if (comp == NULL) + return; + uio_printPathToComp(outStream, comp->up); + fprintf(outStream, "/"); + uio_printPathComp(outStream, comp); +} + diff --git a/sc2/src/sc2code/libs/uio/paths.h b/sc2/src/sc2code/libs/uio/paths.h index 87fefd7e6..7822c6f80 100644 --- a/sc2/src/sc2code/libs/uio/paths.h +++ b/sc2/src/sc2code/libs/uio/paths.h @@ -19,11 +19,26 @@ */ #ifndef _PATHS_H -#define PATHS_H +#define _PATHS_H + +typedef struct uio_PathComp uio_PathComp; #include "types.h" #include "uioport.h" +#include + +struct uio_PathComp { + char *name; + // The name of this path component, 0-terminated + size_t nameLen; + // The length of the 'name' field, for fast lookups. + struct uio_PathComp *next; + // Next component in the path. + struct uio_PathComp *up; + // Previous component in the path. +}; + void getFirstPathComponent(const char *dir, const char *dirEnd, const char **startComp, const char **endComp); void getFirstPath0Component(const char *dir, const char **startComp, @@ -42,6 +57,40 @@ char *joinPaths(const char *first, const char *second); char *joinPathsAbsolute(const char *first, const char *second); uio_bool validPathName(const char *path, size_t len); +size_t uio_skipUNCServerShare(const char *inPath); +size_t uio_getUNCServerShare(const char *inPath, char **outPath, + size_t *outLen); -#endif /* PATHS_H */ +#ifdef WIN32 +static inline int +isDriveLetter(int c) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} +#endif + +static inline int +isPathDelimiter(int c) +{ +#ifdef WIN32 + return c == '/' || c == '\\'; +#else + return c == '/'; +#endif +} + +int decomposePath(const char *path, uio_PathComp **pathComp, + uio_bool *isAbsolute); +void composePath(const uio_PathComp *pathComp, uio_bool absolute, + char **path, size_t *pathLen); +uio_PathComp *uio_PathComp_new(char *name, size_t nameLen, + uio_PathComp *upComp); +void uio_PathComp_delete(uio_PathComp *pathComp); +int uio_countPathComps(const uio_PathComp *comp); +uio_PathComp *uio_lastPathComp(uio_PathComp *comp); +uio_PathComp *uio_makePathComps(const char *path, uio_PathComp *upComp); +void uio_printPathComp(FILE *outStream, const uio_PathComp *comp); +void uio_printPathToComp(FILE *outStream, const uio_PathComp *comp); + +#endif /* _PATHS_H */ diff --git a/sc2/src/sc2code/libs/uio/stdio/stdio.c b/sc2/src/sc2code/libs/uio/stdio/stdio.c index 8b1c9f976..915266589 100644 --- a/sc2/src/sc2code/libs/uio/stdio/stdio.c +++ b/sc2/src/sc2code/libs/uio/stdio/stdio.c @@ -22,7 +22,7 @@ #ifdef __svr4__ # define _POSIX_PTHREAD_SEMANTICS - // For the POSIX variant of r_readdir() + // For the POSIX variant of readdir_r() #endif #include "./stdio.h" @@ -348,13 +348,23 @@ stdio_getPDirEntryHandle(const uio_PDirHandle *pDirHandle, const char *name) { #ifdef WIN32 if (pDirHandle->extra->extra->upDir == NULL) { - // Top dir. Contains only drive letters. - if (!isDriveLetter(name[0]) || name[1] != ':' || name[2] != '\0') - return NULL; - driveName[0] = tolower(name[0]); - driveName[1] = ':'; - driveName[2] = '\0'; - name = driveName; + // Top dir. Contains only drive letters and UNC \\server\share + // parts. + if (isDriveLetter(name[0]) && name[1] == ':' && name[2] == '\0') { + driveName[0] = tolower(name[0]); + driveName[1] = ':'; + driveName[2] = '\0'; + name = driveName; + } else { + size_t uncLen; + + uncLen = uio_skipUNCServerShare(name); + if (name[uncLen] != '\0') { + // 'name' contains neither a drive letter, nor the + // first part of a UNC path. + return NULL; + } + } } #endif @@ -363,8 +373,9 @@ stdio_getPDirEntryHandle(const uio_PDirHandle *pDirHandle, const char *name) { return result; #ifdef WIN32 - if (name == driveName) { - // Need to create a 'directory' for the drive letter. + if (pDirHandle->extra->extra->upDir == NULL) { + // Need to create a 'directory' for the drive letter or UNC + // "\\server\share" part. // It's no problem if we happen to create a dir for a non-existing // drive. It should just produce an empty dir. uio_GPDir *gPDir; @@ -703,7 +714,7 @@ stdio_getPath(uio_GPDir *gPDir) { if (gPDir->extra->upDir == NULL) { #ifdef WIN32 - // Drive letter still needs to follow follow. + // Drive letter still needs to follow. gPDir->extra->cachedPath = uio_malloc(1); gPDir->extra->cachedPath[0] = '\0'; #else diff --git a/sc2/src/sc2code/libs/uio/stdio/stdio.h b/sc2/src/sc2code/libs/uio/stdio/stdio.h index 3efba576a..f59b3f18c 100644 --- a/sc2/src/sc2code/libs/uio/stdio/stdio.h +++ b/sc2/src/sc2code/libs/uio/stdio/stdio.h @@ -107,11 +107,3 @@ void stdio_EntriesIterator_delete(stdio_EntriesIterator *iterator); uio_PDirEntryHandle *stdio_getPDirEntryHandle( const uio_PDirHandle *pDirHandle, const char *name); -#ifdef WIN32 -static inline int isDriveLetter(int c) -{ - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); -} -#endif - - diff --git a/sc2/src/sc2code/libs/uio/uioutils.c b/sc2/src/sc2code/libs/uio/uioutils.c index a8233d64a..fbe3cd40a 100644 --- a/sc2/src/sc2code/libs/uio/uioutils.c +++ b/sc2/src/sc2code/libs/uio/uioutils.c @@ -23,10 +23,18 @@ #include "uioutils.h" #include "mem.h" +#include "paths.h" #include "uioport.h" -// concattenate two strings into a newly allocated buffer. -// It's up to the caller to free it. +/** + * Concatenate two strings into a newly allocated buffer. + * + * @param[in] first The first (left) string, '\0' terminated. + * @param[in] second The second (right) string, '\0' terminated. + * + * @returns A newly allocated string consisting of the concatenation of + * 'first' and 'second', to be freed using uio_free(). + */ char * strcata(const char *first, const char *second) { char *result, *resPtr; @@ -144,7 +152,7 @@ dosToUnixTime(uio_uint16 date, uio_uint16 tm) { static const int daysUntilMonth[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 334, 334, 334, 334 }; - // Last 4 entries are there so that there's no + // The last 4 entries are there so that there's no // invalid memory access if the date is invalid. year = date >> 9; @@ -181,10 +189,30 @@ char * dosToUnixPath(const char *path) { const char *srcPtr; char *result, *dstPtr; + size_t skip; result = uio_malloc(strlen(path) + 1); srcPtr = path; dstPtr = result; + + // A UNC path will look like this: "\\server\share/..."; the first two + // characters will be backslashes, and the separator between the server + // and the share too. The rest will be slashes. + // The goal is that at every forward slash, the path should be + // stat()'able. + skip = uio_skipUNCServerShare(srcPtr); + if (skip != 0) { + char *slash; + memcpy(dstPtr, srcPtr, skip); + + slash = memchr(srcPtr + 2, '/', skip - 2); + if (slash != NULL) + *slash = '\\'; + + srcPtr += skip; + dstPtr += skip; + } + while (*srcPtr != '\0') { if (*srcPtr == '\\') { *dstPtr = '/'; diff --git a/sc2/src/sc2code/ships/orz/orz.c b/sc2/src/sc2code/ships/orz/orz.c index e0bd3eb33..b03a96edc 100644 --- a/sc2/src/sc2code/ships/orz/orz.c +++ b/sc2/src/sc2code/ships/orz/orz.c @@ -193,7 +193,8 @@ count_marines (STARSHIPPTR StarShipPtr, BOOLEAN FindSpot) LockElement (hElement, &ElementPtr); hNextElement = GetPredElement (ElementPtr); - if (ElementPtr->current.image.farray == StarShipPtr->RaceDescPtr->ship_data.special + if (ElementPtr->current.image.farray == + StarShipPtr->RaceDescPtr->ship_data.special && ElementPtr->life_span && !(ElementPtr->state_flags & (FINITE_LIFE | DISAPPEARING))) { @@ -222,7 +223,8 @@ count_marines (STARSHIPPTR StarShipPtr, BOOLEAN FindSpot) } static void -orz_intelligence (PELEMENT ShipPtr, PEVALUATE_DESC ObjectsOfConcern, COUNT ConcernCounter) +orz_intelligence (PELEMENT ShipPtr, PEVALUATE_DESC ObjectsOfConcern, + COUNT ConcernCounter) { ELEMENTPTR TurretPtr; STARSHIPPTR StarShipPtr; @@ -328,8 +330,7 @@ ion_preprocess (PELEMENT ElementPtr) COLOR Color; Color = COLOR_256 (GetPrimColor (&(GLOBAL (DisplayArray))[ - ElementPtr->PrimIndex - ])); + ElementPtr->PrimIndex])); if (Color != 0x2D) { ElementPtr->life_span = ElementPtr->thrust_wait; @@ -344,8 +345,7 @@ ion_preprocess (PELEMENT ElementPtr) else /* color is between 0x7a and 0x7f */ color_index = (COUNT)(Color - 0x7a) + (NUM_TAB_COLORS >> 1); SetPrimColor (&(GLOBAL (DisplayArray))[ - ElementPtr->PrimIndex - ], color_tab[color_index]); + ElementPtr->PrimIndex], color_tab[color_index]); ElementPtr->state_flags &= ~DISAPPEARING; ElementPtr->state_flags |= CHANGING; @@ -454,15 +454,13 @@ LeftShip: { ElementPtr->state_flags &= ~NONSOLID; ElementPtr->state_flags |= CHANGING | CREW_OBJECT; - SetPrimType (&(GLOBAL (DisplayArray))[ - ElementPtr->PrimIndex - ], STAMP_PRIM); + SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], + STAMP_PRIM); ElementPtr->current.image.frame = ElementPtr->next.image.frame = SetAbsFrameIndex ( - StarShipPtr->RaceDescPtr->ship_data.special[0], 21 - ); + StarShipPtr->RaceDescPtr->ship_data.special[0], 21); ElementPtr->thrust_wait = 0; ElementPtr->turn_wait = MAKE_BYTE (0, NORMALIZE_FACING ((BYTE)TFB_Random ())); @@ -523,9 +521,8 @@ PELEMENT ElementPtr; pfacing = ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)); delta_facing = NORMALIZE_FACING ( pfacing - ANGLE_TO_FACING ( - GetVelocityTravelAngle (&ElementPtr->velocity) - ) + ANGLE_TO_FACING (OCTANT) - ); + GetVelocityTravelAngle (&ElementPtr->velocity)) + + ANGLE_TO_FACING (OCTANT)); if (delta_facing <= ANGLE_TO_FACING (QUADRANT)) { hTarget = hObject; @@ -589,18 +586,17 @@ PELEMENT ElementPtr; (ElementPtr->state_flags & (GOOD_GUY | BAD_GUY)) && (ElementPtr->state_flags & IGNORE_SIMILAR)) { - ElementPtr->next.image.frame = - SetAbsFrameIndex ( - StarShipPtr->RaceDescPtr->ship_data.special[0], 21 - ); + ElementPtr->next.image.frame = SetAbsFrameIndex ( + StarShipPtr->RaceDescPtr->ship_data.special[0], + 21); ElementPtr->state_flags &= ~IGNORE_SIMILAR; ElementPtr->state_flags |= CHANGING; } - if ((num_frames = WORLD_TO_TURN ( + num_frames = WORLD_TO_TURN ( square_root ((long)delta_x * delta_x - + (long)delta_y * delta_y) - )) == 0) + + (long)delta_y * delta_y)); + if (num_frames == 0) num_frames = 1; ShipVelocity = ObjectPtr->velocity; @@ -613,8 +609,7 @@ PELEMENT ElementPtr; - ElementPtr->current.location.y; delta_facing = NORMALIZE_FACING ( - ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) - facing - ); + ANGLE_TO_FACING (ARCTAN (delta_x, delta_y)) - facing); if (delta_facing > 0) { @@ -644,7 +639,8 @@ PELEMENT ElementPtr; OldFacing = StarShipPtr->ShipFacing; OldStatus = StarShipPtr->cur_status_flags; - OldIncrement = StarShipPtr->RaceDescPtr->characteristics.thrust_increment; + OldIncrement = StarShipPtr->RaceDescPtr->characteristics. + thrust_increment; OldThrust = StarShipPtr->RaceDescPtr->characteristics.max_thrust; StarShipPtr->ShipFacing = facing; @@ -655,7 +651,8 @@ PELEMENT ElementPtr; thrust_status = inertial_thrust (ElementPtr); StarShipPtr->RaceDescPtr->characteristics.max_thrust = OldThrust; - StarShipPtr->RaceDescPtr->characteristics.thrust_increment = OldIncrement; + StarShipPtr->RaceDescPtr->characteristics.thrust_increment = + OldIncrement; StarShipPtr->cur_status_flags = OldStatus; StarShipPtr->ShipFacing = OldFacing; @@ -677,15 +674,16 @@ PELEMENT ElementPtr; InsertElement (hIonElement, GetHeadElement ()); LockElement (hIonElement, &IonElementPtr); - IonElementPtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID; - IonElementPtr->life_span = IonElementPtr->thrust_wait = ION_LIFE; + IonElementPtr->state_flags = + APPEARING | FINITE_LIFE | NONSOLID; + IonElementPtr->life_span = + IonElementPtr->thrust_wait = ION_LIFE; SetPrimType (&(GLOBAL (DisplayArray))[ - IonElementPtr->PrimIndex - ], POINT_PRIM); + IonElementPtr->PrimIndex], POINT_PRIM); SetPrimColor (&(GLOBAL (DisplayArray))[ - IonElementPtr->PrimIndex - ], START_ION_COLOR); - IonElementPtr->current.location = ElementPtr->current.location; + IonElementPtr->PrimIndex], START_ION_COLOR); + IonElementPtr->current.location = + ElementPtr->current.location; IonElementPtr->current.location.x += (COORD)COSINE (angle, DISPLAY_TO_WORLD (2)); IonElementPtr->current.location.y += @@ -695,10 +693,10 @@ PELEMENT ElementPtr; SetElementStarShip (IonElementPtr, StarShipPtr); { - /* normally done during preprocess, but because - * object is being inserted at head rather than - * appended after tail it may never get preprocessed. - */ + /* normally done during preprocess, but because + * object is being inserted at head rather than + * appended after tail it may never get preprocessed. + */ IonElementPtr->next = IonElementPtr->current; --IonElementPtr->life_span; IonElementPtr->state_flags |= PRE_PROCESS; @@ -786,7 +784,8 @@ marine_collision (PELEMENT ElementPtr0, PPOINT pPt0, PELEMENT ElementPtr1, PPOIN } ProcessSound (SetAbsSoundIndex ( - StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), ElementPtr1); + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), + ElementPtr1); } ElementPtr0->state_flags &= ~COLLISION; @@ -819,8 +818,7 @@ turret_postprocess (PELEMENT ElementPtr) STARSHIPPTR StarShipPtr; SetPrimType (&(GLOBAL (DisplayArray))[ - ElementPtr->PrimIndex - ], NO_PRIM); + ElementPtr->PrimIndex], NO_PRIM); GetElementStarShip (ElementPtr, &StarShipPtr); if (StarShipPtr->hShip) @@ -866,8 +864,7 @@ turret_postprocess (PELEMENT ElementPtr) << (NORMALIZE_FACING (facing + ANGLE_TO_FACING (OCTANT)) / ANGLE_TO_FACING (QUADRANT)); TurretPtr->current.image.frame = SetAbsFrameIndex ( - TurretPtr->current.image.frame, facing - ); + TurretPtr->current.image.frame, facing); facing = FACING_TO_ANGLE (facing); if (StarShipPtr->cur_status_flags & WEAPON) { @@ -876,14 +873,14 @@ turret_postprocess (PELEMENT ElementPtr) LockElement (GetTailElement (), &TurretEffectPtr); if ((PELEMENT)TurretEffectPtr != ElementPtr - && (TurretEffectPtr->state_flags & (GOOD_GUY | BAD_GUY)) == + && (TurretEffectPtr->state_flags & + (GOOD_GUY | BAD_GUY)) == (ElementPtr->state_flags & (GOOD_GUY | BAD_GUY)) && (TurretEffectPtr->state_flags & APPEARING) && GetPrimType (&(GLOBAL (DisplayArray))[ TurretEffectPtr->PrimIndex ]) == STAMP_PRIM - && (hTurretEffect = AllocElement ()) - ) + && (hTurretEffect = AllocElement ())) { TurretPtr->current.location.x -= COSINE (facing, DISPLAY_TO_WORLD (2)); @@ -891,9 +888,10 @@ turret_postprocess (PELEMENT ElementPtr) SINE (facing, DISPLAY_TO_WORLD (2)); LockElement (hTurretEffect, &TurretEffectPtr); - TurretEffectPtr->state_flags = - FINITE_LIFE | NONSOLID | IGNORE_SIMILAR | APPEARING - | (ElementPtr->state_flags & (GOOD_GUY | BAD_GUY)); + TurretEffectPtr->state_flags = FINITE_LIFE + | NONSOLID | IGNORE_SIMILAR | APPEARING + | (ElementPtr->state_flags & + (GOOD_GUY | BAD_GUY)); TurretEffectPtr->life_span = 4; TurretEffectPtr->current.location.x = @@ -906,18 +904,17 @@ turret_postprocess (PELEMENT ElementPtr) DISPLAY_TO_WORLD (TURRET_OFFSET)); TurretEffectPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; - TurretEffectPtr->current.image.frame = SetAbsFrameIndex ( + TurretEffectPtr->current.image.frame = + SetAbsFrameIndex ( StarShipPtr->RaceDescPtr->ship_data.special[0], - ANGLE_TO_FACING (FULL_CIRCLE) - ); + ANGLE_TO_FACING (FULL_CIRCLE)); TurretEffectPtr->preprocess_func = animate; SetElementStarShip (TurretEffectPtr, StarShipPtr); SetPrimType (&(GLOBAL (DisplayArray))[ - TurretEffectPtr->PrimIndex - ], STAMP_PRIM); + TurretEffectPtr->PrimIndex], STAMP_PRIM); UnlockElement (hTurretEffect); PutElement (hTurretEffect); @@ -927,20 +924,15 @@ turret_postprocess (PELEMENT ElementPtr) TurretPtr->next = TurretPtr->current; SetPrimType (&(GLOBAL (DisplayArray))[ - TurretPtr->PrimIndex - ], + TurretPtr->PrimIndex], GetPrimType (&(GLOBAL (DisplayArray))[ - ShipPtr->PrimIndex - ])); + ShipPtr->PrimIndex])); SetPrimColor (&(GLOBAL (DisplayArray))[ - TurretPtr->PrimIndex - ], + TurretPtr->PrimIndex], GetPrimColor (&(GLOBAL (DisplayArray))[ - ShipPtr->PrimIndex - ])); + ShipPtr->PrimIndex])); - TurretPtr->postprocess_func = - ElementPtr->postprocess_func; + TurretPtr->postprocess_func = ElementPtr->postprocess_func; SetElementStarShip (TurretPtr, StarShipPtr); @@ -969,37 +961,33 @@ turret_postprocess (PELEMENT ElementPtr) facing = FACING_TO_ANGLE (StarShipPtr->ShipFacing); SpaceMarinePtr->current.location.x = ShipPtr->current.location.x - - COSINE (facing, - DISPLAY_TO_WORLD (TURRET_OFFSET)); + - COSINE (facing, DISPLAY_TO_WORLD (TURRET_OFFSET)); SpaceMarinePtr->current.location.y = ShipPtr->current.location.y - - SINE (facing, - DISPLAY_TO_WORLD (TURRET_OFFSET)); + - SINE (facing, DISPLAY_TO_WORLD (TURRET_OFFSET)); SpaceMarinePtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; SpaceMarinePtr->current.image.frame = SetAbsFrameIndex ( - StarShipPtr->RaceDescPtr->ship_data.special[0], 20 - ); + StarShipPtr->RaceDescPtr->ship_data.special[0], 20); - SpaceMarinePtr->turn_wait = MAKE_BYTE (0, - NORMALIZE_FACING ( - ANGLE_TO_FACING (facing + HALF_CIRCLE) - )); + SpaceMarinePtr->turn_wait = + MAKE_BYTE (0, NORMALIZE_FACING ( + ANGLE_TO_FACING (facing + HALF_CIRCLE))); SpaceMarinePtr->preprocess_func = marine_preprocess; SpaceMarinePtr->collision_func = marine_collision; SetElementStarShip (SpaceMarinePtr, StarShipPtr); SetPrimType (&(GLOBAL (DisplayArray))[ - SpaceMarinePtr->PrimIndex - ], STAMP_PRIM); + SpaceMarinePtr->PrimIndex], STAMP_PRIM); UnlockElement (hSpaceMarine); PutElement (hSpaceMarine); DeltaCrew (ShipPtr, -1); ProcessSound (SetAbsSoundIndex ( - StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), SpaceMarinePtr); + StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), + SpaceMarinePtr); StarShipPtr->special_counter = StarShipPtr->RaceDescPtr->characteristics.special_wait;