4 #@ Parse 'enum okeys' from nail.h and create okeys.h. And see accmacvar.c.
7 # Acceptable "longest distance" from hash-modulo-index to key
8 my $MAXDISTANCE_PENALTY = 5;
14 use diagnostics
-verbose
;
18 use sigtrap
qw(handler cleanup normal-signals);
20 my (@ENTS, $CTOOL, $CTOOL_EXE);
37 die "$CTOOL_EXE: couldn't unlink: $^E"
38 if $CTOOL_EXE && -f
$CTOOL_EXE && 1 != unlink $CTOOL_EXE;
39 die "$CTOOL: couldn't unlink: $^E"
40 if $CTOOL && -f
$CTOOL && 1 != unlink $CTOOL;
41 die "Terminating due to signal $_[0]" if $_[0]
45 die "nail.h: open: $^E" unless open F
, '<', 'nail.h';
48 # Only want the enum okeys content
49 if (/^enum okeys/) {$init = 1; next}
50 if (/^};/) {if ($init) {$init = 2; last}; next}
53 # Ignore empty and comment lines
57 # An entry may have a comment with special directives
58 /^\s*(\w+),?\s*(?:\/\
*\s
*(?
:{(.*)})\s
*\
*\
/\s*)?$/;
59 my ($k, $x) = ($1, $2);
62 $vals{binary
} = ($k =~ /^ok_b/ ?
1 : 0);
63 $k = $1 if $k =~ /^ok_[bv]_(.+)$/;
67 while ($x && $x =~ /^([^,]+?)(?:,(.*))?$/) {
70 die "Unsupported special directive: $1"
71 if ($1 ne 'name' && $1 ne 'rdonly' &&
72 $1 ne 'special' && $1 ne 'virtual');
78 if ($init != 2) {die 'nail.h does not have the expected content'}
83 $CTOOL = './tmp-okey-tool-' . $$ . '.c';
84 $CTOOL_EXE = $CTOOL . '.exe';
86 die "$CTOOL: open: $^E" unless open F
, '>', $CTOOL;
87 # xxx optimize: could read lines and write lines in HASH_MODE..
88 print F
'#define MAX_DISTANCE_PENALTY ', $MAXDISTANCE_PENALTY, "\n";
91 #define __CREATE_OKEY_MAP_PL
98 # define NELEM(A) (sizeof(A) / sizeof(A[0]))
101 #define ui32_t uint32_t
102 #define ui16_t uint16_t
103 #define ui8_t uint8_t
107 VM_BINARY
= 1<<0, /* ok_b_* */
108 VM_RDONLY
= 1<<1, /* May not be set by user */
109 VM_SPECIAL
= 1<<2, /* Wants _var_check_specials() evaluation */
110 VM_VIRTUAL
= 1<<3 /* "Stateless": no var* -- implies VM_RDONLY */
113 /* Binary compatible with struct var! (xxx make it superclass?) */
121 struct var_vx vv_var
;
127 ui16_t vm_flags
; /* var_map_flags bits */
131 /* NOTE: copied over verbatim from auxlily.c */
133 torek_hash
(char const
*name
)
135 /* Chris Torek
's hash.
136 * NOTE: need to change *at least* create-okey-map.pl when changing the
140 while (*name != '\
0') {
148 /* Include what has been written in HASH_MODE */
151 static ui8_t seen_wraparound;
152 static size_t longest_distance;
155 next_prime(size_t no) /* blush (brute force) */
159 for (size_t i = 3; i < no; i += 2)
168 struct var_map const *vmp = _var_map, *vmaxp = vmp + NELEM(_var_map);
169 size_t ldist = 0, *arr;
171 arr = malloc(sizeof *arr * size);
172 for (size_t i = 0; i < size; ++i)
173 arr[i] = NELEM(_var_map);
176 longest_distance = 0;
178 while (vmp < vmaxp) {
179 ui32_t hash = vmp->vm_hash, i = hash % size, l;
181 for (l = 0; arr[i] != NELEM(_var_map); ++l)
186 if (l > longest_distance)
187 longest_distance = l;
188 arr[i] = (size_t)(vmp++ - _var_map);
192 #endif /* !HASH_MODE */
195 main(int argc, char **argv)
198 size_t h = torek_hash(argv[1]);
200 printf("%lu\n", (unsigned long)h);
203 size_t *arr, size = NELEM(_var_map);
205 fprintf(stderr, "Starting reversy, okeys=%zu\n", size);
207 arr = reversy(size = next_prime(size));
208 fprintf(stderr, " - size=%zu longest_distance=%zu seen_wraparound=%d\n",
209 size, longest_distance, seen_wraparound);
210 if (longest_distance <= MAX_DISTANCE_PENALTY)
216 "#define _VAR_REV_ILL %zuu\n"
217 "#define _VAR_REV_PRIME %zuu\n"
218 "#define _VAR_REV_LONGEST %zuu\n"
219 "#define _VAR_REV_WRAPAROUND %d\n"
220 "static %s const _var_revmap[_VAR_REV_PRIME] = {\n ",
221 NELEM(_var_map), size, longest_distance, seen_wraparound, argv[1]);
222 for (size_t i = 0; i < size; ++i)
223 printf("%s%zuu", (i == 0 ? "" : (i % 10 == 0 ? ",\n " : ", ")), arr[i]);
229 # <<<<<<<<<<<<<<<<<<<
234 system("c99 -DHASH_MODE -I. -o $CTOOL_EXE $CTOOL");
236 foreach my $e (@ENTS) {
237 my $h = `$CTOOL_EXE $e->{name}`;
243 sub dump_keydat_varmap {
244 die "$OUT: open: $^E" unless open F, '>', $OUT;
245 print F "/*@ $OUT, generated by $0 on ", scalar gmtime(), ".\n",
246 " *@ See accmacvar.c for more */\n\n";
248 print F 'static char const _var_keydat
[] = {', "\n";
249 my ($i, $alen) = (0, 0);
251 foreach my $e (@ENTS) {
252 $e->{keyoff} = $alen;
255 my $a = join '\',\'', split(//, $k);
256 my ($f, $s) = ('', ', ');
257 if ($e->{binary}) {$f .= $s . 'VM_BINARY
'; $s = ' | '}
258 if ($e->{rdonly}) {$f .= $s . 'VM_RDONLY
'; $s = ' | '}
259 if ($e->{special}) {$f .= $s . 'VM_SPECIAL
'; $s = ' | '}
261 die("*$k*: virtual MUST be rdonly, too!") unless $e->{rdonly};
262 $f .= $s . 'VM_VIRTUAL
'; $s = ' | ';
265 print F " /* $i. [$alen]+$l $k$f */\n", " '$a','\\0',\n";
269 print F '};', "\n\n";
271 print F 'static struct var_map const _var_map
[] = {', "\n";
272 foreach my $e (@ENTS) {
274 $f .= ' | VM_BINARY
' if $e->{binary};
275 $f .= ' | VM_RDONLY
' if $e->{rdonly};
276 $f .= ' | VM_SPECIAL
' if $e->{special};
277 $f .= ' | VM_VIRTUAL
' if $e->{virtual};
278 my $n = $1 if $e->{enum} =~ /ok_._(.*)/;
279 print F " {$e->{hash}u, $e->{keyoff}u, $f}, /* $n */\n"
281 print F '};', "\n\n";
283 # We have at least version stuff in here
284 # The problem is that struct var uses a variable sized character buffer
285 # which cannot be initialized in a conforming way :(
286 print F "#ifndef __CREATE_OKEY_MAP_PL\n";
287 print F " /* Unfortunately init of varsized buffer won't work
*/\n";
288 foreach my $k (keys %virts) {
290 $e->{vname} = $1 if $e->{enum} =~ /ok_._(.*)/;
291 $e->{vstruct} = "var_virt_
$e->{vname
}";
292 print F "static struct
{\n";
293 print F " struct var
*v_link
;\n";
294 print F " char const
*v_value
;\n";
295 print F " char const v_name
[", length($e->{name}), " +1];\n";
296 print F "} const _
$e->{vstruct
} = ",
297 "{NULL
, $e->{virtual
}, \"$e->{name
}\"};\n\n";
300 print F 'static struct var_virtual const _var_virtuals[] = {', "\n";
301 foreach my $k (keys %virts) {
303 my $n = $1 if $e->{enum} =~ /ok_._(.*)/;
304 print F " {$e->{enum
}, (void const
*)&_
$e->{vstruct
}},\n";
306 print F "};\n#endif /* __CREATE_OKEY_MAP_PL */\n\n";
308 die "$OUT: close: $^E" unless close F
312 system("c99 -I. -o $CTOOL_EXE $CTOOL");
313 my $t = (@ENTS < 0xFF ?
'ui8_t' : (@ENTS < 0xFFFF ?
'ui16_t' : 'ui32_t'));
314 `$CTOOL_EXE $t >> $OUT`
317 {package main
; main_fun
()}