/******************************************************************************
* *
* A M S E x t e n d e r *
* *
* by Stefan Heule *
* member of boolsoft (www.boolsoft.org) *
* *
* Source Code *
* *
*******************************************************************************
AMS Extender - A utility for TI's 68k calculaters
Copyright (C) 2006-2008 Stefan Heule
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 .
*/
// ----------------------------------------------------------------- //
// --- custom events
// ----------------------------------------------------------------- //
#define CUSTOM_CM_BACKUP_SETTINGS_ALL_TSR 0x6000
#define CUSTOM_CM_RESTORE_SETTINGS_ALL_TSR 0x6001
#define CUSTOM_CM_BACKUP_SETTINGS_AMSEXT 0x6002
#define CUSTOM_CM_RESTORE_SETTINGS_AMSEXT 0x6003
#define CUSTOM_CM_BACKUP_SETTINGS_EASYCHAR 0x6004
#define CUSTOM_CM_RESTORE_SETTINGS_EASYCHAR 0x6005
// ----------------------------------------------------------------- //
// --- defines
// ----------------------------------------------------------------- //
// 'e' 'v' 'H' 'k'
#define EVHK_TAG_HEXA ((long)0x6576486B)
// magic marker for trap 4 hook ('A' 'M' 'E' 'x')
#define MAGIC_TRAP4HOOK 0x414D4578
// no need for exit or atexit
#define NO_EXIT_SUPPORT
#define NO_AMS_CHECK
// smaller code
#define OPTIMIZE_ROM_CALLS
#define USE_FLINE_ROM_CALLS
// produce code for all models
#define USE_TI92PLUS
#define USE_V200
#define USE_TI89
#define MIN_AMS 204
#define fatal(s) {ST_showHelp(s);return;}
// size of the trap 4 hook
#define SIZE_OF_TRAP4HOOK sizeof(trap4hook)
// if you change the backup struct, change this macig, too!
// "amsext01" -> AMS Extender 0.6.0 beta
// -> AMS Extender 0.7.0 beta
// "amsext02" -> AMS Extender 0.8.0 beta
#define OPTIONS_FILE_MAGIC "amsext02"
// name of the backup file
#define OPTIONS_FILE_NAME "amsxtcfg"
typedef struct _options
{
unsigned short keydelay; // key delay, delay in 1/20 second
unsigned short scrolldelay; // scroll delay, delay in 1/20 second
unsigned long cursor_rate; // cursor blink delay, delay in 1/20 second
unsigned long apd; // auto power down, 20 * second
short auto_add_brackets; // automatically add brackets, 0: off, 1: on
unsigned char clock_type; // clock icon, 0: off, 1: 12h, 2: 24h
unsigned char battery_type; // battery icon, 0: off, 1: on
unsigned char keyboard_layout; // keyboard layout, 0: QWERTY, 1: QWERTZ
unsigned char autostart_prgm[18]; // autostart programm, 'name'+'\\'+'folder' or 'name'
unsigned char _2nd_MEM[18]; // programm to be executed when 2nd+MEM is pressed
unsigned char _2nd_CHAR[18]; // programm to be executed when 2nd+CHAR is pressed
unsigned char off_by_on; // turn calc off by pressing on, 0: off, 1: on
} OPTIONS;
// the preferences
OPTIONS pref;
// handle's (used for the options dialog)
unsigned short a, b, c, d, e, f, g, dlg, pop1, pop2, pop3;
// ----------------------------------------------------------------- //
// --- header files
// ----------------------------------------------------------------- //
#include // include all header files
#include "messages.h" // multi-language support
#include "h220xTSR.h" // Kevin Kofler's hw2 ams2 tsr support
#include "eventhook_89.h" // pre-compiled event hook for the ti89
#include "eventhook_v2.h" // pre-compiled event hook for the v200
#include "trap4hook.h" // pre-compiled trap 4 hook for the both
// ----------------------------------------------------------------- //
// --- prototypes
// ----------------------------------------------------------------- //
// trap 4 hook stuff
unsigned short InstallTrap4Hook(const unsigned char* signature, unsigned short key_delay, unsigned short scroll_delay);
void RemoveTrap4Hook(unsigned char* tsr_address);
unsigned char* FindTrap4Hook(const unsigned char* signature);
void UpdateTrap4HookConfig(unsigned char* tsr_address, unsigned short key_delay, unsigned short scroll_delay);
// preferences file
short loadBackup(void);
short saveBackup(void);
void check_for_limits(void);
void default_all_settings(void);
unsigned char checksum(void* data, unsigned short bytes);
// preferences dialog
unsigned short execute_config_dialog(void);
CALLBACK short Callback(short Message, long Value);
CALLBACK HANDLE PopupCallback(short ID);
// ----------------------------------------------------------------- //
// Main routine, handles the user input and installs or uninstalls
// the event/trap 4 hook if necessary.
// ----------------------------------------------------------------- //
// input (as an argument):
// 'r' = restores the config from a file
// 'c' = displays an options dialog
// local:
// signature = 8-byte signature of the trap 4 hook
// eventhookHandle = handle of the event hook
// p_eventhook = pointer to the event hook
// eventhook = pointer to the event hook
// eventhook_size = size of the event hook
// trap4hook_adr = address of the trap 4 hook
// argptr = pointer to the arguments
// ev = event
// arg = temp argument storage
// ----------------------------------------------------------------- //
void _main(void)
{
const unsigned char signature[8] = {'t','r','a','p','4','_','h','k'};
volatile HANDLE eventhookHandle;
char *p_eventhook;
unsigned char* eventhook;
unsigned short eventhook_size;
unsigned char* trap4hook_adr;
ESI argptr;
EVENT ev;
const char* arg;
// find our trap 4 hook
trap4hook_adr = FindTrap4Hook(signature);
// load the backup
if (!loadBackup()) return;
// choose the correct event hook
if (TI92PLUS || V200) {
eventhook = eventhook_v2;
eventhook_size = sizeof(eventhook_v2);
}
else if (TI89) {
eventhook = eventhook_89;
eventhook_size = sizeof(eventhook_89);
}
else
fatal(MSG_ERROR_UNKNOWN_CALC);
// init the argument pointer
InitArgPtr(argptr);
// we are just looking for string arguments
if (GetArgType(argptr) == STR_TAG)
{
arg = GetStrnArg(argptr);
if (strchr(arg, 'r'))
{
// send a custom event, that the event hook can update its config
ev.Type = CUSTOM_CM_RESTORE_SETTINGS_AMSEXT;
EV_sendEvent(TIOS_EV_getAppID("TIHOME"), &ev);
// set trap 4 settings
if (trap4hook_adr) UpdateTrap4HookConfig(trap4hook_adr, pref.keydelay, pref.scrolldelay);
}
else if (strchr(arg, 'c'))
{
// display the config dialog
if (execute_config_dialog()) {
// save the config
if (!saveBackup()) ST_helpMsg(MSG_ERROR_SAVE_CONFIG);
// send a custom event, that the event hook can update its config
ev.Type = CUSTOM_CM_RESTORE_SETTINGS_AMSEXT;
EV_sendEvent(TIOS_EV_getAppID("TIHOME"), &ev);
// set trap 4 settings
if (trap4hook_adr) UpdateTrap4HookConfig(trap4hook_adr, pref.keydelay, pref.scrolldelay);
}
}
return;
}
// check wheter the event hook is already installed (originally written by Olivier Armand (ExtendeD))
if (EV_hook)
{
char *HookPtr = (char*)EV_hook;
char *PrevHookPtr = NULL; // points to the previous hook in the linked list
while (HookPtr != NULL)
{
HookPtr -= 16; // point to the header of the hook
// if the event hook isn't following Kevin Kofler's convention,
// our event hook can't be further in the linked list
if(*(long*)HookPtr != EVHK_TAG_HEXA)
break;
// if this is our event hook, uninstall it :(
if(!memcmp(HookPtr, "evHk"TSR_NAME, 12))
{
// if our event hook is not the first in the linked list
if (PrevHookPtr
// Remove our event hook from the linked list :
// the next event hook of PrevHookPtr becomes the next hook of HookPtr...
// but only if the next event hook follows Kevin's convention !
&& (*(long*)(*(char**)(HookPtr+12) - 16) == EVHK_TAG_HEXA))
*(char**)(PrevHookPtr+12) = *(char**)(HookPtr+12);
else
// Our event hook is the first in the linked list :
// EV_hook becomes the event hook after our hook in the list
EV_hook = (EVENT_HANDLER)*(char**)(HookPtr+12);
// Free the block where the TSR was.
// (don't forget to make HookPtr leave the ghost space)
HeapFree(HeapPtrToHandle ((void*)((long)HookPtr ^ (HW_VERSION == 2 ? 0x40000 : 0))));
// uninstall trap 4 hook
if (trap4hook_adr) RemoveTrap4Hook(trap4hook_adr);
// last message
fatal(HOOK_NAME" "MSG_UNINSTALLED".");
}
// HookPtr is now the previous hook pointer
PrevHookPtr = HookPtr;
// get the address of the entry point of the next hook
HookPtr = *(char**)(HookPtr+12);
}
}
// install Kevin's HW2 AMS 2 TSR support
if(!h220xTSR())
fatal(MSG_ERROR_MEMORY);
// install our trap 4 hook
if (!trap4hook_adr)
if (!InstallTrap4Hook(signature, pref.keydelay, pref.scrolldelay))
fatal(MSG_ERROR_MEMORY);
// allocate RAM for the event hook
if(!(eventhookHandle = HeapAllocHigh(eventhook_size)))
{
// uninstall the trap 4 hook
trap4hook_adr = FindTrap4Hook(signature);
if (trap4hook_adr) RemoveTrap4Hook(trap4hook_adr);
// exit
fatal(MSG_ERROR_MEMORY);
}
// get a pointer to the actual mem and make it point in the "ghost space"
// ghost space is essentially a shadow of regular ram which is not protected very
// well by the hardware... subtract 0x40000 to get the real address
p_eventhook = HeapDeref(eventhookHandle)+(HW_VERSION == 2 ? 0x40000 : 0);
// copy the eventhook array to its new location
memcpy(p_eventhook, eventhook, eventhook_size);
// save the old address for the uninstall prog and for this hook to call
*(unsigned long*)&p_eventhook[12] = (unsigned long)EV_hook;
EX_patch(p_eventhook, p_eventhook+eventhook_size);
ASM_fastcall(&p_eventhook[16]);
EV_hook = (EVENT_HANDLER)&p_eventhook[16];
// last message
ST_helpMsg(HOOK_NAME" "HOOK_VERSION" "MSG_INSTALLED".");
}
// ----------------------------------------------------------------- //
// Installs our trap4 hook
// ----------------------------------------------------------------- //
// input:
// signature = signature of the trap 4 hook
// key_delay = key delay
// scroll_delay = scroll delay
// local:
// mem = pointer to the allocated memory for our hook
// HookMain = function pointer to the main routine of our
// trap 4 hook
// return:
// 1 if successfully installed, 0 otherwise
// ----------------------------------------------------------------- //
unsigned short InstallTrap4Hook(const unsigned char* signature, unsigned short key_delay, unsigned short scroll_delay)
{
unsigned char* mem = HeapAllocPtr(SIZE_OF_TRAP4HOOK+12)+(HW_VERSION == 2 ? 0x40000 : 0);
void (*HookMain)(unsigned short, unsigned short, unsigned char);
// return if there isn't enought free RAM
if (!mem) return 0;
// write MAGIC_TSR (4 bytes) at the beginning of memory
*mem++ = (MAGIC_TRAP4HOOK >> 24) & 0xff;
*mem++ = (MAGIC_TRAP4HOOK >> 16) & 0xff;
*mem++ = (MAGIC_TRAP4HOOK >> 8) & 0xff;
*mem++ = (MAGIC_TRAP4HOOK ) & 0xff;
// copy afterwards the 8 bytes signature to memory
memcpy(mem, signature, 8);
mem += 8;
// ... and the program itself from the pre-compiled array
memcpy(mem, trap4hook, SIZE_OF_TRAP4HOOK);
// relocate program and execute the program
EX_patch(mem, mem+SIZE_OF_TRAP4HOOK);
HookMain = (void(*)(unsigned short, unsigned short, unsigned char))(mem);
HookMain(key_delay, scroll_delay, 0);
return 1;
}
// ----------------------------------------------------------------- //
// Uninstalls the trap 4 hook
// ----------------------------------------------------------------- //
// input:
// tsr_address = pointer to the header (signatur + magic) of
// our trap 4 hook
// local:
// HookMain = function pointer to the main routine of our
// trap 4 hook
// ----------------------------------------------------------------- //
void RemoveTrap4Hook(unsigned char* tsr_address)
{
void (*HookMain)(unsigned short, unsigned short, unsigned char);
// uninstall the trap 4 hook
HookMain = (void(*)(unsigned short, unsigned short, unsigned char))(tsr_address+12+(HW_VERSION == 2 ? 0x40000 : 0));
HookMain(0, 0, 0);
// fill memory holding signature with zeros
memset(tsr_address, 0, 12);
// free the allocated memory
HeapFreePtr((void*)((long)tsr_address^ (HW_VERSION == 2 ? 0x40000 : 0)));
}
// ----------------------------------------------------------------- //
// Scans the hole RAM to find our trap 4 hook, looking for its magic
// (4 bytes) followed by the signature (8 bytes).
// ----------------------------------------------------------------- //
// input:
// signature = signature of the trap 4 hook
// local:
// end = pointer to the memory location where we search
// return:
// address of the already installed trap 4 hook or NULL
// note:
// Scans backwards
// ----------------------------------------------------------------- //
unsigned char* FindTrap4Hook(const unsigned char* signature)
{
unsigned char* end = HeapEnd();
while (end)
{
if (*end == ((MAGIC_TRAP4HOOK >> 24) & 0xff) &&
*(end+1) == ((MAGIC_TRAP4HOOK >> 16) & 0xff) &&
*(end+2) == ((MAGIC_TRAP4HOOK >> 8) & 0xff) &&
*(end+3) == ((MAGIC_TRAP4HOOK ) & 0xff) &&
!strncmp(end+4, signature, 8))
{
// we have found our trap 4 hook
return end;
}
end -= 2;
}
// if we'll come here our trap 4 hook is not installed
return NULL;
}
// ----------------------------------------------------------------- //
// Updates the config of our trap 4 hook
// ----------------------------------------------------------------- //
// input:
// tsr_address = pointer to the header (signatur + magic) of
// our trap 4 hook
// key_delay = key delay
// scroll_delay = scroll delay
// local:
// HookMain = function pointer to the main routine of our
// trap 4 hook
// ----------------------------------------------------------------- //
void UpdateTrap4HookConfig(unsigned char* tsr_address, unsigned short key_delay, unsigned short scroll_delay)
{
void (*HookMain)(unsigned short, unsigned short, unsigned char);
// update the trap 4 hook config
HookMain = (void(*)(unsigned short, unsigned short, unsigned char))(tsr_address+12+(HW_VERSION == 2 ? 0x40000 : 0));
HookMain(key_delay, scroll_delay, 1);
}
// ----------------------------------------------------------------- //
// Executes the config dialog
// ----------------------------------------------------------------- //
// local:
// pulldown_buffer = buffer for the popups
// ptr = pointer
// dlg_ret_val = return value of the DialogDo function
// return:
// TRUE if the user pressed ENTER, FALSE otherwise
// ----------------------------------------------------------------- //
unsigned short execute_config_dialog(void)
{
short pulldown_buffer[5];
char* ptr;
unsigned short dlg_ret_val = 0;
a = b = c = d = e = f = g = dlg = pop1 = pop2 = pop3 = 0;
if ((a = HeapAlloc(6)) == H_NULL) goto error;
if ((b = HeapAlloc(6)) == H_NULL) goto error;
if ((c = HeapAlloc(6)) == H_NULL) goto error;
if ((d = HeapAlloc(6)) == H_NULL) goto error;
if ((e = HeapAlloc(20)) == H_NULL) goto error;
if ((f = HeapAlloc(20)) == H_NULL) goto error;
if ((g = HeapAlloc(20)) == H_NULL) goto error;
if ((pop1 = PopupNew(NULL, 0)) == H_NULL) goto error;
if ((pop2 = PopupNew(NULL, 0)) == H_NULL) goto error;
if ((pop3 = PopupNew(NULL, 0)) == H_NULL) goto error;
// add the texts to the popup's
PopupAddText(pop1, -1, MSG_OPTIONS_ON , 0);
PopupAddText(pop1, -1, MSG_OPTIONS_OFF, 0);
PopupAddText(pop2, -1, MSG_OPTIONS_OFF, 0);
PopupAddText(pop2, -1, "12h", 0);
PopupAddText(pop2, -1, "24h", 0);
PopupAddText(pop3, -1, "QWERTZ", 0);
PopupAddText(pop3, -1, "QWERTY", 0);
ptr = HeapDeref(a);
sprintf(ptr, "%i", pref.keydelay);
ptr = HeapDeref(b);
sprintf(ptr, "%i", pref.scrolldelay);
ptr = HeapDeref(c);
sprintf(ptr, "%lu", pref.cursor_rate);
ptr = HeapDeref(d);
sprintf(ptr, "%lu", pref.apd/20);
ptr = HeapDeref(e);
strcpy(ptr, pref.autostart_prgm);
ptr = HeapDeref(f);
strcpy(ptr, pref._2nd_MEM);
ptr = HeapDeref(g);
strcpy(ptr, pref._2nd_CHAR);
// auto add brackets
if (pref.auto_add_brackets) pulldown_buffer[0] = 1;
else pulldown_buffer[0] = 2;
// off by on
if (pref.off_by_on) pulldown_buffer[4] = 1;
else pulldown_buffer[4] = 2;
if (CALCULATOR)
{
// clock type
pulldown_buffer[2] = pref.clock_type+1;
// battery
if (pref.battery_type) pulldown_buffer[1] = 1;
else pulldown_buffer[1] = 2;
// keyboard layout
if (pref.keyboard_layout) pulldown_buffer[3] = 1;
else pulldown_buffer[3] = 2;
// new dialog
if ((dlg = DialogNew(160, 117, Callback)) == H_NULL)
{
goto error;
}
DialogAddScrollRegion(dlg, DF_CLR_ON_REDRAW, 9, 18-2, 160, 90+10, 0, 10, 7, 12, 12);
// add all request's
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 18, MSG_OPTIONS_KEYDELAY, 4);
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 30, MSG_OPTIONS_SCROLLDELAY, 4);
#if defined(LANG_EN)
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 42, MSG_OPTIONS_CURSOR_BLINK" ", 4);
#elif defined(LANG_DE)
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 42, MSG_OPTIONS_CURSOR_BLINK, 4);
#endif
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 54, MSG_OPTIONS_APD_TIMER, 4);
DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 66, MSG_OPTIONS_AUTOSTART" ", 9);
DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 78, MSG_OPTIONS_2ND_MEM" ", 9);
DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 90, MSG_OPTIONS_2ND_CHAR" ", 9);
// add all pulldown's
DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 102, MSG_OPTIONS_AUTO_ADD_BR, PopupCallback, 0);
DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 114, MSG_OPTIONS_BATTERY, PopupCallback, 1);
DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 126, MSG_OPTIONS_CLOCK, PopupCallback, 2);
DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 138, MSG_OPTIONS_OFF_BY_ON, PopupCallback, 4);
DialogAddDynamicPulldown(dlg, DF_SCROLLABLE, 10, 150, MSG_OPTIONS_KEYBOARD_LAYOUT, PopupCallback, 3);
} else {
// new dialog
if ((dlg = DialogNew(122, 89, Callback)) == H_NULL)
{
goto error;
}
// add the scroll region
DialogAddScrollRegion(dlg, DF_CLR_ON_REDRAW, 11, 13, 122, 74, 0, 8, 6, 10, 10);
// add all request's
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 15, MSG_OPTIONS_KEYDELAY, 4);
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 25, MSG_OPTIONS_SCROLLDELAY, 4);
#if defined(LANG_EN)
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 35, MSG_OPTIONS_CURSOR_BLINK" ", 4);
#elif defined(LANG_DE)
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 35, MSG_OPTIONS_CURSOR_BLINK, 4);
#endif
DialogAddDynamicRequest(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 45, MSG_OPTIONS_APD_TIMER, 4);
DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 55, MSG_OPTIONS_AUTOSTART" ", 9);
DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 65, MSG_OPTIONS_2ND_MEM" ", 9);
DialogAddDynamicRequest(dlg, DF_SCROLLABLE, 10, 75, MSG_OPTIONS_2ND_CHAR" ", 9);
// add all pulldown's
DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 85, MSG_OPTIONS_AUTO_ADD_BR, PopupCallback, 0);
DialogAddDynamicPulldown(dlg, DF_SCROLLABLE | DF_TAB_SPACES, 10, 95, MSG_OPTIONS_OFF_BY_ON, PopupCallback, 4);
DialogAddXFlags(dlg, 0, XF_NO_ALPHA_LOCK, 0, 0, 0);
}
// add the title
DialogAddTitle(dlg, HOOK_NAME" "HOOK_VERSION" "MSG_OPTIONS, BT_CANCEL, BT_SAVE);
if ((dlg_ret_val = DialogDo(dlg, CENTER, CENTER, NULL, pulldown_buffer)) == KEY_ENTER)
{
// delays
pref.keydelay = atoi(HeapDeref(a));
pref.scrolldelay = atoi(HeapDeref(b));
pref.cursor_rate = atoi(HeapDeref(c));
pref.apd = atoi(HeapDeref(d))*20;
// check for limits
check_for_limits();
// auto add brackets
if (pulldown_buffer[0] == 1) pref.auto_add_brackets = 1;
else pref.auto_add_brackets = 0;
// off by on
if (pulldown_buffer[4] == 1) pref.off_by_on = 1;
else pref.off_by_on = 0;
if (CALCULATOR)
{
// clock type
pref.clock_type = pulldown_buffer[2] - 1;
// battery
if (pulldown_buffer[1] == 1) pref.battery_type = 1;
else pref.battery_type = 0;
// keyboard layout
if (pulldown_buffer[3] == 1) pref.keyboard_layout = 1;
else pref.keyboard_layout = 0;
}
// autostart / 2nd+MEM
strncpy(pref.autostart_prgm, HeapDeref(e), 17);
pref.autostart_prgm[17] = 0;
strncpy(pref._2nd_MEM, HeapDeref(f), 17);
pref._2nd_MEM[17] = 0;
strncpy(pref._2nd_CHAR, HeapDeref(g), 17);
pref._2nd_CHAR[17] = 0;
}
error:
// free all elements
if (a) HeapFree(a);
if (b) HeapFree(b);
if (c) HeapFree(c);
if (d) HeapFree(d);
if (e) HeapFree(e);
if (f) HeapFree(f);
if (g) HeapFree(g);
if (dlg) HeapFree(dlg);
if (pop1) HeapFree(pop1);
if (pop2) HeapFree(pop2);
if (pop3) HeapFree(pop3);
return (dlg_ret_val == KEY_ESC ? 0 : 1);
}
// ----------------------------------------------------------------- //
// Dialog callback function, used for the options dialog
// ----------------------------------------------------------------- //
// input:
// Message = message
// Value = value of this message
// return:
// Handle of the correct item
// ----------------------------------------------------------------- //
CALLBACK short Callback(short Message, long Value)
{
if (Message == DB_GET_EDIT_HANDLE)
{
if (Value == 1)
return a;
if (Value == 2)
return b;
if (Value == 3)
return c;
if (Value == 4)
return d;
if (Value == 5)
return e;
if (Value == 6)
return f;
if (Value == 7)
return g;
}
return 1;
};
// ----------------------------------------------------------------- //
// Popup callback function, used for the options dialog
// ----------------------------------------------------------------- //
// input:
// ID = ID of the requested popup
// return:
// Handle of the correct popup
// ----------------------------------------------------------------- //
CALLBACK HANDLE PopupCallback(short ID)
{
if (CALCULATOR)
{
if (ID == 8 || ID == 9 || ID == 11)
{
return pop1;
}
if (ID == 10)
{
return pop2;
}
if (ID == 12)
{
return pop3;
}
}
else
{
return pop1;
}
return H_NULL;
}
// ----------------------------------------------------------------- //
// Loads the configuration from a file
// ----------------------------------------------------------------- //
// local:
// backup = config structure
// file = file structure
// chcksm = file checksum
// backup_file_magic = file magic
// return:
// TRUE, or, in case of an error, FALSE
// note:
// If there's no config file, a new one with default values will
// be created
// ----------------------------------------------------------------- //
short loadBackup(void)
{
OPTIONS backup;
FILES file;
unsigned char chcksm;
unsigned char backup_file_magic[strlen(OPTIONS_FILE_MAGIC)+1];
// unarchive the file
EM_moveSymFromExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL);
// open the backup file
if (FOpen(OPTIONS_FILE_NAME, &file, FM_READ, "cfg") != FS_OK)
{
default_all_settings();
// open the backup file
if (FOpen(OPTIONS_FILE_NAME, &file, FM_WRITE, "cfg") != FS_OK)
{
ST_helpMsg(MSG_ERROR_CREATE_FILE);
return FALSE;
}
// write the file magic
if (FWrite((void*)OPTIONS_FILE_MAGIC, strlen(OPTIONS_FILE_MAGIC), &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_WRITE_TO_FILE);
return FALSE;
}
// write backup
if (FWrite((void*)&pref, sizeof(OPTIONS), &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_WRITE_TO_FILE);
return FALSE;
}
// calculate checksum
unsigned char chcksm = checksum((void*)&pref, sizeof(OPTIONS));
// write the checksum
if (FWrite((void*)&chcksm, 1, &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_WRITE_TO_FILE);
return FALSE;
}
FClose(&file);
// archive the file
EM_moveSymToExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL);
return TRUE;
}
// read the file magic
backup_file_magic[strlen(OPTIONS_FILE_MAGIC)] = 0;
if (FRead((void*)backup_file_magic, strlen(OPTIONS_FILE_MAGIC), &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_READ_FROM_FILE);
return FALSE;
}
// check file version
if (strcmp(OPTIONS_FILE_MAGIC, backup_file_magic) != 0)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_OUTDATED_FILE);
return FALSE;
}
// read the file content
if (FRead((void*)&backup, sizeof(OPTIONS), &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_READ_FROM_FILE);
return FALSE;
}
// read the checksum
if (FRead((void*)&chcksm, 1, &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_READ_FROM_FILE);
return FALSE;
}
// check checksum
if (checksum((void*)&backup, sizeof(OPTIONS)) != chcksm)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_CORRUPTED_FILE);
return FALSE;
}
// close the file
FClose(&file);
pref = backup;
// archive the file
EM_moveSymToExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL);
return TRUE;
}
// ----------------------------------------------------------------- //
// Calculates a simple 1-byte-checksum of the provided data
// ----------------------------------------------------------------- //
// local:
// md5 = MD5 structure
// res = 16 byte MD5 checksum
// return:
// first byte of MD5 checksum
// note:
// only one byte of the 16-byte MD5 checksum will be used
// ----------------------------------------------------------------- //
unsigned char checksum(void* data, unsigned short bytes)
{
unsigned char res[16];
MD5_CTX md5;
// get MD5 hash of the data
MD5Init(&md5);
MD5Update(&md5, data, bytes);
MD5Final(res, &md5);
// we just use the first byte of the 16 byte long MD5 hash
return res[0];
}
// ----------------------------------------------------------------- //
// Saves the configuration ot a file
// ----------------------------------------------------------------- //
// local:
// file = file structure
// return:
// TRUE, or, in case of an error, FALSE
// note:
// Any old file will be overwritten
// ----------------------------------------------------------------- //
short saveBackup(void)
{
FILES file;
// unarchive the file
EM_moveSymFromExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL);
// open the backup file
if (FOpen(OPTIONS_FILE_NAME, &file, FM_WRITE, "cfg") != FS_OK)
{
ST_helpMsg(MSG_ERROR_CREATE_FILE);
return FALSE;
}
// write the file magic
if (FWrite((void*)OPTIONS_FILE_MAGIC, strlen(OPTIONS_FILE_MAGIC), &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_WRITE_TO_FILE);
return FALSE;
}
// write backup
if (FWrite((void*)&pref, sizeof(OPTIONS), &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_WRITE_TO_FILE);
return FALSE;
}
// calculate checksum
unsigned char chcksm = checksum((void*)&pref, sizeof(OPTIONS));
// write the checksum
if (FWrite((void*)&chcksm, 1, &file) != FS_OK)
{
FClose(&file);
ST_helpMsg(MSG_ERROR_WRITE_TO_FILE);
return FALSE;
}
FClose(&file);
// archive the file
EM_moveSymToExtMem(SYMSTR(OPTIONS_FILE_NAME), HS_NULL);
return TRUE;
}
/// ----------------------------------------------------------------- //
// Checks for weird values of the configuration
// ----------------------------------------------------------------- //
// note:
// Does not check all options, only the timers
// ----------------------------------------------------------------- //
void check_for_limits(void)
{
if (pref.keydelay < 2) pref.keydelay = 2;
if (pref.keydelay > 600) pref.keydelay = 600;
if (pref.scrolldelay < 2) pref.scrolldelay = 2;
if (pref.scrolldelay > 200) pref.scrolldelay = 200;
if (pref.cursor_rate < 1) pref.cursor_rate = 1;
if (pref.cursor_rate > 200) pref.cursor_rate = 200;
if (pref.apd < 20) pref.apd = 20;
if (pref.apd > 20*20*60) pref.apd = 20*20*60;
}
// ----------------------------------------------------------------- //
// Sets all settings to their default values
// ----------------------------------------------------------------- //
// note:
// The settings may not directly take influence. You need to
// call first.
// ----------------------------------------------------------------- //
void default_all_settings(void)
{
pref.scrolldelay = 18;
pref.keydelay = 50;
pref.cursor_rate = 6;
pref.apd = 120*20;
pref.auto_add_brackets = 1;
pref.clock_type = 0;
pref.battery_type = 1;
pref.keyboard_layout = 0;
pref.autostart_prgm[0] = 0;
pref._2nd_MEM[0] = 0;
strcpy(pref._2nd_CHAR, "main\\easychar");
pref.off_by_on = 1;
}