ADDED   bindings.c
Index: bindings.c
==================================================================
--- /dev/null
+++ bindings.c
@@ -0,0 +1,159 @@
+#if 0
+gcc -s -O2 -c -Wno-unused-result bindings.c `sdl-config --cflags`
+exit
+#endif
+
+/*
+  This program is part of Free Hero Mesh and is public domain.
+*/
+
+#define HEROMESH_BINDINGS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+#include "sqlite3.h"
+#include "smallxrm.h"
+#include "quarks.h"
+#include "heromesh.h"
+
+#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 KeyBinding*editor_bindings[SDLK_LAST];
+static KeyBinding*game_bindings[SDLK_LAST];
+static KeyBinding*editor_mouse_bindings[4];
+static KeyBinding*game_mouse_bindings[4];
+static int cur_modifiers,loose_modifiers;
+
+static void set_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));
+  if(!kb) fatal("Allocation failed\n");
+  uc=kb->m+mod;
+  if(uc->cmd) return;
+  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,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 BINDING_MODIFIER(a,b) \
+  if(q==a && !(cur_modifiers&b)) { \
+    cur_modifiers|=b; \
+    xrm_enumerate(sub,cb_2,usr); \
+    cur_modifiers&=~b; \
+    if(loose) --loose_modifiers; \
+    return 0; \
+  }
+
+static void*cb_2(xrm_db*db,void*usr,int loose,xrm_quark q) {
+  KeyBinding**kb=usr;
+  const char*txt;
+  xrm_db*sub=xrm_sub(db,loose,q);
+  if(loose) ++loose_modifiers;
+  BINDING_MODIFIER(Q_shift,MOD_SHIFT);
+  BINDING_MODIFIER(Q_ctrl,MOD_CTRL);
+  BINDING_MODIFIER(Q_alt,MOD_ALT);
+  BINDING_MODIFIER(Q_meta,MOD_META);
+  BINDING_MODIFIER(Q_numLock,MOD_NUMLOCK);
+  if(txt=xrm_get(sub)) {
+    if(usr==editor_mouse_bindings || usr==game_mouse_bindings) {
+      switch(q) {
+        case Q_left: kb+=SDL_BUTTON_LEFT; break;
+        case Q_middle: kb+=SDL_BUTTON_MIDDLE; break;
+        case Q_right: kb+=SDL_BUTTON_RIGHT; break;
+        default: goto stop;
+      }
+    } else {
+      if(q>=FirstKeyQuark && q<=LastKeyQuark) kb+=quark_to_key[q-FirstKeyQuark]; else goto stop;
+    }
+    set_binding(kb,cur_modifiers,txt);
+    if(loose_modifiers) {
+      int i;
+      for(i=0;i<16;i++) if((i&cur_modifiers)==cur_modifiers && !kb[0]->m[i].cmd) kb[0]->m[i]=kb[0]->m[cur_modifiers];
+    }
+  }
+stop:
+  if(loose) --loose_modifiers;
+  return 0;
+}
+
+static void*cb_1(xrm_db*db,void*usr) {
+  xrm_enumerate(db,cb_2,usr);
+  return 0;
+}
+
+void load_key_bindings(void) {
+  fprintf(stderr,"Loading key bindings...\n");
+  cur_modifiers=loose_modifiers=0;
+  optionquery[1]=Q_editKey;
+  xrm_search(resourcedb,optionquery,optionquery,2,cb_1,editor_bindings);
+  optionquery[1]=Q_gameKey;
+  xrm_search(resourcedb,optionquery,optionquery,2,cb_1,game_bindings);
+  optionquery[1]=Q_editClick;
+  xrm_search(resourcedb,optionquery,optionquery,2,cb_1,editor_mouse_bindings);
+  optionquery[1]=Q_gameClick;
+  xrm_search(resourcedb,optionquery,optionquery,2,cb_1,game_mouse_bindings);
+  fprintf(stderr,"Done\n");
+}
+
+const UserCommand*find_key_binding(SDL_Event*ev,int editing) {
+  KeyBinding*kb;
+  static const UserCommand nul={cmd:0};
+  SDLMod m;
+  int i;
+  if(ev->type==SDL_KEYDOWN) {
+    m=ev->key.keysym.mod;
+    if(ev->key.keysym.sym>=SDLK_LAST) return &nul;
+    kb=(editing?editor_bindings:game_bindings)[ev->key.keysym.sym];
+  } else if(ev->type==SDL_MOUSEBUTTONDOWN) {
+    m=SDL_GetModState();
+    if(ev->button.button>3) return &nul;
+    kb=(editing?editor_mouse_bindings:game_mouse_bindings)[ev->button.button];
+  } else {
+    return &nul;
+  }
+  if(!kb) return &nul;
+  i=0;
+  if(m&KMOD_CTRL) i|=MOD_CTRL;
+  if(m&KMOD_SHIFT) i|=MOD_SHIFT;
+  if(m&KMOD_ALT) i|=MOD_ALT;
+  if(m&KMOD_META) i|=MOD_META;
+  if((m&KMOD_NUM) && kb->m[i|MOD_NUMLOCK].cmd) i|=MOD_NUMLOCK;
+  return kb->m+i;
+}
+

