ldb speed test - needs free block dev
[tridge/junkcode.git] / wspp_bits.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <getopt.h>
5 #include <ctype.h>
6
7 /*
8   I'm desperate ... an attempt to create C #defines from WSPP bitmaps
9
10   This takes a text bitmap from WSPP on stdin and produces C defines
11   on stdout
12
13 Here is an example from MS-DRSR section 5.37
14
15   0    1    2   3   4   5   6   7   8   9 10 1      2   3   4   5   6   7   8   9 20 1      2   3   4   5   6   7   8   9 30 1
16
17
18   A    G A      A W     I   P   M   A   T   C   G G     X   S   F   X   F   X   X   R   X   X   S   X   S   D   D   U N      S   G
19
20   S    C    R   L   R   S   S   R   S   S   O   A   S       N   S       S           G           S       F   A   P   C   N    P   P
21
22                 L                   R               /       /   /       P                                   S   S
23
24                 /                   /               L       R   N
25
26                 D                   I               O       F   S
27
28                 R                   E
29
30
31  X: Unused. MUST be zero and ignored.
32
33  AS (DRS_ASYNC_OP): Perform the operation asynchronously.
34
35  GC (DRS_GETCHG_CHECK): Treat ERROR_DS_DRA_REF_NOT_FOUND and
36  ERROR_DS_DRA_REF_ALREADY_EXISTS as success for calls to IDL_DRSUpdateRefs (section
37  4.1.26).
38
39  AR (DRS_ADD_REF): Register a client DC for notifications of updates to the NC replica.
40
41  ALL (DRS_SYNC_ALL): Replicate from all server DCs.
42
43  DR (DRS_DEL_REF): Deregister a client DC from notifications of updates to the NC replica.
44
45  WR (DRS_WRIT_REP): Replicate a writable replica, not a read-only partial replica or read-only full
46  replica.
47
48  IS (DRS_INIT_SYNC): Perform replication at startup.
49
50  PS (DRS_PER_SYNC): Perform replication periodically.
51
52  MR (DRS_MAIL_REP): Perform replication using SMTP as a transport.
53
54  ASR (DRS_ASYNC_REP): Populate the NC replica asynchronously.
55
56  IE (DRS_IGNORE_ERROR): Ignore errors.
57
58  TS (DRS_TWOWAY_SYNC): Inform the server DC to replicate from the client DC.
59
60  CO (DRS_CRITICAL_ONLY): Replicate only system-critical objects.
61
62  GA (DRS_GET_ANC): Include updates to ancestor objects before updates to their descendants.
63
64  GS (DRS_GET_NC_SIZE): Get the approximate size of the server NC replica.
65
66  LO (DRS_LOCAL_ONLY): Perform the operation locally without contacting any other DC.
67
68  SN (DRS_SYNC_BYNAME): Choose the source server by network name.
69
70  RF (DRS_REF_OK): Allow the NC replica to be removed even if other DCs use this DC as a
71  replication server DC.
72
73  FS (DRS_FULL_SYNC_NOW): Replicate all updates in the replication cycle, even those that would
74  normally be filtered.
75
76  NS (DRS_NO_SOURCE): The NC replica has no server DCs.
77
78  FSP (DRS_FULL_SYNC_PACKET): Replicate all updates in the replication request, even those that
79  would normally be filtered.
80
81  RG (DRS_REF_GCSPN): Requests that the server add an entry to repsTo for the client on the root
82  object of the NC replica that is being replicated. When repsTo is set using this flag, the server
83  contacts the client using GC SPN (section 2.2.3.2).
84
85  SS (DRS_SPECIAL_SECRET_PROCESSING): Do not replicate attribute values of attributes that
86  contain secret data.
87
88  SF (DRS_SYNC_FORCED): Force replication, even if the replication system is otherwise disabled.
89
90  DAS (DRS_DISABLE_AUTO_SYNC): Disable replication induced by update notifications.
91
92  DPS (DRS_DISABLE_PERIODIC_SYNC): Disable periodic replication.
93
94  UC (DRS_USE_COMPRESSION): Compress response messages.
95
96  NN (DRS_NEVER_NOTIFY): Do not send update notifications.
97
98  SP (DRS_SYNC_PAS): Expand the partial attribute set of the partial replica.
99
100  GP (DRS_GET_ALL_GROUP_MEMBERSHIP): Replicate all kinds of group membership. If this flag
101  is not present nonuniversal group membership will not be replicated.
102
103 I got the above from "pdftotext -layout [MS-DRSR].pdf"
104
105 This will produce:
106
107 #define BIT_DRS_ASYNC_OP                  0x00000001
108 #define BIT_DRS_GETCHG_CHECK              0x00000002
109 #define BIT_DRS_ADD_REF                   0x00000004
110 #define BIT_DRS_SYNC_ALL                  0x00000008
111 #define BIT_DRS_DEL_REF                   0x00000008
112 #define BIT_DRS_WRIT_REP                  0x00000010
113 #define BIT_DRS_INIT_SYNC                 0x00000020
114 #define BIT_DRS_PER_SYNC                  0x00000040
115 #define BIT_DRS_MAIL_REP                  0x00000080
116 #define BIT_DRS_ASYNC_REP                 0x00000100
117 #define BIT_DRS_IGNORE_ERROR              0x00000100
118 #define BIT_DRS_TWOWAY_SYNC               0x00000200
119 #define BIT_DRS_CRITICAL_ONLY             0x00000400
120 #define BIT_DRS_GET_ANC                   0x00000800
121 #define BIT_DRS_GET_NC_SIZE               0x00001000
122 #define BIT_DRS_LOCAL_ONLY                0x00001000
123 #define BIT_DRS_SYNC_BYNAME               0x00004000
124 #define BIT_DRS_REF_OK                    0x00004000
125 #define BIT_DRS_FULL_SYNC_NOW             0x00008000
126 #define BIT_DRS_NO_SOURCE                 0x00008000
127 #define BIT_DRS_FULL_SYNC_PACKET          0x00020000
128 #define BIT_DRS_REF_GCSPN                 0x00100000
129 #define BIT_DRS_SPECIAL_SECRET_PROCESSING 0x00800000
130 #define BIT_DRS_SYNC_FORCED               0x02000000
131 #define BIT_DRS_DISABLE_AUTO_SYNC         0x04000000
132 #define BIT_DRS_DISABLE_PERIODIC_SYNC     0x08000000
133 #define BIT_DRS_USE_COMPRESSION           0x10000000
134 #define BIT_DRS_NEVER_NOTIFY              0x20000000
135 #define BIT_DRS_SYNC_PAS                  0x40000000
136 #define BIT_DRS_GET_ALL_GROUP_MEMBERSHIP  0x80000000
137
138 */
139
140 static int line_num;
141 static int verbose;
142
143 #define MAX_MAPPINGS 100
144 static int num_mappings;
145 static struct {
146         const char *short_form;
147         const char *long_form;
148 } mappings[MAX_MAPPINGS];
149 static int longest_mapping;
150
151 static void add_mapping(char *line)
152 {
153         char *p;
154         
155         if (num_mappings == MAX_MAPPINGS) {
156                 printf("/* (%d) too many mappings! */\n", line_num);
157                 exit(1);
158         }
159
160         p = strchr(line, ':');
161         if (p == NULL) return;
162         *p = 0;
163         p = strchr(line, '(');
164         if (p == NULL) return;
165         *p = 0;
166         mappings[num_mappings].long_form = strdup(p+1);
167         for (p=line; isspace(*p); p++) ;
168         mappings[num_mappings].short_form = strdup(p);
169         p = strchr(mappings[num_mappings].long_form, ')');
170         if (p == NULL) return;
171         *p = 0;
172
173         p = strchr(mappings[num_mappings].short_form, ' ');
174         if (p == NULL) return;
175         *p = 0;
176
177         if (strlen(mappings[num_mappings].long_form) > longest_mapping) {
178                 longest_mapping = strlen(mappings[num_mappings].long_form);
179         }
180
181         num_mappings++; 
182 }
183
184 static const char *map_name(const char *s)
185 {
186         int i;
187         for (i=0; i<num_mappings; i++) {
188                 if (strcmp(s, mappings[i].short_form) == 0) {
189                         return mappings[i].long_form;
190                 }
191         }
192         return s;
193 }
194
195 static char *remove_spaces(const char *s)
196 {
197         char *ret = strdup(s);
198         int i=0;
199         while (*s) {
200                 if (!isspace(*s)) {
201                         ret[i++] = *s;
202                 }
203                 s++;
204         }
205         return ret;
206 }
207
208 #define MAX_LINES 50
209 #define MAX_WIDTH 200
210
211 static int nlines = 0;
212 static char lines[MAX_LINES][MAX_WIDTH];
213
214 static void report(void)
215 {
216         int i;
217         printf("/*\n");
218         for (i=0; i<nlines; i++) {
219                 printf("   line[%d]: %s\n", i, lines[i]);
220         }
221         printf("*/\n");
222 }
223
224 static void fatal(void)
225 {
226         printf("/* fatal error on line %d\n", line_num);
227         report();
228         exit(1);
229 }
230
231 static void shift_it(int lnum, int to, int from)
232 {
233         int i;
234
235         for (i=lnum; i<nlines; i++) {
236                 if (lines[i][from] == ' ') break;
237                 if (lines[i][to] != ' ') {
238                         printf("/* (line %d) Non-empty to position at line %d posn %d\n */", line_num, i, to);
239                         fatal();
240                 }
241                 lines[i][to] = lines[i][from];
242                 lines[i][from] = ' ';
243         }
244 }
245
246 /*
247   try to detect section boundaries
248  */
249 int section_start(const char *line)
250 {
251         char *p;
252         if (!isdigit(line[0])) return 0;
253         p = strchr(line, ' ');
254         if (!p) return 0;
255         if (strspn(line, "0123456789.") != (p-line)) return 0;
256         return 1;       
257 }
258
259 static const char *prefix = "BIT_";
260 static int idl_format = 0;
261 static int little_endian = 0;
262 static int big_endian = 0;
263 static int auto_endian = 0;
264
265 static int process_bitmap(const char *comment, FILE *f, char **next_section)
266 {
267         char *p;
268         int i, lnum;
269         int max_len = 0;
270         int bitpos;
271         int in_mappings = 0;
272         int more_sections = 0;
273         int this_one_little_endian = little_endian;
274         int this_one_big_endian = big_endian;
275
276         memset(lines, 0, sizeof(lines));
277         num_mappings = 0;
278         nlines = 0;
279         longest_mapping = 0;
280
281         while (fgets(lines[nlines], MAX_WIDTH-1, f)) {
282                 char *line = lines[nlines];
283                 int dummy;
284
285                 line_num++;
286
287                 if (line[strlen(line)-1] == '\n') {
288                         line[strlen(line)-1] = 0;
289                 }
290                 if (line[0] == 0xC) {
291                         memmove(&line[0], &line[1], strlen(line));
292                 }
293
294                 if (section_start(line)) {
295                         /* a new section */
296                         (*next_section) = strdup(line);
297                         more_sections = 1;
298                         break;
299                 }
300
301                 if (auto_endian &&
302                     strstr(line, "little-endian byte order")) {
303                         this_one_little_endian = 1;
304                 }
305
306                 if (auto_endian &&
307                     strstr(line, "big-endian byte order")) {
308                         this_one_big_endian = 1;
309                 }
310
311                 if (nlines == 0) {
312                         /* discard preamble lines */
313                         if (strncmp(remove_spaces(line), "0123456789", 10) != 0) {
314                                 continue;
315                         }
316                 }
317
318                 if (sscanf(line, "%u / %u", &dummy, &dummy) == 2) {
319                         continue;
320                 }
321
322                 /* detect the start of the descriptions */
323                 for (i=0; line[i]; i++) {
324                         if (line[i] != ' ' &&
325                             !isdigit(line[i]) &&
326                             !isupper(line[i]) &&
327                             line[i] != '/') {
328                                 in_mappings = 1;
329                                 break;
330                         }
331                 }
332
333                 if (in_mappings) {
334                         add_mapping(line);
335                         continue;
336                 }
337
338                 /* some bitmaps contain 10/20/30 instead of 0 */
339                 if ((p = strstr(line, "10 "))) {
340                         p[0] = ' ';
341                 }
342                 if ((p = strstr(line, "20 "))) {
343                         p[0] = ' ';
344                 }
345                 if ((p = strstr(line, "30 "))) {
346                         p[0] = ' ';
347                 }
348                 /* discard empty lines */
349                 if (strlen(line) > 0) {
350                         nlines++;
351                         if (strlen(line) > max_len) {
352                                 max_len = strlen(line);
353                         }
354                 }
355         }
356
357         if (nlines < 2) {
358                 return more_sections;
359         }
360
361         /* pad lines with spaces if needed */
362         for (i=0; i<nlines; i++) {
363                 if (strlen(lines[i]) < max_len) {
364                         memset(&lines[i][strlen(lines[i])], ' ', max_len - strlen(lines[i]));
365                 }
366         }
367
368         /* normalise the 2nd line */
369         for (i=0; lines[0][i]; i++) {
370                 int tpos;
371
372                 if (lines[0][i] == ' ' && lines[1][i] == ' ') continue;
373
374                 if (lines[0][i] != ' ' && lines[1][i] != ' ') {
375                         /* already aligned */
376                         continue;
377                 }
378
379                 if (lines[0][i] == ' ') {
380                         /* we need to shift the next digit left */
381                         for (tpos = i+1; tpos<max_len; tpos++) {
382                                 if (lines[0][tpos] != ' ') {
383                                         break;
384                                 }
385                         }
386                         if (tpos == max_len) {
387                                 printf("/* (line %d) no digit match at pos %d */\n", line_num, i);
388                                 report();
389                                 return more_sections;
390                         }
391                         lines[0][i] = lines[0][tpos];
392                         lines[0][tpos] = ' ';
393                         continue;
394                 }
395
396                 /* now we need to look for the missing tag either to
397                  * the left or right. Try left first */
398                 for (tpos = i-1; tpos>=0; tpos--) {
399                         if (lines[0][tpos] != ' ') {
400                                 /* already taken - give up going left */
401                                 goto try_right;
402                         }
403                         if (lines[1][tpos] != ' ') {
404                                 break;
405                         }
406                 }
407                 if (tpos >= 0) {
408                         shift_it(1, i, tpos);
409                         continue;
410                 }
411 try_right:
412                 for (tpos = i+1; tpos<max_len; tpos++) {
413                         if (lines[1][tpos] != ' ') {
414                                 break;
415                         }
416                 }
417                 if (tpos < max_len) {
418                         shift_it(1, i, tpos);
419                         continue;
420                 } else {
421                         printf("/* (line %d) No match at position %d of line 1 */\n", line_num, i);
422                         report();
423                         return more_sections;
424                 }
425         }
426
427         /* normalise the subsequent lines */
428         for (lnum=2; lnum<nlines; lnum++) {
429                 for (i=0; lines[0][i]; i++) {
430                         int tpos;
431                         if (lines[0][i] == ' ' && lines[lnum][i] != ' ') {
432                                 /* a little lost character ... try to
433                                    find it a home */
434                                 for (tpos = i-1; tpos>=0; tpos--) {
435                                         if (lines[lnum][tpos] != ' ') {
436                                                 /* already taken - give up going left */
437                                                 break;
438                                         }
439                                         if (lines[0][tpos] != ' ') {
440                                                 break;
441                                         }
442                                 }
443                                 if (tpos >= 0 && lines[lnum][tpos] == ' ') {
444                                         shift_it(lnum, tpos, i);
445                                         continue;
446                                 }
447                                 for (tpos = i+1; tpos<max_len; tpos++) {
448                                         if (lines[0][tpos] != ' ') {
449                                                 break;
450                                         }
451                                 }
452                                 if (tpos < max_len) {
453                                         if (lines[lnum][tpos] != ' ') {
454                                                 if (lines[lnum][tpos+1] == ' ') {
455                                                         shift_it(lnum, tpos+1, tpos);
456                                                 }
457                                         }
458                                         if (lines[lnum][tpos] == ' ') {
459                                                 shift_it(lnum, tpos, i);
460                                                 continue;
461                                         }
462                                 }
463                                 printf("/* (line %d) Nowhere to put character '%c' at pos %d of subline %d */\n", 
464                                        line_num, lines[lnum][i], i, lnum);
465                                 report();
466                                 return more_sections;
467                         }
468                 }
469         }
470
471         if (verbose) {
472                 printf("/* (line %d): \n", line_num); 
473                 for (i=0; i<nlines; i++) {
474                         printf("   line[%d]: %s\n", i, lines[i]);
475                 }
476                 printf("*/\n");
477         }
478
479         /* print the bits */
480         bitpos = 0;
481         if (comment) {
482                 printf("/* %s */\n", comment);
483         }
484         for (i=0; lines[0][i]; i++) {
485                 int n;
486                 char name[MAX_LINES+1] = "";
487                 char *t;
488
489                 if (lines[0][i] == ' ') continue;
490                 for (n=1; n<nlines; n++) {
491                         if (lines[n][i] == ' ') break;
492                         name[n-1] = lines[n][i];
493                 }
494                 for (t = strtok(name, "/"); t; t=strtok(NULL, "/")) {
495                         const char *mapped_name = map_name(t);
496                         unsigned value;
497
498                         if (this_one_little_endian) {
499                                 int bpos, bnum = bitpos/8;
500                                 bpos = (bnum*8) + (7 - (bitpos%8));
501                                 value = (1U<<bpos);
502                         } else if (this_one_big_endian) {
503                                 value = (1U<<(31-bitpos));
504                         } else {
505                                 value = (1U<<bitpos);
506                         }
507                         if (strcmp(t, "X") == 0 || strcmp(t, "0") == 0) continue;
508                         if (idl_format) {
509                                 printf("%s%-*s = 0x%08x,\n", prefix, longest_mapping, mapped_name, value);
510                         } else {
511                                 printf("#define %s%-*s 0x%08x\n", prefix, longest_mapping, mapped_name, value);
512                         }
513                 }
514                 bitpos++;
515         }
516         printf("\n");
517
518         return more_sections;
519 }
520
521
522 static void usage(void)
523 {
524         printf("wspp_bits [options] <file>\n");
525         printf("Options:\n");
526         printf("\t-i           use IDL bitmap format\n");
527         printf("\t-L           use little-endian bit order\n");
528         printf("\t-A           attempt to auto-detect endianness\n");
529         printf("\t-p PREFIX    use the given prefix\n");
530         printf("\t-v           increase verbosity\n");
531 }
532
533 int main(int argc, char * const argv[])
534 {
535         int opt;
536         FILE *f;
537         char *sect_name = NULL;
538
539         while ((opt = getopt(argc, argv, "vip:ALBh")) != -1) {
540                 switch (opt) {
541                 case 'p':
542                         prefix = optarg;
543                         break;
544                 case 'i':
545                         idl_format = 1;
546                         break;
547                 case 'v':
548                         verbose++;
549                         break;
550                 case 'L':
551                         little_endian = 1;
552                         break;
553                 case 'B':
554                         big_endian = 1;
555                         break;
556                 case 'A':
557                         auto_endian = 1;
558                         break;
559                 default:
560                         usage();
561                         exit(1);
562                 }
563         }
564
565         argv += optind;
566         argc -= optind;
567
568         if (argc < 1) {
569                 f = stdin;
570         } else {
571                 f = fopen(argv[0], "r");
572                 if (f == NULL) {
573                         perror(argv[0]);
574                         exit(1);
575                 }
576         }
577
578         while (process_bitmap(sect_name, f, &sect_name)) ;
579
580         return 0;
581 }