Free Hero Mesh

Check-in [f6f1c94d23]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.
Overview
Comment:Add smallxrm
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f6f1c94d23363504afe56e64e72f7fd9a4361db2
User & Date: user on 2018-03-09 06:00:54
Other Links: manifest | tags
Context
2018-03-10
22:48
RLE compression of levels check-in: 06cd05742f user: user tags: trunk
2018-03-09
06:00
Add smallxrm check-in: f6f1c94d23 user: user tags: trunk
01:33
Add key names to names.js and names.h check-in: ceadd9ba47 user: user tags: trunk
Changes

Added smallxrm.c version [4ef0f077c3].













































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#if 0
gcc -s -O2 -c smallxrm.c
exit
#endif

/*
  Small XRM (X Resource Manager) in C.
  Public domain.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "smallxrm.h"

typedef struct xrm_pair {
  xrm_quark k;
  xrm_db*x;
} xrm_pair;

typedef struct xrm_map {
  int n;
  xrm_pair*p;
} xrm_map;

typedef struct xrm_db {
  xrm_map l;
  xrm_map t;
  char*v;
} xrm_db;

#define BUFINC 1024

static char anyq_name[2]="?";
static void*(*my_realloc)(void*,size_t);
static int nquarks;
static xrm_quark*quarklook;
static char**quarknames;
static xrm_quark keyquark=0;
static const char*keyname;
static char*inbuf;
static int inbufsize;
static int staticquarks;

static void*cb_get_resource(xrm_db*db,void*usr) {
  return db->v;
}

static int db_compar(const void*a,const void*b) {
  const xrm_pair*x=a;
  const xrm_pair*y=b;
  return x->k<y->k?-1:x->k==y->k?0:1;
}

static char*my_strdup(const char*p) {
  char*s=my_realloc(0,strlen(p)+1);
  if(!s) return 0;
  strcpy(s,p);
  return s;
}

static int quarklook_compar(const void*a,const void*b) {
  xrm_quark x=*(const xrm_quark*)a;
  xrm_quark y=*(const xrm_quark*)b;
  return strcmp(x?quarknames[x-1]?:"":keyname,y?quarknames[y-1]?:"":keyname);
}

void xrm_annihilate(void) {
  int i;
  if(!my_realloc) return;
  for(i=staticquarks;i<nquarks;i++) my_realloc(quarknames[i],0);
  my_realloc(quarknames,0);
  nquarks=0;
  quarklook=0;
  quarknames=0;
  my_realloc(inbuf,0);
  inbuf=0;
  inbufsize=0;
  my_realloc=0;
}

xrm_db*xrm_create(void) {
  xrm_db*db=my_realloc(0,sizeof(xrm_db));
  if(!db) return 0;
  db->l.n=0;
  db->l.p=0;
  db->t.n=0;
  db->t.p=0;
  db->v=0;
  return db;
}

void xrm_destroy(xrm_db*db) {
  int i;
  if(!db) return;
  my_realloc(db->v,0);
  for(i=0;i<db->l.n;i++) xrm_destroy(db->l.p[i].x);
  my_realloc(db->l.p,0);
  for(i=0;i<db->t.n;i++) xrm_destroy(db->t.p[i].x);
  my_realloc(db->t.p,0);
  my_realloc(db,0);
}

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;
  return 0;
}

const char*xrm_get(xrm_db*db) {
  return db?db->v:0;
}

const char*xrm_get_resource(xrm_db*db,const xrm_quark*ns,const xrm_quark*cs,int len) {
  if(!db) return 0;
  return xrm_search(db,ns,cs,len,cb_get_resource,0);
}

int xrm_init(void*(*f)(void*,size_t)) {
  if(my_realloc || !f) return -1;
  my_realloc=f;
  nquarks=1;
  quarknames=my_realloc(0,sizeof(char*));
  if(!quarknames) goto bad;
  quarklook=my_realloc(0,sizeof(xrm_quark));
  if(!quarklook) {
    my_realloc(quarknames,0);
    quarknames=0;
    goto bad;
  }
  *quarklook=xrm_anyq;
  *quarknames=anyq_name;
  inbuf=0;
  inbufsize=0;
  staticquarks=1;
  return 0;
bad:
  my_realloc=0;
  return -1;
}

int xrm_init_quarks(const char*const*list) {
  void*mem;
  int i=0;
  if(!my_realloc || !list || nquarks!=1 || staticquarks!=1) return -1;
  while(list[i]) i++;
  mem=my_realloc(quarknames,(i+1)*sizeof(char*));
  if(!mem) return -1;
  quarknames=mem;
  mem=my_realloc(quarklook,(i+1)*sizeof(xrm_quark));
  if(!mem) return -1;
  quarklook=mem;
  nquarks=staticquarks=i+1;
  for(i=0;list[i];i++) {
    quarknames[i+1]=(char*)(list[i]);
    quarklook[i+1]=i+2;
  }
  qsort(quarklook,nquarks,sizeof(xrm_quark),quarklook_compar);
  return 0;
}

int xrm_link(xrm_db*db,int loose,xrm_quark q,xrm_db*ins) {
  xrm_map*m;
  xrm_pair*p;
  xrm_pair k={q,ins};
  if(!db || !q) return 0;
  m=loose?&db->l:&db->t;
  if(m->n) {
    p=bsearch(&k,m->p,m->n,sizeof(xrm_pair),db_compar);
    if(p) {
      *p=k;
      return 0;
    }
  }
  p=my_realloc(m->p,(m->n+1)*sizeof(xrm_pair));
  if(!p) return -1;
  p[m->n]=k;
  qsort(p,++m->n,sizeof(xrm_pair),db_compar);
  m->p=p;
  return 0;
}

int xrm_load(xrm_db*db,FILE*fp,int o) {
  int bs,c,n,x;
  if(!inbuf) {
    inbuf=my_realloc(0,BUFINC+2);
    if(!inbuf) return -1;
    inbufsize=BUFINC;
  }
  if(!db || !fp) return -1;
  for(c=0;c!=EOF;) {
    for(x=bs=0;(c=fgetc(fp))!=EOF;) {
      if(c=='\r') continue;
      if(c=='\\') {
        bs^=1;
      } else if(c=='\n') {
        if(bs--) x--; else break;
      } else {
        bs=0;
      }
      inbuf[x++]=c;
      if(x>=inbufsize) {
        char*buf=my_realloc(inbuf,inbufsize+BUFINC+2);
        if(!buf) return -1;
        inbuf=buf;
        inbufsize+=BUFINC;
      }
    }
    inbuf[x]=0;
    xrm_load_line(db,inbuf,o);
  }
  return 0;
}

int xrm_load_line(xrm_db*db,const char*s,int o) {
  int c;
  int loose=0;
  char*p;
  char*q=0;
  char*r;
  if(!s) return -1;
  if(!*s || *s=='!') return 0;
  if(*s=='#') return -1;
  if(s!=inbuf) {
    int i=strlen(s)+1;
    if(i>=inbufsize) {
      char*buf=my_realloc(inbuf,i+2);
      if(!buf) return -1;
      inbuf=buf;
      inbufsize=i;
    }
    strcpy(inbuf,s);
  }
  p=inbuf;
  while(*p==' ' || *p=='\t') s++;
  if(!*p) return 0;
  while(c=*p++) {
    if(c=='.' || c=='*' || c==':') {
      if(q) {
        r=p-1;
        *r--=0;
        while(r>q && (*r==' ' || *r=='\t')) *r--=0;
        db=xrm_sub(db,loose,xrm_make_quark(q,1));
        if(!db) return -1;
        loose=0;
        q=0;
      }
      if(c=='*') loose=1;
      if(c==':') break;
    } else if(c!=' ' && c!='\t' && !q) {
      q=p-1;
    }
  }
  if(!c) return -1;
  if(db->v && !o) return 0;
  while(*p==' ' || *p=='\t') p++;
  q=p;
  while(c=*p++) {
    if(c=='\\') {
      if(p[0]>='0' && p[0]<'8' && p[1]>='0' && p[1]<'8' && p[2]>='0' && p[2]<'8') {
        r=p+2;
        *r=((p[0]-'0')<<6)|((p[1]-'0')<<3)|(p[2]-'0');
        while(*r) r[-3]=*r,++r;
        r[-3]=0;
      } else {
        if(*p=='n') *p='\n';
        r=p;
        while(*r) r[-1]=*r,++r;
        r[-1]=0;
      }
    } else if(c=='\r' || c=='\n') {
      break;
    }
  }
  *p=0;
  return xrm_put(db,q,1);
}

xrm_quark xrm_make_quark(const char*name,int addnew) {
  xrm_quark*q;
  if(name && !*name) return 0;
  keyname=name;
  if(!name) {
    if(!addnew) return 0;
    q=0;
  } else {
    q=bsearch(&keyquark,quarklook,nquarks,sizeof(xrm_quark),quarklook_compar);
  }
  if(addnew && !q) {
    xrm_quark*ql=my_realloc(quarklook,(nquarks+1)*sizeof(xrm_quark));
    char**qn=my_realloc(quarknames,(nquarks+1)*sizeof(char*));
    if(ql) quarklook=ql;
    if(qn) quarknames=qn;
    if(!ql || !qn) return 0;
    if(name) {
      qn[nquarks]=my_strdup(name);
      if(!qn[nquarks]) return 0;
    } else {
      qn[nquarks]=0;
    }
    ql[nquarks]=++nquarks;
    qsort(quarklook,nquarks,sizeof(xrm_quark),quarklook_compar);
    return nquarks;
  } else {
    return q?*q:0;
  }
}

int xrm_merge(xrm_db*to,xrm_db*from,int o) {
  int i;
  if(!from) return 0;
  if(!to) return -1;
  if(xrm_put(to,from->v,o)) return -1;
  for(i=0;i<from->t.n;i++) if(xrm_merge(xrm_sub(to,0,from->t.p[i].k),from->t.p[i].x,o)) return -1;
  for(i=0;i<from->l.n;i++) if(xrm_merge(xrm_sub(to,1,from->l.p[i].k),from->l.p[i].x,o)) return -1;
  return 0;
}

const char*xrm_name(xrm_quark n) {
  if(!n || n>nquarks) return 0;
  return quarknames[n-1];
}

int xrm_put(xrm_db*db,const char*v,int o) {
  char*s;
  if(!db) return -1;
  if(db->v && !o) return 0;
  if(v) {
    s=my_strdup(v);
    if(!s) return -1;
    my_realloc(db->v,0);
    db->v=s;
  } else {
    my_realloc(db->v,0);
    db->v=0;
  }
  return 0;
}

int xrm_put_resource(xrm_db*db,const xrm_quark*q,const char*b,const char*v,int o) {
  while(*b) {
    if(*b!='.' && *b!='*') return -1;
    db=xrm_sub(db,*b=='*',*q);
    q++; b++;
  }
  return xrm_put(db,v,o);
}

void*xrm_search(xrm_db*db,const xrm_quark*ns,const xrm_quark*cs,int len,void*(*cb)(xrm_db*,void*),void*usr) {
  xrm_db*p;
  void*r;
  if(!len) return cb(db,usr);
  if((p=xrm_sub(db,0,*ns)) && (r=xrm_search(p,ns+1,cs+1,len-1,cb,usr))) return r;
  if(ns!=cs && (p=xrm_sub(db,0,*cs)) && (r=xrm_search(p,ns+1,cs+1,len-1,cb,usr))) return r;
  if((p=xrm_sub(db,0,xrm_anyq)) && (r=xrm_search(p,ns+1,cs+1,len-1,cb,usr))) return r;
again:
  if((p=xrm_sub(db,1,*ns)) && (r=xrm_search(p,ns+1,cs+1,len-1,cb,usr))) return r;
  if(ns!=cs && (p=xrm_sub(db,1,*cs)) && (r=xrm_search(p,ns+1,cs+1,len-1,cb,usr))) return r;
  if((p=xrm_sub(db,1,xrm_anyq)) && (r=xrm_search(p,ns+1,cs+1,len-1,cb,usr))) return r;
  ns++; cs++;
  if(--len) goto again;
  return 0;
}

xrm_db*xrm_sub(xrm_db*db,int loose,xrm_quark q) {
  xrm_map*m;
  xrm_pair*p;
  xrm_pair k={q,0};
  if(!db || !q) return 0;
  m=loose?&db->l:&db->t;
  if(m->n) {
    p=bsearch(&k,m->p,m->n,sizeof(xrm_pair),db_compar);
    if(p) return p->x;
  }
  k.x=xrm_create();
  if(!k.x) return 0;
  p=my_realloc(m->p,(m->n+1)*sizeof(xrm_pair));
  if(!p) {
    my_realloc(k.x,0);
    return 0;
  }
  p[m->n]=k;
  qsort(p,++m->n,sizeof(xrm_pair),db_compar);
  m->p=p;
  return k.x;
}

Added smallxrm.h version [4b3decb0ca].

























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
  Small XRM (X Resource Manager) in C.
  Public domain.
*/

