b6ab0b0fbb4ff805dff0e746bbf5aef1dae66505
[mupen64plus-pandora.git] / source / gles2glide64 / src / Glide64 / Ini.cpp
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
63 FILE *ini;
64 int sectionstart;
65 int last_line;      // last good line
66 int last_line_ret;  // last line ended in return?
67 wxUint16 cr = 0x0A0D;
68 static char configdir[PATH_MAX] = {0};
69
70
71 //TODO: move INI_xxxx() function code into class and clean up
72 Ini *Ini::singleton = 0;
73
74 Ini::Ini()
75 {
76         if (!INI_Open())
77         {
78                 printf("Could not find INI file!");
79                 exit(1);
80         }
81 }
82
83 Ini *Ini::OpenIni()
84 {
85         if (!singleton)
86                 singleton = new Ini();
87         return singleton;
88 }
89
90 void 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
99 bool 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
114 bool Ini::Read(const char *key, int *l, int defaultVal)
115 {
116         *l = INI_ReadInt(key, defaultVal, false);
117         return true;
118 }
119
120 int Ini::Read(const char *key, int defaultVal)
121 {
122         return INI_ReadInt(key, defaultVal, false);
123 }
124
125
126 BOOL 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
225 void INI_Close ()
226 {
227     //if (ini)
228       //  fclose(ini);
229 }
230
231 void 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
297 BOOL 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.
401 const 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.
500 void 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
591 int 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
606 void 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
617 void SetConfigDir( const char *configDir )
618 {
619     strncpy(configdir, configDir, PATH_MAX);
620 }
621