Index: main.c ================================================================== --- main.c +++ main.c @@ -1,7 +1,7 @@ #if 0 -gcc -s -O2 -o ~/bin/heromesh main.c smallxrm.o sqlite3.o `sdl-config --cflags --libs` +gcc -s -O2 -o ~/bin/heromesh main.c smallxrm.o sqlite3.o `sdl-config --cflags --libs` -ldl -lpthread exit #endif /* This program is part of Free Hero Mesh and is public domain. @@ -17,10 +17,28 @@ #include "smallxrm.h" #include "names.h" #include "quarks.h" #include "cursorshapes.h" #include "pcfont.h" + +typedef struct { + char cmd; + union { + int n; + sqlite3_stmt*stmt; + const char*txt; + }; +} UserCommand; + +#define MOD_SHIFT 1 +#define MOD_CTRL 2 +#define MOD_ALT 4 +#define MOD_META 8 +#define MOD_NUMLOCK 14 +typedef struct { + UserCommand m[16]; +} KeyBinding; static const char schema[]= "PRAGMA APPLICATION_ID(1296388936);" "PRAGMA RECURSIVE_TRIGGERS(1);" "CREATE TABLE IF NOT EXISTS `USERCACHEINDEX`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `LVLTIME` INT, `SOLTIME` INT, `VERSION` INT);" @@ -38,10 +56,12 @@ static xrm_quark optionquery[16]; static FILE*hamarc_fp; static long hamarc_pos; static Uint16 picture_size; static SDL_Surface*picture_surface; +static KeyBinding*editor_bindings[SDLK_LAST]; +static KeyBinding*game_bindings[SDLK_LAST]; #define fatal(...) do{ fprintf(stderr,__VA_ARGS__); exit(1); }while(0) #define boolxrm(a,b) (*a=='1'||*a=='y'||*a=='t'||*a=='Y'||*a=='T'?1:*a=='0'||*a=='n'||*a=='f'||*a=='N'||*a=='F'?0:b) static void hamarc_begin(FILE*fp,const char*name) { @@ -141,11 +161,16 @@ if(!--len) return; } } static Uint16 decide_picture_size(int nwantsize,const Uint8*wantsize,const Uint16*havesize) { - + int i,j; + if(!nwantsize) fatal("Unable to determine what picture size is wanted\n"); + for(i=0;i4 && !memcmp(".IMG",nam+i-4,4)) { + j=1; + if(n++==32768) fatal("Too many pictures\n"); + sqlite3_reset(st); + sqlite3_bind_int(st,1,n); + sqlite3_bind_text(st,2,nam,i,SQLITE_TRANSIENT); + sqlite3_bind_int64(st,3,ftell(fp)+4); + while((i=sqlite3_step(st))==SQLITE_ROW); + if(i!=SQLITE_DONE) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb)); + } else { + j=0; + } i=fgetc(fp)<<16; i|=fgetc(fp)<<24; i|=fgetc(fp)<<0; i|=fgetc(fp)<<8; - i-=j=fgetc(fp)&15; - while(j--) ++havesize[fgetc(fp)&255]; - fseek(fp,i-1,SEEK_CUR); + if(j) { + i-=j=fgetc(fp)&15; + while(j--) ++havesize[fgetc(fp)&255]; + fseek(fp,i-1,SEEK_CUR); + } else { + fseek(fp,i,SEEK_CUR); + } } nomore1: + if(!n) fatal("Cannot find any pictures in this puzzle set\n"); free(nam); sqlite3_finalize(st); rewind(fp); for(i=0;i<256;i++) havesize[i]=(havesize[i]==n)?1:0; picture_size=decide_picture_size(nwantsize,wantsize,havesize); @@ -232,25 +267,118 @@ static void read_options(int argc,char**argv) { xrm_db*db=xrm_sub(resourcedb,0,xrm_make_quark(globalclassname,0)?:xrm_anyq); while(argc--) xrm_load_line(db,*argv++,1); } + +static int find_globalclassname(void) { + char*s=malloc(strlen(basefilename)+7); + FILE*fp; + if(!s) fatal("Allocation failed\n"); + sprintf(s,"%s.name",basefilename); + fp=fopen(s,"r"); + free(s); + if(!fp) return 1; + s=malloc(256); + if(!s) fatal("Allocation failed\n"); + if(fscanf(fp," %255s",s)!=1) fatal("Unable to scan name of class set\n"); + globalclassname=s; + return !*s; +} + +static void set_key_binding(KeyBinding**pkb,int mod,const char*txt) { + int i; + KeyBinding*kb=*pkb; + UserCommand*uc; + if(!*txt) return; + if(!kb) kb=*pkb=calloc(1,sizeof(KeyBinding)); + uc=kb->m+mod; + switch(*txt) { + case '^': // Miscellaneous + uc->cmd='^'; + uc->n=txt[1]; + break; + case '=': case '-': case '+': // Restart, rewind, advance + uc->cmd=*txt; + uc->n=strtol(txt+1,0,0); + break; + case '\'': // Input move + uc->cmd='\''; + for(i=1;i<256;i++) if(heromesh_key_names[i] && !strcmp(txt+1,heromesh_key_names[i])) { + uc->n=i; + return; + } + fatal("Error in key binding: %s\nInvalid Hero Mesh key name\n",txt); + break; + case '!': // System command + uc->cmd='!'; + uc->txt=txt+1; + break; + case 'A' ... 'Z': case 'a' ... 'z': // Execute SQL statement + uc->cmd='s'; + if(i=sqlite3_prepare_v3(userdb,txt+1,-1,SQLITE_PREPARE_PERSISTENT,&uc->stmt,0)) fatal("Error in key binding: %s\n%s\n",txt,sqlite3_errmsg(userdb)); + break; + default: + fatal("Error in key binding: %s\nUnrecognized character\n",txt); + } +} + +#define SetKeyBinding(n,m) do { \ + optionquery[1]=Q_editKey; \ + if(s=xrm_get_resource(resourcedb,optionquery,optionquery,n)) set_key_binding(editor_bindings+quark_to_key[q-FirstKeyQuark],m,s); \ + optionquery[1]=Q_gameKey; \ + if(s=xrm_get_resource(resourcedb,optionquery,optionquery,n)) set_key_binding(game_bindings+quark_to_key[q-FirstKeyQuark],m,s); \ +} while(0) +static void load_key_bindings(void) { + xrm_quark q; + const char*s; + for(q=FirstKeyQuark;q<=LastKeyQuark;q++) { + optionquery[2]=optionquery[3]=optionquery[4]=q; + SetKeyBinding(3,0); + optionquery[2]=Q_shift; + SetKeyBinding(4,MOD_SHIFT); + optionquery[2]=Q_ctrl; + SetKeyBinding(4,MOD_CTRL); + optionquery[2]=Q_alt; + SetKeyBinding(4,MOD_ALT); + optionquery[2]=Q_meta; + SetKeyBinding(4,MOD_META); + optionquery[2]=Q_numLock; + SetKeyBinding(4,MOD_NUMLOCK); + optionquery[3]=Q_shift; + SetKeyBinding(5,MOD_NUMLOCK|MOD_SHIFT); +#if 0 + optionquery[2]=Q_alt; + SetKeyBinding(5,MOD_ALT|MOD_SHIFT); + optionquery[2]=Q_ctrl; + SetKeyBinding(5,MOD_CTRL|MOD_SHIFT); + optionquery[2]=Q_meta; + SetKeyBinding(5,MOD_META|MOD_SHIFT); +#endif + } +} int main(int argc,char**argv) { if(argc<2) fatal("usage: %s basename [options...]\n",argc?argv[0]:"heromesh"); if(xrm_init(realloc)) fatal("Failed to initialize resource manager\n"); if(xrm_init_quarks(global_quarks)) fatal("Failed to initialize resource manager\n"); resourcedb=xrm_create(); if(!resourcedb) fatal("Allocation of resource database failed\n"); basefilename=argv[1]; - globalclassname=basefilename; //TODO: Fix this + if(argc>2 && argv[1][0]=='=') { + globalclassname=argv[2]+1; + ++argv; --argc; + } else if(find_globalclassname()) { + globalclassname=strrchr(basefilename,'/'); + globalclassname=globalclassname?globalclassname+1:basefilename; + } load_options(); if(argc>2) read_options(argc-2,argv+2); *optionquery=xrm_make_quark(globalclassname,0)?:xrm_anyq; init_sql(); - set_cursor(XC_arrow); + //set_cursor(XC_arrow); - atexit(SDL_Quit); + //atexit(SDL_Quit); return 0; } Index: quarks ================================================================== --- quarks +++ quarks @@ -168,10 +168,12 @@ sysreq break menu power euro +compose +undo ! Key modifiers shift ctrl alt @@ -201,8 +203,5 @@ sqlMemStatus sqlSmallAllocations sqlCoveringIndexScan sqlPowerSafe -! Miscellaneous -followSymlinkNames - Index: quarks.h ================================================================== --- quarks.h +++ quarks.h @@ -147,30 +147,32 @@ #define Q_sysreq 148 #define Q_break 149 #define Q_menu 150 #define Q_power 151 #define Q_euro 152 -#define Q_shift 153 -#define Q_ctrl 154 -#define Q_alt 155 -#define Q_meta 156 -#define Q_numLock 157 -#define Q_editClick 158 -#define Q_gameClick 159 -#define Q_allowMouseWarp 160 -#define Q_middle 161 -#define Q_class 162 -#define Q_quiz 163 -#define Q_saveSolutions 164 -#define Q_solutionComment 165 -#define Q_solutionTimestamp 166 -#define Q_sqlInit 167 -#define Q_sqlExtensions 168 -#define Q_sqlMemStatus 169 -#define Q_sqlSmallAllocations 170 -#define Q_sqlCoveringIndexScan 171 -#define Q_followSymlinkNames 172 +#define Q_compose 153 +#define Q_undo 154 +#define Q_shift 155 +#define Q_ctrl 156 +#define Q_alt 157 +#define Q_meta 158 +#define Q_numLock 159 +#define Q_editClick 160 +#define Q_gameClick 161 +#define Q_allowMouseWarp 162 +#define Q_middle 163 +#define Q_class 164 +#define Q_quiz 165 +#define Q_saveSolutions 166 +#define Q_solutionComment 167 +#define Q_solutionTimestamp 168 +#define Q_sqlInit 169 +#define Q_sqlExtensions 170 +#define Q_sqlMemStatus 171 +#define Q_sqlSmallAllocations 172 +#define Q_sqlCoveringIndexScan 173 +#define Q_sqlPowerSafe 174 static const char*const global_quarks[]={ "screenWidth", "screenHeight", "palette", "popupColors", @@ -319,10 +321,12 @@ "sysreq", "break", "menu", "power", "euro", + "compose", + "undo", "shift", "ctrl", "alt", "meta", "numLock", @@ -338,7 +342,144 @@ "sqlInit", "sqlExtensions", "sqlMemStatus", "sqlSmallAllocations", "sqlCoveringIndexScan", - "followSymlinkNames", -0}; + "sqlPowerSafe", +0}; static const SDLKey quark_to_key[Q_undo+1-Q_backspace]={ +SDLK_BACKSPACE, +SDLK_TAB, +SDLK_CLEAR, +SDLK_RETURN, +SDLK_PAUSE, +SDLK_ESCAPE, +SDLK_SPACE, +SDLK_EXCLAIM, +SDLK_QUOTEDBL, +SDLK_HASH, +SDLK_DOLLAR, +SDLK_AMPERSAND, +SDLK_QUOTE, +SDLK_LEFTPAREN, +SDLK_RIGHTPAREN, +SDLK_ASTERISK, +SDLK_PLUS, +SDLK_COMMA, +SDLK_MINUS, +SDLK_PERIOD, +SDLK_SLASH, +SDLK_0, +SDLK_1, +SDLK_2, +SDLK_3, +SDLK_4, +SDLK_5, +SDLK_6, +SDLK_7, +SDLK_8, +SDLK_9, +SDLK_COLON, +SDLK_SEMICOLON, +SDLK_LESS, +SDLK_EQUALS, +SDLK_GREATER, +SDLK_QUESTION, +SDLK_AT, +SDLK_LEFTBRACKET, +SDLK_RIGHTBRACKET, +SDLK_CARET, +SDLK_UNDERSCORE, +SDLK_BACKQUOTE, +SDLK_a, +SDLK_b, +SDLK_c, +SDLK_d, +SDLK_e, +SDLK_f, +SDLK_g, +SDLK_h, +SDLK_i, +SDLK_j, +SDLK_k, +SDLK_l, +SDLK_m, +SDLK_n, +SDLK_o, +SDLK_p, +SDLK_q, +SDLK_r, +SDLK_s, +SDLK_t, +SDLK_u, +SDLK_v, +SDLK_w, +SDLK_x, +SDLK_y, +SDLK_z, +SDLK_DELETE, +SDLK_KP0, +SDLK_KP1, +SDLK_KP2, +SDLK_KP3, +SDLK_KP4, +SDLK_KP5, +SDLK_KP6, +SDLK_KP7, +SDLK_KP8, +SDLK_KP9, +SDLK_KP_PERIOD, +SDLK_KP_DIVIDE, +SDLK_KP_MULTIPLY, +SDLK_KP_MINUS, +SDLK_KP_PLUS, +SDLK_KP_ENTER, +SDLK_KP_EQUALS, +SDLK_UP, +SDLK_DOWN, +SDLK_RIGHT, +SDLK_LEFT, +SDLK_INSERT, +SDLK_HOME, +SDLK_END, +SDLK_PAGEUP, +SDLK_PAGEDOWN, +SDLK_F1, +SDLK_F2, +SDLK_F3, +SDLK_F4, +SDLK_F5, +SDLK_F6, +SDLK_F7, +SDLK_F8, +SDLK_F9, +SDLK_F10, +SDLK_F11, +SDLK_F12, +SDLK_F13, +SDLK_F14, +SDLK_F15, +SDLK_NUMLOCK, +SDLK_CAPSLOCK, +SDLK_SCROLLOCK, +SDLK_RSHIFT, +SDLK_LSHIFT, +SDLK_RCTRL, +SDLK_LCTRL, +SDLK_RALT, +SDLK_LALT, +SDLK_RMETA, +SDLK_LMETA, +SDLK_LSUPER, +SDLK_RSUPER, +SDLK_MODE, +SDLK_HELP, +SDLK_PRINT, +SDLK_SYSREQ, +SDLK_BREAK, +SDLK_MENU, +SDLK_POWER, +SDLK_EURO, +SDLK_COMPOSE, +SDLK_UNDO, +}; +#define FirstKeyQuark Q_backspace +#define LastKeyQuark Q_undo Index: quarks.js ================================================================== --- quarks.js +++ quarks.js @@ -2,6 +2,8 @@ const fs=require("fs"); const quarks=fs.readFileSync("quarks","ascii").split("\n").map(x=>x.trim()).filter(x=>x&&x[0]!="!"); quarks.forEach((x,y)=>console.log("#define Q_"+x+" "+(y+2))); console.log("static const char*const global_quarks[]={"); quarks.forEach(x=>console.log(" \""+x+"\",")); -console.log("0};"); +console.log("0}; static const SDLKey quark_to_key[Q_undo+1-Q_backspace]={"); +quarks.slice(quarks.indexOf("backspace"),quarks.indexOf("undo")+1).forEach(x=>console.log("SDLK_"+x[x.length==1?"toLowerCase":"toUpperCase"]()+",")); +console.log("};\n#define FirstKeyQuark Q_backspace\n#define LastKeyQuark Q_undo");