#ifndef SMALLXRM_H_INCLUDED
#define SMALLXRM_H_INCLUDED

typedef struct xrm_db xrm_db; // type of database nodes
typedef unsigned int xrm_quark; // type of quarks

#define xrm_nullq ((xrm_quark)0) // not a valid quark
#define xrm_anyq ((xrm_quark)1) // the "?" quark

// Memory handling: Any xrm_db* values returned by these functions are
// invalid if xrm_destroy() is subsequently used on that node or on any of
// its ancestor nodes. Any string pointers returned by these functions are
// invalid if the node it belongs to is destroyed, if the resource value is
// changed, or if xrm_annihilate() is called. Do not free them by yourself.

void xrm_annihilate(void);
// Releases all memory used by this library. Does nothing if not
// initialized. You must first call xrm_destroy() on any existing resource
// databases you may have allocated. After xrm_annihilate() is called,
// nothing else should be called without calling xrm_init() first. You may
// safely terminate the program without calling this function, since the
// only thing it does is free memory, which is automatically done when the
// program terminates anyways.

xrm_db*xrm_create(void);
// Creates a new empty resource database.

void xrm_destroy(xrm_db*db);
// Destroy an existing resource database. All sub-databases are also
// destroyed. The memory is freed.

void*xrm_enumerate(xrm_db*db,void*(*cb)(xrm_db*,void*,int,xrm_quark),void*usr);
// Calls the given callback function for each child node of the resource
// database; the first two arguments are the same as db and usr given to
// this function, while the next is 1 if loose or 0 if tight, and the next
// is the quark that is in use. You can then call xrm_sub() in order to
// access the sub-database it contains. If the callback returns null, then
// the enumeration continues, otherwise it returns with the same value. It
// only goes one level deep; you can use it recursively to go more deep.

