--- /dev/null
+/*
+* 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
+
+#include "m64p.h"
+
+#include "Ini.h"
+#include "Gfx_1.3.h"
+#include <limits.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdlib.h>
+#else
+#include <io.h>
+#endif // _WIN32
+
+#include <errno.h>
+#ifndef _WIN32
+#include <sys/resource.h>
+#endif
+
+#ifdef _WIN32
+ #define PATH_MAX _MAX_PATH
+ #define stricmp _stricmp
+#endif
+
+FILE *ini;
+int sectionstart;
+int last_line; // last good line
+int last_line_ret; // last line ended in return?
+wxUint16 cr = 0x0A0D;
+static char configdir[PATH_MAX] = {0};
+
+
+//TODO: move INI_xxxx() function code into class and clean up
+Ini *Ini::singleton = 0;
+
+Ini::Ini()
+{
+ if (!INI_Open())
+ {
+ printf("Could not find INI file!");
+ exit(1);
+ }
+}
+
+Ini *Ini::OpenIni()
+{
+ if (!singleton)
+ singleton = new Ini();
+ return singleton;
+}
+
+void Ini::SetPath(const char *path)
+{
+ if (!INI_FindSection(path, false))
+ {
+ printf("Could not find [%s] section in INI file!", path);
+ }
+}
+
+
+bool Ini::Read(const char *key, int *l)
+{
+ int undef = 0xDEADBEEF;
+ int tmpVal = INI_ReadInt(key, undef, false);
+ if (tmpVal == undef)
+ {
+ return false;
+ }
+ else
+ {
+ *l = tmpVal;
+ return true;
+ }
+}
+
+bool Ini::Read(const char *key, int *l, int defaultVal)
+{
+ *l = INI_ReadInt(key, defaultVal, false);
+ return true;
+}
+
+int Ini::Read(const char *key, int defaultVal)
+{
+ return INI_ReadInt(key, defaultVal, false);
+}
+
+
+BOOL INI_Open ()
+{
+ //TODO: use ConfigGetSharedDataFilepath
+
+ // 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 (NULL, 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, "Glide64mk2.ini", PATH_MAX - strlen(path));
+ LOG("opening %s\n", path);
+ // Open the file
+ ini = fopen (path, "rb");
+ if (ini == NULL)
+ {
+ ERRLOG("Could not find Glide64mk2.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)
+{
+ printf("Inserting space, space to insert is %d\n", 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);
+ if (ftruncate(file, t2+space) != 0)
+ ERRLOG("Failed to truncate .ini file to %i bytes", 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);
+ if (fread(chunk,1,len,ini) != (size_t) len)
+ ERRLOG("Failed to read %i bytes from .ini file", len);
+ fseek (ini,-len+space,SEEK_CUR);
+ if (fwrite(chunk,1,len,ini) != (size_t) len)
+ ERRLOG("Failed to write %i bytes to .ini file", len);
+ 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);
+ if (ftruncate(file, t2+space) != 0)
+ ERRLOG("Failed to truncate .ini file to %i bytes", t2+space);
+ }
+#endif // _WIN32
+}
+
+BOOL INI_FindSection (const char *sectionname, BOOL create)
+{
+ if (ini == NULL)
+ return FALSE;
+/* static char cached_secion[200]="\0";
+ static BOOL cached_result;
+ if (!strcasecmp(section,sectionname))
+ return cached_result;*/
+
+
+// printf("INI_FindSection trying to find name for %s\n", sectionname);
+
+ 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;
+ if (fgets(line,255,ini) == NULL)
+ break;
+
+ // 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)
+ if (fwrite(&cr, 1, 2, ini) != 2)
+ ERRLOG("Failed to write <CR><LF> to .ini file");
+ sprintf (section, "[%s]", sectionname);
+ if (fwrite(&cr, 1, 2, ini) != 2 ||
+ fwrite(section, 1, strlen(section), ini) != strlen(section) ||
+ fwrite(&cr, 1, 2, ini) != 2)
+ ERRLOG("Failed to write Section line to .ini file");
+ 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;
+ if (fgets(line,255,ini) == NULL)
+ break;
+
+ // 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)
+ if (fwrite(&cr, 1, 2, ini) != 2)
+ ERRLOG("Failed to write <CR><LF> to .ini file");
+ sprintf (line, "%s = %s", itemname, def_value);
+ if (fwrite(line, 1, strlen(line), ini) != strlen(line) ||
+ fwrite(&cr, 1, 2, ini) != 2)
+ ERRLOG("Failed to write key,value line to .ini file");
+ 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;
+ if (fgets(line,255,ini) == NULL) break;
+
+ // 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);
+ if (fwrite(line, 1, strlen(line), ini) != strlen(line) ||
+ fwrite(&cr, 1, 2, ini) != 2)
+ {
+ ERRLOG("Failed to write line '%s' to .ini file", line);
+ }
+ 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);
+ sprintf (line, "%s = %s", itemname, value);
+ if (!last_line_ret)
+ if (fwrite(&cr, 1, 2, ini) != 2)
+ ERRLOG("Failed to write <CR> to .ini file");
+ if (fwrite(line, 1, strlen(line), ini) != strlen(line) ||
+ fwrite(&cr, 1, 2, ini) != 2)
+ {
+ ERRLOG("Failed to write line '%s' to .ini file", line);
+ }
+ 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);
+}
+