perfect vsync, bugfixes
[fceu.git] / general.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Xodnizel
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #ifndef _GNU_SOURCE
22 #define _GNU_SOURCE // for asprintf
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33
34 #include "types.h"
35 #include "fce.h"
36
37 #include "general.h"
38 #include "state.h"
39 #include "movie.h"
40
41 #include "driver.h"
42
43 #include "md5.h"
44 #include "svga.h"
45
46 static char BaseDirectory[2048];
47 char FileBase[2048];
48 static char FileExt[2048];      /* Includes the . character, as in ".nes" */
49
50 static char FileBaseDirectory[2048];
51
52 void FCEUI_SetBaseDirectory(char *dir)
53 {
54  strncpy(BaseDirectory,dir,2047);
55  BaseDirectory[2047]=0;
56 }
57
58 static char *odirs[FCEUIOD__COUNT]={0,0,0,0,0};     // odirs, odors. ^_^
59
60 void FCEUI_SetDirOverride(int which, char *n)
61 {
62 //      FCEU_PrintError("odirs[%d]=%s->%s", which, odirs[which], n);
63 if(which < FCEUIOD__COUNT)
64  odirs[which]=n;
65
66 #if 0
67  if(FCEUGameInfo)  /* Rebuild cache of present states/movies. */
68  {
69   if(which==FCEUIOD_STATE)
70    FCEUSS_CheckStates();
71   else if(which == FCEUIOD_MISC)
72    FCEUMOV_CheckMovies();
73  }
74 #endif
75 }
76
77 #ifndef HAVE_ASPRINTF
78 static int asprintf(char **strp, const char *fmt, ...)
79 {
80  va_list ap;
81  int ret;
82
83  va_start(ap,fmt);
84  if(!(*strp=malloc(2048)))
85   return(0);
86  ret=vsnprintf(*strp,2048,fmt,ap);
87  va_end(ap);
88  return(ret);
89 }
90 #endif
91
92 char* FCEU_GetPath(int type)
93 {
94  char *ret=0;
95  switch(type)
96  {
97   case FCEUMKF_STATE:if(odirs[FCEUIOD_STATE])
98                       ret=strdup(odirs[FCEUIOD_STATE]);
99                      else
100                       asprintf(&ret,"%s"PSS"movie",BaseDirectory);
101                      break;
102   case FCEUMKF_MOVIE:if(odirs[FCEUIOD_MISC])
103                       ret=strdup(odirs[FCEUIOD_MISC]);
104                      else
105                       asprintf(&ret,"%s"PSS"movie",BaseDirectory);
106                      break;
107  }
108  return(ret);
109 }
110
111 char *FCEU_MakePath(int type, const char* filebase)
112 {
113  char *ret=0;
114
115  switch(type)
116  {
117   case FCEUMKF_MOVIE:if(odirs[FCEUIOD_MISC])
118                       asprintf(&ret,"%s"PSS"%s",odirs[FCEUIOD_MISC],filebase);
119                      else
120                       asprintf(&ret,"%s"PSS"movie"PSS"%s",BaseDirectory,filebase);
121                      break;
122  }
123  return(ret);
124 }
125
126 char *FCEU_MakeFName(int type, int id1, char *cd1)
127 {
128  char *ret=0;
129  struct stat tmpstat;
130
131  switch(type)
132  {
133   case FCEUMKF_NPTEMP: asprintf(&ret,"%s"PSS"m590plqd94fo.tmp",BaseDirectory);break;
134   case FCEUMKF_MOVIE:if(id1>=0)
135                                          {
136                           if(odirs[FCEUIOD_MISC])
137                        asprintf(&ret,"%s"PSS"%s.%d.fcm",odirs[FCEUIOD_MISC],FileBase,id1);
138                       else
139                        asprintf(&ret,"%s"PSS"movie"PSS"%s.%d.fcm",BaseDirectory,FileBase,id1);
140                       if(stat(ret,&tmpstat)==-1)
141                       {
142                        if(odirs[FCEUIOD_MISC])
143                         asprintf(&ret,"%s"PSS"%s.%d.fcm",odirs[FCEUIOD_MISC],FileBase,id1);
144                        else
145                         asprintf(&ret,"%s"PSS"movie"PSS"%s.%d.fcm",BaseDirectory,FileBase,id1);
146                       }
147                                          }
148                                          else
149                                          {
150                                           if(odirs[FCEUIOD_MISC])
151                                            asprintf(&ret,"%s"PSS"%s.fcm",odirs[FCEUIOD_MISC],FileBase);
152                                           else
153                                            asprintf(&ret,"%s"PSS"movie"PSS"%s.fcm",BaseDirectory,FileBase);
154                                          }
155                      break;
156   case FCEUMKF_STATE:if(odirs[FCEUIOD_STATE])
157                                          {
158                       asprintf(&ret,"%s"PSS"%s.fc%d",odirs[FCEUIOD_STATE],FileBase,id1);
159 //                                        FCEU_PrintError("A");
160                                          }
161                      else
162                                          {
163                       asprintf(&ret,"%s"PSS"fcs"PSS"%s.fc%d",BaseDirectory,FileBase,id1);
164 //                                        FCEU_PrintError("B");
165                                          }
166                      if(stat(ret,&tmpstat)==-1)
167                      {
168                       if(odirs[FCEUIOD_STATE])
169                           {
170                        asprintf(&ret,"%s"PSS"%s.fc%d",odirs[FCEUIOD_STATE],FileBase,id1);
171 //                                        FCEU_PrintError("C");
172                           }
173                       else
174                                           {
175                        asprintf(&ret,"%s"PSS"fcs"PSS"%s.fc%d",BaseDirectory,FileBase,id1);
176 //                                        FCEU_PrintError("D");
177                                           }
178                      }
179                      break;
180   case FCEUMKF_SNAP:
181                     if(FSettings.SnapName)
182                     {
183                      if(odirs[FCEUIOD_SNAPS])
184                       asprintf(&ret,"%s"PSS"%s-%d.%s",odirs[FCEUIOD_SNAPS],FileBase,id1,cd1);
185                      else
186                       asprintf(&ret,"%s"PSS"snaps"PSS"%s-%d.%s",BaseDirectory,FileBase,id1,cd1);
187                     }
188                     else
189                     {
190                      if(odirs[FCEUIOD_SNAPS])
191                       asprintf(&ret,"%s"PSS"%d.%s",odirs[FCEUIOD_SNAPS],id1,cd1);
192                      else
193                       asprintf(&ret,"%s"PSS"snaps"PSS"%d.%s",BaseDirectory,id1,cd1);
194                     }
195                     break;
196   case FCEUMKF_FDS:if(odirs[FCEUIOD_NV])
197                     asprintf(&ret,"%s"PSS"%s.fds",odirs[FCEUIOD_NV],FileBase);
198                    else
199                     asprintf(&ret,"%s"PSS"sav"PSS"%s.fds",BaseDirectory,FileBase);
200                    break;
201   case FCEUMKF_SAV:if(odirs[FCEUIOD_NV])
202                     asprintf(&ret,"%s"PSS"%s.%s",odirs[FCEUIOD_NV],FileBase,cd1);
203                    else
204                     asprintf(&ret,"%s"PSS"sav"PSS"%s.%s",BaseDirectory,FileBase,cd1);
205                    break;
206   case FCEUMKF_CHEAT:
207                      if(odirs[FCEUIOD_CHEATS])
208                       asprintf(&ret,"%s"PSS"%s.cht",odirs[FCEUIOD_CHEATS],FileBase);
209                      else
210                       asprintf(&ret,"%s"PSS"cheats"PSS"%s.cht",BaseDirectory,FileBase);
211                      break;
212   case FCEUMKF_IPS:  asprintf(&ret,"%s"PSS"%s%s.ips",FileBaseDirectory,FileBase,FileExt);
213                      break;
214   case FCEUMKF_GGROM:asprintf(&ret,"%s"PSS"gg.rom",BaseDirectory);break;
215   case FCEUMKF_FDSROM:asprintf(&ret,"%s"PSS"disksys.rom",BaseDirectory);break;
216   case FCEUMKF_PALETTE:
217                        if(odirs[FCEUIOD_MISC])
218                         asprintf(&ret,"%s"PSS"%s.pal",odirs[FCEUIOD_MISC],FileBase);
219                        else
220                         asprintf(&ret,"%s"PSS"pal"PSS"%s.pal",BaseDirectory,FileBase);
221                        break;
222   case FCEUMKF_MOVIEGLOB:
223                      if(odirs[FCEUIOD_MISC])
224 //                      asprintf(&ret,"%s"PSS"%s*.fcm",odirs[FCEUIOD_MISC],FileBase);
225                       asprintf(&ret,"%s"PSS"*.???",odirs[FCEUIOD_MISC]);
226                      else
227 //                      asprintf(&ret,"%s"PSS"fcs"PSS"%s*.fcm",BaseDirectory,FileBase);
228                       asprintf(&ret,"%s"PSS"movie"PSS"*.???",BaseDirectory);
229                      break;
230   case FCEUMKF_MOVIEGLOB2:
231                       asprintf(&ret,"%s"PSS"*.???",BaseDirectory);
232                      break;
233   case FCEUMKF_STATEGLOB:
234                      if(odirs[FCEUIOD_STATE])
235                       asprintf(&ret,"%s"PSS"%s*.fc?",odirs[FCEUIOD_STATE],FileBase);
236                      else
237                       asprintf(&ret,"%s"PSS"fcs"PSS"%s*.fc?",BaseDirectory,FileBase);
238                      break;
239  }
240  return(ret);
241 }
242
243 void GetFileBase(const char *f)
244 {
245         const char *tp1,*tp3;
246
247  #if PSS_STYLE==4
248      tp1=((char *)strrchr(f,':'));
249  #elif PSS_STYLE==1
250      tp1=((char *)strrchr(f,'/'));
251  #else
252      tp1=((char *)strrchr(f,'\\'));
253   #if PSS_STYLE!=3
254      tp3=((char *)strrchr(f,'/'));
255      if(tp1<tp3) tp1=tp3;
256   #endif
257  #endif
258      if(!tp1)
259      {
260       tp1=f;
261       strcpy(FileBaseDirectory,".");
262      }
263      else
264      {
265       memcpy(FileBaseDirectory,f,tp1-f);
266       FileBaseDirectory[tp1-f]=0;
267       tp1++;
268      }
269
270      if(((tp3=strrchr(f,'.'))!=NULL) && (tp3>tp1))
271      {
272       memcpy(FileBase,tp1,tp3-tp1);
273       FileBase[tp3-tp1]=0;
274       strcpy(FileExt,tp3);
275      }
276      else
277      {
278       strcpy(FileBase,tp1);
279       FileExt[0]=0;
280      }
281 }
282
283 uint32 uppow2(uint32 n)
284 {
285  int x;
286
287  for(x=31;x>=0;x--)
288   if(n&(1<<x))
289   {
290    if((1<<x)!=n)
291     return(1<<(x+1));
292    break;
293   }
294  return n;
295 }
296