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  * Main routine, calls fileselector and interface code
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
25  *    -complete restructuring of fsMain_ etc. to enable non-playable
26  *     file types which are handled differently
27  *    -therefore, added "handler" line in CP.INI filetype entries
28  *    -added routines to read out PLS and M3U play lists
29  *    -as always, added dllinfo record ;)
30  *  -fd981014   Felix Domke <tmbinc@gmx.net>
31  *    -small bugfix (tf was closed, even if it was NULL)
32  *  -ss040918   Stian Skjelstad <stian@nixia.no>
33  *    -minor tweak.. Do not touch any screen functions after conRestore and
34  *     before conSave
35  */
36 
37 #define NO_PFILESEL_IMPORT
38 #include "config.h"
39 #include <assert.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include "types.h"
44 
45 #include "boot/plinkman.h"
46 #include "boot/pmain.h"
47 #include "boot/psetting.h"
48 #include "dirdb.h"
49 #include "filesystem.h"
50 #include "mdb.h"
51 #include "pfilesel.h"
52 #include "stuff/err.h"
53 #include "stuff/poutput.h"
54 
55 extern struct mdbreadinforegstruct fsReadInfoReg;
56 
57 static struct moduleinfostruct nextinfo;
58 static struct moduleinfostruct plModuleInfo;
59 
60 typedef enum
61 {
62 	DoNotForceCallFS = 0,
63 	DoForceCallFS = 1
64 } enumForceCallFS;
65 
66 typedef enum
67 {
68 	DoNotAutoCallFS = 0,
69 	DoAutoCallFS = 1
70 } enumAutoCallFS;
71 
72 typedef enum
73 {
74 	DoNotForceNext=0,
75 	DoForceNext=1,
76 	DoForcePrev=2
77 } enumForceNext;
78 
79 static enumAutoCallFS callfs;
80 static char firstfile;
81 
82 static interfaceReturnEnum stop;
83 
84 /* stop: 0 cont
85  *       1 next song
86  *       6 prev song
87  *       2 quit
88  *       3 iface : next song or fs
89  *       4 iface : call fs
90  *       5 iface : dosshell
91  */
92 
93 
94 
95 /* return values:
96  * 0  - no files available (and user hit esc)
97  * 1  - we have a new song availble
98  * -1 - error occured
99  */
100 
callselector(struct moduleinfostruct * info,struct ocpfilehandle_t ** fi,enumAutoCallFS callfs,enumForceCallFS forcecall,enumForceNext forcenext,struct interfacestruct ** iface)101 static int callselector (struct moduleinfostruct *info,
102                          struct ocpfilehandle_t **fi,
103                          enumAutoCallFS callfs,
104                          enumForceCallFS forcecall,
105                          enumForceNext forcenext,
106                          struct interfacestruct **iface)
107 {
108 	int ret;
109 	int result;
110 	struct interfacestruct *intr;
111 	struct moduleinfostruct tmodinfo;
112 	char secname[20];
113 
114 	if (*fi)
115 	{
116 		(*fi)->unref (*fi);
117 		*fi = 0;
118 	}
119 	*iface=0;
120 
121 	do
122 	{
123 		ret=result=0;
124 		if ((callfs && !fsFilesLeft())||forcecall)
125 			ret=result=fsFileSelect();
126 
127 		if (!fsFilesLeft())
128 			return 0;
129 
130 		while (ret || forcenext)
131 		{
132 			conRestore();
133 
134 			if (!fsFilesLeft())
135 			{
136 				conSave();
137 				break;
138 			}
139 			if (forcenext==2)
140 			{
141 				if (!fsGetPrevFile(&tmodinfo, fi))
142 				{
143 					assert ((*fi)==NULL);
144 					conSave();
145 					continue;
146 				}
147 			} else {
148 				if (!fsGetNextFile(&tmodinfo, fi))
149 				{
150 					assert ((*fi)==NULL);
151 					conSave();
152 					continue;
153 				}
154 			}
155 
156 			sprintf(secname, "filetype %d", tmodinfo.modtype&0xFF);
157 			intr=plFindInterface(cfGetProfileString(secname, "interface", ""));
158 #if 0
159 			hdlr=(struct filehandlerstruct *)_lnkGetSymbol(cfGetProfileString(secname, "handler", ""));
160 			if (hdlr)
161 			{
162 				hdlr->Process(*dirdbref, &tmodinfo, &tf);
163 			}
164 #endif
165 
166 			conSave();
167 			{
168 				unsigned int i;
169 				for (i=0;i<plScrHeight;i++)
170 					displayvoid(i, 0, plScrWidth);
171 			}
172 
173 			if (intr)
174 			{
175 				ret=0;
176 				*iface = intr;
177 				*info = tmodinfo;
178 
179 				return result?-1:1;
180 			} else {
181 				/* we failed to get an interface for this file */
182 				if (*fi)
183 				{
184 					fsForceRemove ((*fi)->dirdb_ref);
185 					(*fi)->unref (*fi);
186 					*fi = 0;
187 				}
188 			}
189 		}
190 		if (ret)
191 			conSave();
192 	} while (ret);
193 
194 	return 0;
195 }
196 
_fsMain(int argc,char * argv[])197 static int _fsMain(int argc, char *argv[])
198 {
199 	struct interfacestruct *plintr = 0;
200 	struct interfacestruct *nextintr = 0;
201 	struct ocpfilehandle_t *thisf=NULL;
202 	struct ocpfilehandle_t *nextf=NULL;
203 
204 	conSave();
205 
206 	callfs=DoNotAutoCallFS;
207 	stop=interfaceReturnContinue;
208 	firstfile=1;
209 
210 #ifdef DOS32
211   /* TODO.. this can be done on xterm consoles, and proc titles*/
212 	setwintitle("OpenCP");
213 #endif
214 
215 	fsRescanDir();
216 
217 	while (1)
218 	{
219 		struct preprocregstruct *prep;
220 
221 /*
222 		while (ekbhit())
223 		{
224 			uint16_t key=egetch();
225 			if ((key==0)||(key==3)||(key==27))
226 				stop=interfaceReturnQuit;
227 		}*/
228 		if (stop==interfaceReturnQuit)
229 			break;
230 
231 		if (!plintr)
232 		{
233 			int fsr;
234 			conSave();
235 			fsr=callselector (&nextinfo, &nextf, (callfs||firstfile), (stop==interfaceReturnCallFs)?DoForceCallFS:DoNotForceCallFS, DoForceNext, &nextintr);
236 			if (!fsr)
237 			{
238 				break;
239 			} else if (fsr==-1)
240 			{
241 				callfs=DoAutoCallFS;
242 			}
243 			conRestore();
244 		}
245 		stop=interfaceReturnContinue;
246 
247 		if (callfs)
248 			firstfile=0;
249 
250 		if (nextintr)
251 		{
252 			conRestore();
253 
254 			if (plintr)
255 			{
256 				plintr->Close();
257 				plintr=0;
258 				/* _heapshrink(); */
259 			}
260 
261 			if (thisf)
262 			{
263 				thisf->unref (thisf);
264 				thisf=NULL;
265 			}
266 
267 			thisf = nextf;
268 			nextf = 0;
269 			plModuleInfo=nextinfo;
270 			plintr=nextintr;
271 			nextintr=0;
272 
273 			stop=interfaceReturnContinue;
274 
275 			for (prep=plPreprocess; prep; prep=prep->next)
276 			{
277 				prep->Preprocess(&plModuleInfo, &thisf);
278 			}
279 
280 			if (!plintr->Init(&plModuleInfo, thisf))
281 			{
282 				stop = interfaceReturnCallFs; /* file failed, exit to filebrowser, if we don't do this, we can end up with a freeze if we only have this invalid file in the playlist, optional we could remove the file... */
283 				plintr=0;
284 			} else {
285 				/*
286 				char wt[256];
287 				char realname[13];
288 				memset(wt,0,256);
289 				fsConv12FileName(realname,plModuleInfo.name);
290 				strncpy(wt,realname,12);
291 				strcat(wt," - ");
292 				strncat(wt,plModuleInfo.modname,32);
293 			#ifdef DOS32
294 				setwintitle(wt);
295 			#endif
296 				*/
297 			}
298 			conSave();
299 		}
300 
301 		if (plintr)
302 		{
303 			while (!stop) /* != interfaceReturnContinue */
304 			{
305 				stop=plintr->Run();
306 				switch (stop)
307 				{
308 					case interfaceReturnContinue: /* 0 */
309 					case interfaceReturnQuit:
310 						break;
311 					case interfaceReturnNextAuto: /* next playlist file (auto) */
312 						if (callselector (&nextinfo, &nextf, DoAutoCallFS, DoNotForceCallFS, DoNotForceNext, &nextintr)==0)
313 						{
314 							if (fsFilesLeft())
315 							{
316 								callselector (&nextinfo, &nextf, DoNotAutoCallFS, DoNotForceCallFS, DoForceNext, &nextintr);
317 								stop = interfaceReturnNextAuto;
318 							} else
319 								stop = interfaceReturnQuit;
320 						} else
321 							stop = interfaceReturnNextAuto;
322 						break;
323 					case interfaceReturnPrevManuel: /* prev playlist file (man) */
324 						if (fsFilesLeft())
325 							stop=callselector (&nextinfo, &nextf, DoNotAutoCallFS, DoNotForceCallFS, DoForcePrev, &nextintr)?interfaceReturnNextAuto:interfaceReturnContinue;
326 						else
327 							stop=callselector (&nextinfo, &nextf, DoAutoCallFS, DoNotForceCallFS, DoNotForceNext, &nextintr)?interfaceReturnNextAuto:interfaceReturnContinue;
328 						break;
329 					case interfaceReturnNextManuel: /* next playlist file (man) */
330 						if (fsFilesLeft())
331 							stop=callselector (&nextinfo, &nextf, DoNotAutoCallFS, DoNotForceCallFS, DoForceNext, &nextintr)?interfaceReturnNextAuto:interfaceReturnContinue;
332 						else
333 							stop=callselector (&nextinfo, &nextf, DoAutoCallFS, DoNotForceCallFS, DoNotForceNext, &nextintr)?interfaceReturnNextAuto:interfaceReturnContinue;
334 						break;
335 					case interfaceReturnCallFs: /* call fs */
336 						stop=callselector (&nextinfo, &nextf, DoAutoCallFS, DoForceCallFS, DoNotForceNext, &nextintr)?interfaceReturnNextAuto:interfaceReturnContinue;
337 						break;
338 					case interfaceReturnDosShell: /* dos shell */
339 						plSetTextMode(fsScrType);
340 						if (conRestore())
341 							break;
342 						stop=interfaceReturnContinue;
343 						plDosShell();
344 						conSave();
345 /*
346 						while (ekbhit())
347 							egetch();*/
348 						break;
349 				}
350 			}
351 			firstfile=0;
352 		}
353 	}
354 
355 	plSetTextMode(fsScrType);
356 	conRestore();
357 	if (plintr)
358 		plintr->Close();
359 	if (thisf)
360 	{
361 		thisf->unref (thisf);
362 		thisf = NULL;
363 	}
364 
365 	return errOk;
366 }
367 
fspreint(void)368 static int fspreint(void)
369 {
370 	mdbRegisterReadInfo(&fsReadInfoReg);
371 
372 	fprintf(stderr, "initializing fileselector...\n");
373 	if (!fsPreInit())
374 	{
375 		fprintf(stderr, "fileselector pre-init failed!\n");
376 		return errGen;
377 	}
378 
379 	return errOk;
380 }
381 
fsint(void)382 static int fsint(void)
383 {
384 	if (!fsInit())
385 	{
386 		fprintf(stderr, "fileselector init failed!\n");
387 		return errGen;
388 	}
389 
390 	return errOk;
391 }
392 
fslateint(void)393 static int fslateint(void)
394 {
395 	if (!fsLateInit())
396 	{
397 		fprintf(stderr, "fileselector post-init failed!\n");
398 		return errGen;
399 	}
400 
401 	return errOk;
402 }
403 
fsclose()404 static void fsclose()
405 {
406 	mdbUnregisterReadInfo(&fsReadInfoReg);
407 
408 	fsClose();
409 }
410 
411 static struct mainstruct fsmain = { _fsMain };
412 
init(void)413 static void __attribute__((constructor))init(void)
414 {
415 	if (ocpmain)
416 		fprintf(stderr, "pfsmain.c: ocpmain != NULL\n");
417 	else
418 		ocpmain = &fsmain;
419 }
420 
done(void)421 static void __attribute__((destructor))done(void)
422 {
423 	if (ocpmain!=&fsmain)
424 		ocpmain = 0;
425 }
426 
427 #ifndef SUPPORT_STATIC_PLUGINS
428 char *dllinfo = "";
429 #endif
430 
431 DLLEXTINFO_PREFIX struct linkinfostruct dllextinfo = {.name = "pfilesel", .desc = "OpenCP Fileselector (c) 1994-'21 Niklas Beisert, Tammo Hinrichs, Stian Skjelstad", .ver = DLLVERSION, .size = 0, .PreInit = fspreint, .Init = fsint, .LateInit = fslateint, .LateClose = fsclose};
432