/*
* TilEm II
*
* Copyright (c) 2010-2011 Thibault Duponchelle
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include "gui.h"
#include "filedlg.h"
#include "emucore.h"
/* Allocate a new TilemMacro structure which is empty */
static TilemMacro* tilem_macro_new() {
TilemMacro *macro = g_new(TilemMacro, 1);
macro->n = 0;
macro->actions = NULL;
return macro;
}
/* New or renew the table of actions (each TilemMacroAtom is an action) */
static TilemMacroAtom** tilem_macro_actions_new(TilemMacro *macro, int n) {
TilemMacroAtom **atom;
if(n == 0) {
atom = g_new(TilemMacroAtom*, n);
} else {
atom = g_renew(TilemMacroAtom*, macro->actions, n);
}
return atom;
}
/* Try to destroy the TilemMacro if really allocated */
static void tilem_macro_finalize(TilemMacro* macro) {
if(macro) {
if(macro->actions)
g_free(macro->actions);
g_free(macro);
}
}
/* Firstly free the memory then create a new TilemMacro */
void tilem_macro_start(TilemCalcEmulator *emu) {
emu->isMacroRecording = TRUE;
/* Firstly destroy the macro if exists */
tilem_macro_finalize(emu->macro);
/* Then allocate a new one */
emu->macro = tilem_macro_new(emu);
}
/* Add an action to the macro. The action could be :
* A keypress (type == 0)
* A file load (type == 1)
* Or something else if I implement it :)
*/
void tilem_macro_add_action(TilemMacro* macro, int type, char * value) {
int n = macro->n;
/* We want to allocate for 1 object, but index is 0 */
macro->actions = tilem_macro_actions_new(macro, n + 1);
/* Then we need to save the action */
macro->actions[n] = g_new(char, strlen(value)); /* FIXME : gcc says : "assignment from incompatible pointer type" ??? */
macro->actions[n]->value = g_strdup(value);
macro->actions[n]->type = type;
macro->n++;
}
/* Stop the macro */
void tilem_macro_stop(TilemCalcEmulator *emu)
{
if(emu->isMacroRecording)
emu->isMacroRecording = FALSE;
}
/* Print the macro actions content (debug) */
void tilem_macro_print(TilemMacro *macro) {
int i = 0;
printf("macro->n : %d\n", macro->n);
for(i = 0; i < macro->n; i++ ){
printf("type : %d value : %s\n", macro->actions[i]->type, macro->actions[i]->value);
}
}
/* Write a file using TilemMacro structure */
void tilem_macro_write_file(TilemCalcEmulator *emu) {
char *dir, *filename;
tilem_config_get("macro",
"directory/f", &dir,
NULL);
filename = prompt_save_file("Save macro",
GTK_WINDOW(emu->ewin->window),
NULL,
dir,
"Macro files", "*.txt",
"All files", "*",
NULL);
if(filename) {
FILE * fp = g_fopen(filename, "w");
if(fp) {
int i = 0;
for(i = 0; i< emu->macro->n; i++ ){
printf("type : %d value : %s\n", emu->macro->actions[i]->type, emu->macro->actions[i]->value);
/* Test if it's a key press or a file loading action */
if(emu->macro->actions[i]->type == 1) {
char * lengthchar = g_new0(char, 4);
int length = strlen(emu->macro->actions[i]->value);
fwrite("file=", 1, 5, fp);
sprintf(lengthchar, "%04d", strlen(emu->macro->actions[i]->value));
fwrite(lengthchar, 1, sizeof(int), fp);
fwrite("-", 1, 1, fp);
fwrite(emu->macro->actions[i]->value, 1, length, fp);
g_free(lengthchar);
} else {
fwrite(emu->macro->actions[i]->value, 1, 4, fp);
fwrite(",", 1, 1, fp);
}
}
tilem_config_set("macro", "directory/f", g_path_get_dirname(filename), NULL);
fclose(fp);
}
g_free(filename);
g_free(dir);
}
}
#define MACRO_KEYPRESS 0
#define MACRO_FILE 1
/* Play the macro (macro should be created or loaded before else it does nothing) */
static gboolean tilem_macro_play_main(TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data) {
if(!emu->macro) {
printf("Nothing to play\n");
return FALSE;
}
int i;
for(i = 0; i < emu->macro->n; i++ ){
if(emu->macro->actions[i]->type == MACRO_FILE) {
/* Type == 1 is load file */
struct TilemSendFileInfo *sf;
sf = g_slice_new0(struct TilemSendFileInfo);
sf->filename = g_strdup(emu->macro->actions[i]->value);
sf->display_name = g_filename_display_basename(emu->macro->actions[i]->value);
sf->slot = -1;
sf->first = TRUE;
sf->last = TRUE;
send_file_main(emu, sf);
} else {
/* type == 0 is keypress */
int code = atoi(emu->macro->actions[i]->value);
tilem_em_unlock(emu);
run_with_key_slowly(emu->calc, code);
tilem_em_lock(emu);
}
}
return TRUE;
}
static void tilem_macro_play_finished(G_GNUC_UNUSED TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data,
G_GNUC_UNUSED gboolean cancelled) {
}
/* Play the macro */
void tilem_macro_play(TilemCalcEmulator* emu) {
tilem_calc_emulator_begin(emu, &tilem_macro_play_main, &tilem_macro_play_finished, NULL);
}
/* Load a macro (when finished, task manager will normally call tilem_macro_play) */
static gboolean tilem_macro_load_main(TilemCalcEmulator* emu, gpointer data) {
char* filename = (char*) data;
char c = 'a';
if(filename) {
FILE * fp = g_fopen(filename, "r");
/* printf("filename : %s\n", filename); */
tilem_macro_start(emu);
while(c != EOF) {
char* codechar = g_new0(char, 4);
fread(codechar, 1, 4, fp);
if(strcmp(codechar, "file") == 0) {
c = fgetc(fp); /* Drop the "="*/
char *lengthchar = g_new0(char, 4);
fread(lengthchar, 1, 4, fp);
c = fgetc(fp); /* Drop the "-"*/
int length = atoi(lengthchar);
char* filetoload= g_new0(char, length);
fread(filetoload, 1, length, fp);
tilem_macro_add_action(emu->macro, 1, filetoload);
g_free(lengthchar);
g_free(filetoload);
} else {
int code = atoi(codechar);
if(code <= 0)
break;
/*printf("code : %d, codechar : %s\n",code, codechar); */
tilem_macro_add_action(emu->macro, 0, codechar);
c = fgetc(fp);
}
}
tilem_macro_stop(emu);
fclose(fp);
}
return TRUE;
}
/* When the macro is totally loaded, then we can play it ! */
static void tilem_macro_load_finished(G_GNUC_UNUSED TilemCalcEmulator *emu, G_GNUC_UNUSED gpointer data,
G_GNUC_UNUSED gboolean cancelled)
{
tilem_calc_emulator_begin(emu, &tilem_macro_play_main, &tilem_macro_play_finished, NULL);
}
/* Load a macro from filename.
* If filename == NULL prompt the user
*/
void tilem_macro_load(TilemCalcEmulator *emu, char* filename) {
/* printf("tilem_macro_load : filename : %s\n", filename); */
if(!filename) {
char *dir;
tilem_config_get("macro", "directory/f", &dir, NULL);
filename = prompt_open_file("Open macro",
GTK_WINDOW(emu->ewin->window),
dir,
"Macro files", "*.txt",
"All files", "*",
NULL);
if(dir)
g_free(dir);
}
tilem_calc_emulator_begin(emu, &tilem_macro_load_main, &tilem_macro_load_finished, filename);
}