mirror of
https://github.com/nzp-team/dquakeplus.git
synced 2024-11-14 16:30:40 +00:00
523 lines
10 KiB
C++
523 lines
10 KiB
C++
/*
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
Copyright (C) 2007 Peter Mackay and Chris Swindle.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
//
|
|
// 12/5/2020 - Use ADQuake's system.cpp and its move from std to sceIO for file I/O
|
|
// because std::fclose() is bunked -- cypress
|
|
// creds to st1x51
|
|
//
|
|
|
|
#define ENABLE_PRINTF 0
|
|
|
|
#include "system.hpp"
|
|
|
|
#include <cstddef>
|
|
#include <stdexcept>
|
|
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
|
|
#include <pspctrl.h>
|
|
#include <pspdebug.h>
|
|
#include <pspkernel.h>
|
|
#include <psppower.h>
|
|
#include <psprtc.h>
|
|
|
|
#ifdef PROFILE
|
|
#include <pspprof.h>
|
|
#endif
|
|
|
|
extern "C"
|
|
{
|
|
#include "sys.h"
|
|
#include "../quakedef.h"
|
|
}
|
|
#include "fnmatch.h"
|
|
|
|
extern int cpuClockSpeed;
|
|
extern int ramClockSpeed;
|
|
extern int busClockSpeed;
|
|
|
|
void CDAudio_Stop(void);
|
|
|
|
namespace quake
|
|
{
|
|
namespace system
|
|
{
|
|
struct file
|
|
{
|
|
// Set on open.
|
|
char name[MAX_OSPATH + 1];
|
|
bool write;
|
|
#if 0
|
|
// Set on open, suspend, restore.
|
|
FILE* handle;
|
|
#else
|
|
SceUID handle;
|
|
#endif
|
|
// Set on suspend.
|
|
SceOff offset;
|
|
};
|
|
|
|
static bool debugScreenInitialized = false;
|
|
static const std::size_t file_count = 64;
|
|
static file files[file_count];
|
|
|
|
void suspend()
|
|
{
|
|
Con_Printf("Suspend requested \n");
|
|
CDAudio_Pause();
|
|
// Close each file.
|
|
for (std::size_t file_index = 0; file_index < file_count; ++file_index)
|
|
{
|
|
// Is the file in use?
|
|
file& file = files[file_index];
|
|
if (file.name[0])
|
|
{
|
|
// Save the offset;
|
|
#if 0
|
|
file.offset = ftell(file.handle);
|
|
#else
|
|
file.offset = sceIoLseek(file.handle, 0, SEEK_CUR);
|
|
#endif
|
|
// Close the file.
|
|
#if 0
|
|
fclose(file.handle);
|
|
#else
|
|
sceIoClose(file.handle);
|
|
#endif
|
|
file.handle = 0;
|
|
}
|
|
}
|
|
|
|
Con_Printf("Filesystem sunspended\n");
|
|
}
|
|
|
|
void resume()
|
|
{
|
|
Con_Printf("Resume requested\n");
|
|
// Check each file.
|
|
for (std::size_t file_index = 0; file_index < file_count; ++file_index)
|
|
{
|
|
// Is the file in use?
|
|
file& file = files[file_index];
|
|
if (file.name[0])
|
|
{
|
|
// Reopen the file. This can repeatedly fail, so we keep trying.
|
|
#if 0
|
|
const char* mode = file.write ? "ab" : "rb";
|
|
#else
|
|
int mode = file.write ? PSP_O_APPEND : PSP_O_RDONLY;
|
|
#endif
|
|
#if 0
|
|
do
|
|
{
|
|
file.handle = fopen(file.name, mode);
|
|
}
|
|
while (!file.handle);
|
|
|
|
// Restore the offset;
|
|
if (fseek(file.handle, file.offset, SEEK_SET) != 0)
|
|
{
|
|
throw std::runtime_error("Couldn't seek in file");
|
|
}
|
|
#else
|
|
file.handle = sceIoOpen(file.name, mode, 0777);
|
|
if(file.handle < 0)
|
|
{
|
|
throw std::runtime_error("Couldn't open file");
|
|
}
|
|
|
|
// Restore the offset;
|
|
if (sceIoLseek(file.handle, file.offset, SEEK_SET) != 0)
|
|
{
|
|
throw std::runtime_error("Couldn't seek in file");
|
|
}
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
CDAudio_Resume();
|
|
Con_Printf("Filesystem resumed\n");
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
using namespace quake;
|
|
using namespace quake::system;
|
|
|
|
int Sys_FileOpenRead (char *path, int *hndl)
|
|
{
|
|
// Find an unused file.
|
|
for (std::size_t file_index = 1; file_index < file_count; ++file_index)
|
|
{
|
|
// Is the file in use?
|
|
file& file = files[file_index];
|
|
if (file.name[0])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Open the file.
|
|
#if 0
|
|
file.handle = fopen(path, "rb");
|
|
if (!file.handle)
|
|
#else
|
|
file.handle = sceIoOpen(path, PSP_O_RDONLY, 0777);
|
|
if (file.handle < 0)
|
|
#endif
|
|
{
|
|
*hndl = -1;
|
|
return -1;
|
|
}
|
|
|
|
// Get the length.
|
|
#if 0
|
|
if (fseek(file.handle, 0, SEEK_END) != 0)
|
|
{
|
|
Sys_Error("fseek failed");
|
|
}
|
|
const long length = ftell(file.handle);
|
|
if (fseek(file.handle, 0, SEEK_SET) != 0)
|
|
{
|
|
Sys_Error("fseek failed");
|
|
}
|
|
#else
|
|
SceOff pos = sceIoLseek(file.handle, 0, SEEK_CUR);
|
|
const long length = sceIoLseek(file.handle, 0, SEEK_END);
|
|
sceIoLseek(file.handle, pos, SEEK_SET);
|
|
#endif
|
|
// The file is now in use!
|
|
Q_strncpy(file.name, path, MAX_OSPATH);
|
|
file.write = false;
|
|
|
|
// Done.
|
|
*hndl = file_index;
|
|
return length;
|
|
}
|
|
|
|
Sys_Error("Out of file slots");
|
|
return -1;
|
|
}
|
|
|
|
int Sys_FileOpenWrite (char *path)
|
|
{
|
|
// Find an unused file.
|
|
for (std::size_t file_index = 1; file_index < file_count; ++file_index)
|
|
{
|
|
// Is the file in use?
|
|
file& file = files[file_index];
|
|
if (file.name[0])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Open the file.
|
|
#if 0
|
|
file.handle = fopen(path, "wb");
|
|
if (!file.handle)
|
|
#else
|
|
file.handle = sceIoOpen(path, PSP_O_WRONLY, 0777);
|
|
if (file.handle < 0)
|
|
#endif
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// The file is now in use!
|
|
Q_strncpy(file.name, path, MAX_OSPATH);
|
|
file.write = true;
|
|
|
|
// Done.
|
|
return file_index;
|
|
}
|
|
|
|
Sys_Error("Out of file slots");
|
|
return -1;
|
|
}
|
|
|
|
void Sys_FileClose (int handle)
|
|
{
|
|
// Close the file.
|
|
file& file = files[handle];
|
|
#if 0
|
|
fclose(file.handle);
|
|
#else
|
|
sceIoClose(file.handle);
|
|
#endif
|
|
file.handle = 0;
|
|
file.name[0] = 0;
|
|
}
|
|
|
|
void Sys_FileSeek (int handle, int position)
|
|
{
|
|
file& file = files[handle];
|
|
#if 0
|
|
if (fseek(file.handle, position, SEEK_SET) != 0)
|
|
{
|
|
Sys_Error("fseek failed");
|
|
}
|
|
#else
|
|
sceIoLseek(file.handle, position, SEEK_SET);
|
|
#endif
|
|
}
|
|
|
|
int Sys_FileRead (int handle, void *dest, int count)
|
|
{
|
|
file& file = files[handle];
|
|
#if 0
|
|
return fread(dest, 1, count, file.handle);
|
|
#else
|
|
return sceIoRead(file.handle, dest, count);
|
|
#endif
|
|
}
|
|
|
|
int Sys_FileWrite (int handle, void *data, int count)
|
|
{
|
|
file& file = files[handle];
|
|
#if 0
|
|
return fwrite(data, 1, count, file.handle);
|
|
#else
|
|
return sceIoWrite(file.handle, data, count);
|
|
#endif
|
|
}
|
|
|
|
int Sys_FileTime (char *path)
|
|
{
|
|
/*
|
|
#ifdef _WIN32
|
|
return -1;
|
|
#else
|
|
*/
|
|
struct stat s;
|
|
memset(&s, 0, sizeof(s));
|
|
|
|
if (stat(path, &s) < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return s.st_ctime;
|
|
/*
|
|
#endif
|
|
*/
|
|
}
|
|
|
|
void Sys_mkdir (char *path)
|
|
{
|
|
Sys_Printf("Mkdir: %s\n", path);
|
|
sceIoMkdir(path, 0x777);
|
|
}
|
|
|
|
void Sys_Error (char *error, ...)
|
|
{
|
|
// Clear the sound buffer.
|
|
S_ClearBuffer();
|
|
|
|
// Put the error message in a buffer.
|
|
va_list args;
|
|
va_start(args, error);
|
|
char buffer[1024];
|
|
memset(buffer, 0, sizeof(buffer));
|
|
vsnprintf(buffer, sizeof(buffer) - 1, error, args);
|
|
va_end(args);
|
|
|
|
Con_Printf(buffer);
|
|
// Print the error message to the debug screen.
|
|
if (!debugScreenInitialized)
|
|
{
|
|
pspDebugScreenInit();
|
|
debugScreenInitialized = true;
|
|
}
|
|
pspDebugScreenSetTextColor(0xffffff);
|
|
pspDebugScreenPrintf("The following error occurred:\n");
|
|
pspDebugScreenSetTextColor(0x0000ff);
|
|
pspDebugScreenPrintData(buffer, strlen(buffer));
|
|
pspDebugScreenSetTextColor(0xffffff);
|
|
pspDebugScreenPrintf("\n\nPress CROSS to quit.\n");
|
|
|
|
// Wait for a button press.
|
|
sceCtrlSetSamplingCycle(0);
|
|
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
|
|
SceCtrlData pad;
|
|
do {
|
|
sceCtrlReadBufferPositive(&pad, 1);
|
|
} while (pad.Buttons & PSP_CTRL_CROSS);
|
|
do {
|
|
sceCtrlReadBufferPositive(&pad, 1);
|
|
} while ((pad.Buttons & PSP_CTRL_CROSS) == 0);
|
|
do {
|
|
sceCtrlReadBufferPositive(&pad, 1);
|
|
} while (pad.Buttons & PSP_CTRL_CROSS);
|
|
|
|
// Quit.
|
|
pspDebugScreenPrintf("Shutting down...\n");
|
|
Sys_Quit();
|
|
}
|
|
|
|
void Sys_Printf (char *fmt, ...)
|
|
{
|
|
#if ENABLE_PRINTF
|
|
char buffer[1024];
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
memset(buffer, 0, sizeof(buffer));
|
|
vsnprintf(buffer, sizeof(buffer) - 1, fmt, args);
|
|
va_end(args);
|
|
|
|
if (!debugScreenInitialized)
|
|
{
|
|
pspDebugScreenInit();
|
|
debugScreenInitialized = true;
|
|
}
|
|
pspDebugScreenPrintData(buffer, strlen(buffer));
|
|
#endif
|
|
}
|
|
|
|
void Sys_Quit (void)
|
|
{
|
|
// Shut down the host system.
|
|
if (host_initialized)
|
|
{
|
|
Host_Shutdown();
|
|
}
|
|
|
|
// Restore the old clock frequency.
|
|
scePowerSetClockFrequency(cpuClockSpeed, ramClockSpeed, busClockSpeed);
|
|
|
|
// Insert a false delay so files and stuff can be saved before the kernel kills us.
|
|
sceKernelDelayThread(50 * 1000);
|
|
#ifdef PROFILE
|
|
gprof_cleanup();
|
|
#endif
|
|
// Exit.
|
|
sceKernelExitGame();
|
|
}
|
|
|
|
double Sys_FloatTime (void)
|
|
{
|
|
u64 ticks;
|
|
sceRtcGetCurrentTick(&ticks);
|
|
return ticks * 0.000001;
|
|
}
|
|
|
|
char *Sys_ConsoleInput (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void Sys_SendKeyEvents (void)
|
|
{
|
|
}
|
|
|
|
void Sys_LowFPPrecision (void)
|
|
{
|
|
}
|
|
|
|
void Sys_HighFPPrecision (void)
|
|
{
|
|
}
|
|
|
|
/*
|
|
=================================================
|
|
simplified findfirst/findnext implementation:
|
|
Sys_FindFirstFile and Sys_FindNextFile return
|
|
filenames only, not a dirent struct. this is
|
|
what we presently need in this engine.
|
|
=================================================
|
|
*/
|
|
|
|
static DIR *finddir;
|
|
static struct dirent *finddata;
|
|
static char *findpath, *findpattern;
|
|
|
|
char *Sys_FindFirstFile (char *path, char *pattern);
|
|
void Sys_FindClose (void);
|
|
char *Sys_FindNextFile (void);
|
|
|
|
char *Sys_FindFirstFile (char *path, char *pattern)
|
|
{
|
|
size_t tmp_len;
|
|
|
|
if (finddir)
|
|
Sys_Error ("Sys_FindFirst without FindClose");
|
|
|
|
finddir = opendir (path);
|
|
if (!finddir)
|
|
return NULL;
|
|
|
|
tmp_len = strlen (pattern);
|
|
findpattern = (char*) Q_malloc (tmp_len + 1);
|
|
if (!findpattern)
|
|
return NULL;
|
|
strcpy (findpattern, pattern);
|
|
findpattern[tmp_len] = '\0';
|
|
tmp_len = strlen (path);
|
|
findpath = (char*) Q_malloc (tmp_len + 1);
|
|
if (!findpath)
|
|
return NULL;
|
|
strcpy (findpath, path);
|
|
findpath[tmp_len] = '\0';
|
|
|
|
return Sys_FindNextFile();
|
|
}
|
|
|
|
char *Sys_FindNextFile (void)
|
|
{
|
|
struct stat test;
|
|
|
|
if (!finddir)
|
|
return NULL;
|
|
|
|
do {
|
|
finddata = readdir(finddir);
|
|
if (finddata != NULL)
|
|
{
|
|
if (!fnmatch (findpattern, finddata->d_name, FNM_PATHNAME))
|
|
{
|
|
if ( (stat(va("%s/%s", findpath, finddata->d_name), &test) == 0) && S_ISREG(test.st_mode) )
|
|
return finddata->d_name;
|
|
}
|
|
}
|
|
} while (finddata != NULL);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void Sys_FindClose (void)
|
|
{
|
|
if (finddir != NULL)
|
|
closedir(finddir);
|
|
if (findpath != NULL)
|
|
free (findpath);
|
|
if (findpattern != NULL)
|
|
free (findpattern);
|
|
finddir = NULL;
|
|
findpath = NULL;
|
|
findpattern = NULL;
|
|
}
|
|
|