Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / Ini.cpp
CommitLineData
98e75f2d 1/*
2* Glide64 - Glide video plugin for Nintendo 64 emulators.
3* Copyright (c) 2002 Dave2001
4*
5* This program is free software; you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation; either version 2 of the License, or
8* any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public
16* Licence along with this program; if not, write to the Free
17* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18* Boston, MA 02110-1301, USA
19*/
20
21//****************************************************************
22//
23// Glide64 - Glide Plugin for Nintendo 64 emulators (tested mostly with Project64)
24// Project started on December 29th, 2001
25//
26// To modify Glide64:
27// * 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.
28// * 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.
29//
30// Official Glide64 development channel: #Glide64 on EFnet
31//
32// Original author: Dave2001 (Dave2999@hotmail.com)
33// Other authors: Gonetz, Gugaman
34//
35//****************************************************************
36
37// INI code v1.1
38
39#include "m64p.h"
40
41#include "Ini.h"
42#include "Gfx_1.3.h"
43#include <limits.h>
44#ifndef _WIN32
45#include <unistd.h>
46#include <string.h>
47#include <dirent.h>
48#include <stdlib.h>
49#else
50#include <io.h>
51#endif // _WIN32
52
53#include <errno.h>
54#ifndef _WIN32
55#include <sys/resource.h>
56#endif
57
58#ifdef _WIN32
59 #define PATH_MAX _MAX_PATH
60 #define stricmp _stricmp
61#endif
62
63FILE *ini;
64int sectionstart;
65int last_line; // last good line
66int last_line_ret; // last line ended in return?
67wxUint16 cr = 0x0A0D;
68static char configdir[PATH_MAX] = {0};
69
70
71//TODO: move INI_xxxx() function code into class and clean up
72Ini *Ini::singleton = 0;
73
74Ini::Ini()
75{
76 if (!INI_Open())
77 {
78 printf("Could not find INI file!");
79 exit(1);
80 }
81}
82
83Ini *Ini::OpenIni()
84{
85 if (!singleton)
86 singleton = new Ini();
87 return singleton;
88}
89
90void Ini::SetPath(const char *path)
91{
92 if (!INI_FindSection(path, false))
93 {
94 printf("Could not find [%s] section in INI file!", path);
95 }
96}
97
98
99bool Ini::Read(const char *key, int *l)
100{
101 int undef = 0xDEADBEEF;
102 int tmpVal = INI_ReadInt(key, undef, false);
103 if (tmpVal == undef)
104 {
105 return false;
106 }
107 else
108 {
109 *l = tmpVal;
110 return true;
111 }
112}
113
114bool Ini::Read(const char *key, int *l, int defaultVal)
115{
116 *l = INI_ReadInt(key, defaultVal, false);
117 return true;
118}
119
120int Ini::Read(const char *key, int defaultVal)
121{
122 return INI_ReadInt(key, defaultVal, false);
123}
124
125
126BOOL INI_Open ()
127{
128 //TODO: use ConfigGetSharedDataFilepath
129
130 // Get the path of the dll, ex: C:\Games\Project64\Plugin\Glide64.dll
131 char path[PATH_MAX];
132 if(strlen(configdir) > 0)
133 {
134 strncpy(path, configdir, PATH_MAX);
135 // make sure there's a trailing '/'
136 //if(path[strlen(path)-1] != '/')
137 // strncat(path, "/", PATH_MAX - strlen(path));
138 }
139 else
140 {
141#ifdef _WIN32
142 GetModuleFileName (NULL, path, PATH_MAX);
143#else // _WIN32
144# ifdef __FreeBSD__
145 int n = readlink("/proc/curproc/files", path, PATH_MAX);
146#else
147 int n = readlink("/proc/self/exe", path, PATH_MAX);
148#endif
149 if (n == -1) strcpy(path, "./");
150 else
151 {
152 char path2[PATH_MAX];
153 int i;
154
155 path[n] = '\0';
156 strcpy(path2, path);
157 for (i=strlen(path2)-1; i>0; i--)
158 {
159 if(path2[i] == '/') break;
160 }
161 if(i == 0) strcpy(path, "./");
162 else
163 {
164 DIR *dir;
165 struct dirent *entry;
166 int gooddir = 0;
167
168 path2[i+1] = '\0';
169 dir = opendir(path2);
170 while((entry = readdir(dir)) != NULL)
171 {
172 if(!strcmp(entry->d_name, "plugins"))
173 gooddir = 1;
174 }
175 closedir(dir);
176 if(!gooddir) strcpy(path, "./");
177 }
178 }
179
180#endif // _WIN32
181
182 // Find the previous backslash
183 int i;
184 for (i=strlen(path)-1; i>0; i--)
185 {
186#ifdef _WIN32
187 if (path[i] == '\\')
188#else // _WIN32
189 if (path[i] == '/')
190#endif // _WIN32
191 break;
192 }
193 if (path == 0) return FALSE;
194 path[i+1] = 0;
195
196#ifndef _WIN32
197 strcat(path, "plugins/");
198#endif // _WIN32
199 }
200
201 //strncat (path, "Glide64mk2.ini", PATH_MAX - strlen(path));
202 LOG("opening %s\n", path);
203 // Open the file
204 ini = fopen (path, "rb");
205 if (ini == NULL)
206 {
207 ERRLOG("Could not find Glide64mk2.ini!");
208 return FALSE;
209 /*
210 ini = fopen (path, "w+b");
211 if (ini == NULL)
212 {
213 return FALSE;
214 }
215 */
216 }
217
218 sectionstart = 0;
219 last_line = 0;
220 last_line_ret = 1;
221
222 return TRUE;
223}
224
225void INI_Close ()
226{
227 //if (ini)
228 // fclose(ini);
229}
230
231void INI_InsertSpace(int space)
232{
233 printf("Inserting space, space to insert is %d\n", space);
234 // Since there is no good way to normally insert to or delete from a certain location in
235 // a file, this function was added. It will insert (or delete) space bytes at the
236 // current location.
237
238 // note: negative count means delete
239 char chunk[2048];
240 int len, file, start_pos, cur_pos;
241
242#ifdef _WIN32
243 file = _fileno(ini);
244#else // _WIN32
245 file = fileno(ini);
246#endif // _WIN32
247
248 start_pos = ftell(ini);
249 fseek(ini,0,SEEK_END);
250
251 // if adding, extend the file
252 if (space > 0)
253#ifdef _WIN32
254 _chsize (file, _filelength(file)+space);
255#else // _WIN32
256 {
257 int t1 = ftell(ini);
258 fseek(ini, 0L, SEEK_END);
259 int t2 = ftell(ini);
260 fseek(ini, t1, SEEK_SET);
261 if (ftruncate(file, t2+space) != 0)
262 ERRLOG("Failed to truncate .ini file to %i bytes", t2+space);
263 }
264#endif // _WIN32
265
266 while (1) {
267 cur_pos = ftell(ini);
268 len = cur_pos - start_pos;
269 if (len == 0) break;
270 if (len > 2048) len = 2048;
271
272 fseek (ini,-len,SEEK_CUR);
273 if (fread(chunk,1,len,ini) != (size_t) len)
274 ERRLOG("Failed to read %i bytes from .ini file", len);
275 fseek (ini,-len+space,SEEK_CUR);
276 if (fwrite(chunk,1,len,ini) != (size_t) len)
277 ERRLOG("Failed to write %i bytes to .ini file", len);
278 fseek (ini,-len-space,SEEK_CUR);
279 }
280
281 // if deleted, make the file shorter
282 if (space < 0)
283#ifdef _WIN32
284 _chsize (file, _filelength(file)+space);
285#else // _WIN32
286 {
287 int t1 = ftell(ini);
288 fseek(ini, 0L, SEEK_END);
289 int t2 = ftell(ini);
290 fseek(ini, t1, SEEK_SET);
291 if (ftruncate(file, t2+space) != 0)
292 ERRLOG("Failed to truncate .ini file to %i bytes", t2+space);
293 }
294#endif // _WIN32
295}
296
297BOOL INI_FindSection (const char *sectionname, BOOL create)
298{
299 if (ini == NULL)
300 return FALSE;
301/* static char cached_secion[200]="\0";
302 static BOOL cached_result;
303 if (!strcasecmp(section,sectionname))
304 return cached_result;*/
305
306
307// printf("INI_FindSection trying to find name for %s\n", sectionname);
308
309 char line[256], section[64];
310 char *p;
311 int i, sectionfound, ret;
312
313 rewind (ini);
314
315 last_line = 0;
316 sectionfound = 0;
317
318 while(!feof(ini)) {
319 ret = 0;
320 *line=0;
321 if (fgets(line,255,ini) == NULL)
322 break;
323
324 // remove enter
325 i=strlen(line);
326 // ZIGGY there was a bug here if EOL was unix like on a short line (i.e. a line
327 // with just EOL), it would write into line[-1]
328 if(i>=1 && line[i-1]==0xa) {
329 ret=1;
330 line[i-1]=0;
331 if (i>=2 && line[i-2]==0xd) line[i-2]=0;
332 }
333
334 // remove comments
335 p=line;
336 while(*p)
337 {
338 if (p[0]=='/' && p[1]=='/')
339 {
340 p[0]=0;
341 break;
342 }
343 p++;
344 }
345
346 // skip starting space
347 p=line;
348 while(*p<=' ' && *p) p++;
349
350 // empty line
351 if(!*p) continue;
352
353 last_line=ftell(ini); // where to add if not found
354 last_line_ret = ret;
355
356 if(*p!='[') continue;
357
358 p++;
359 for (i=0;i<63;i++)
360 {
361 if(*p==']' || !*p) break;
362 section[i]=*p++;
363 }
364 section[i]=0;
365
366#ifdef _WIN32
367 if(!stricmp(section,sectionname))
368#else // _WIN32
369 if (!strcasecmp(section,sectionname))
370#endif // _WIN32
371 {
372 sectionstart=ftell(ini);
373 sectionfound=1;
374 return TRUE;
375 }
376 }
377
378 if (!sectionfound && create)
379 {
380 // create the section
381 fseek(ini,last_line,SEEK_SET);
382 INI_InsertSpace ((!last_line_ret) * 2 + 6 + strlen(sectionname));
383 if (!last_line_ret)
384 if (fwrite(&cr, 1, 2, ini) != 2)
385 ERRLOG("Failed to write <CR><LF> to .ini file");
386 sprintf (section, "[%s]", sectionname);
387 if (fwrite(&cr, 1, 2, ini) != 2 ||
388 fwrite(section, 1, strlen(section), ini) != strlen(section) ||
389 fwrite(&cr, 1, 2, ini) != 2)
390 ERRLOG("Failed to write Section line to .ini file");
391 sectionstart = ftell(ini);
392 last_line = sectionstart;
393 last_line_ret = 1;
394 return TRUE;
395 }
396
397 return FALSE;
398}
399
400// Reads the value of item 'itemname' as a string.
401const char *INI_ReadString (const char *itemname, char *value, const char *def_value, BOOL create)
402{
403 char line[256], name[64];
404 char *p, *n;
405 int ret, i;
406 *value = 0;
407
408 fseek(ini,sectionstart,SEEK_SET);
409
410 while(!feof(ini)) {
411 ret = 0;
412 *line=0;
413 if (fgets(line,255,ini) == NULL)
414 break;
415
416 // remove enter
417 i=strlen(line);
418 // ZIGGY there was a bug here if EOL was unix like on a short line (i.e. a line
419 // with just EOL), it would write into line[-1]
420 // OLD CODE : if(line[i-1]=='\n') ret=1, line[i-2]=0;
421 if(i>=1 && line[i-1]==0xa) {
422 ret=1;
423 line[i-1]=0;
424 if (i>=2 && line[i-2]==0xd) line[i-2]=0;
425 }
426
427 // remove comments
428 p=line;
429 while(*p)
430 {
431 if (p[0]==';')
432 {
433 p[0]=0;
434 break;
435 }
436 p++;
437 }
438
439 // skip starting space
440 p=line;
441 while(*p<=' ' && *p) p++;
442
443 // empty line
444 if(!*p) continue;
445
446 // new section
447 if(*p=='[') break;
448
449 last_line=ftell(ini); // where to add if not found
450 last_line_ret = ret;
451
452 // read name
453 n = name;
454 while(*p && *p!='=' && *p>' ') *n++ = *p++;
455 *n = 0;
456
457#ifdef _WIN32
458 if(!stricmp(name,itemname))
459#else // _WIN32
460 if(!strcasecmp(name,itemname))
461#endif // _WIN32
462 {
463 // skip spaces/equal sign
464 while(*p<=' ' || *p=='=') p++;
465
466 // read value
467 n = value;
468 while(*p) *n++ = *p++;
469
470 // remove trailing spaces
471 while (*(n-1) == ' ') n--;
472
473 *n=0;
474
475 return value;
476 }
477 }
478
479 // uh-oh, not found. we need to create
480 if (create)
481 {
482 fseek(ini,last_line,SEEK_SET);
483 INI_InsertSpace ((!last_line_ret) * 2 + strlen(itemname) + strlen(def_value) + 5);
484 if (!last_line_ret)
485 if (fwrite(&cr, 1, 2, ini) != 2)
486 ERRLOG("Failed to write <CR><LF> to .ini file");
487 sprintf (line, "%s = %s", itemname, def_value);
488 if (fwrite(line, 1, strlen(line), ini) != strlen(line) ||
489 fwrite(&cr, 1, 2, ini) != 2)
490 ERRLOG("Failed to write key,value line to .ini file");
491 last_line = ftell(ini);
492 last_line_ret = 1;
493 }
494
495 strcpy (value, def_value);
496 return value;
497}
498
499// Reads the value of item 'itemname' as a string.
500void INI_WriteString (const char *itemname, const char *value)
501{
502 char line[256], name[64];
503 char *p, *n;
504 int ret, i;
505
506 fseek(ini,sectionstart,SEEK_SET);
507
508 while(!feof(ini)) {
509 ret = 0;
510 *line=0;
511 if (fgets(line,255,ini) == NULL) break;
512
513 // remove enter
514 i=strlen(line);
515 // ZIGGY there was a bug here if EOL was unix like on a short line (i.e. a line
516 // with just EOL), it would write into line[-1]
517 // OLD CODE : if(line[i-1]=='\n') ret=1, line[i-2]=0;
518 if(i>=1 && line[i-1]==0xa) {
519 ret=1;
520 line[i-1]=0;
521 if (i>=2 && line[i-2]==0xd) line[i-2]=0;
522 }
523
524 // remove comments
525 p=line;
526 while(*p)
527 {
528 if (p[0]=='/' && p[1]=='/')
529 {
530 p[0]=0;
531 break;
532 }
533 p++;
534 }
535
536 // skip starting space
537 p=line;
538 while(*p<=' ' && *p) p++;
539
540 // empty line
541 if(!*p) continue;
542
543 // new section
544 if(*p=='[') break;
545
546 last_line=ftell(ini); // where to add if not found
547 last_line_ret = ret;
548
549 // read name
550 n = name;
551 while(*p && *p!='=' && *p>' ') *n++ = *p++;
552 *n = 0;
553
554#ifdef _WIN32
555 if(!stricmp(name,itemname))
556#else // _WIN32
557 if(!strcasecmp(name,itemname))
558#endif // _WIN32
559 {
560 INI_InsertSpace (-i + (strlen(itemname) + strlen(value) + 5));
561 sprintf (line, "%s = %s", itemname, value);
562 fseek (ini, -i, SEEK_CUR);
563 if (fwrite(line, 1, strlen(line), ini) != strlen(line) ||
564 fwrite(&cr, 1, 2, ini) != 2)
565 {
566 ERRLOG("Failed to write line '%s' to .ini file", line);
567 }
568 last_line = ftell(ini);
569 last_line_ret = 1;
570 return;
571 }
572 }
573
574 // uh-oh, not found. we need to create
575 fseek(ini,last_line,SEEK_SET);
576 INI_InsertSpace ((!last_line_ret) * 2 + strlen(itemname) + strlen(value) + 5);
577 sprintf (line, "%s = %s", itemname, value);
578 if (!last_line_ret)
579 if (fwrite(&cr, 1, 2, ini) != 2)
580 ERRLOG("Failed to write <CR> to .ini file");
581 if (fwrite(line, 1, strlen(line), ini) != strlen(line) ||
582 fwrite(&cr, 1, 2, ini) != 2)
583 {
584 ERRLOG("Failed to write line '%s' to .ini file", line);
585 }
586 last_line = ftell(ini);
587 last_line_ret = 1;
588 return;
589}
590
591int INI_ReadInt (const char *itemname, int def_value, BOOL create)
592{
593 if (ini == NULL)
594 return def_value;
595
596 char value[64], def[64];
597#ifdef _WIN32
598 _itoa (def_value, def, 10);
599#else // _WIN32
600 sprintf(def, "%d", def_value);
601#endif // _WIN32
602 INI_ReadString (itemname, value, def, create);
603 return atoi (value);
604}
605
606void INI_WriteInt (const char *itemname, int value)
607{
608 char valstr[64];
609#ifdef _WIN32
610 _itoa (value, valstr, 10);
611#else // _WIN32
612 sprintf(valstr, "%d", value);
613#endif // _WIN32
614 INI_WriteString (itemname, valstr);
615}
616
617void SetConfigDir( const char *configDir )
618{
619 strncpy(configdir, configDir, PATH_MAX);
620}
621