const char*xrm_get(xrm_db*db);
// Retrieves the value of the resource at the root of the given database.
// If there is no value, the result is a null pointer.

const char*xrm_get_resource(xrm_db*db,const xrm_quark*ns,const xrm_quark*cs,int len);
// Retrieves the value of a given resource, given the root node, list of
// quarks for the name of the query, list of quarks for the class of the
// query, and the length of the name and class list. Both list pointers
// must be non-null, but you may give the same pointers for each. If there
// is no such resource, the result is a null pointer.

int xrm_init(void*(*f)(void*,size_t));
// Initialize the library; must be called exactly once, before anything
// else is called. The argument should be realloc, or your own function
// that does the same thing; all dynamic memory allocation done by the
// library will use the function you give for this purpose. Return value
// is 0 if success or -1 if error.

int xrm_init_quarks(const char*const*list);
// Optional. If you call it, it must be called after xrm_init() is called
// before any other library functions are called. The argument is a null
// terminated list of strings, all of which must be unique, and none of
// them may be "?". They are assigned constant quark numbers, where the
// first string is the name of quark number 2, the next being quark number
// 3, and so on. You can use this in order to make compile-time constants
// for the quarks used in your program. The library does not make copies
// of the strings; they must exist for the entire duration of the library.
// The return value is 0 if OK or -1 if not OK.

