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, &microseconds) < 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