1 /*
2 * TilEm II
3 *
4 * Copyright (c) 2010-2011 Thibault Duponchelle
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <glib/gstdio.h>
28 #include <ticalcs.h>
29 #include <tilem.h>
30
31 #include "gui.h"
32 #include "filedlg.h"
33 #include "emucore.h"
34
35
36 /* Allocate a new TilemMacro structure which is empty */
tilem_macro_new()37 static TilemMacro* tilem_macro_new() {
38 TilemMacro *macro = g_new(TilemMacro, 1);
39 macro->n = 0;
40 macro->actions = NULL;
41 return macro;
42 }
43
44 /* New or renew the table of actions (each TilemMacroAtom is an action) */
tilem_macro_actions_new(TilemMacro * macro,int n)45 static TilemMacroAtom** tilem_macro_actions_new(TilemMacro *macro, int n) {
46 TilemMacroAtom **atom;
47
48 if(n == 0) {
49 atom = g_new(TilemMacroAtom*, n);
50 } else {
51 atom = g_renew(TilemMacroAtom*, macro->actions, n);
52 }
53 return atom;
54 }
55
56 /* Try to destroy the TilemMacro if really allocated */
tilem_macro_finalize(TilemMacro * macro)57 static void tilem_macro_finalize(TilemMacro* macro) {
58 if(macro) {
59 if(macro->actions)
60 g_free(macro->actions);
61 g_free(macro);
62 }
63 }
64
65 /* Firstly free the memory then create a new TilemMacro */
tilem_macro_start(TilemCalcEmulator * emu)66 void tilem_macro_start(TilemCalcEmulator *emu) {
67 emu->isMacroRecording = TRUE;
68
69 /* Firstly destroy the macro if exists */
70 tilem_macro_finalize(emu->macro);
71
72 /* Then allocate a new one */
73 emu->macro = tilem_macro_new(emu);
74 }
75
76 /* Add an action to the macro. The action could be :
77 * A keypress (type == 0)
78 * A file load (type == 1)
79 * Or something else if I implement it :)
80 */
tilem_macro_add_action(TilemMacro * macro,int type,char * value)81 void tilem_macro_add_action(TilemMacro* macro, int type, char * value) {
82
83 int n = macro->n;
84
85 /* We want to allocate for 1 object, but index is 0 */
86 macro->actions = tilem_macro_actions_new(macro, n + 1);
87
88 /* Then we need to save the action */
89 macro->actions[n] = g_new(char, strlen(value)); /* FIXME : gcc says : "assignment from incompatible pointer type" ??? */
90 macro->actions[n]->value = g_strdup(value);
91 macro->actions[n]->type = type;
92 macro->n++;
93 }
94
95 /* Stop the macro */
tilem_macro_stop(TilemCalcEmulator * emu)96 void tilem_macro_stop(TilemCalcEmulator *emu)
97 {
98 if(emu->isMacroRecording)
99 emu->isMacroRecording = FALSE;
100 }
101
102 /* Print the macro actions content (debug) */
tilem_macro_print(TilemMacro * macro)103 void tilem_macro_print(TilemMacro *macro) {
104 int i = 0;
105
106 printf("macro->n : %d\n", macro->n);
107 for(i = 0; i < macro->n; i++ ){
108 printf("type : %d value : %s\n", macro->actions[i]->type, macro->actions[i]->value);
109 }
110 }
111
112 /* Write a file using TilemMacro structure */
tilem_macro_write_file(TilemCalcEmulator * emu)113 void tilem_macro_write_file(TilemCalcEmulator *emu) {
114 char *dir, *filename;
115 tilem_config_get("macro",
116 "directory/f", &dir,
117 NULL);
118
119 filename = prompt_save_file("Save macro",
120 GTK_WINDOW(emu->ewin->window),
121 NULL,
122 dir,
123 "Macro files", "*.txt",
124 "All files", "*",
125 NULL);
126 if(filename) {
127 FILE * fp = g_fopen(filename, "w");
128 if(fp) {
129 int i = 0;
130 for(i = 0; i< emu->macro->n; i++ ){
131 printf("type : %d value : %s\n", emu->macro->actions[i]->type, emu->macro->actions[i]->value);
132 /* Test if it's a key press or a file loading action */
133 if(emu->macro->actions[i]->type == 1) {
134 char * lengthchar = g_new0(char, 4);
135 int length = strlen(emu->macro->actions[i]->value);
136 fwrite("file=", 1, 5, fp);
137 sprintf(lengthchar, "%04d", strlen(emu->macro->actions[i]->value));
138 fwrite(lengthchar, 1, sizeof(int), fp);
139 fwrite("-", 1, 1, fp);
140 fwrite(emu->macro->actions[i]->value, 1, length, fp);
141 g_free(lengthchar);
142 } else {
143 fwrite(emu->macro->actions[i]->value, 1, 4, fp);
144 fwrite(",", 1, 1, fp);
145 }
146 }
147 tilem_config_set("macro", "directory/f", g_path_get_dirname(filename), NULL);
148 fclose(fp);
149 }
150 g_free(filename);
151 g_free(dir);
152 }
153 }
154
155 #define MACRO_KEYPRESS 0
156 #define MACRO_FILE 1
157
158 /* Play the macro (macro should be created or loaded before else it does nothing) */
tilem_macro_play_main(TilemCalcEmulator * emu,G_GNUC_UNUSED gpointer data)159 static gboolean tilem_macro_play_main(TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data) {
160
161 if(!emu->macro) {
162 printf("Nothing to play\n");
163 return FALSE;
164 }
165
166 int i;
167 for(i = 0; i < emu->macro->n; i++ ){
168 if(emu->macro->actions[i]->type == MACRO_FILE) {
169 /* Type == 1 is load file */
170 struct TilemSendFileInfo *sf;
171 sf = g_slice_new0(struct TilemSendFileInfo);
172 sf->filename = g_strdup(emu->macro->actions[i]->value);
173 sf->display_name = g_filename_display_basename(emu->macro->actions[i]->value);
174 sf->slot = -1;
175 sf->first = TRUE;
176 sf->last = TRUE;
177 send_file_main(emu, sf);
178
179 } else {
180 /* type == 0 is keypress */
181 int code = atoi(emu->macro->actions[i]->value);
182 tilem_em_unlock(emu);
183 run_with_key_slowly(emu->calc, code);
184 tilem_em_lock(emu);
185
186 }
187 }
188
189
190 return TRUE;
191 }
192
193
tilem_macro_play_finished(G_GNUC_UNUSED TilemCalcEmulator * emu,G_GNUC_UNUSED gpointer data,G_GNUC_UNUSED gboolean cancelled)194 static void tilem_macro_play_finished(G_GNUC_UNUSED TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data,
195 G_GNUC_UNUSED gboolean cancelled) {
196
197 }
198
199 /* Play the macro */
tilem_macro_play(TilemCalcEmulator * emu)200 void tilem_macro_play(TilemCalcEmulator* emu) {
201
202 tilem_calc_emulator_begin(emu, &tilem_macro_play_main, &tilem_macro_play_finished, NULL);
203 }
204
205 /* Load a macro (when finished, task manager will normally call tilem_macro_play) */
tilem_macro_load_main(TilemCalcEmulator * emu,gpointer data)206 static gboolean tilem_macro_load_main(TilemCalcEmulator* emu, gpointer data) {
207
208 char* filename = (char*) data;
209 char c = 'a';
210
211 if(filename) {
212 FILE * fp = g_fopen(filename, "r");
213 /* printf("filename : %s\n", filename); */
214
215 tilem_macro_start(emu);
216 while(c != EOF) {
217 char* codechar = g_new0(char, 4);
218 fread(codechar, 1, 4, fp);
219 if(strcmp(codechar, "file") == 0) {
220 c = fgetc(fp); /* Drop the "="*/
221 char *lengthchar = g_new0(char, 4);
222 fread(lengthchar, 1, 4, fp);
223 c = fgetc(fp); /* Drop the "-"*/
224 int length = atoi(lengthchar);
225 char* filetoload= g_new0(char, length);
226 fread(filetoload, 1, length, fp);
227 tilem_macro_add_action(emu->macro, 1, filetoload);
228 g_free(lengthchar);
229 g_free(filetoload);
230 } else {
231 int code = atoi(codechar);
232 if(code <= 0)
233 break;
234 /*printf("code : %d, codechar : %s\n",code, codechar); */
235 tilem_macro_add_action(emu->macro, 0, codechar);
236 c = fgetc(fp);
237 }
238 }
239 tilem_macro_stop(emu);
240 fclose(fp);
241 }
242
243 return TRUE;
244 }
245
246 /* When the macro is totally loaded, then we can play it ! */
tilem_macro_load_finished(G_GNUC_UNUSED TilemCalcEmulator * emu,G_GNUC_UNUSED gpointer data,G_GNUC_UNUSED gboolean cancelled)247 static void tilem_macro_load_finished(G_GNUC_UNUSED TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data,
248 G_GNUC_UNUSED gboolean cancelled)
249 {
250 tilem_calc_emulator_begin(emu, &tilem_macro_play_main, &tilem_macro_play_finished, NULL);
251 }
252
253 /* Load a macro from filename.
254 * If filename == NULL prompt the user
255 */
tilem_macro_load(TilemCalcEmulator * emu,char * filename)256 void tilem_macro_load(TilemCalcEmulator *emu, char* filename) {
257
258 /* printf("tilem_macro_load : filename : %s\n", filename); */
259 if(!filename) {
260 char *dir;
261 tilem_config_get("macro", "directory/f", &dir, NULL);
262
263 filename = prompt_open_file("Open macro",
264 GTK_WINDOW(emu->ewin->window),
265 dir,
266 "Macro files", "*.txt",
267 "All files", "*",
268 NULL);
269 if(dir)
270 g_free(dir);
271 }
272 tilem_calc_emulator_begin(emu, &tilem_macro_load_main, &tilem_macro_load_finished, filename);
273 }
274
275