int xrm_link(xrm_db*db,int loose,xrm_quark q,xrm_db*ins);
// Insert a node (the fourth argument) as child of the node given by the
// first argument. The node is now "owned" by the parent; if you then call
// xrm_destroy() without unlinking it, it will destroy that one too. You
// normally do not need to use this function. Return value is 0 if it is
// successful or -1 in case of error.

int xrm_load(xrm_db*db,FILE*fp,int o);
// Load a resource database from an open file handle. #include is not
// currently implemented. It loads into the given database, and returns 0
// if successful or -1 if error. The third argument is nonzero if it
// should override existing resources, or zero if it doesn't.

int xrm_load_line(xrm_db*db,const char*s,int o);
// Load a resource from a string, which must be a single line; in case of
// any line breaks, they and anything after them are ignored. Line
// continuation is not implemented by xrm_load_line() (but xrm_load() does
// implement it).

xrm_quark xrm_make_quark(const char*name,int addnew);
// Make a new quark (or retrieves an existing quark by name) and returns
// it. The return value is zero (xrm_nullq) if it does not exist. The
// second argument is zero to retrieve only existing quarks, or nonzero if
// it should make a new quark if there isn't an existing quark with the
// given name. If the first argument is null and the second argument is
// nonzero, then it makes a new unique quark. The library makes a copy of
// the passed string if a new quark is made; you need not copy it yourself.

