1 /* OpenCP Module Player
2  * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3  * copyright (c) '04-'21 Stian Skjelstad <stian.skjelstad@gmail.com>
4  *
5  * PMain - main module (loads and inits all startup modules)
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  * revision history: (please note changes here)
22  *  -nb980510   Niklas Beisert <nbeisert@physik.tu-muenchen.de>
23  *    -first release
24  *  -kb980717   Tammo Hinrichs <opencp@gmx.net>
25  *    - plScreenChanged variable to notify the interfaces when the
test1()26  *      screen mode has changed
27  *    - added command line help
28  *    - replaced INI link symbol reader with _dllinfo reader
29  *    - added screen mode check for avoiding redundant mode changes
30  *    - various minor changes
31  *  -fd981016   Felix Domke    <tmbinc@gmx.net>
32  *    - Win32-Port
33  *  -doj981213  Dirk Jagdmann  <doj@cubic.org>
34  *    - added the nice end ansi
35  *  -fd981220   Felix Domke    <tmbinc@gmx.net>
36  *    - added stack dump and fault-in-faultproc-check
37  *  -kb981224   Tammo Hinrichs <kb@ms.demo.org>
38  *    - cleaned up dos shell code a bit (but did not help much)
39  *  -doj990421  Dirk Jagdmann  <doj@cubic.org>
40  *    - changed conSave(), conRestore, conInit()
41  *  -fd990518   Felix Domke <tmbinc@gmx.net>
42  *    - clearscreen now works in higher-modes too. dos shell now switches
43  *      to mode 3
44  *  -ss040613   Stian Skjelstad <stian@nixia.no>
45  *    - rewritten for unix
46  */
47 
48 #include "config.h"
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include "types.h"
54 
55 #include "pmain.h"
56 #include "stuff/err.h"
57 #include "stuff/poutput.h"
58 #include "plinkman.h"
59 #include "psetting.h"
60 
61 struct mainstruct *ocpmain = 0;
62 
63 static void plCloseAll(void)
64 {
65 	int i;
66 
67 	for (i=0;i<loadlist_n;i++)
68 		if (loadlist[i].info->PreClose)
69 			loadlist[i].info->PreClose();
70 
71 	for (i=0;i<loadlist_n;i++)
72 		if (loadlist[i].info->Close)
73 			loadlist[i].info->Close();
74 
75 	for (i=0;i<loadlist_n;i++)
76 		if (loadlist[i].info->LateClose)
77 			loadlist[i].info->LateClose();
78 }
79 
80 static int cmdhlp(void)
81 {
82 	if (cfGetProfileString("commandline", "h", 0) || cfGetProfileString("commandline", "?", 0) || cfGetProfileString("commandline--", "help", 0))
83 	{
84 		printf("\nopencp command line help\n");
85 		printf("Usage: ocp [<options>]* [@<playlist>]* [<modulename>]* \n");
86 		printf("\nOptions:\n");
87 		printf("-h                : show this help\n");
88 		printf("-c<name>          : use specific configuration\n");
89 		printf("-f : fileselector settings\n");
90 		printf("     r[0|1]       : remove played files from module list\n");
91 		printf("     o[0|1]       : don't scramble module list order\n");
92 		printf("     l[0|1]       : loop modules\n");
93 		printf("-v : sound settings\n");
94 		printf("     a{0..800}    : set amplification\n");
95 		printf("     v{0..100}    : set volume\n");
96 		printf("     b{-100..100} : set balance\n");
97 		printf("     p{-100..100} : set panning\n");
98 		printf("     r{-100..100} : set reverb\n");
99 		printf("     c{-100..100} : set chorus\n");
100 		printf("     s{0|1}       : set surround on/off\n");
101 		printf("     f{0..2}      : set filter (0=off, 1=AOI, 2=FOI)\n");
102 		printf("-s : device settings\n");
103 		printf("     p<name>      : use specific player device\n");
104 		printf("     s<name>      : use specific sampler device\n");
105 		printf("     w<name>      : use specific wavetable device\n");
106 		printf("     r{0..64000}  : sample at specific rate\n");
107 		printf("     8            : play/sample/mix as 8bit\n");
108 		printf("     m            : play/sample/mix mono\n");
109 		printf("-p                : quit when playlist is empty\n");
110 		printf("-d : force display driver\n");
111 		printf("     curses       : ncurses driver\n");
112 		printf("     x11          : x11 driver\n");
113 		printf("     vcsa         : vcsa/fb linux console driver\n");
114 		printf("     sdl          : SDL video driver\n");
115 		printf("\nExample : ocp -fl0,r1 -vp75,f2 -spdevpdisk -sr48000 ftstar.xm\n");
116 		printf("          (for nice HD rendering of modules)\n");
117 		return errHelpPrinted;
118 	}
119 	return errOk;
120 }
121 
122 
123 extern char compiledate[], compiletime[]/*, compiledby[]*/;
124 
125 static int init_modules(int argc, char *argv[])
126 {
127 	int ret;
128 	int i;
129 
130 	if ((ret=cmdhlp()))
131 		return ret;
132 
133 	if (!geteuid())
134 		if (getuid())
135 		{
136 			fprintf(stderr, "Changing user to non-root\n");
137 			if (seteuid(getuid()))
138 			{
139 				perror("seteuid()");
140 				return errGen;
141 			}
142 		}
143 	if (!getegid())
144 		if (getgid())
145 		{
146 			fprintf(stderr, "Changing group to non-root\n");
147 			if (setegid(getgid()))
148 			{
149 				perror("setegid()");
150 				return errGen;
151 			}
152 		}
153 
154 	lnkInit();
155 
156 	fprintf(stderr, "linking default objects...\n");
157 
158 	cfConfigSec="defaultconfig";
159 
160 	{
161 		int epoch = cfGetProfileInt("version", "epoch", 0, 10);
162 		if (epoch <= 20060815)
163 		{
164 			char temp[1024];
165 
166 			fprintf(stderr, "ocp.ini update (0.1.10) adds devpALSA to [sound] playerdevices=....\n");
167 			snprintf(temp, sizeof(temp), "devpALSA %s", cfGetProfileString("sound", "playerdevices", ""));
168 			cfSetProfileString("sound", "playerdevices", temp);
169 
170 			fprintf(stderr, "ocp.ini update (0.1.10) adds [sound] digitalcd=on\n");
171 			cfSetProfileBool("sound", "digitalcd", 1);
172 
173 			fprintf(stderr, "ocp.ini update (0.1.10) adds AY to [fileselector] modextensions=....\n");
174 			snprintf(temp, sizeof(temp), "%s AY", cfGetProfileString("fileselector", "modextensions", ""));
175 			cfSetProfileString("fileselector", "modextensions", temp);
176 
177 			fprintf(stderr, "ocp.ini update (0.1.10) adds [devpALSA]\n");
178 			cfSetProfileString("devpALSA", "link", "devpalsa");
179 			cfSetProfileInt("devpALSA", "keep", 1, 10);
180 
181 			fprintf(stderr, "ocp.ini update (0.1.10) adds [filetype 37]\n");
182 			cfSetProfileInt("filetype 37", "color", 6, 10);
183 			cfSetProfileString("filetype 37", "name", "AY");
184 			cfSetProfileString("filetype 37", "interface", "plOpenCP");
185 			cfSetProfileString("filetype 37", "pllink", "playay");
186 			cfSetProfileString("filetype 37", "player", "ayPlayer");
187 		}
188 
189 		if (epoch <= 20070712)
190 		{
191 			char temp[1024];
192 			fprintf(stderr, "ocp.ini update (0.1.13/0.1.14) adds devpCA to [sound] playerdevices=....\n");
193 			snprintf(temp, sizeof(temp), "devpCA %s", cfGetProfileString("sound", "playerdevices", ""));
194 			cfSetProfileString("sound", "playerdevices", temp);
195 
196 			fprintf(stderr, "ocp.ini update (0.1.13/0.1.14) adds [devpCA]\n");
197 			cfSetProfileString("devpCA", "link", "devpcoreaudio");
198 
199 			fprintf(stderr, "ocp.ini update (0.1.14) changed [devsOSS] revstereo to off\nn");
200 			cfSetProfileBool("devsOSS", "revstereo", 0);
201 
202 			fprintf(stderr, "ocp.ini update (0.1.14) adds [filetype 38]\n");
203 			cfSetProfileInt("filetype 38", "color", 6, 10);
204 			cfSetProfileString("filetype 38", "name", "FLA");
205 			cfSetProfileString("filetype 38", "interface", "plOpenCP");
206 			cfSetProfileString("filetype 38", "pllink", "playflac");
207 			cfSetProfileString("filetype 38", "player", "flacPlayer");
208 		}
209 
210 		if (epoch <= 20081117)
211 		{
212 			fprintf(stderr, "ocp.ini update (0.1.17) removes [general] autoload=....\n");
213 			cfRemoveEntry("general", "autoload");
214 
215 			fprintf(stderr, "ocp.ini update (0.1.16/0.1.17) removes [general] link=....\n");
216 			cfRemoveEntry("general", "link");
217 			fprintf(stderr, "ocp.ini update (0.1.16/0.1.17) removes [defaultconfig] link=....\n");
218 			cfRemoveEntry("defaultconfig", "link");
219 
220 			fprintf(stderr, "ocp.ini update (0.1.16) renames [x11] framebuffer to autodetect\n");
221 			cfSetProfileBool("x11", "autodetect", cfGetProfileBool("x11", "framebuffer", 1, 1));
222 			cfRemoveEntry("x11", "framebuffer");
223 
224 			fprintf(stderr, "ocp.ini update (0.1.16) adds [x11] font=1\n");
225 			cfSetProfileInt("x11", "font", cfGetProfileInt("x11", "font", 1, 10), 10);
226 
227 			fprintf(stderr, "ocp.ini update (0.1.16) adds [x11] xvidmode=on\n");
228 			cfSetProfileBool("x11", "xvidmode", cfGetProfileBool("x11", "xvidmode", 1, 1));
229 		}
230 
231 		if (epoch <= 20090208)
232 		{
233 			fprintf(stderr, "ocp.ini update (0.1.18) removes [driver] keep=1\n");
234 			cfRemoveEntry("devpALSA", "keep");
235 		}
236 
237 		if (epoch <= 20100515)
238 		{
239 			fprintf(stderr, "ocp.ini update (0.1.19) adds [filetype 39]\n");
240 			cfSetProfileInt("filetype 39", "color", 6, 10);
241 			cfSetProfileString("filetype 39", "name", "YM");
242 			cfSetProfileString("filetype 39", "interface", "plOpenCP");
243 			cfSetProfileString("filetype 39", "pllink", "playym");
244 			cfSetProfileString("filetype 39", "player", "ymPlayer");
245 		}
246 
247 		if (epoch <= 20100515)
248 		{
249 			const char *temp;
250 			char *new_temp;
251 
252 			temp = cfGetProfileString("fileselector", "modextensions", "");
253 			new_temp = malloc (strlen (temp) + 8);
254 			strcpy (new_temp, temp);
255 
256 			if (!strstr(temp, " YM"))
257 			{
258 				fprintf(stderr, "ocp.ini update (0.1.19) adds YM to [fileselector] modextensions=....\n");
259 				strcat (new_temp, " YM");
260 			}
261 
262 			if (!strstr(temp, " OGA"))
263 			{
264 				fprintf(stderr, "ocp.ini update (0.1.19) adds OGA to [fileselector] modextensions=....\n");
265 				strcat (new_temp, " OGA");
266 			}
267 
268 			cfSetProfileString("fileselector", "modextensions", new_temp);
269 			free (new_temp);
270 		}
271 
272 		if (epoch < 20110319)
273 		{
274 			const char *list;
275 			char temp1[1024];
276 
277 			fprintf(stderr, "ocp.ini update (0.1.21) adds devpSDL\n");
278 
279 			list = cfGetProfileString("sound", "playerdevices", "");
280 
281 			if (strstr(list, "devpSDL"))
282 			{
283 				snprintf(temp1, sizeof(temp1), "%s", list);
284 			} else {
285 				int added = 0;
286 				temp1[0] = 0;
287 				while (1)
288 				{
289 					char drvhand[9];
290 					if (!cfGetSpaceListEntry(drvhand, &list, 8))
291 						break;
292 
293 					if (!strcmp (drvhand, "devpNONE"))
294 					{
295 						added = 1;
296 						if (strlen(temp1) < 1014)
297 							strcat (temp1, " devpSDL");
298 					}
299 					if (strlen(temp1) < 1014)
300 					{
301 						strcat (temp1, " ");
302 						strcat (temp1, drvhand);
303 					}
304 				}
305 
306 				if (!added)
307 				{
308 					added = 1;
309 					if (strlen(temp1) < 1014)
310 						strcat (temp1, " devpSDL");
311 				}
312 			}
313 
314 			cfSetProfileString("sound", "playerdevices", temp1);
315 
316 			cfSetProfileString("devpSDL", "link", "devpsdl");
317 		}
318 
319 		if (epoch < 20160606)
320 		{
321 			fprintf (stderr, "ocp.ini update (0.2.0), remove wavetostereo and waveratetolerance\n");
322 			cfRemoveEntry("sound", "wavetostereo");
323 			cfRemoveEntry("sound", "waveratetolerance");
324 		}
325 
326 		if (epoch < 20181129)
327 		{
328 			const char *list;
329 			char temp1[1024];
330 
331 			fprintf (stderr, "ocp.ini update (0.2.0), add SDL2 audio driver\n");
332 
333 			list = cfGetProfileString("sound", "playerdevices", "");
334 
335 			if (strstr(list, "devpSDL2"))
336 			{
337 				snprintf(temp1, sizeof(temp1), "%s", list);
338 			} else {
339 				int added = 0;
340 				temp1[0] = 0;
341 				while (1)
342 				{
343 					char drvhand[9];
344 					if (!cfGetSpaceListEntry(drvhand, &list, 8))
345 						break;
346 
347 					if (!strcmp (drvhand, "devpSDL"))
348 					{
349 						added = 1;
350 						if (strlen(temp1) < 1014)
351 							strcat (temp1, " devpSDL2");
352 					}
353 					if (strlen(temp1) < 1014)
354 					{
355 						strcat (temp1, " ");
356 						strcat (temp1, drvhand);
357 					}
358 				}
359 
360 				if (!added)
361 				{
362 					added = 1;
363 					if (strlen(temp1) < 1014)
364 						strcat (temp1, " devpSDL2");
365 				}
366 			}
367 
368 			cfSetProfileString("sound", "playerdevices", temp1);
369 
370 			cfSetProfileString("devpSDL2", "link", "devpsdl2");
371 		}
372 
373 		if (epoch < 20190801)
374 		{
375 			fprintf (stderr, "ocp.ini update (0.2.0) replaces playgmi with playtimidity for playback of MIDI files\n");
376 
377 			if (!strcmp (cfGetProfileString ("filetype 16", "pllink", "playgmi"), "playgmi"))
378 			{
379 				cfSetProfileString ("filetype 16", "pllink", "playtimidity");
380 				cfSetProfileString ("filetype 16", "player", "timidityPlayer");
381 			}
382 			if (!strcmp (cfGetProfileString ("filetype 18", "pllink", "playgmi"), "playgmi"))
383 			{
384 				cfSetProfileString ("filetype 18", "pllink", "playtimidity");
385 				cfSetProfileString ("filetype 18", "player", "timidityPlayer");
386 			}
387 		}
388 
389 		if (epoch < 20190815)
390 		{
391 			fprintf(stderr, "ocp.ini update (0.2.0) adds [filetype 40]\n");
392 			cfSetProfileInt("filetype 40", "color", 6, 10);
393 			cfSetProfileString("filetype 40", "name", "STM");
394 			cfSetProfileString("filetype 40", "interface", "plOpenCP");
395 			cfSetProfileString("filetype 40", "pllink", "playgmd");
396 			cfSetProfileString("filetype 40", "player", "gmdPlayer");
397 			cfSetProfileString("filetype 40", "ldlink", "loadstm");
398 			cfSetProfileString("filetype 40", "loader", "mpLoadSTM");
399 		}
400 
401 		if (epoch < 20190815)
402 		{
403 			const char *temp;
404 			char *new_temp;
405 
406 			temp = cfGetProfileString("fileselector", "modextensions", "");
407 			new_temp = malloc (strlen (temp) + 5);
408 			strcpy (new_temp, temp);
409 
410 			if (!strstr(temp, " STM"))
411 			{
412 				fprintf(stderr, "ocp.ini update (0.2.0) adds STM to [fileselector] modextensions=....\n");
413 				strcat (new_temp, " STM");
414 			}
415 
416 			cfSetProfileString("fileselector", "modextensions", new_temp);
417 			free (new_temp);
418 		}
419 
420 		if (epoch < 20190927)
421 		{
422 			fprintf(stderr, "ocp.ini update (0.2.0) adds [filetype 41]\n");
423 			cfSetProfileInt("filetype 41", "color", 3, 10);
424 			cfSetProfileString("filetype 41", "name", "HVL");
425 			cfSetProfileString("filetype 41", "interface", "plOpenCP");
426 			cfSetProfileString("filetype 41", "pllink", "playhvl");
427 			cfSetProfileString("filetype 41", "player", "hvlPlayer");
428 		}
429 
430 		if (epoch < 20190927)
431 		{
432 			const char *temp;
433 			char *new_temp;
434 
435 			temp = cfGetProfileString("fileselector", "modextensions", "");
436 			new_temp = malloc (strlen (temp) + 9);
437 			strcpy (new_temp, temp);
438 
439 			if (!strstr(temp, " HVL"))
440 			{
441 				fprintf(stderr, "ocp.ini update (0.2.0) adds HVL to [fileselector] modextensions=....\n");
442 				strcat (new_temp, " HVL");
443 			}
444 
445 			if (!strstr(temp, " AHX"))
446 			{
447 				fprintf(stderr, "ocp.ini update (0.2.0) adds AHX to [fileselector] modextensions=....\n");
448 				strcat (new_temp, " AHX");
449 			}
450 
451 
452 			cfSetProfileString("fileselector", "modextensions", new_temp);
453 			free (new_temp);
454 		}
455 
456 		if (epoch < 20191019)
457 		{
458 			const char *temp;
459 			char *new_temp, *temp2;
460 
461 			temp = cfGetProfileString("fileselector", "modextensions", "");
462 			new_temp = strdup (temp);
463 
464 			temp2 = strstr (new_temp, " OGA");
465 			if (temp2)
466 			{
467 				temp2 = strstr(temp2, " OGA");
468 				printf("ocp.ini update (0.2.0) removed double OGA entry in [fileselector] modextensions=....\n");
469 				memmove (temp2, temp2 + 4, strlen (temp2) - 3);
470 			}
471 
472 			temp2 = strstr (new_temp, " OGG");
473 			if (temp2)
474 			{
475 				temp2 = strstr(temp2, " OGG");
476 				printf("ocp.ini update (0.2.0) removed double OGG entry in [fileselector] modextensions=....\n");
477 				memmove (temp2, temp2 + 4, strlen (temp2) - 3);
478 			}
479 
480 			cfSetProfileString("fileselector", "modextensions", new_temp);
481 			free (new_temp);
482 		}
483 
484 		if (epoch < 20191101)
485 		{
486 			printf("ocp.ini update (0.2.0) renamed filetype FLA to FLAC\n");
487 			cfSetProfileString("filetype 38", "name", "FLAC");
488 		}
489 
490 		if (epoch < 20191111)
491 		{
492 			printf("ocp.ini update (0.2.0) changed default value of [screen] insttype=2\n");
493 			cfSetProfileString("screen", "insttype", "2");
494 			printf("ocp.ini update (0.2.0) changed default value of [screen] channeltype=2\n");
495 			cfSetProfileString("screen", "channeltype", "2");
496 		}
497 
498 		if (epoch < 20200225)
499 		{
500 			printf("ocp.ini update (0.2.90) added [libsidplayfp] section\n");
501 			cfSetProfileString("libsidplayfp", "emulator", "residfp");
502 			cfSetProfileString("libsidplayfp", "defaultC64", "PAL");
503 			cfSetProfileBool("libsidplayfp", "forceC64", 0);
504 			cfSetProfileString("libsidplayfp", "defaultSID", "MOS6581");
505 			cfSetProfileBool("libsidplayfp", "forceSID", 0);
506 			cfSetProfileString("libsidplayfp", "CIA", "MOS6526");
507 			cfSetProfileBool("libsidplayfp", "filter", 1);
508 			cfSetProfileString("libsidplayfp", "filterbias", "0.0");
509 			cfSetProfileString("libsidplayfp", "filtercurve6581", "0.5");
510 			cfSetProfileString("libsidplayfp", "filtercurve8580", "0.5");
511 			cfSetProfileBool("libsidplayfp", "digiboost", 0);
512 			cfSetProfileString("libsidplayfp", "kernal", "KERNAL.ROM");
513 			cfSetProfileString("libsidplayfp", "basic", "BASIC.ROM");
514 			cfSetProfileString("libsidplayfp", "chargen", "CHARGEN.ROM");
515 		}
516 
517 		if (epoch < 20210118)
518 		{
519 			char *temp;
520 			printf("ocp.ini update (0.2.90) moved PLS and M3U from files to virtual directories\n");
521 			cfRemoveProfile("filetype 128");
522 			cfRemoveProfile("filetype 129");
523 
524 			temp = (char *)cfGetProfileString("fileselector", "modextensions", "");
525 			if (temp)
526 			{
527 				char *ptr;
528 				temp = strdup (temp);
529 				while ((ptr = strstr (temp, "PLS")))
530 				{
531 					memmove (ptr, ptr + 3, strlen (ptr) - 3 + 1);
532 				}
533 				while ((ptr = strstr (temp, "M3U")))
534 				{
535 					memmove (ptr, ptr + 3, strlen (ptr) - 3 + 1);
536 				}
537 				while ((ptr = strstr (temp, "  ")))
538 				{
539 					memmove (ptr, ptr + 2, strlen (ptr) - 2 + 1);
540 				}
541 				cfSetProfileString("fileselector", "modextensions", temp);
542 				free (temp); temp = 0;
543 			}
544 		}
545 
546 		if (epoch < 20210118)
547 		{
548 			printf("ocp.ini update (0.2.90) removed obsolete arcZIP and friends\n");
549 			cfRemoveProfile("arcZIP");
550 			cfRemoveProfile("arcARJ");
551 			cfRemoveProfile("arcARJ");
552 			cfRemoveProfile("arcRAR");
553 			cfRemoveProfile("arcLHA");
554 			cfRemoveProfile("arcACE");
555 		}
556 
557 		if (epoch < 20210118)
558 		{
559 			printf("ocp.ini update (0.2.90) DEVv VirtualInterface replaced DEVs DEVp and DEVw\n");
560 			cfRemoveProfile("filetype 24");
561 			cfRemoveProfile("filetype 25");
562 			cfRemoveProfile("filetype 26");
563 
564 			cfSetProfileInt ("filetype 254", "color", 6, 10);
565 			cfSetProfileString ("filetype 254", "name", "DEVv");
566 			cfSetProfileString ("filetype 254", "interface", "VirtualInterface");
567 		}
568 
569 		if (epoch < 20210118)
570 		{
571 			cfSetProfileInt("version", "epoch", 20210118, 10);
572 			cfStoreConfig();
573 			if (isatty(2))
574 			{
575 				fprintf(stderr,"\n\033[1m\033[31mWARNING, ocp.ini has changed, have tried my best to update it. If OCP failes to start, please try to remove by doing this:\033[0m\nrm -f ~/.ocp/ocp.ini\n\n");
576 			} else {
577 				fprintf(stderr,"\nWARNING, ocp.ini has changed, have tried my best to update it. If OCP failes to start, please try to remove by doing this:\nrm -f ~/.ocp/ocp.ini\n\n");
578 			}
579 			sleep(5);
580 		}
581 	}
582 	if (cfGetProfileInt("version", "epoch", 0, 10) != 20210118)
583 	{
584 		if (isatty(2))
585 		{
586 			fprintf(stderr,"\n\033[1m\033[31mWARNING, ocp.ini [version] epoch != 20210118\033[0m\n\n");
587 		} else {
588 			fprintf(stderr,"\nWARNING, ocp.ini [version] epoch != 20210118\n\n");
589 		}
590 		sleep(5);
591 	}
592 
593 	cfScreenSec=cfGetProfileString(cfConfigSec, "screensec", "screen");
594 	cfSoundSec=cfGetProfileString(cfConfigSec, "soundsec", "sound");
595 
596 	lnkLink(cfGetProfileString2(cfConfigSec, "defaultconfig", "prelink", ""));
597 	lnkLink(cfGetProfileString("general", "prelink", ""));
598 
599 	{
600 		char *buffer;
601 		buffer = malloc (strlen (cfProgramDir) + 9 + 1);
602 		sprintf(buffer, "%sautoload/", cfProgramDir);
603 		if (lnkLinkDir(buffer)<0)
604 		{
605 			fprintf(stderr, "could not autoload directory: %s\n", buffer);
606 			free (buffer);
607 			return -1;
608 		}
609 		free (buffer);
610 	}
611 
612 	if (lnkLink(cfGetProfileString("general", "link", ""))<0)
613 	{
614 		fprintf(stderr, "could not link default objects!\n");
615 		return -1;
616 	}
617 
618 	if ((lnkLink(cfGetProfileString2(cfConfigSec, "defaultconfig", "link", ""))<0))
619 	{
620 		fprintf(stderr, "could not link default objects!\n");
621 		return -1;
622 	}
623 
624 	fprintf(stderr, "running initializers...\n");
625 
626 	for (i=0;i<loadlist_n;i++)
627 		if (loadlist[i].info->PreInit)
628 			if (loadlist[i].info->PreInit()<0)
629 				return errGen;
630 
631 	for (i=0;i<loadlist_n;i++)
632 		if (loadlist[i].info->Init)
633 			if (loadlist[i].info->Init()<0)
634 				return errGen;
635 
636 	for (i=0;i<loadlist_n;i++)
637 		if (loadlist[i].info->LateInit)
638 			if (loadlist[i].info->LateInit()<0)
639 				return errGen;
640 
641 	if (!ocpmain)
642 	{
643 		fprintf(stderr, "ERROR - No main specified in libraries\n");
644 		return errGen;
645 	}
646 	if (ocpmain->main(argc, argv)<0)
647 		return errGen;
648 
649 	plSetTextMode(255);
650 
651 	return 0;
652 }
653 
654 void done_modules(void)
655 {
656 	plCloseAll();
657 	lnkFree(0);
658 }
659 
660 #ifdef GCC_411_RUNTIMECHECK
661 int failcheck(signed int source, signed int filter)
662 {
663 	if ((source>128)&&(filter>0))
664 		return 1;
665 	return 0;
666 }
667 #endif
668 
669 static int _bootup(int argc, char *argv[], const char *ConfigDir, const char *DataDir, const char *ProgramDir)
670 {
671 	int result;
672 	if (isatty(2))
673 	{
674 		fprintf(stderr, "\033[33m\033[1mOpen Cubic Player for Unix \033[32mv" VERSION "\033[33m, compiled on %s, %s\n", compiledate, compiletime);
675 		fprintf(stderr, "\033[31m\033[22mPorted to \033[1m\033[32mUnix \033[31m\033[22mby \033[1mStian Skjelstad\033[0m\n");
676 	} else {
677 		fprintf(stderr, "Open Cubic Player for Unix v" VERSION ", compiled on %s, %s\n", compiledate, compiletime);
678 		fprintf(stderr, "Ported to Unix by Stian Skjelstad\n");
679 	}
680 
681 #ifdef GCC_411_RUNTIMECHECK
682 	fprintf(stderr, "Checking for gcc known 4.1.1 fault - ");
683 	{
684 		int j;
685 		for (j=0;j<256;j++)
686 		{
687 			signed char j2=(signed char)j;
688 			signed int j3=j2;
689 			if (failcheck(j, j3))
690 			{
691 				fprintf(stderr, "failed\nTry to remove any -O flag or to add -fwrapv to CFLAGS and CXXFLAGS and recompile\n");
692 				return 0;
693 			}
694 		}
695 	}
696 	fprintf(stderr, "pass\n");
697 #endif
698 
699 	cfConfigDir = (char *)ConfigDir;
700 	cfDataDir = strdup (DataDir);
701 	cfProgramDir = (char *)ProgramDir;
702 
703 	if (cfGetConfig(argc, argv))
704 	{
705 		cfConfigDir = 0;
706 		free (cfDataDir); cfDataDir = 0;
707 		cfProgramDir = 0;
708 		free (cfTempDir); cfTempDir = 0;
709 		return -1;
710 	}
711 
712 	result=init_modules(argc, argv);
713 	if (result)
714 		if (result!=errHelpPrinted)
715 			fprintf(stderr, "%s\n", errGetLongString(result));
716 
717 	done_modules();
718 
719 	cfCloseConfig();
720 
721 	cfConfigDir = 0;
722 	free (cfDataDir); cfDataDir = 0;
723 	cfProgramDir = 0;
724 	free (cfTempDir); cfTempDir = 0;
725 
726 	return 0;
727 }
728 
729 struct bootupstruct bootup = { _bootup };
730