void *__PHYSFS_platformCreateMutex(void) { int rc; PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex)); BAIL_IF_MACRO(m == NULL, ERR_OUT_OF_MEMORY, NULL); rc = pthread_mutex_init(&m->mutex, NULL); if (rc != 0) { allocator.Free(m); BAIL_MACRO(strerror(rc), NULL); } /* if */ m->count = 0; m->owner = (pthread_t) 0xDEADBEEF; return ((void *) m); } /* __PHYSFS_platformCreateMutex */
static int ZIP_fileClose(fvoid *opaque) { ZIPfileinfo *finfo = (ZIPfileinfo *) opaque; BAIL_IF_MACRO(!__PHYSFS_platformClose(finfo->handle), NULL, 0); if (finfo->entry->compression_method != COMPMETH_NONE) inflateEnd(&finfo->stream); /* FIXME clean AES context */ if (finfo->buffer != NULL) allocator.Free(finfo->buffer); allocator.Free(finfo); return(1); } /* ZIP_fileClose */
static char *unicodeToUtf8Heap(const WCHAR *w_str) { char *retval = NULL; if (w_str != NULL) { void *ptr = NULL; const PHYSFS_uint64 len = (wStrLen(w_str) * 4) + 1; retval = allocator.Malloc(len); BAIL_IF_MACRO(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL); PHYSFS_utf8FromUtf16((const PHYSFS_uint16 *) w_str, retval, len); ptr = allocator.Realloc(retval, strlen(retval) + 1); /* shrink. */ if (ptr != NULL) retval = (char *) ptr; } /* if */ return retval; } /* unicodeToUtf8Heap */
static DirHandle *HOG_openArchive(const char *name, int forWriting) { HOGinfo *info; DirHandle *retval = malloc(sizeof (DirHandle)); PHYSFS_sint64 modtime = __PHYSFS_platformGetLastModTime(name); BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL); info = retval->opaque = malloc(sizeof (HOGinfo)); if (info == NULL) { __PHYSFS_setError(ERR_OUT_OF_MEMORY); goto HOG_openArchive_failed; } /* if */ memset(info, '\0', sizeof (HOGinfo)); info->filename = (char *) malloc(strlen(name) + 1); if (info->filename == NULL) { __PHYSFS_setError(ERR_OUT_OF_MEMORY); goto HOG_openArchive_failed; } /* if */ if (!hog_load_entries(name, forWriting, info)) goto HOG_openArchive_failed; strcpy(info->filename, name); info->last_mod_time = modtime; retval->funcs = &__PHYSFS_DirFunctions_HOG; return(retval); HOG_openArchive_failed: if (retval != NULL) { if (retval->opaque != NULL) { if (info->filename != NULL) free(info->filename); if (info->entries != NULL) free(info->entries); free(info); } /* if */ free(retval); } /* if */ return(NULL); } /* HOG_openArchive */
/* * Read in a fmt_t from disk. This makes this process safe regardless of * the processor's byte order or how the fmt_t structure is packed. * Note that the union "fmt" is not read in here; that is handled as * needed in the read_fmt_* functions. */ static int read_fmt_chunk(SDL_RWops *rw, fmt_t *fmt) { /* skip reading the chunk ID, since it was already read at this point... */ fmt->chunkID = fmtID; BAIL_IF_MACRO(!read_le32(rw, &fmt->chunkSize), NULL, 0); BAIL_IF_MACRO(fmt->chunkSize < 16, "WAV: Invalid chunk size", 0); fmt->next_chunk_offset = SDL_RWtell(rw) + fmt->chunkSize; BAIL_IF_MACRO(!read_le16(rw, &fmt->wFormatTag), NULL, 0); BAIL_IF_MACRO(!read_le16(rw, &fmt->wChannels), NULL, 0); BAIL_IF_MACRO(!read_le32(rw, &fmt->dwSamplesPerSec), NULL, 0); BAIL_IF_MACRO(!read_le32(rw, &fmt->dwAvgBytesPerSec), NULL, 0); BAIL_IF_MACRO(!read_le16(rw, &fmt->wBlockAlign), NULL, 0); BAIL_IF_MACRO(!read_le16(rw, &fmt->wBitsPerSample), NULL, 0); return(1); } /* read_fmt_chunk */
char *__PHYSFS_platformGetUserName(void) { DWORD bufsize = 0; char *retval = NULL; if (pGetUserNameW(NULL, &bufsize) == 0) /* This SHOULD fail. */ { LPWSTR wbuf = (LPWSTR)__PHYSFS_smallAlloc(bufsize * sizeof(WCHAR)); BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL); if (pGetUserNameW(wbuf, &bufsize) == 0) /* ?! */ __PHYSFS_setError(winApiStrError()); else retval = unicodeToUtf8Heap(wbuf); __PHYSFS_smallFree(wbuf); } /* if */ return(retval); } /* __PHYSFS_platformGetUserName */
int Sound_Rewind(Sound_Sample *sample) { Sound_SampleInternal *internal; BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); internal = (Sound_SampleInternal *) sample->opaque; if (!internal->funcs->rewind(sample)) { sample->flags |= SOUND_SAMPLEFLAG_ERROR; return(0); } /* if */ sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; sample->flags &= ~SOUND_SAMPLEFLAG_ERROR; sample->flags &= ~SOUND_SAMPLEFLAG_EOF; return(1); } /* Sound_Rewind */
static LinkedStringList *HOG_enumerateFiles(DirHandle *h, const char *dirname, int omitSymLinks) { HOGinfo *info = ((HOGinfo *) h->opaque); HOGentry *entry = info->entries; LinkedStringList *retval = NULL, *p = NULL; PHYSFS_uint32 max = info->entryCount; PHYSFS_uint32 i; /* no directories in HOG files. */ BAIL_IF_MACRO(*dirname != '\0', ERR_NOT_A_DIR, NULL); for (i = 0; i < max; i++, entry++) retval = __PHYSFS_addToLinkedStringList(retval, &p, entry->name, -1); return(retval); } /* HOG_enumerateFiles */
static char *codepageToUtf8Heap(const char *cpstr) { char *retval = NULL; if (cpstr != NULL) { const int len = (int)(strlen(cpstr) + 1); WCHAR *wbuf = (WCHAR *)__PHYSFS_smallAlloc(len * sizeof(WCHAR)); BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, cpstr, len, wbuf, len); retval = (char *)allocator.Malloc(len * 4); if (retval == NULL) __PHYSFS_setError(ERR_OUT_OF_MEMORY); else PHYSFS_utf8FromUcs2((const PHYSFS_uint16*)wbuf, retval, len * 4); __PHYSFS_smallFree(wbuf); } /* if */ return(retval); } /* codepageToUtf8Heap */
int Sound_Quit(void) { ErrMsg *err; ErrMsg *nexterr = NULL; size_t i; BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); while (((volatile Sound_Sample *) sample_list) != NULL) Sound_FreeSample(sample_list); initialized = 0; SDL_DestroyMutex(samplelist_mutex); samplelist_mutex = NULL; sample_list = NULL; for (i = 0; decoders[i].funcs != NULL; i++) { if (decoders[i].available) { decoders[i].funcs->quit(); decoders[i].available = 0; } /* if */ } /* for */ if (available_decoders != NULL) free((void *) available_decoders); available_decoders = NULL; /* clean up error state for each thread... */ SDL_LockMutex(errorlist_mutex); for (err = error_msgs; err != NULL; err = nexterr) { nexterr = err->next; free(err); } /* for */ error_msgs = NULL; SDL_UnlockMutex(errorlist_mutex); SDL_DestroyMutex(errorlist_mutex); errorlist_mutex = NULL; return(1); } /* Sound_Quit */
static UNPKentry *slbLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount) { UNPKentry *entries = NULL; UNPKentry *entry = NULL; entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount); BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); for (entry = entries; fileCount > 0; fileCount--, entry++) { char *ptr; /* don't include the '\' in the beginning */ char backslash; GOTO_IF_MACRO(!__PHYSFS_readAll(io, &backslash, 1), ERRPASS, failed); GOTO_IF_MACRO(backslash != '\\', ERRPASS, failed); /* read the rest of the buffer, 63 bytes */ GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->name, 63), ERRPASS, failed); entry->name[63] = '\0'; /* in case the name lacks the null terminator */ /* convert backslashes */ for (ptr = entry->name; *ptr; ptr++) { if (*ptr == '\\') *ptr = '/'; } /* for */ GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->startPos, 4), ERRPASS, failed); entry->startPos = PHYSFS_swapULE32(entry->startPos); GOTO_IF_MACRO(!__PHYSFS_readAll(io, &entry->size, 4), ERRPASS, failed); entry->size = PHYSFS_swapULE32(entry->size); } /* for */ return entries; failed: allocator.Free(entries); return NULL; } /* slbLoadEntries */
char *__PHYSFS_platformGetUserName(void) { DWORD bufsize = 0; LPTSTR retval = NULL; if (GetUserName(NULL, &bufsize) == 0) /* This SHOULD fail. */ { retval = (LPTSTR) malloc(bufsize); BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL); if (GetUserName(retval, &bufsize) == 0) /* ?! */ { __PHYSFS_setError(win32strerror()); free(retval); retval = NULL; } /* if */ } /* if */ return((char *) retval); } /* __PHYSFS_platformGetUserName */
static int mvl_load_entries(const char *name, int forWriting, MVLinfo *info) { void *fh = NULL; PHYSFS_uint32 fileCount; PHYSFS_uint32 location = 8; /* sizeof sig. */ MVLentry *entry; BAIL_IF_MACRO(!mvl_open(name, forWriting, &fh, &fileCount), NULL, 0); info->entryCount = fileCount; info->entries = (MVLentry *) allocator.Malloc(sizeof(MVLentry)*fileCount); if (info->entries == NULL) { __PHYSFS_platformClose(fh); BAIL_MACRO(ERR_OUT_OF_MEMORY, 0); } /* if */ location += (17 * fileCount); for (entry = info->entries; fileCount > 0; fileCount--, entry++) { if (__PHYSFS_platformRead(fh, &entry->name, 13, 1) != 1) { __PHYSFS_platformClose(fh); return 0; } /* if */ if (__PHYSFS_platformRead(fh, &entry->size, 4, 1) != 1) { __PHYSFS_platformClose(fh); return 0; } /* if */ entry->size = PHYSFS_swapULE32(entry->size); entry->startPos = location; location += entry->size; } /* for */ __PHYSFS_platformClose(fh); __PHYSFS_sort(info->entries, info->entryCount, mvl_entry_cmp, mvl_entry_swap); return 1; } /* mvl_load_entries */
static void *doOpen(const char *filename, int mode) { int fd; int *retval; errno = 0; fd = open(filename, mode, S_IRUSR | S_IWUSR); BAIL_IF_MACRO(fd < 0, strerror(errno), NULL); retval = (int *) malloc(sizeof (int)); if (retval == NULL) { close(fd); BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL); } /* if */ *retval = fd; return((void *) retval); } /* doOpen */
static FileHandle *doOpen(DirHandle *h, const char *name, void *(*openFunc)(const char *filename), int *fileExists, const FileFunctions *fileFuncs) { char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL); void *rc; FileHandle *retval; BAIL_IF_MACRO(f == NULL, NULL, NULL); if (fileExists != NULL) { *fileExists = __PHYSFS_platformExists(f); if (!(*fileExists)) { free(f); return(NULL); } /* if */ } /* if */ retval = (FileHandle *) malloc(sizeof (FileHandle)); if (!retval) { free(f); BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL); } /* if */ rc = openFunc(f); free(f); if (!rc) { free(retval); return(NULL); } /* if */ retval->opaque = (void *) rc; retval->dirHandle = h; retval->funcs = fileFuncs; return(retval); } /* doOpen */
/* * Try to make use of GetUserProfileDirectoryW(), which isn't available on * some common variants of Win32. If we can't use this, we just punt and * use the physfs base dir for the user dir, too. * * On success, module-scope variable (userDir) will have a pointer to * a malloc()'d string of the user's profile dir, and a non-zero value is * returned. If we can't determine the profile dir, (userDir) will * be NULL, and zero is returned. */ static int determineUserDir(void) { if (userDir != NULL) return(1); /* already good to go. */ const wchar_t* path = Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data(); wchar_t path2[1024]; wcscpy_s(path2, path); wcscat_s(path2, L"\\"); userDir = unicodeToUtf8Heap(path2); if (userDir == NULL) /* couldn't get profile for some reason. */ { /* Might just be a non-NT system; resort to the basedir. */ userDir = getExePath(); BAIL_IF_MACRO(userDir == NULL, NULL, 0); /* STILL failed?! */ } /* if */ return(1); /* We made it: hit the showers. */ } /* determineUserDir */
int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st) { struct stat statbuf; BAIL_IF_MACRO(lstat(filename, &statbuf) == -1, errcodeFromErrno(), 0); if (S_ISREG(statbuf.st_mode)) { st->filetype = PHYSFS_FILETYPE_REGULAR; st->filesize = statbuf.st_size; } /* if */ else if(S_ISDIR(statbuf.st_mode)) { st->filetype = PHYSFS_FILETYPE_DIRECTORY; st->filesize = 0; } /* else if */ else if(S_ISLNK(statbuf.st_mode)) { st->filetype = PHYSFS_FILETYPE_SYMLINK; st->filesize = 0; } /* else if */ else { st->filetype = PHYSFS_FILETYPE_OTHER; st->filesize = statbuf.st_size; } /* else */ st->modtime = statbuf.st_mtime; st->createtime = statbuf.st_ctime; st->accesstime = statbuf.st_atime; /* !!! FIXME: maybe we should just report full permissions? */ st->readonly = access(filename, W_OK); return 1; } /* __PHYSFS_platformStat */
static UNPKentry *qpakLoadEntries(PHYSFS_Io *io, PHYSFS_uint32 fileCount) { UNPKentry *entries = NULL; UNPKentry *entry = NULL; entries = (UNPKentry *) allocator.Malloc(sizeof (UNPKentry) * fileCount); BAIL_IF_MACRO(entries == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL); for (entry = entries; fileCount > 0; fileCount--, entry++) { if (!__PHYSFS_readAll(io, &entry->name, 56)) goto failed; if (!__PHYSFS_readAll(io, &entry->startPos, 4)) goto failed; if (!__PHYSFS_readAll(io, &entry->size, 4)) goto failed; entry->size = PHYSFS_swapULE32(entry->size); entry->startPos = PHYSFS_swapULE32(entry->startPos); } /* for */ return entries; failed: allocator.Free(entries); return NULL; } /* qpakLoadEntries */
char *__PHYSFS_platformCurrentDir(void) { char *retval = NULL; WCHAR *wbuf = NULL; DWORD buflen = 0; buflen = pGetCurrentDirectoryW(buflen, NULL); wbuf = (WCHAR *) __PHYSFS_smallAlloc((buflen + 2) * sizeof (WCHAR)); BAIL_IF_MACRO(wbuf == NULL, ERR_OUT_OF_MEMORY, NULL); pGetCurrentDirectoryW(buflen, wbuf); if (wbuf[buflen - 2] == '\\') wbuf[buflen-1] = '\0'; /* just in case... */ else { wbuf[buflen - 1] = '\\'; wbuf[buflen] = '\0'; } /* else */ retval = unicodeToUtf8Heap(wbuf); __PHYSFS_smallFree(wbuf); return(retval); } /* __PHYSFS_platformCurrentDir */
static int is_cdrom_drive(ULONG drive) { PHYSFS_uint32 param, data; ULONG ul1, ul2; APIRET rc; HFILE hfile = NULLHANDLE; char drivename[3] = { 'A' + drive, ':', '\0' }; rc = DosOpen(drivename, &hfile, &ul1, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE, NULL); BAIL_IF_MACRO(rc != NO_ERROR, NULL, 0); data = 0; param = PHYSFS_swapULE32(CD01); ul1 = ul2 = sizeof (PHYSFS_uint32); rc = DosDevIOCtl(hfile, IOCTL_CDROMDISK, CDROMDISK_GETDRIVER, ¶m, sizeof (param), &ul1, &data, sizeof (data), &ul2); DosClose(hfile); return((rc == NO_ERROR) && (PHYSFS_swapULE32(data) == CD01)); } /* is_cdrom_drive */
static fvoid *doOpen(dvoid *opaque, const char *name, void *(*openFunc)(const char *filename), int *fileExists) { char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL); void *rc = NULL; BAIL_IF_MACRO(f == NULL, NULL, NULL); if (fileExists != NULL) { *fileExists = __PHYSFS_platformExists(f); if (!(*fileExists)) { allocator.Free(f); return(NULL); } /* if */ } /* if */ rc = openFunc(f); allocator.Free(f); return((fvoid *) rc); } /* doOpen */
static int MIDI_init(void) { BAIL_IF_MACRO(Timidity_Init() < 0, "MIDI: Could not initialise", 0); return(1); } /* MIDI_init */
int PHYSFS_writeUBE64(PHYSFS_File *file, PHYSFS_uint64 val) { PHYSFS_uint64 out = PHYSFS_swapUBE64(val); BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0); return(1); } /* PHYSFS_writeUBE64 */
int PHYSFS_writeSBE32(PHYSFS_File *file, PHYSFS_sint32 val) { PHYSFS_sint32 out = PHYSFS_swapSBE32(val); BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0); return(1); } /* PHYSFS_writeSBE32 */
int PHYSFS_writeULE16(PHYSFS_File *file, PHYSFS_uint16 val) { PHYSFS_uint16 out = PHYSFS_swapULE16(val); BAIL_IF_MACRO(PHYSFS_write(file, &out, sizeof (out), 1) != 1, NULL, 0); return(1); } /* PHYSFS_writeULE16 */
int __PHYSFS_platformDelete(const char *path) { BAIL_IF_MACRO(remove(path) == -1, errcodeFromErrno(), 0); return 1; } /* __PHYSFS_platformDelete */
int __PHYSFS_platformFlush(void *opaque) { const int fd = *((int *) opaque); BAIL_IF_MACRO(fsync(fd) == -1, errcodeFromErrno(), 0); return 1; } /* __PHYSFS_platformFlush */
int __PHYSFS_platformMkDir(const char *path) { const int rc = mkdir(path, S_IRWXU); BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0); return 1; } /* __PHYSFS_platformMkDir */
static int AU_open(Sound_Sample *sample, const char *ext) { Sound_SampleInternal *internal = sample->opaque; SDL_RWops *rw = internal->rw; int skip, hsize, i, bytes_per_second; struct au_file_hdr hdr; struct audec *dec; char c; /* read_au_header() will do byte order swapping. */ BAIL_IF_MACRO(!read_au_header(rw, &hdr), "AU: bad header", 0); dec = malloc(sizeof *dec); BAIL_IF_MACRO(dec == NULL, ERR_OUT_OF_MEMORY, 0); internal->decoder_private = dec; if (hdr.magic == AU_MAGIC) { /* valid magic */ dec->encoding = hdr.encoding; switch(dec->encoding) { case AU_ENC_ULAW_8: /* Convert 8-bit µ-law to 16-bit linear on the fly. This is slightly wasteful if the audio driver must convert them back, but µ-law only devices are rare (mostly _old_ Suns) */ sample->actual.format = AUDIO_S16SYS; break; case AU_ENC_LINEAR_8: sample->actual.format = AUDIO_S8; break; case AU_ENC_LINEAR_16: sample->actual.format = AUDIO_S16MSB; break; default: free(dec); BAIL_MACRO("AU: Unsupported .au encoding", 0); } /* switch */ sample->actual.rate = hdr.sample_rate; sample->actual.channels = hdr.channels; dec->remaining = hdr.data_size; hsize = hdr.hdr_size; /* skip remaining part of header (input may be unseekable) */ for (i = HDR_SIZE; i < hsize; i++) { if (SDL_RWread(rw, &c, 1, 1) != 1) { free(dec); BAIL_MACRO(ERR_IO_ERROR, 0); } /* if */ } /* for */ } /* if */ else if (__Sound_strcasecmp(ext, "au") == 0) { /* * A number of files in the wild have the .au extension but no valid * header; these are traditionally assumed to be 8kHz µ-law. Handle * them here only if the extension is recognized. */ SNDDBG(("AU: Invalid header, assuming raw 8kHz µ-law.\n")); /* if seeking fails, we lose 24 samples. big deal */ SDL_RWseek(rw, -HDR_SIZE, SEEK_CUR); dec->encoding = AU_ENC_ULAW_8; dec->remaining = (Uint32)-1; /* no limit */ sample->actual.format = AUDIO_S16SYS; sample->actual.rate = 8000; sample->actual.channels = 1; } /* else if */ else { free(dec); BAIL_MACRO("AU: Not an .AU stream.", 0); } /* else */ bytes_per_second = ( ( dec->encoding == AU_ENC_LINEAR_16 ) ? 2 : 1 ) * sample->actual.rate * sample->actual.channels ; internal->total_time = ((dec->remaining == -1) ? (-1) : ( ( dec->remaining / bytes_per_second ) * 1000 ) + ( ( dec->remaining % bytes_per_second ) * 1000 / bytes_per_second ) ); sample->flags = SOUND_SAMPLEFLAG_CANSEEK; dec->total = dec->remaining; dec->start_offset = SDL_RWtell(rw); SNDDBG(("AU: Accepting data stream.\n")); return(1); } /* AU_open */
char *__PHYSFS_platformCalcBaseDir(const char *argv0) { char *retval = NULL; const char *envr = NULL; /* Try to avoid using argv0 unless forced to. Try system-specific stuff. */ #if PHYSFS_PLATFORM_FREEBSD { char fullpath[PATH_MAX]; size_t buflen = sizeof (fullpath); int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1) retval = __PHYSFS_strdup(fullpath); } #elif PHYSFS_PLATFORM_SOLARIS { const char *path = getexecname(); if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */ retval = __PHYSFS_strdup(path); } #endif if (retval) return retval; /* already got it. */ /* If there's a Linux-like /proc filesystem, you can get the full path to * the current process from a symlink in there. */ if (access("/proc", F_OK) == 0) { retval = readSymLink("/proc/self/exe"); if (!retval) retval = readSymLink("/proc/curproc/file"); if (!retval) retval = readSymLink("/proc/curproc/exe"); if (retval == NULL) { /* older kernels don't have /proc/self ... try PID version... */ const unsigned long long pid = (unsigned long long) getpid(); char path[64]; const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid); if ( (rc > 0) && (rc < sizeof(path)) ) retval = readSymLink(path); } /* if */ } /* if */ if (retval != NULL) /* chop off filename. */ { char *ptr = strrchr(retval, '/'); if (ptr != NULL) *(ptr+1) = '\0'; else /* shouldn't happen, but just in case... */ { physfs_alloc.Free(retval); retval = NULL; } /* else */ } /* if */ /* No /proc/self/exe, etc, but we have an argv[0] we can parse? */ if ((retval == NULL) && (argv0 != NULL)) { /* fast path: default behaviour can handle this. */ if (strchr(argv0, '/') != NULL) return NULL; /* higher level parses out real path from argv0. */ /* If there's no dirsep on argv0, then look through $PATH for it. */ envr = getenv("PATH"); if (envr != NULL) { char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1); BAIL_IF_MACRO(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL); strcpy(path, envr); retval = findBinaryInPath(argv0, path); __PHYSFS_smallFree(path); } /* if */ } /* if */ if (retval != NULL) { /* try to shrink buffer... */ char *ptr = (char *) physfs_alloc.Realloc(retval, strlen(retval) + 1); if (ptr != NULL) retval = ptr; /* oh well if it failed. */ } /* if */ return retval; } /* __PHYSFS_platformCalcBaseDir */