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