int xrm_merge(xrm_db*to,xrm_db*from,int o);
// Merge the second database into the first one. Returns 0 if success or
// -1 if error. The third argument is zero if the existing resources have
// priority or nonzero if the new ones do.

const char*xrm_name(xrm_quark n);
// Returns the name of the given quark. If there is no such quark, or if
// it is xrm_nullq, or if it has no name, the result is null.

int xrm_put(xrm_db*db,const char*v,int o);
// Set the value of the node. First argument is the node, second argument
// is the value (the library makes a copy of it) or null to delete the
// value, and third argument is nonzero to override an existing value or
// zero to not change an existing value. Returns 0 if successful.

int xrm_put_resource(xrm_db*db,const xrm_quark*q,const char*b,const char*v,int o);
// Set the value of a resource. The second argument is the quark list, the
// third argument is the binding list, the fourth argument is the value,
// and the fifth argument specifies to override or not. The binding list
// is a string containing characters '*' and '.' and must have the same
// length as the quark list.

void*xrm_search(xrm_db*db,const xrm_quark*ns,const xrm_quark*cs,int len,void*(*cb)(xrm_db*,void*),void*usr);
// Perform a search of the given resource database, given the list of
// quarks for name of the query, quarks for class of the query, length of
// the quark lists, a callback function, and the user value for the
// callback function. Both the name and class list must be not null, but
// they may be the same pointer. It calls the callback function for each
// node in priority order, and stops once the callback function returns
// not null, and then xrm_search() returns the same value.

xrm_db*xrm_sub(xrm_db*db,int loose,xrm_quark q);
// Access a child node of the given node. The second argument is zero for
// a tight binding or nonzero for loose. The third is the quark. If no
// such node exists, a new node with no value or children is created.

#endif