BizHawk/libmupen64plus/mupen64plus-video-glide64/src/Ini.cpp

541 lines
13 KiB
C++

/*
* Glide64 - Glide video plugin for Nintendo 64 emulators.
* Copyright (c) 2002 Dave2001
*
* 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
* 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
* Licence along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA
*/
//****************************************************************
//
// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)
// Project started on December 29th, 2001
//
// To modify Glide64:
// * Write your name and (optional)email, commented by your work, so I know who did it, and so that you can find which parts you modified when it comes time to send it to me.
// * Do NOT send me the whole project or file that you modified. Take out your modified code sections, and tell me where to put them. If people sent the whole thing, I would have many different versions, but no idea how to combine them all.
//
// Official Glide64 development channel: #Glide64 on EFnet
//
// Original author: Dave2001 (Dave2999@hotmail.com)
// Other authors: Gonetz, Gugaman
//
//****************************************************************
// INI code v1.1
#define M64P_PLUGIN_PROTOTYPES 1
#include "m64p_types.h"
#include "m64p_plugin.h"
#include "m64p_config.h"
#include "m64p_vidext.h"
#include "Ini.h"
#include "Gfx1.3.h"
#include <limits.h>
#ifndef _WIN32
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#endif // _WIN32
#include <errno.h>
#ifndef _WIN32
#include <sys/resource.h>
#endif
#ifdef _WIN32
#define PATH_MAX _MAX_PATH
#endif
/* PATH_MAX only may be defined by limits.h */
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
FILE *ini;
int sectionstart;
int last_line; // last good line
int last_line_ret; // last line ended in return?
WORD cr = 0x0A0D;
static char configdir[PATH_MAX] = {0};
BOOL INI_Open ()
{
// Get the path of the dll, ex: C:\Games\Project64\Plugin\Glide64.dll
char path[PATH_MAX];
if(strlen(configdir) > 0)
{
strncpy(path, configdir, PATH_MAX);
// make sure there's a trailing '/'
//if(path[strlen(path)-1] != '/')
// strncat(path, "/", PATH_MAX - strlen(path));
}
else
{
#ifdef _WIN32
GetModuleFileName (hInstance, path, PATH_MAX);
#else // _WIN32
# ifdef __FreeBSD__
int n = readlink("/proc/curproc/files", path, PATH_MAX);
#else
int n = readlink("/proc/self/exe", path, PATH_MAX);
#endif
if (n == -1) strcpy(path, "./");
else
{
char path2[PATH_MAX];
int i;
path[n] = '\0';
strcpy(path2, path);
for (i=strlen(path2)-1; i>0; i--)
{
if(path2[i] == '/') break;
}
if(i == 0) strcpy(path, "./");
else
{
DIR *dir;
struct dirent *entry;
int gooddir = 0;
path2[i+1] = '\0';
dir = opendir(path2);
while((entry = readdir(dir)) != NULL)
{
if(!strcmp(entry->d_name, "plugins"))
gooddir = 1;
}
closedir(dir);
if(!gooddir) strcpy(path, "./");
}
}
#endif // _WIN32
// Find the previous backslash
int i;
for (i=strlen(path)-1; i>0; i--)
{
#ifdef _WIN32
if (path[i] == '\\')
#else // _WIN32
if (path[i] == '/')
#endif // _WIN32
break;
}
if (path == 0) return FALSE;
path[i+1] = 0;
#ifndef _WIN32
strcat(path, "plugins/");
#endif // _WIN32
}
//strncat (path, "Glide64.ini", PATH_MAX - strlen(path));
WriteLog(M64MSG_INFO, "opening %s\n", path);
// Open the file
ini = fopen (path, "rb");
if (ini == NULL)
{
WriteLog(M64MSG_ERROR, "Could not find Glide64.ini!");
return FALSE;
/*
ini = fopen (path, "w+b");
if (ini == NULL)
{
return FALSE;
}
*/
}
sectionstart = 0;
last_line = 0;
last_line_ret = 1;
return TRUE;
}
void INI_Close ()
{
//if (ini)
// fclose(ini);
}
void INI_InsertSpace(int space)
{
// Since there is no good way to normally insert to or delete from a certain location in
// a file, this function was added. It will insert (or delete) space bytes at the
// current location.
// note: negative count means delete
char chunk[2048];
int len, file, start_pos, cur_pos;
#ifdef _WIN32
file = _fileno(ini);
#else // _WIN32
file = fileno(ini);
#endif // _WIN32
start_pos = ftell(ini);
fseek(ini,0,SEEK_END);
// if adding, extend the file
if (space > 0)
#ifdef _WIN32
_chsize (file, _filelength(file)+space);
#else // _WIN32
{
int t1 = ftell(ini);
fseek(ini, 0L, SEEK_END);
int t2 = ftell(ini);
fseek(ini, t1, SEEK_SET);
ftruncate(file, t2+space);
}
#endif // _WIN32
while (1) {
cur_pos = ftell(ini);
len = cur_pos - start_pos;
if (len == 0) break;
if (len > 2048) len = 2048;
fseek (ini,-len,SEEK_CUR);
fread (chunk,1,len,ini);
fseek (ini,-len+space,SEEK_CUR);
fwrite (chunk,1,len,ini);
fseek (ini,-len-space,SEEK_CUR);
}
// if deleted, make the file shorter
if (space < 0)
#ifdef _WIN32
_chsize (file, _filelength(file)+space);
#else // _WIN32
{
int t1 = ftell(ini);
fseek(ini, 0L, SEEK_END);
int t2 = ftell(ini);
fseek(ini, t1, SEEK_SET);
ftruncate(file, t2+space);
}
#endif // _WIN32
}
BOOL INI_FindSection (const char *sectionname, BOOL create)
{
if (ini == NULL)
return FALSE;
char line[256], section[64];
char *p;
int i, sectionfound, ret;
rewind (ini);
last_line = 0;
sectionfound = 0;
while(!feof(ini)) {
ret = 0;
*line=0;
fgets(line,255,ini);
// remove enter
i=strlen(line);
// ZIGGY there was a bug here if EOL was unix like on a short line (i.e. a line
// with just EOL), it would write into line[-1]
if(i>=1 && line[i-1]==0xa) {
ret=1;
line[i-1]=0;
if (i>=2 && line[i-2]==0xd) line[i-2]=0;
}
// remove comments
p=line;
while(*p)
{
if (p[0]=='/' && p[1]=='/')
{
p[0]=0;
break;
}
p++;
}
// skip starting space
p=line;
while(*p<=' ' && *p) p++;
// empty line
if(!*p) continue;
last_line=ftell(ini); // where to add if not found
last_line_ret = ret;
if(*p!='[') continue;
p++;
for (i=0;i<63;i++)
{
if(*p==']' || !*p) break;
section[i]=*p++;
}
section[i]=0;
#ifdef _WIN32
if(!stricmp(section,sectionname))
#else // _WIN32
if (!strcasecmp(section,sectionname))
#endif // _WIN32
{
sectionstart=ftell(ini);
sectionfound=1;
return TRUE;
}
}
if (!sectionfound && create)
{
// create the section
fseek(ini,last_line,SEEK_SET);
INI_InsertSpace ((!last_line_ret) * 2 + 6 + strlen(sectionname));
if (!last_line_ret) fwrite (&cr, 1, 2, ini);
fwrite (&cr, 1, 2, ini);
sprintf (section, "[%s]", sectionname);
fwrite (section, 1, strlen(section), ini);
fwrite (&cr, 1, 2, ini);
sectionstart = ftell(ini);
last_line = sectionstart;
last_line_ret = 1;
return TRUE;
}
return FALSE;
}
// Reads the value of item 'itemname' as a string.
const char *INI_ReadString (const char *itemname, char *value, const char *def_value, BOOL create)
{
char line[256], name[64];
char *p, *n;
int ret, i;
*value = 0;
fseek(ini,sectionstart,SEEK_SET);
while(!feof(ini)) {
ret = 0;
*line=0;
fgets(line,255,ini);
// remove enter
i=strlen(line);
// ZIGGY there was a bug here if EOL was unix like on a short line (i.e. a line
// with just EOL), it would write into line[-1]
// OLD CODE : if(line[i-1]=='\n') ret=1, line[i-2]=0;
if(i>=1 && line[i-1]==0xa) {
ret=1;
line[i-1]=0;
if (i>=2 && line[i-2]==0xd) line[i-2]=0;
}
// remove comments
p=line;
while(*p)
{
if (p[0]==';')
{
p[0]=0;
break;
}
p++;
}
// skip starting space
p=line;
while(*p<=' ' && *p) p++;
// empty line
if(!*p) continue;
// new section
if(*p=='[') break;
last_line=ftell(ini); // where to add if not found
last_line_ret = ret;
// read name
n = name;
while(*p && *p!='=' && *p>' ') *n++ = *p++;
*n = 0;
#ifdef _WIN32
if(!stricmp(name,itemname))
#else // _WIN32
if(!strcasecmp(name,itemname))
#endif // _WIN32
{
// skip spaces/equal sign
while(*p<=' ' || *p=='=') p++;
// read value
n = value;
while(*p) *n++ = *p++;
// remove trailing spaces
while (*(n-1) == ' ') n--;
*n=0;
return value;
}
}
// uh-oh, not found. we need to create
if (create)
{
fseek(ini,last_line,SEEK_SET);
INI_InsertSpace ((!last_line_ret) * 2 + strlen(itemname) + strlen(def_value) + 5);
if (!last_line_ret) fwrite (&cr, 1, 2, ini);
sprintf (line, "%s = %s", itemname, def_value);
fwrite (line, 1, strlen(line), ini);
fwrite (&cr, 1, 2, ini);
last_line = ftell(ini);
last_line_ret = 1;
}
strcpy (value, def_value);
return value;
}
// Reads the value of item 'itemname' as a string.
void INI_WriteString (const char *itemname, const char *value)
{
char line[256], name[64];
char *p, *n;
int ret, i;
fseek(ini,sectionstart,SEEK_SET);
while(!feof(ini)) {
ret = 0;
*line=0;
fgets(line,255,ini);
// remove enter
i=strlen(line);
// ZIGGY there was a bug here if EOL was unix like on a short line (i.e. a line
// with just EOL), it would write into line[-1]
// OLD CODE : if(line[i-1]=='\n') ret=1, line[i-2]=0;
if(i>=1 && line[i-1]==0xa) {
ret=1;
line[i-1]=0;
if (i>=2 && line[i-2]==0xd) line[i-2]=0;
}
// remove comments
p=line;
while(*p)
{
if (p[0]=='/' && p[1]=='/')
{
p[0]=0;
break;
}
p++;
}
// skip starting space
p=line;
while(*p<=' ' && *p) p++;
// empty line
if(!*p) continue;
// new section
if(*p=='[') break;
last_line=ftell(ini); // where to add if not found
last_line_ret = ret;
// read name
n = name;
while(*p && *p!='=' && *p>' ') *n++ = *p++;
*n = 0;
#ifdef _WIN32
if(!stricmp(name,itemname))
#else // _WIN32
if(!strcasecmp(name,itemname))
#endif // _WIN32
{
INI_InsertSpace (-i + (strlen(itemname) + strlen(value) + 5));
sprintf (line, "%s = %s", itemname, value);
fseek (ini, -i, SEEK_CUR);
fwrite (line, 1, strlen(line), ini);
fwrite (&cr, 1, 2, ini);
last_line = ftell(ini);
last_line_ret = 1;
return;
}
}
// uh-oh, not found. we need to create
fseek(ini,last_line,SEEK_SET);
INI_InsertSpace ((!last_line_ret) * 2 + strlen(itemname) + strlen(value) + 5);
if (!last_line_ret) fwrite (&cr, 1, 2, ini);
sprintf (line, "%s = %s", itemname, value);
fwrite (line, 1, strlen(line), ini);
fwrite (&cr, 1, 2, ini);
last_line = ftell(ini);
last_line_ret = 1;
return;
}
int INI_ReadInt (const char *itemname, int def_value, BOOL create)
{
if (ini == NULL)
return def_value;
char value[64], def[64];
#ifdef _WIN32
_itoa (def_value, def, 10);
#else // _WIN32
sprintf(def, "%d", def_value);
#endif // _WIN32
INI_ReadString (itemname, value, def, create);
return atoi (value);
}
void INI_WriteInt (const char *itemname, int value)
{
char valstr[64];
#ifdef _WIN32
_itoa (value, valstr, 10);
#else // _WIN32
sprintf(valstr, "%d", value);
#endif // _WIN32
INI_WriteString (itemname, valstr);
}
void SetConfigDir( const char *configDir )
{
strncpy(configdir, configDir, PATH_MAX);
}