build plugins in
[pcsx_rearmed.git] / frontend / main.c
1 /*
2  * (C) notaz, 2010
3  *
4  * This work is licensed under the terms of the GNU GPLv2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdarg.h>
11 #include <dlfcn.h>
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 #include <unistd.h>
15
16 #include "plugin.h"
17 #include "../gui/Linux.h"
18 #include "../libpcsxcore/misc.h"
19
20 int UseGui;
21
22 static void make_path(char *buf, size_t size, const char *dir, const char *fname)
23 {
24         if (fname)
25                 snprintf(buf, size, ".%s%s", dir, fname);
26         else
27                 snprintf(buf, size, ".%s", dir);
28 }
29 #define MAKE_PATH(buf, dir, fname) \
30         make_path(buf, sizeof(buf), dir, fname)
31
32 static void create_profile_dir(const char *directory) {
33         char path[MAXPATHLEN];
34
35         MAKE_PATH(path, directory, NULL);
36         mkdir(path, S_IRWXU | S_IRWXG);
37 }
38
39 static void CheckSubDir() {
40         // make sure that ~/.pcsx exists
41         create_profile_dir(PCSX_DOT_DIR);
42
43         create_profile_dir(BIOS_DIR);
44         create_profile_dir(MEMCARD_DIR);
45         create_profile_dir(STATES_DIR);
46         create_profile_dir(PLUGINS_DIR);
47         create_profile_dir(PLUGINS_CFG_DIR);
48         create_profile_dir(CHEATS_DIR);
49         create_profile_dir(PATCHES_DIR);
50 }
51
52 static void CreateMemcard(char *filename, char *conf_mcd) {
53         struct stat buf;
54
55         make_path(conf_mcd, MAXPATHLEN, MEMCARD_DIR, filename);
56
57         /* Only create a memory card if an existing one does not exist */
58         if (stat(conf_mcd, &buf) == -1) {
59                 SysPrintf(_("Creating memory card: %s\n"), conf_mcd);
60                 CreateMcd(conf_mcd);
61         }
62 }
63
64 int main(int argc, char *argv[])
65 {
66         char file[MAXPATHLEN] = "";
67         char path[MAXPATHLEN];
68         int runcd = 0;
69         int loadst = 0;
70         int i;
71
72         // what is the name of the config file?
73         // it may be redefined by -cfg on the command line
74         strcpy(cfgfile_basename, "pcsx.cfg");
75
76         emuLog = stdout;
77         SetIsoFile(NULL);
78         Config.PsxOut = 1;
79
80         // read command line options
81         for (i = 1; i < argc; i++) {
82                      if (!strcmp(argv[i], "-psxout")) Config.PsxOut = 1;
83                 else if (!strcmp(argv[i], "-load")) loadst = atol(argv[++i]);
84                 else if (!strcmp(argv[i], "-cfg")) {
85                         if (i+1 >= argc) break;
86                         strncpy(cfgfile_basename, argv[++i], MAXPATHLEN-100);   /* TODO buffer overruns */
87                         printf("Using config file %s.\n", cfgfile_basename);
88                 }
89                 else if (!strcmp(argv[i], "-cdfile")) {
90                         char isofilename[MAXPATHLEN];
91
92                         if (i+1 >= argc) break;
93                         strncpy(isofilename, argv[++i], MAXPATHLEN);
94                         if (isofilename[0] != '/') {
95                                 getcwd(path, MAXPATHLEN);
96                                 if (strlen(path) + strlen(isofilename) + 1 < MAXPATHLEN) {
97                                         strcat(path, "/");
98                                         strcat(path, isofilename);
99                                         strcpy(isofilename, path);
100                                 } else
101                                         isofilename[0] = 0;
102                         }
103
104                         SetIsoFile(isofilename);
105                         runcd = 1;
106                 }
107                 else if (!strcmp(argv[i], "-h") ||
108                          !strcmp(argv[i], "-help") ||
109                          !strcmp(argv[i], "--help")) {
110                          printf(PACKAGE_NAME " " PACKAGE_VERSION "\n");
111                          printf("%s\n", _(
112                                                         " pcsx [options] [file]\n"
113                                                         "\toptions:\n"
114                                                         "\t-cdfile FILE\tRuns a CD image file\n"
115                                                         "\t-nogui\t\tDon't open the GTK GUI\n"
116                                                         "\t-cfg FILE\tLoads desired configuration file (default: ~/.pcsx/pcsx.cfg)\n"
117                                                         "\t-psxout\t\tEnable PSX output\n"
118                                                         "\t-load STATENUM\tLoads savestate STATENUM (1-5)\n"
119                                                         "\t-h -help\tDisplay this message\n"
120                                                         "\tfile\t\tLoads file\n"));
121                          return 0;
122                 } else {
123                         strncpy(file, argv[i], MAXPATHLEN);
124                         if (file[0] != '/') {
125                                 getcwd(path, MAXPATHLEN);
126                                 if (strlen(path) + strlen(file) + 1 < MAXPATHLEN) {
127                                         strcat(path, "/");
128                                         strcat(path, file);
129                                         strcpy(file, path);
130                                 } else
131                                         file[0] = 0;
132                         }
133                 }
134         }
135
136         memset(&Config, 0, sizeof(PcsxConfig));
137         strcpy(Config.Net, "Disabled");
138
139         CheckSubDir();
140 //      ScanAllPlugins();
141
142         strcpy(Config.Bios, "HLE");
143         strcpy(Config.BiosDir, "./");
144
145         strcpy(Config.PluginsDir, "plugins");
146         strcpy(Config.Gpu, "builtin_gpu");
147         strcpy(Config.Spu, "builtin_spu");
148         strcpy(Config.Cdr, "builtin_cdr");
149         strcpy(Config.Pad1, "builtin_pad");
150         strcpy(Config.Pad2, "builtin_pad");
151
152         // try to load config
153         // if the config file doesn't exist
154         if (LoadConfig() == -1) {
155                 // Uh oh, no config file found, use some defaults
156                 Config.PsxAuto = 1;
157
158                 // create & load default memcards if they don't exist
159                 CreateMemcard("card1.mcd", Config.Mcd1);
160                 CreateMemcard("card2.mcd", Config.Mcd2);
161
162                 LoadMcds(Config.Mcd1, Config.Mcd2);
163
164                 SaveConfig();
165         }
166
167         snprintf(Config.PatchesDir, sizeof(Config.PatchesDir), "." PATCHES_DIR);
168 /*
169         // switch to plugin dotdir
170         // this lets plugins work without modification!
171         gchar *plugin_default_dir = g_build_filename(getenv("HOME"), PLUGINS_DIR, NULL);
172         chdir(plugin_default_dir);
173         g_free(plugin_default_dir);
174 */
175         if (SysInit() == -1) return 1;
176
177         // if !gui
178         {
179                 // the following only occurs if the gui isn't started
180                 if (LoadPlugins() == -1) {
181                         SysMessage("Failed loading plugins!");
182                         return 1;
183                 }
184
185                 if (OpenPlugins() == -1) {
186                         return 1;
187                 }
188
189                 SysReset();
190                 CheckCdrom();
191
192                 if (file[0] != '\0') {
193                         Load(file);
194                 } else {
195                         if (runcd) {
196                                 if (LoadCdrom() == -1) {
197                                         ClosePlugins();
198                                         printf(_("Could not load CD-ROM!\n"));
199                                         return -1;
200                                 }
201                         }
202                 }
203
204                 // If a state has been specified, then load that
205                 if (loadst) {
206                         StatesC = loadst - 1;
207                         char *state_filename = get_state_filename(StatesC);
208                         LoadState(state_filename);
209                         free(state_filename);
210                 }
211
212                 psxCpu->Execute();
213         }
214
215         return 0;
216 }
217
218 int SysInit() {
219         if (EmuInit() == -1) {
220                 printf("PSX emulator couldn't be initialized.\n");
221                 return -1;
222         }
223
224         LoadMcds(Config.Mcd1, Config.Mcd2);     /* TODO Do we need to have this here, or in the calling main() function?? */
225
226         if (Config.Debug) {
227                 StartDebugger();
228         }
229
230         return 0;
231 }
232
233 void SysRunGui() {
234         printf("SysRunGui\n");
235 }
236
237 void StartGui() {
238         printf("StartGui\n");
239 }
240
241 void SysReset() {
242         EmuReset();
243 }
244
245 void SysClose() {
246         EmuShutdown();
247         ReleasePlugins();
248
249         StopDebugger();
250
251         if (emuLog != NULL) fclose(emuLog);
252 }
253
254 void SysUpdate() {
255         PADhandleKey(PAD1_keypressed());
256         PADhandleKey(PAD2_keypressed());
257 }
258
259 void UpdateMenuSlots() {
260 }
261
262 void OnFile_Exit() {
263         printf("OnFile_Exit\n");
264         exit(0);
265 }
266
267 void state_save(gchar *state_filename) {
268         char Text[MAXPATHLEN + 20];
269
270         GPU_updateLace();
271
272         if (SaveState(state_filename) == 0)
273                 sprintf(Text, _("Saved state %s."), state_filename);
274         else
275                 sprintf(Text, _("Error saving state %s!"), state_filename);
276
277         GPU_displayText(Text);
278 }
279
280 void state_load(gchar *state_filename) {
281         int ret;
282         char Text[MAXPATHLEN + 20];
283         FILE *fp;
284
285         // check if the state file actually exists
286         fp = fopen(state_filename, "rb");
287         if (fp == NULL) {
288                 // file does not exist
289                 return;
290         }
291
292         fclose(fp);
293
294         ret = CheckState(state_filename);
295
296         if (ret == 0) {
297                 SysReset();
298                 ret = LoadState(state_filename);
299         }
300
301         if (ret == 0) {
302                 // Check the CD-ROM is valid
303                 if (CheckCdrom() == -1) {
304                         ClosePlugins();
305                         SysRunGui();
306                         return;
307                 }
308
309                 sprintf(Text, _("Loaded state %s."), state_filename);
310         } else {
311                 sprintf(Text, _("Error loading state %s!"), state_filename);
312         }
313         GPU_displayText(Text);
314 }
315
316 char *get_state_filename(int i) {
317         char SStateFile[256];
318         char trimlabel[33];
319         int j;
320
321         strncpy(trimlabel, CdromLabel, 32);
322         trimlabel[32] = 0;
323         for (j = 31; j >= 0; j--)
324                 if (trimlabel[j] == ' ')
325                         trimlabel[j] = 0;
326                 else
327                         continue;
328
329         snprintf(SStateFile, sizeof(SStateFile), "." STATES_DIR "%.32s-%.9s.%3.3d",
330                 trimlabel, CdromId, i);
331
332         return strdup(SStateFile);
333 }
334
335 void SysPrintf(const char *fmt, ...) {
336         va_list list;
337         char msg[512];
338
339         va_start(list, fmt);
340         vsprintf(msg, fmt, list);
341         va_end(list);
342
343         if (Config.PsxOut) {
344                 static char linestart = 1;
345                 int l = strlen(msg);
346
347                 printf(linestart ? " * %s" : "%s", msg);
348
349                 if (l > 0 && msg[l - 1] == '\n') {
350                         linestart = 1;
351                 } else {
352                         linestart = 0;
353                 }
354         }
355
356         fprintf(emuLog, "%s", msg);
357 }
358
359 void SysMessage(const char *fmt, ...) {
360         va_list list;
361         char msg[512];
362
363         va_start(list, fmt);
364         vsprintf(msg, fmt, list);
365         va_end(list);
366
367         if (msg[strlen(msg) - 1] == '\n')
368                 msg[strlen(msg) - 1] = 0;
369
370         fprintf(stderr, "%s\n", msg);
371 }
372
373 #if 1
374 /* this is to avoid having to hack every plugin to stop using $HOME */
375 char *getenv(const char *name)
376 {
377         static char ret[8] = ".";
378
379         // HACK
380         if (name && strcmp(name, "DISPLAY") == 0)
381                 return ":0";
382
383         if (name && strcmp(name, "HOME") != 0)
384                 fprintf(stderr, "getenv called with %s\n", name);
385
386         return ret;
387 }
388 #endif
389
390 /* we hook statically linked plugins here */
391 static const char *builtin_plugins[] = {
392         "builtin_gpu", "builtin_spu", "builtin_cdr", "builtin_pad"
393 };
394
395 static const int builtin_plugin_ids[] = {
396         PLUGIN_GPU, PLUGIN_SPU, PLUGIN_CDR, PLUGIN_PAD,
397 };
398
399 void *SysLoadLibrary(const char *lib) {
400         const char *tmp = strrchr(lib, '/');
401         int i;
402
403         printf("dlopen %s\n", lib);
404         if (tmp != NULL) {
405                 tmp++;
406                 for (i = 0; i < ARRAY_SIZE(builtin_plugins); i++)
407                         if (strcmp(tmp, builtin_plugins[i]) == 0)
408                                 return (void *)(long)(PLUGIN_DL_BASE + builtin_plugin_ids[i]);
409         }
410
411         return dlopen(lib, RTLD_NOW);
412 }
413
414 void *SysLoadSym(void *lib, const char *sym) {
415         unsigned int plugid = (unsigned int)(long)lib;
416
417         if (PLUGIN_DL_BASE <= plugid && plugid < PLUGIN_DL_BASE + ARRAY_SIZE(builtin_plugins))
418                 return plugin_link(plugid - PLUGIN_DL_BASE, sym);
419
420         return dlsym(lib, sym);
421 }
422
423 const char *SysLibError() {
424         return dlerror();
425 }
426
427 void SysCloseLibrary(void *lib) {
428         unsigned int plugid = (unsigned int)(long)lib;
429
430         if (PLUGIN_DL_BASE <= plugid && plugid < PLUGIN_DL_BASE + ARRAY_SIZE(builtin_plugins))
431                 return;
432
433         dlclose(lib);
434 }
435
436