Index: heromesh.h
==================================================================
--- heromesh.h
+++ heromesh.h
@@ -22,10 +22,14 @@
     Uint32 u;
   };
   Uint32 t; // Type 0-15, or a generation_number of an object
 } Value;
 
+extern const char*const standard_message_names[];
+extern const char*const standard_sound_names[];
+extern const char*const heromesh_key_names[256];
+
 extern sqlite3*userdb;
 extern xrm_db*resourcedb;
 extern const char*basefilename;
 extern xrm_quark optionquery[16];
 extern Uint32 generation_number;
@@ -80,5 +84,19 @@
 extern Class*classes[0x4000]; // 0 isn't used
 extern const char*messages[0x4000]; // index is 256 less than message number
 extern int max_animation; // max steps in animation queue
 extern Sint32 max_volume; // max total volume to allow moving diagonally (default 10000)
 
+// == bindings ==
+
+typedef struct {
+  char cmd;
+  union {
+    int n;
+    sqlite3_stmt*stmt;
+    const char*txt;
+  };
+} UserCommand;
+
+void load_key_bindings(void);
+const UserCommand*find_key_binding(SDL_Event*ev,int editing);
+

Index: main.c
==================================================================
--- main.c
+++ main.c
@@ -1,7 +1,7 @@
 #if 0
