1 /*
2 * TTTTTTTTTTTTTT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
3 * TTTTTTTTTTTTTT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
4 * TT EE OO OO
5 * TT EE OO OO
6 * TT EE OO OO
7 * TT EEEEEEEEEE OO OO
8 * TT EEEEEEEEEE OO OO
9 * TT EE OO OO
10 * TT EE OO OO
11 * TT EE OO OO
12 * TT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
13 * TT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
14 *
15 * L'�mulateur Thomson TO8
16 *
17 * Copyright (C) 1997-2017 Gilles F�tis, Eric Botcazou, Alexandre Pukall,
18 * J�r�mie Guillaume, Fran�ois Mouret
19 * Samuel Devulder
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 */
35
36 /*
37 * Module : linux/main.c
38 * Version : 1.8.4
39 * Cr�� par : Eric Botcazou octobre 1999
40 * Modifi� par: Eric Botcazou 19/11/2006
41 * Fran�ois Mouret 26/01/2010 08/2011 23/03/2012
42 * 09/06/2012 19/10/2012 19/09/2013
43 * 13/04/2014 31/07/2016
44 * Samuel Devulder 07/2011
45 * Gilles F�tis 07/2011
46 *
47 * Boucle principale de l'�mulateur.
48 */
49
50
51 #ifndef SCAN_DEPEND
52 #include <locale.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <signal.h>
57 #include <unistd.h>
58 #include <sys/time.h>
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <gtk/gtk.h>
62 #include <X11/Xlib.h>
63 #include <X11/Xresource.h>
64 #include <X11/Xutil.h>
65 #endif
66
67 #include "defs.h"
68 #include "teo.h"
69 #include "option.h"
70 #include "image.h"
71 #include "errors.h"
72 #include "main.h"
73 #include "std.h"
74 #include "ini.h"
75 #include "media/disk.h"
76 #include "media/cass.h"
77 #include "media/memo.h"
78 #include "media/printer.h"
79 #include "linux/floppy.h"
80 #include "linux/display.h"
81 #include "linux/graphic.h"
82 #include "linux/sound.h"
83 #include "linux/gui.h"
84
85
86 struct EMUTEO teo;
87
88 static int idle_data = 0;
89 static GTimer *timer;
90
91 static gboolean reset = FALSE;
92 static gchar *cass_name = NULL;
93 static gchar *memo_name = NULL;
94 static gchar *disk_name[4] = { NULL, NULL, NULL, NULL };
95 static gchar **remain_name = NULL;
96
97
98 /* RunTO8:
99 * Boucle principale de l'�mulateur.
100 */
RunTO8(gpointer user_data)101 static gboolean RunTO8 (gpointer user_data)
102 {
103 static gulong microseconds;
104
105 if ((teo.setting.exact_speed)
106 && (teo.setting.sound_enabled == 0)
107 && (g_timer_elapsed (timer, µseconds) < 0.02))
108 return TRUE;
109
110 g_timer_start (timer);
111
112 if (teo_DoFrame() == 0)
113 teo.command=TEO_COMMAND_BREAKPOINT;
114
115 if ((teo.command == TEO_COMMAND_BREAKPOINT)
116 || (teo.command == TEO_COMMAND_DEBUGGER)) {
117 udebug_Panel();
118 if (teo_DebugBreakPoint == NULL)
119 teo_FlushFrame();
120 }
121
122 if (teo.command == TEO_COMMAND_PANEL)
123 ugui_Panel();
124
125 if (teo.command == TEO_COMMAND_RESET)
126 teo_Reset();
127
128 if (teo.command == TEO_COMMAND_COLD_RESET)
129 teo_ColdReset();
130
131 if (teo.command == TEO_COMMAND_FULL_RESET)
132 teo_FullReset();
133
134 if (teo.command == TEO_COMMAND_QUIT)
135 {
136 mc6809_FlushExec();
137 gtk_main_quit ();
138 return FALSE;
139 }
140
141 teo.command = TEO_COMMAND_NONE;
142
143 ugraphic_Refresh ();
144 if ((teo.setting.exact_speed)
145 && (teo.setting.sound_enabled))
146 usound_Play ();
147
148 disk_WriteTimeout();
149
150 return TRUE;
151 (void)user_data;
152 }
153
154
155
156 /* ReadCommandLine:
157 * Lit la ligne de commande
158 */
ReadCommandLine(int argc,char * argv[])159 static void ReadCommandLine(int argc, char *argv[])
160 {
161 int i;
162 GError *error = NULL;
163 GOptionContext *context;
164 GOptionEntry entries[] = {
165 { "reset", 'r', 0, G_OPTION_ARG_NONE, &reset,
166 is_fr?"Reset à froid de l'émulateur"
167 :"Cold-reset emulator", NULL },
168 { "disk0", '0', 0, G_OPTION_ARG_FILENAME, &disk_name[0],
169 is_fr?"Charge un disque virtuel (lecteur 0)"
170 :"Load virtual disk (drive 0)", is_fr?"FICHIER":"FILE" },
171 { "disk1", '1', 0, G_OPTION_ARG_FILENAME, &disk_name[1],
172 is_fr?"Charge un disque virtuel (lecteur 1)"
173 :"Load virtual disk (drive 1)", is_fr?"FICHIER":"FILE" },
174 { "disk2", '2', 0, G_OPTION_ARG_FILENAME, &disk_name[2],
175 is_fr?"Charge un disque virtuel (lecteur 2)"
176 :"Load virtual disk (drive 2)", is_fr?"FICHIER":"FILE" },
177 { "disk3", '3', 0, G_OPTION_ARG_FILENAME, &disk_name[3],
178 is_fr?"Charge un disque virtuel (lecteur 3)"
179 :"Load virtual disk (drive 3)", is_fr?"FICHIER":"FILE" },
180 { "cass", 0, 0, G_OPTION_ARG_FILENAME, &cass_name,
181 is_fr?"Charge une cassette":"Load a tape", is_fr?"FICHIER":"FILE" },
182 { "memo", 0, 0, G_OPTION_ARG_FILENAME, &memo_name,
183 is_fr?"Charge une cartouche":"Load a cartridge",
184 is_fr?"FICHIER":"FILE" },
185 { G_OPTION_REMAINING, 0, G_OPTION_FLAG_IN_MAIN,
186 G_OPTION_ARG_FILENAME_ARRAY, &remain_name, "", NULL },
187 { NULL, 0, 0, 0, NULL, NULL, NULL }
188 };
189
190 /* Lit la ligne de commande */
191 context = g_option_context_new (is_fr?"[FICHIER...]"
192 :"[FILE...]");
193 g_option_context_add_main_entries (context, entries, NULL);
194 g_option_context_set_ignore_unknown_options (context, FALSE);
195 g_option_context_set_description (context, is_fr
196 ?"Options non définies :\n Charge cassette, disquette et cartouche\n"
197 :"Undefined options :\n load tape, disk and cartridge\n");
198 if (g_option_context_parse (context, &argc, &argv, &error) == FALSE)
199 main_ExitMessage (error->message);
200
201 /* Transfert des cha�nes dans la structure g�n�rale */
202 /* Oblig� de faire comme �a : les cha�nes de la structure
203 g�n�rale peuvent avoir �t� initialis�es par la lecture
204 du fichier de configuration, et malheureusement
205 g_option_context_parse() ne lib�re pas la m�moire avant
206 de l'allouer pour une nouvelle cha�ne */
207 for (i=0;i<NBDRIVE;i++) {
208 if (disk_name[i] != NULL) {
209 teo.disk[i].file = std_free (teo.disk[i].file);
210 teo.disk[i].file = std_strdup_printf ("%s", disk_name[i]);
211 g_free (disk_name[i]);
212 }
213 }
214 if (cass_name != NULL) {
215 teo.cass.file = std_free (teo.cass.file);
216 teo.cass.file = std_strdup_printf ("%s", cass_name);
217 g_free (cass_name);
218 }
219 if (memo_name != NULL) {
220 teo.memo.file = std_free (teo.memo.file);
221 teo.memo.file = std_strdup_printf ("%s", memo_name);
222 g_free (memo_name);
223 }
224 g_option_context_free(context);
225 }
226
227
228
229 #ifdef DEBIAN_BUILD
copy_debian_file(const char filename[])230 static void copy_debian_file (const char filename[])
231 {
232 char *src_name = NULL;
233 char *dst_name = NULL;
234 FILE *src_file = NULL;
235 FILE *dst_file = NULL;
236 int c;
237
238 src_name = std_strdup_printf ("/usr/share/teo/%s", filename);
239 dst_name = std_ApplicationPath (APPLICATION_DIR, filename);
240 if ((src_name != NULL) && (*src_name != '\0')
241 && (dst_name != NULL) && (*dst_name != '\0')
242 && (access (dst_name, F_OK) < 0))
243 {
244 src_file = fopen (src_name, "rb");
245 dst_file = fopen (dst_name, "wb");
246
247 while ((src_file != NULL)
248 && (dst_file != NULL)
249 && ((c = fgetc(src_file)) != EOF))
250 {
251 fputc (c, dst_file);
252 }
253
254 src_file = std_fclose (src_file);
255 dst_file = std_fclose (dst_file);
256 }
257 src_name = std_free (src_name);
258 dst_name = std_free (dst_name);
259 }
260 #endif
261
262
263 /* ------------------------------------------------------------------------- */
264
265
266 /* DisplayMessage:
267 * Affiche un message.
268 */
main_DisplayMessage(const char msg[])269 void main_DisplayMessage(const char msg[])
270 {
271 fprintf(stderr, "%s\n", msg);
272 ugui_Error (msg, wMain);
273 }
274
275
276
277 /* ExitMessage:
278 * Affiche un message de sortie et sort du programme.
279 */
main_ExitMessage(const char msg[])280 void main_ExitMessage(const char msg[])
281 {
282 main_DisplayMessage(msg);
283 exit(EXIT_FAILURE);
284 }
285
286
287 #define IS_3_INCHES(drive) ((drive_type[drive]>2) && (drive_type[drive]<7))
288
289
290 /* main:
291 * Point d'entr�e du programme appel� par Linux.
292 */
main(int argc,char * argv[])293 int main(int argc, char *argv[])
294 {
295 int i;
296 int direct_write_support = TRUE;
297 int drive_type[4];
298 char *lang;
299
300 /* Rep�rage du language utilis� */
301 lang=getenv("LANG");
302 if (lang==NULL) lang="fr_FR";
303 setlocale(LC_ALL, "");
304 is_fr = (strncmp(lang,"fr",2)==0) ? -1 : 0;
305
306 gtk_init (&argc, &argv); /* Initialisation gtk */
307 ini_Load(); /* Charge les param�tres par d�faut */
308 ReadCommandLine(argc, argv); /* R�cup�ration des options */
309
310 #ifdef DEBIAN_BUILD
311 copy_debian_file ("empty.hfe");
312 #endif
313
314 /* Affichage du message de bienvenue du programme */
315 printf((is_fr?"Voici %s l'émulateur Thomson TO8.\n"
316 :"Here's %s the thomson TO8 emulator.\n"),
317 "Teo "TEO_VERSION_STR" (Linux/X11)");
318 printf("Copyright (C) 1997-2017 Gilles Fétis, Eric Botcazou, "
319 "Alexandre Pukall, François Mouret, Samuel Devulder.\n\n");
320 printf((is_fr?"Touches: [ESC] Panneau de contrôle\n"
321 :"Keys : [ESC] Control pannel\n"));
322 printf((is_fr?" [F12] Débogueur\n\n"
323 :" [F12] Debugger\n\n"));
324
325 /* Initialisation du TO8 */
326 printf((is_fr?"Initialisation de l'émulateur..."
327 :"Initialization of the emulator...")); fflush(stderr);
328
329 if ( teo_Init(TEO_NJOYSTICKS) < 0 )
330 main_ExitMessage(teo_error_msg);
331
332 /* Initialisation de l'interface d'acc�s direct */
333 ufloppy_Init (drive_type, direct_write_support);
334
335 /* D�tection des lecteurs support�s (3"5 seulement) */
336 for (i=0; i<4; i++)
337 teo.disk[i].direct_access_allowed = (IS_3_INCHES(i)) ? 1 : 0;
338
339 udisplay_Window (); /* Cr�ation de la fen�tre principale */
340 udisplay_Init(); /* Initialisation du serveur X */
341 ugraphic_Init(); /* Initialisation du module graphique */
342 disk_FirstLoad (); /* Chargement des disquettes �ventuelles */
343 cass_FirstLoad (); /* Chargement de la cassette �ventuelle */
344 if (memo_FirstLoad () < 0) /* Chargement de la cartouche �ventuelle */
345 reset = 1;
346
347 /* Chargement des options non d�finies */
348 for (i=0;(remain_name!=NULL)&&(remain_name[i]!=NULL);i++)
349 if (option_Undefined (remain_name[i]) == 1)
350 reset = 1;
351 g_strfreev(remain_name); /* Lib�re la m�moire des options ind�finies */
352
353 /* Initialise le son */
354 if (usound_Init() < 0)
355 main_DisplayMessage(teo_error_msg);
356
357 /* Restitue l'�tat sauvegard� de l'�mulateur */
358 teo_FullReset();
359 if (reset == 0)
360 if (image_Load ("autosave.img") != 0)
361 teo_FullReset();
362
363 /* Initialise l'interface graphique */
364 ugui_Init();
365 udebug_Init();
366
367 /* Et c'est parti !!! */
368 printf((is_fr?"Lancement de l'émulation...\n":"Launching emulation...\n"));
369 teo.command=TEO_COMMAND_NONE;
370 timer = g_timer_new ();
371 g_timeout_add_full (G_PRIORITY_DEFAULT, 1, RunTO8, &idle_data, NULL);
372 gtk_main ();
373 g_timer_destroy (timer);
374
375 /* Sauvegarde de l'�tat de l'�mulateur */
376 ini_Save();
377 image_Save ("autosave.img");
378
379 ufloppy_Exit(); /* Mise au repos de l'interface d'acc�s direct */
380 ugui_Free (); /* Lib�re la m�moire utilis�e par la GUI */
381 udebug_Free(); /* Free memory used by the debugger */
382 usound_Close(); /* Referme le p�riph�rique audio*/
383
384 /* Sortie de l'�mulateur */
385 printf((is_fr?"\nA bientôt !\n":"\nGoodbye !\n"));
386 exit(EXIT_SUCCESS);
387 }
388
389