mirror of https://github.com/mgba-emu/mgba.git
GBA Thread: Redo state directories for future expansion
This commit is contained in:
parent
5147a5160f
commit
91cf3be128
|
@ -0,0 +1,82 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "directories.h"
|
||||
|
||||
#include "util/vfs.h"
|
||||
|
||||
void GBADirectorySetInit(struct GBADirectorySet* dirs) {
|
||||
dirs->base = 0;
|
||||
dirs->archive = 0;
|
||||
dirs->save = 0;
|
||||
dirs->patch = 0;
|
||||
dirs->state = 0;
|
||||
dirs->screenshot = 0;
|
||||
}
|
||||
|
||||
void GBADirectorySetDeinit(struct GBADirectorySet* dirs) {
|
||||
GBADirectorySetDetachBase(dirs);
|
||||
|
||||
if (dirs->archive) {
|
||||
dirs->archive->close(dirs->archive);
|
||||
dirs->archive = 0;
|
||||
}
|
||||
|
||||
if (dirs->save) {
|
||||
dirs->save->close(dirs->save);
|
||||
dirs->save = 0;
|
||||
}
|
||||
|
||||
if (dirs->patch) {
|
||||
dirs->patch->close(dirs->patch);
|
||||
dirs->patch = 0;
|
||||
}
|
||||
|
||||
if (dirs->state) {
|
||||
dirs->state->close(dirs->state);
|
||||
dirs->state = 0;
|
||||
}
|
||||
|
||||
if (dirs->screenshot) {
|
||||
dirs->screenshot->close(dirs->screenshot);
|
||||
dirs->screenshot = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GBADirectorySetAttachBase(struct GBADirectorySet* dirs, struct VDir* base) {
|
||||
dirs->base = base;
|
||||
if (!dirs->save) {
|
||||
dirs->save = dirs->base;
|
||||
}
|
||||
if (!dirs->patch) {
|
||||
dirs->patch = dirs->base;
|
||||
}
|
||||
if (!dirs->state) {
|
||||
dirs->state = dirs->base;
|
||||
}
|
||||
if (!dirs->screenshot) {
|
||||
dirs->screenshot = dirs->base;
|
||||
}
|
||||
}
|
||||
|
||||
void GBADirectorySetDetachBase(struct GBADirectorySet* dirs) {
|
||||
if (dirs->save == dirs->base) {
|
||||
dirs->save = 0;
|
||||
}
|
||||
if (dirs->patch == dirs->base) {
|
||||
dirs->patch = 0;
|
||||
}
|
||||
if (dirs->state == dirs->base) {
|
||||
dirs->state = 0;
|
||||
}
|
||||
if (dirs->screenshot == dirs->base) {
|
||||
dirs->screenshot = 0;
|
||||
}
|
||||
|
||||
if (dirs->base) {
|
||||
dirs->base->close(dirs->base);
|
||||
dirs->base = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef DIRECTORIES_H
|
||||
#define DIRECTORIES_H
|
||||
|
||||
#include "util/common.h"
|
||||
|
||||
struct VDir;
|
||||
|
||||
struct GBADirectorySet {
|
||||
struct VDir* base;
|
||||
struct VDir* archive;
|
||||
struct VDir* save;
|
||||
struct VDir* patch;
|
||||
struct VDir* state;
|
||||
struct VDir* screenshot;
|
||||
};
|
||||
|
||||
void GBADirectorySetInit(struct GBADirectorySet* dirs);
|
||||
void GBADirectorySetDeinit(struct GBADirectorySet* dirs);
|
||||
|
||||
void GBADirectorySetAttachBase(struct GBADirectorySet* dirs, struct VDir* base);
|
||||
void GBADirectorySetDetachBase(struct GBADirectorySet* dirs);
|
||||
|
||||
#endif
|
|
@ -198,9 +198,11 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
}
|
||||
|
||||
struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool write) {
|
||||
char suffix[5] = { '\0' };
|
||||
snprintf(suffix, sizeof(suffix), ".ss%d", slot);
|
||||
return VDirOptionalOpenFile(dir, gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
|
||||
char basename[PATH_MAX];
|
||||
separatePath(gba->activeFile, 0, basename, 0);
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s.ss%i", basename, slot);
|
||||
return dir->openFile(dir, path, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
|
||||
}
|
||||
|
||||
#ifdef USE_PNG
|
||||
|
@ -709,7 +711,9 @@ void GBATakeScreenshot(struct GBA* gba, struct VDir* dir) {
|
|||
#ifdef USE_PNG
|
||||
unsigned stride;
|
||||
const void* pixels = 0;
|
||||
struct VFile* vf = VDirOptionalOpenIncrementFile(dir, gba->activeFile, "screenshot", "-", ".png", O_CREAT | O_TRUNC | O_WRONLY);
|
||||
char basename[PATH_MAX];
|
||||
separatePath(gba->activeFile, 0, basename, 0);
|
||||
struct VFile* vf = VDirFindNextAvailable(dir, basename, "-", ".png", O_CREAT | O_TRUNC | O_WRONLY);
|
||||
bool success = false;
|
||||
if (vf) {
|
||||
gba->video.renderer->getPixels(gba->video.renderer, &stride, &pixels);
|
||||
|
|
|
@ -106,7 +106,7 @@ static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
|
||||
struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
|
||||
|
||||
GBALoadState(gbaDebugger->context, gbaDebugger->context->stateDir, dv->intValue, SAVESTATE_SCREENSHOT);
|
||||
GBALoadState(gbaDebugger->context, gbaDebugger->context->dirs.state, dv->intValue, SAVESTATE_SCREENSHOT);
|
||||
}
|
||||
|
||||
static void _rewind(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
||||
|
@ -133,6 +133,6 @@ static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) {
|
|||
|
||||
struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system;
|
||||
|
||||
GBASaveState(gbaDebugger->context, gbaDebugger->context->stateDir, dv->intValue, SAVESTATE_SCREENSHOT);
|
||||
GBASaveState(gbaDebugger->context, gbaDebugger->context->dirs.state, dv->intValue, SAVESTATE_SCREENSHOT);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -22,10 +22,39 @@
|
|||
|
||||
#include <signal.h>
|
||||
|
||||
static void _loadGameDir(struct GBAThread* threadContext);
|
||||
|
||||
static const float _defaultFPSTarget = 60.f;
|
||||
|
||||
bool _reloadDirectories(struct GBAThread* threadContext) {
|
||||
GBADirectorySetDetachBase(&threadContext->dirs);
|
||||
|
||||
char basename[PATH_MAX];
|
||||
if (threadContext->fname) {
|
||||
char dirname[PATH_MAX];
|
||||
separatePath(threadContext->fname, dirname, basename, 0);
|
||||
GBADirectorySetAttachBase(&threadContext->dirs, VDirOpen(dirname));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s.sav", basename);
|
||||
threadContext->save = threadContext->dirs.save->openFile(threadContext->dirs.save, path, O_CREAT | O_RDWR);
|
||||
|
||||
if (!threadContext->patch) {
|
||||
snprintf(path, sizeof(path), "%s.ups", basename);
|
||||
threadContext->patch = threadContext->dirs.patch->openFile(threadContext->dirs.patch, path, O_RDONLY);
|
||||
}
|
||||
if (!threadContext->patch) {
|
||||
snprintf(path, sizeof(path), "%s.ips", basename);
|
||||
threadContext->patch = threadContext->dirs.patch->openFile(threadContext->dirs.patch, path, O_RDONLY);
|
||||
}
|
||||
if (!threadContext->patch) {
|
||||
snprintf(path, sizeof(path), "%s.bps", basename);
|
||||
threadContext->patch = threadContext->dirs.patch->openFile(threadContext->dirs.patch, path, O_RDONLY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_THREADING
|
||||
#ifdef USE_PTHREADS
|
||||
static pthread_key_t _contextKey;
|
||||
|
@ -196,11 +225,9 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
|
|||
|
||||
if (threadContext->movie) {
|
||||
struct VDir* movieDir = VDirOpen(threadContext->movie);
|
||||
#ifdef USE_LIBZIP
|
||||
if (!movieDir) {
|
||||
movieDir = VDirOpenZip(threadContext->movie, 0);
|
||||
movieDir = VDirOpenArchive(threadContext->movie);
|
||||
}
|
||||
#endif
|
||||
if (movieDir) {
|
||||
struct GBAMGMContext* mgm = malloc(sizeof(*mgm));
|
||||
GBAMGMContextCreate(mgm);
|
||||
|
@ -376,12 +403,7 @@ void GBAMapOptionsToContext(const struct GBAOptions* opts, struct GBAThread* thr
|
|||
}
|
||||
|
||||
void GBAMapArgumentsToContext(const struct GBAArguments* args, struct GBAThread* threadContext) {
|
||||
if (args->dirmode) {
|
||||
threadContext->gameDir = VDirOpen(args->fname);
|
||||
threadContext->stateDir = threadContext->gameDir;
|
||||
} else {
|
||||
GBAThreadLoadROM(threadContext, args->fname);
|
||||
}
|
||||
GBAThreadLoadROM(threadContext, args->fname);
|
||||
threadContext->fname = args->fname;
|
||||
threadContext->patch = VFileOpen(args->patch, O_RDONLY);
|
||||
threadContext->cheatsFile = VFileOpen(args->cheatsFile, O_RDONLY);
|
||||
|
@ -413,26 +435,13 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
|
|||
threadContext->rom = 0;
|
||||
}
|
||||
|
||||
if (threadContext->gameDir) {
|
||||
_loadGameDir(threadContext);
|
||||
}
|
||||
|
||||
if (!threadContext->rom && !bootBios) {
|
||||
threadContext->state = THREAD_SHUTDOWN;
|
||||
return false;
|
||||
}
|
||||
|
||||
threadContext->save = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "sram", ".sav", O_CREAT | O_RDWR);
|
||||
|
||||
if (!threadContext->patch) {
|
||||
threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".ups", O_RDONLY);
|
||||
}
|
||||
if (!threadContext->patch) {
|
||||
threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".ips", O_RDONLY);
|
||||
}
|
||||
if (!threadContext->patch) {
|
||||
threadContext->patch = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "patch", ".bps", O_RDONLY);
|
||||
}
|
||||
GBADirectorySetInit(&threadContext->dirs);
|
||||
_reloadDirectories(threadContext);
|
||||
|
||||
MutexInit(&threadContext->stateMutex);
|
||||
ConditionInit(&threadContext->stateCond);
|
||||
|
@ -562,18 +571,7 @@ void GBAThreadJoin(struct GBAThread* threadContext) {
|
|||
threadContext->patch = 0;
|
||||
}
|
||||
|
||||
if (threadContext->gameDir) {
|
||||
if (threadContext->stateDir == threadContext->gameDir) {
|
||||
threadContext->stateDir = 0;
|
||||
}
|
||||
threadContext->gameDir->close(threadContext->gameDir);
|
||||
threadContext->gameDir = 0;
|
||||
}
|
||||
|
||||
if (threadContext->stateDir) {
|
||||
threadContext->stateDir->close(threadContext->stateDir);
|
||||
threadContext->stateDir = 0;
|
||||
}
|
||||
GBADirectorySetDeinit(&threadContext->dirs);
|
||||
}
|
||||
|
||||
bool GBAThreadIsActive(struct GBAThread* threadContext) {
|
||||
|
@ -687,31 +685,11 @@ void GBAThreadPauseFromThread(struct GBAThread* threadContext) {
|
|||
}
|
||||
|
||||
void GBAThreadLoadROM(struct GBAThread* threadContext, const char* fname) {
|
||||
threadContext->rom = VFileOpen(fname, O_RDONLY);
|
||||
threadContext->gameDir = 0;
|
||||
if (!threadContext->gameDir) {
|
||||
threadContext->gameDir = VDirOpenArchive(fname);
|
||||
}
|
||||
}
|
||||
|
||||
static void _loadGameDir(struct GBAThread* threadContext) {
|
||||
threadContext->gameDir->rewind(threadContext->gameDir);
|
||||
struct VDirEntry* dirent = threadContext->gameDir->listNext(threadContext->gameDir);
|
||||
while (dirent) {
|
||||
struct Patch patchTemp;
|
||||
struct VFile* vf = threadContext->gameDir->openFile(threadContext->gameDir, dirent->name(dirent), O_RDONLY);
|
||||
if (!vf) {
|
||||
dirent = threadContext->gameDir->listNext(threadContext->gameDir);
|
||||
continue;
|
||||
}
|
||||
if (!threadContext->rom && GBAIsROM(vf)) {
|
||||
threadContext->rom = vf;
|
||||
} else if (!threadContext->patch && loadPatch(vf, &patchTemp)) {
|
||||
threadContext->patch = vf;
|
||||
} else {
|
||||
vf->close(vf);
|
||||
}
|
||||
dirent = threadContext->gameDir->listNext(threadContext->gameDir);
|
||||
threadContext->dirs.archive = VDirOpenArchive(fname);
|
||||
if (threadContext->dirs.archive) {
|
||||
threadContext->rom = VDirFindFirst(threadContext->dirs.archive, GBAIsROM);
|
||||
} else {
|
||||
threadContext->rom = VFileOpen(fname, O_RDONLY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -728,13 +706,15 @@ void GBAThreadReplaceROM(struct GBAThread* threadContext, const char* fname) {
|
|||
threadContext->save = 0;
|
||||
}
|
||||
|
||||
GBAThreadLoadROM(threadContext, fname);
|
||||
if (threadContext->gameDir) {
|
||||
_loadGameDir(threadContext);
|
||||
if (threadContext->dirs.archive) {
|
||||
threadContext->dirs.archive->close(threadContext->dirs.archive);
|
||||
threadContext->dirs.archive = 0;
|
||||
}
|
||||
|
||||
GBAThreadLoadROM(threadContext, fname);
|
||||
|
||||
threadContext->fname = fname;
|
||||
threadContext->save = VDirOptionalOpenFile(threadContext->stateDir, threadContext->fname, "sram", ".sav", O_CREAT | O_RDWR);
|
||||
_reloadDirectories(threadContext);
|
||||
|
||||
GBARaiseIRQ(threadContext->gba, IRQ_GAMEPAK);
|
||||
GBALoadROM(threadContext->gba, threadContext->rom, threadContext->save, threadContext->fname);
|
||||
|
@ -753,7 +733,7 @@ struct GBAThread* GBAThreadGetContext(void) {
|
|||
#endif
|
||||
|
||||
void GBAThreadTakeScreenshot(struct GBAThread* threadContext) {
|
||||
GBATakeScreenshot(threadContext->gba, threadContext->stateDir);
|
||||
GBATakeScreenshot(threadContext->gba, threadContext->dirs.screenshot);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "gba/gba.h"
|
||||
#include "gba/input.h"
|
||||
#include "gba/context/directories.h"
|
||||
#include "gba/context/overrides.h"
|
||||
#include "gba/context/sync.h"
|
||||
|
||||
|
@ -47,8 +48,7 @@ struct GBAThread {
|
|||
struct GBAVideoRenderer* renderer;
|
||||
struct GBASIODriverSet sioDrivers;
|
||||
struct ARMDebugger* debugger;
|
||||
struct VDir* gameDir;
|
||||
struct VDir* stateDir;
|
||||
struct GBADirectorySet dirs;
|
||||
struct VFile* rom;
|
||||
struct VFile* save;
|
||||
struct VFile* bios;
|
||||
|
|
|
@ -110,8 +110,8 @@ GameController::GameController(QObject* parent)
|
|||
context->gba->video.renderer->disableOBJ = !controller->m_videoLayers[4];
|
||||
controller->m_fpsTarget = context->fpsTarget;
|
||||
|
||||
if (GBALoadState(context, context->stateDir, 0, SAVESTATE_SCREENSHOT)) {
|
||||
VFile* vf = GBAGetState(context->gba, context->stateDir, 0, true);
|
||||
if (GBALoadState(context, context->dirs.state, 0, SAVESTATE_SCREENSHOT)) {
|
||||
VFile* vf = GBAGetState(context->gba, context->dirs.state, 0, true);
|
||||
if (vf) {
|
||||
vf->truncate(vf, 0);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ GameController::GameController(QObject* parent)
|
|||
return false;
|
||||
}
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
if (!GBASaveState(context, context->stateDir, 0, true)) {
|
||||
if (!GBASaveState(context, context->dirs.state, 0, true)) {
|
||||
return false;
|
||||
}
|
||||
QMetaObject::invokeMethod(controller, "closeGame");
|
||||
|
@ -317,18 +317,12 @@ void GameController::openGame(bool biosOnly) {
|
|||
m_threadContext.sync.audioWait = m_audioSync;
|
||||
}
|
||||
|
||||
m_threadContext.gameDir = 0;
|
||||
m_threadContext.bootBios = biosOnly;
|
||||
if (biosOnly) {
|
||||
m_threadContext.fname = nullptr;
|
||||
} else {
|
||||
m_threadContext.fname = strdup(m_fname.toUtf8().constData());
|
||||
if (m_dirmode) {
|
||||
m_threadContext.gameDir = VDirOpen(m_threadContext.fname);
|
||||
m_threadContext.stateDir = m_threadContext.gameDir;
|
||||
} else {
|
||||
GBAThreadLoadROM(&m_threadContext, m_threadContext.fname);
|
||||
}
|
||||
GBAThreadLoadROM(&m_threadContext, m_threadContext.fname);
|
||||
}
|
||||
|
||||
if (!m_bios.isNull() && m_useBios) {
|
||||
|
@ -712,7 +706,7 @@ void GameController::loadState(int slot) {
|
|||
controller->m_backupLoadState = new GBASerializedState;
|
||||
}
|
||||
GBASerialize(context->gba, controller->m_backupLoadState);
|
||||
if (GBALoadState(context, context->stateDir, controller->m_stateSlot, SAVESTATE_SCREENSHOT)) {
|
||||
if (GBALoadState(context, context->dirs.state, controller->m_stateSlot, SAVESTATE_SCREENSHOT)) {
|
||||
controller->frameAvailable(controller->m_drawContext);
|
||||
controller->stateLoaded(context);
|
||||
}
|
||||
|
@ -725,13 +719,13 @@ void GameController::saveState(int slot) {
|
|||
}
|
||||
GBARunOnThread(&m_threadContext, [](GBAThread* context) {
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
VFile* vf = GBAGetState(context->gba, context->stateDir, controller->m_stateSlot, false);
|
||||
VFile* vf = GBAGetState(context->gba, context->dirs.state, controller->m_stateSlot, false);
|
||||
if (vf) {
|
||||
controller->m_backupSaveState.resize(vf->size(vf));
|
||||
vf->read(vf, controller->m_backupSaveState.data(), controller->m_backupSaveState.size());
|
||||
vf->close(vf);
|
||||
}
|
||||
GBASaveState(context, context->stateDir, controller->m_stateSlot, SAVESTATE_SCREENSHOT | EXTDATA_SAVEDATA);
|
||||
GBASaveState(context, context->dirs.state, controller->m_stateSlot, SAVESTATE_SCREENSHOT | EXTDATA_SAVEDATA);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -759,7 +753,7 @@ void GameController::saveBackupState() {
|
|||
|
||||
GBARunOnThread(&m_threadContext, [](GBAThread* context) {
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
VFile* vf = GBAGetState(context->gba, context->stateDir, controller->m_stateSlot, true);
|
||||
VFile* vf = GBAGetState(context->gba, context->dirs.state, controller->m_stateSlot, true);
|
||||
if (vf) {
|
||||
vf->write(vf, controller->m_backupSaveState.constData(), controller->m_backupSaveState.size());
|
||||
vf->close(vf);
|
||||
|
|
|
@ -170,7 +170,7 @@ bool LoadSaveState::eventFilter(QObject* object, QEvent* event) {
|
|||
|
||||
void LoadSaveState::loadState(int slot) {
|
||||
GBAThread* thread = m_controller->thread();
|
||||
VFile* vf = GBAGetState(thread->gba, thread->stateDir, slot, false);
|
||||
VFile* vf = GBAGetState(thread->gba, thread->dirs.state, slot, false);
|
||||
if (!vf) {
|
||||
m_slots[slot - 1]->setText(tr("Empty"));
|
||||
return;
|
||||
|
|
|
@ -423,7 +423,7 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLPlayer
|
|||
case SDLK_F8:
|
||||
case SDLK_F9:
|
||||
GBAThreadInterrupt(context);
|
||||
GBASaveState(context, context->stateDir, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
|
||||
GBASaveState(context, context->dirs.state, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
|
||||
GBAThreadContinue(context);
|
||||
break;
|
||||
default:
|
||||
|
@ -441,7 +441,7 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, struct GBASDLPlayer
|
|||
case SDLK_F8:
|
||||
case SDLK_F9:
|
||||
GBAThreadInterrupt(context);
|
||||
GBALoadState(context, context->stateDir, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
|
||||
GBALoadState(context, context->dirs.state, event->keysym.sym - SDLK_F1 + 1, SAVESTATE_SCREENSHOT);
|
||||
GBAThreadContinue(context);
|
||||
break;
|
||||
default:
|
||||
|
|
115
src/util/vfs.c
115
src/util/vfs.c
|
@ -157,6 +157,52 @@ ssize_t VFileRead16LE(struct VFile* vf, void* hword) {
|
|||
return r;
|
||||
}
|
||||
|
||||
void separatePath(const char* path, char* dirname, char* basename, char* extension) {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
char* dotPoint = strrchr(path, '.');
|
||||
char* separatorPoint = strnrstr(path, PATH_SEP, strlen(path));
|
||||
if (separatorPoint) {
|
||||
if (dirname) {
|
||||
ptrdiff_t len = separatorPoint - path;
|
||||
if (PATH_MAX <= len) {
|
||||
len = PATH_MAX - 1;
|
||||
}
|
||||
strncpy(dirname, path, len);
|
||||
dirname[len] = '\0';
|
||||
}
|
||||
path = separatorPoint + 1;
|
||||
|
||||
}
|
||||
if (basename) {
|
||||
size_t len;
|
||||
if (dotPoint) {
|
||||
len = dotPoint - path;
|
||||
} else {
|
||||
len = strlen(path);
|
||||
}
|
||||
if (PATH_MAX <= len) {
|
||||
len = PATH_MAX - 1;
|
||||
}
|
||||
strncpy(basename, path, len);
|
||||
basename[len] = '\0';
|
||||
}
|
||||
if (extension) {
|
||||
if (dotPoint) {
|
||||
++dotPoint;
|
||||
size_t len = strlen(dotPoint);
|
||||
if (PATH_MAX <= len) {
|
||||
len = PATH_MAX - 1;
|
||||
}
|
||||
strncpy(extension, dotPoint, len);
|
||||
extension[len] = '\0';
|
||||
} else {
|
||||
extension[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) {
|
||||
char path[PATH_MAX];
|
||||
path[PATH_MAX - 1] = '\0';
|
||||
|
@ -185,64 +231,37 @@ struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const
|
|||
return vf;
|
||||
}
|
||||
|
||||
struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix, const char* infix, const char* suffix, int mode) {
|
||||
char path[PATH_MAX];
|
||||
path[PATH_MAX - 1] = '\0';
|
||||
char realPrefix[PATH_MAX];
|
||||
realPrefix[PATH_MAX - 1] = '\0';
|
||||
if (!dir) {
|
||||
if (!realPath) {
|
||||
return 0;
|
||||
struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*)) {
|
||||
dir->rewind(dir);
|
||||
struct VDirEntry* dirent = dir->listNext(dir);
|
||||
while (dirent) {
|
||||
struct VFile* vf = dir->openFile(dir, dirent->name(dirent), O_RDONLY);
|
||||
if (!vf) {
|
||||
dirent = dir->listNext(dir);
|
||||
continue;
|
||||
}
|
||||
const char* separatorPoint = strrchr(realPath, '/');
|
||||
const char* dotPoint;
|
||||
size_t len;
|
||||
if (!separatorPoint) {
|
||||
strcpy(path, "./");
|
||||
separatorPoint = realPath;
|
||||
dotPoint = strrchr(realPath, '.');
|
||||
} else {
|
||||
path[0] = '\0';
|
||||
dotPoint = strrchr(separatorPoint, '.');
|
||||
|
||||
if (separatorPoint - realPath + 1 >= PATH_MAX - 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = separatorPoint - realPath;
|
||||
strncat(path, realPath, len);
|
||||
path[len] = '\0';
|
||||
++separatorPoint;
|
||||
if (filter(vf)) {
|
||||
return vf;
|
||||
}
|
||||
|
||||
if (dotPoint - realPath + 1 >= PATH_MAX - 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dotPoint >= separatorPoint) {
|
||||
len = dotPoint - separatorPoint;
|
||||
} else {
|
||||
len = PATH_MAX - 1;
|
||||
}
|
||||
|
||||
strncpy(realPrefix, separatorPoint, len);
|
||||
realPrefix[len] = '\0';
|
||||
|
||||
prefix = realPrefix;
|
||||
dir = VDirOpen(path);
|
||||
vf->close(vf);
|
||||
dirent = dir->listNext(dir);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct VFile* VDirFindNextAvailable(struct VDir* dir, const char* basename, const char* infix, const char* suffix, int mode) {
|
||||
if (!dir) {
|
||||
// This shouldn't be possible
|
||||
return 0;
|
||||
}
|
||||
dir->rewind(dir);
|
||||
struct VDirEntry* dirent;
|
||||
size_t prefixLen = strlen(prefix);
|
||||
size_t prefixLen = strlen(basename);
|
||||
size_t infixLen = strlen(infix);
|
||||
char path[PATH_MAX];
|
||||
unsigned next = 0;
|
||||
while ((dirent = dir->listNext(dir))) {
|
||||
const char* filename = dirent->name(dirent);
|
||||
char* dotPoint = strrchr(filename, '.');
|
||||
const char* dotPoint = strrchr(filename, '.');
|
||||
size_t len = strlen(filename);
|
||||
if (dotPoint) {
|
||||
len = (dotPoint - filename);
|
||||
|
@ -255,7 +274,7 @@ struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPa
|
|||
if (len != prefixLen) {
|
||||
continue;
|
||||
}
|
||||
if (strncmp(filename, prefix, prefixLen) == 0) {
|
||||
if (strncmp(filename, basename, prefixLen) == 0) {
|
||||
int nlen;
|
||||
separator += infixLen;
|
||||
snprintf(path, PATH_MAX - 1, "%%u%s%%n", suffix);
|
||||
|
@ -272,7 +291,7 @@ struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPa
|
|||
}
|
||||
}
|
||||
}
|
||||
snprintf(path, PATH_MAX - 1, "%s%s%u%s", prefix, infix, next, suffix);
|
||||
snprintf(path, PATH_MAX - 1, "%s%s%u%s", basename, infix, next, suffix);
|
||||
path[PATH_MAX - 1] = '\0';
|
||||
return dir->openFile(dir, path, mode);
|
||||
}
|
||||
|
|
|
@ -82,10 +82,13 @@ struct VDir* VDirOpen7z(const char* path, int flags);
|
|||
|
||||
struct VDir* VDeviceList(void);
|
||||
|
||||
void separatePath(const char* path, char* dirname, char* basename, char* extension);
|
||||
|
||||
struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix,
|
||||
int mode);
|
||||
struct VFile* VDirOptionalOpenIncrementFile(struct VDir* dir, const char* realPath, const char* prefix,
|
||||
const char* infix, const char* suffix, int mode);
|
||||
|
||||
struct VFile* VDirFindFirst(struct VDir* dir, bool (*filter)(struct VFile*));
|
||||
struct VFile* VDirFindNextAvailable(struct VDir*, const char* basename, const char* infix, const char* suffix, int mode);
|
||||
|
||||
ssize_t VFileReadline(struct VFile* vf, char* buffer, size_t size);
|
||||
|
||||
|
|
Loading…
Reference in New Issue