-gcc -s -O2 -o ~/bin/heromesh main.c picture.o smallxrm.o sqlite3.o `sdl-config --cflags --libs` -ldl -lpthread
+gcc -s -O2 -o ~/bin/heromesh main.c picture.o bindings.o smallxrm.o sqlite3.o `sdl-config --cflags --libs` -ldl -lpthread
 exit
 #endif
 
 /*
   This program is part of Free Hero Mesh and is public domain.
@@ -19,28 +19,10 @@
 #include "names.h"
 #include "quarks.h"
 #include "cursorshapes.h"
 #include "heromesh.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[]=
   "BEGIN;"
   "PRAGMA APPLICATION_ID(1296388936);"
   "PRAGMA RECURSIVE_TRIGGERS(1);"
   "CREATE TABLE IF NOT EXISTS `USERCACHEINDEX`(`ID` INTEGER PRIMARY KEY, `NAME` TEXT, `TIME` INT);"
@@ -59,14 +41,10 @@
 static FILE*levelfp;
 static FILE*solutionfp;
 static FILE*hamarc_fp;
 static long hamarc_pos;
 static char main_options[128];
-static KeyBinding*editor_bindings[SDLK_LAST];
-static KeyBinding*game_bindings[SDLK_LAST];
-static KeyBinding*editor_mouse_bindings[4];
-static KeyBinding*game_mouse_bindings[4];
 
 static void hamarc_begin(FILE*fp,const char*name) {
   while(*name) fputc(*name++,fp);
   fwrite("\0\0\0\0",1,5,hamarc_fp=fp);
   hamarc_pos=ftell(fp);
@@ -170,118 +148,10 @@
   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)
-#define SetMouseBinding(o,n,m) do { \
-  optionquery[1]=Q_editClick; \
-  if(s=xrm_get_resource(resourcedb,optionquery,optionquery,n)) set_key_binding(editor_mouse_bindings+o,m,s); \
-  optionquery[1]=Q_gameClick; \
-  if(s=xrm_get_resource(resourcedb,optionquery,optionquery,n)) set_key_binding(game_mouse_bindings+o,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
-  }
-  optionquery[2]=optionquery[3]=Q_left;
-  SetMouseBinding(SDL_BUTTON_LEFT,3,0);
-  optionquery[2]=Q_shift;
-  SetMouseBinding(SDL_BUTTON_LEFT,4,MOD_SHIFT);
-  optionquery[2]=Q_ctrl;
-  SetMouseBinding(SDL_BUTTON_LEFT,4,MOD_CTRL);
-  optionquery[2]=Q_alt;
-  SetMouseBinding(SDL_BUTTON_LEFT,4,MOD_ALT);
-  optionquery[2]=Q_meta;
-  SetMouseBinding(SDL_BUTTON_LEFT,4,MOD_META);
-  optionquery[2]=optionquery[3]=Q_middle;
-  SetMouseBinding(SDL_BUTTON_MIDDLE,3,0);
-  optionquery[2]=Q_shift;
-  SetMouseBinding(SDL_BUTTON_MIDDLE,4,MOD_SHIFT);
-  optionquery[2]=Q_ctrl;
-  SetMouseBinding(SDL_BUTTON_MIDDLE,4,MOD_CTRL);
-  optionquery[2]=Q_alt;
-  SetMouseBinding(SDL_BUTTON_MIDDLE,4,MOD_ALT);
-  optionquery[2]=Q_meta;
-  SetMouseBinding(SDL_BUTTON_MIDDLE,4,MOD_META);
-  optionquery[2]=optionquery[3]=Q_right;
-  SetMouseBinding(SDL_BUTTON_RIGHT,3,0);
-  optionquery[2]=Q_shift;
-  SetMouseBinding(SDL_BUTTON_RIGHT,4,MOD_SHIFT);
-  optionquery[2]=Q_ctrl;
-  SetMouseBinding(SDL_BUTTON_RIGHT,4,MOD_CTRL);
-  optionquery[2]=Q_alt;
-  SetMouseBinding(SDL_BUTTON_RIGHT,4,MOD_ALT);
-  optionquery[2]=Q_meta;
-  SetMouseBinding(SDL_BUTTON_RIGHT,4,MOD_META);
-}
-
 static int test_sql_callback(void*usr,int argc,char**argv,char**name) {
   int i;
   if(argc) printf("%s",*argv);
   for(i=1;i<argc;i++) printf("|%s",argv[i]);
   putchar('\n');
@@ -288,12 +158,14 @@
   return 0;
 }
 
 static void test_mode(void) {
   Uint32 n=0;
+  SDLKey k;
   SDL_Event ev;
   char buf[32];
+  const UserCommand*uc;
   set_cursor(XC_tcross);
   SDL_LockSurface(screen);
   draw_text(0,0,"Hello, World!",0xF0,0xFF);
   SDL_UnlockSurface(screen);
   SDL_Flip(screen);
@@ -316,10 +188,16 @@
           break;
         case SDLK_c:
           SDL_FillRect(screen,0,n);
           SDL_Flip(screen);
           break;
+        case SDLK_e:
+          n=1;
+          goto keytest;
+        case SDLK_g:
+          n=0;
+          goto keytest;
         case SDLK_p:
           sqlite3_exec(userdb,"SELECT * FROM `PICTURES`;",test_sql_callback,0,0);
           break;
         case SDLK_q:
           exit(0);
@@ -333,14 +211,47 @@
     case SDL_QUIT:
       exit(0);
       break;
   }
   fatal("An error occurred waiting for events.\n");
+keytest:
+  SDL_FillRect(screen,0,0xF0);
+  SDL_LockSurface(screen);
+  draw_text(1,5,n?"Edit Key":"Game Key",0xF1,0xF7);
+  SDL_UnlockSurface(screen);
+  SDL_EnableUNICODE(1);
+  SDL_Flip(screen);
+  set_cursor(XC_arrow);
+  while(SDL_WaitEvent(&ev)) switch(ev.type) {
+    case SDL_KEYDOWN:
+      printf("[%d %d %d %d] ",ev.key.keysym.scancode,ev.key.keysym.sym,ev.key.keysym.mod,ev.key.keysym.unicode);
+      goto bindingtest;
+    case SDL_MOUSEBUTTONDOWN:
+      printf("[%d %d %d] ",ev.button.x,ev.button.y,ev.button.button);
+    bindingtest:
+      uc=find_key_binding(&ev,n);
+      switch(uc->cmd) {
+        case 0: printf("<Unbound>\n"); break;
+        case '^': printf("<Misc> %c\n",uc->n); break;
+        case '=': printf("<Reset> %d\n",uc->n); break;
+        case '-': printf("<Rewind> %d\n",uc->n); break;
+        case '+': printf("<Advance> %d\n",uc->n); break;
+        case '\'': printf("<Play> %s (%d)\n",heromesh_key_names[uc->n],uc->n); break;
+        case '!': printf("<System> %s",uc->txt); break;
+        case 's': printf("<SQL> %s",sqlite3_sql(uc->stmt)); break;
+        default: printf("<Unknown>\n");
+      }
+      break;
+    case SDL_QUIT:
+      exit(0);
+      break;
+  }
 }
 
 int main(int argc,char**argv) {
   int optind=1;
+  fprintf(stderr,"FREE HERO MESH\n");
   while(argc>optind && argv[optind][0]=='-') {
     int i;
     const char*s=argv[optind++];
     if(s[1]=='-' && !s[2]) break;
     for(i=1;s[i];i++) main_options[s[i]&127]=1;
@@ -359,14 +270,15 @@
   }
   load_options();
   if(argc>optind) read_options(argc-optind,argv+optind);
   *optionquery=xrm_make_quark(globalclassname,0)?:xrm_anyq;
   init_sql();
+  load_key_bindings();
   init_screen();
   load_pictures();
   if(main_options['T']) {
     test_mode();
     return 0;
   }
   
   return 0;
 }

Index: names.h
==================================================================
--- names.h
+++ names.h
@@ -18,11 +18,11 @@
 #define MSG_DESTROYED 16
 #define MSG_CREATED 17
 #define MSG_POSTINIT 18
 #define MSG_END_TURN 19
 #define MSG_CLEANUP 20
-static const char*const standard_message_names[]={
+const char*const standard_message_names[]={
  "INIT",
  "CREATE",
  "DESTROY",
  "BEGIN_TURN",
  "ARRIVED",
@@ -91,11 +91,11 @@
 #define SND_FAROUT 45
 #define SND_KEWEL 46
 #define SND_WHACK 47
 #define SND_STEAM 48
 #define SND_HAWK 49
-static const char*const standard_sound_names[]={
+const char*const standard_sound_names[]={
  "SPLASH",
  "POUR",
  "DOOR",
  "GLASS",
  "BANG",
@@ -143,11 +143,11 @@
  "KEWEL",
  "WHACK",
  "STEAM",
  "HAWK",
 };
-static const char*const heromesh_key_names[256]={
+const char*const heromesh_key_names[256]={
  [8]="BACK",
  [9]="TAB",
  [12]="CENTER",
  [13]="ENTER",
  [16]="SHIFT",

Index: names.js
==================================================================
--- names.js
+++ names.js
@@ -135,15 +135,15 @@
 [..."ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"].forEach(x=>{
   heromesh_key_names[x.charCodeAt()]=x;
 });
 console.log("// Auto-generated! Do not modify directly!");
 standard_message_names.forEach(([a,b,c])=>console.log("#define MSG_"+c+" "+b));
-console.log("static const char*const standard_message_names[]={");
+console.log("const char*const standard_message_names[]={");
 standard_message_names.forEach(([a,b,c])=>console.log(" \""+c+"\","));
 console.log("};");
 standard_sound_names.forEach((x,y)=>console.log("#define SND_"+x+" "+y));
-console.log("static const char*const standard_sound_names[]={");
+console.log("const char*const standard_sound_names[]={");
 standard_sound_names.forEach(x=>console.log(" \""+x+"\","));
 console.log("};");
-console.log("static const char*const heromesh_key_names[256]={");
+console.log("const char*const heromesh_key_names[256]={");
 Object.keys(heromesh_key_names).forEach(x=>console.log(" ["+x+"]=\""+heromesh_key_names[x]+"\","));
 console.log("};");

Index: picture.c
==================================================================
--- picture.c
+++ picture.c
@@ -213,10 +213,11 @@
   Uint16 havesize[256];
   char*nam=sqlite3_mprintf("%s.xclass",basefilename);
   const char*v;
   int i,j,n;
   if(!nam) fatal("Allocation failed\n");
+  fprintf(stderr,"Loading pictures...\n");
   fp=fopen(nam,"r");
   if(!fp) fatal("Failed to open xclass file (%m)\n");
   sqlite3_free(nam);
   optionquery[1]=Q_altImage;
   altImage=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"0",0,10);
@@ -295,10 +296,11 @@
   }
   sqlite3_finalize(st);
   fclose(fp);
   sqlite3_exec(userdb,"COMMIT;",0,0,0);
   SDL_SetColorKey(picts,SDL_SRCCOLORKEY|SDL_RLEACCEL,0);
+  fprintf(stderr,"Done\n");
 }
 
 void init_screen(void) {
   const char*v;
   int w,h,i;

Index: quarks.h
==================================================================
--- quarks.h
+++ quarks.h
@@ -346,11 +346,11 @@
   "sqlSmallAllocations",
   "sqlCoveringIndexScan",
   "sqlPowerSafe",
   "level",
 0};
-#ifdef HEROMESH_MAIN
+#ifdef HEROMESH_BINDINGS
 static const SDLKey quark_to_key[Q_undo+1-Q_backspace]={
 SDLK_BACKSPACE,
 SDLK_TAB,
 SDLK_CLEAR,
 SDLK_RETURN,

Index: quarks.js
==================================================================
--- quarks.js
+++ quarks.js
@@ -2,8 +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};\n#ifdef HEROMESH_MAIN\nstatic const SDLKey quark_to_key[Q_undo+1-Q_backspace]={");
+console.log("0};\n#ifdef HEROMESH_BINDINGS\nstatic 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\n#endif");

Index: smallxrm.c
==================================================================
--- smallxrm.c
+++ smallxrm.c
@@ -103,12 +103,12 @@
 
 void*xrm_enumerate(xrm_db*db,void*(*cb)(xrm_db*,void*,int,xrm_quark),void*usr) {
   int i;
   void*r;
   if(!db) return 0;
-  for(i=0;i<db->l.n;i++) if(r=cb(db,usr,1,db->l.p[i].k)) return r;
   for(i=0;i<db->t.n;i++) if(r=cb(db,usr,0,db->t.p[i].k)) return r;
+  for(i=0;i<db->l.n;i++) if(r=cb(db,usr,1,db->l.p[i].k)) return r;
   return 0;
 }
 
 const char*xrm_get(xrm_db*db) {
   return db?db->v:0;