~ubuntu-branches/ubuntu/wily/maradns/wily-proposed

« back to all changes in this revision

Viewing changes to deadwood-3.2.05/src/DwMararc.c

  • Committer: Package Import Robot
  • Author(s): Dariusz Dwornikowski, Tomasz Buchert, Dariusz Dwornikowski
  • Date: 2015-03-27 18:34:08 UTC
  • mfrom: (1.2.12)
  • Revision ID: package-import@ubuntu.com-20150327183408-wnfachdkdjt96yu6
Tags: 2.0.11-1
[ Tomasz Buchert ]
* Imported Upstream version 2.0.11

[ Dariusz Dwornikowski ]
* d/patches: 
  - refreshed all patches for new deadwood version
  - removed generating of random prime on build (Closes: #785536) 
* d/rules: date taken from changelog (Closes: #785535)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2007-2012 Sam Trenholme
2
 
 *
3
 
 * TERMS
4
 
 *
5
 
 * Redistribution and use in source and binary forms, with or without
6
 
 * modification, are permitted provided that the following conditions
7
 
 * are met:
8
 
 *
9
 
 * 1. Redistributions of source code must retain the above copyright
10
 
 *    notice, this list of conditions and the following disclaimer.
11
 
 * 2. Redistributions in binary form must reproduce the above copyright
12
 
 *    notice, this list of conditions and the following disclaimer in the
13
 
 *    documentation and/or other materials provided with the distribution.
14
 
 *
15
 
 * This software is provided 'as is' with no guarantees of correctness or
16
 
 * fitness for purpose.
17
 
 */
18
 
 
19
 
#define MARARC_C
20
 
#include "DwMararc.h"
21
 
#include "DwStr.h"
22
 
#include "DwSys.h"
23
 
#include "DwStr_functions.h"
24
 
#include <stdint.h>
25
 
#include <stdio.h>
26
 
 
27
 
dwm_fs fsm[DWM_MAX_STATES + 1]; /* Finite state machine */
28
 
char *fsm_desc=dwm_machine;
29
 
 
30
 
int dwm_linenum = 0;
31
 
 
32
 
int dwm_file_depth = 0; /* How many files we're nested in */
33
 
 
34
 
/* Set the new fsm state for a given pattern seen in a given fsm state
35
 
 * Input: c: Pointer to string with FSM description (pointing to the
36
 
 *           character we are currently parsing)
37
 
 *        d: The action number for this state that we are processing
38
 
 *        state: The state we are processing
39
 
 * Output: A revised pointer to the FSM description */
40
 
char *dwm_set_newstate(char *c, int d, int32_t state) {
41
 
        if(*c < 'a' || *c > 'z') {
42
 
                return 0;
43
 
        }
44
 
        /* If the state starts with x, it's an "expanded" state, with a
45
 
         * two-letter name like "xa", "xc", "xp", or "xz" */
46
 
        if(*c == 'x') {
47
 
                c++;
48
 
                if(*c < 'a' || *c > 'z') {
49
 
                        return 0;
50
 
                }
51
 
                fsm[state].newstate[d] = *c - 'a' + 26;
52
 
        } else {
53
 
                fsm[state].newstate[d] = *c - 'a';
54
 
        }
55
 
        c++;
56
 
        return c;
57
 
}
58
 
 
59
 
/* Set the action for a given pattern in a given fsm state
60
 
 * Input: c: Pointer to string with FSM description (pointing to the
61
 
 *           character we are currently parsing)
62
 
 *        max: How far we are in the current line (bounds checker)
63
 
 *        d: The action number for this state that we are processing
64
 
 *        state: The state we are processing
65
 
 * Output: A revised pointer to the FSM description */
66
 
char *dwm_set_action(char *c, int max, int d, int32_t state) {
67
 
        int b = 0;
68
 
        if(*c == ';') {
69
 
                fsm[state].action[d] = 10; /* Terminate with success */
70
 
                fsm[state].newstate[d] = 0;
71
 
                c++;
72
 
                max++;
73
 
                if(max > 52) {
74
 
                        return 0;
75
 
                }
76
 
                return c;
77
 
        } else {
78
 
                b = *c - '0';
79
 
                if(b < 1 || b > 9) {
80
 
                        return 0;
81
 
                }
82
 
                fsm[state].action[d] = b;
83
 
        }
84
 
        c++;
85
 
        max++;
86
 
        if(max >= 52) {
87
 
                return 0;
88
 
        }
89
 
        return dwm_set_newstate(c,d,state);
90
 
}
91
 
 
92
 
/* Convert a one-character FSM class in to a number we put in to
93
 
 * the tokenized FSM machine */
94
 
char dwm_pattern_process(int b) {
95
 
        /* We don't allow literal hashes or quotes in the FSM definition */
96
 
        if(b == '#' || b == '"') {
97
 
                return 0;
98
 
        }
99
 
        /* H becomes a hash symbol (so a FSM definition can have comments) */
100
 
        if(b == 'H') {
101
 
                b = '#';
102
 
        }
103
 
        /* Q becomes a " symbol (so we don't have ugly escape quoted sequences
104
 
         * in the FSM definition) */
105
 
        if(b == 'Q') {
106
 
                b = '"';
107
 
        }
108
 
        /* Make letter shortcuts non-printable ASCII control characters */
109
 
        if(b >= 'A' && b <= 'Z') {
110
 
                b = b - '@'; /* '@' is 'A' - 1 in ASCII */
111
 
        }
112
 
        return b;
113
 
}
114
 
 
115
 
/* Set a single state in the finite state machine */
116
 
char *dwm_set_fsm(int32_t state, char *c, int max) {
117
 
        int b = 0 , d = 0;
118
 
 
119
 
        for(; max<52; max++) {
120
 
 
121
 
                /* First letter: pattern */
122
 
                b = *c;
123
 
                if(b < '!' || b > '~') {
124
 
                        return 0;
125
 
                }
126
 
                fsm[state].pattern[d] = dwm_pattern_process(b);
127
 
 
128
 
                /* Second latter: action -or- next state */
129
 
                c++;
130
 
                max++;
131
 
                if(*c >= 'a' && *c <= 'z') {
132
 
                        fsm[state].action[d] = 0;
133
 
                        c = dwm_set_newstate(c,d,state);
134
 
                } else {
135
 
                        c = dwm_set_action(c,max,d,state);
136
 
                }
137
 
 
138
 
                /* Sanity check */
139
 
                if(c == 0) {
140
 
                        return 0;
141
 
                }
142
 
 
143
 
                /* Advance past whitespace between patterns/actions */
144
 
                while(*c == ' ') {
145
 
                        c++;
146
 
                        max++;
147
 
                        if(max >= 52) {
148
 
                                return 0;
149
 
                        }
150
 
                }
151
 
 
152
 
                if(*c == '\r' || *c == '\n') { /* Newline ends a state */
153
 
                        return c;
154
 
                }
155
 
                d++;
156
 
                if(d >= DWM_MAX_PATTERNS - 1) { /* Bounds checking */
157
 
                        return 0;
158
 
                }
159
 
        }
160
 
        return 0;
161
 
}
162
 
 
163
 
/* Tokenize a single line describing the finite state machine */
164
 
char *dwm_tokenize_line(char *c) {
165
 
        int b = 0;
166
 
        int max = 0;
167
 
 
168
 
        /* The first character of a line is the state we are describing */
169
 
        if(*c < 'a' || *c > 'z') {
170
 
                return 0;
171
 
        }
172
 
        /* If the first character happens to be an 'x', the state description
173
 
         * is two letters long in a form like "xa", "xb", and so on */
174
 
        if(*c == 'x') {
175
 
                c++;
176
 
                max++;
177
 
                if(*c < 'a' || *c > 'z') {
178
 
                        return 0;
179
 
                }
180
 
                b = *c - 'a' + 26;
181
 
        } else {
182
 
                b = *c - 'a';
183
 
        }
184
 
        if(b < 0 || b > DWM_MAX_STATES - 1) {
185
 
                return 0;
186
 
        }
187
 
        /* OK, now move forward to see the first pattern description */
188
 
        c++;
189
 
        if(*c != ' ') {
190
 
                return 0;
191
 
        }
192
 
        while(*c == ' ' && max < 52) {
193
 
                c++;
194
 
                max++;
195
 
        }
196
 
        if(max >= 52) {
197
 
                return 0;
198
 
        }
199
 
        /* dwm_set_fsm sets how we react to various patterns when in this
200
 
         * state */
201
 
        c = dwm_set_fsm(b,c,max);
202
 
        if(c == 0) {
203
 
                return 0;
204
 
        }
205
 
        if(*c != '\r' && *c != '\n') {
206
 
                return 0;
207
 
        }
208
 
        c++;
209
 
        return c;
210
 
}
211
 
 
212
 
/* Initialize the finite state machine based on the vales set in the
213
 
 * dwm_machine constant (which is set in DwMararc.h) */
214
 
void dwm_init_fsm() {
215
 
        char *c = 0;
216
 
        int a = 0;
217
 
        int b = 0;
218
 
 
219
 
        /* First, we zero it out */
220
 
        for(a=0;a<DWM_MAX_STATES;a++) {
221
 
                for(b=0;b<DWM_MAX_PATTERNS;b++) {
222
 
                        fsm[a].pattern[b] = 0;
223
 
                        fsm[a].action[b] = 0;
224
 
                        fsm[a].newstate[b] = 0;
225
 
                }
226
 
        }
227
 
 
228
 
        /* Now, we look at the defined fsm and tokenize it */
229
 
        c=fsm_desc;
230
 
        b=0;
231
 
        for(a=0;a<DWM_MAX_STATES;a++) {
232
 
                c = dwm_tokenize_line(c);
233
 
                /* Error */
234
 
                if(c == 0) {
235
 
                        return;
236
 
                }
237
 
                /* Success */
238
 
                if(*c == 0) {
239
 
                        return;
240
 
                }
241
 
        }
242
 
}
243
 
 
244
 
/* Fatal error while parsing Mararc file */
245
 
void dwm_fatal(char *why) {
246
 
        dw_alog_number("Fatal error in dwood3rc file on line ",dwm_linenum,
247
 
                why);
248
 
        exit(1);
249
 
}
250
 
 
251
 
/* Given an input character, and a character class (a number from one
252
 
 * to 32), return -1 if we don't match, 1 if we do match */
253
 
int dwm_char_class(int32_t in, int cclass) {
254
 
        /* In order to save space, we use this C bit of messyness:
255
 
         * condition ? true : false
256
 
         * This is normally against coding style; we do it so the function
257
 
         * fits within the 52-line-per-function limit */
258
 
        switch(cclass) {
259
 
                case 1: /* A-Za-z_ */
260
 
                        return dwm_is_alpha(in) ? 1 : -1;
261
 
 
262
 
                case 2: /* A-Za-z0-9_ */
263
 
                        return dwm_is_alphanum(in) ? 1 : -1;
264
 
 
265
 
                case 4: /* A-Za-z0-9_- */
266
 
                        return dwm_is_dname(in) ? 1 : -1;
267
 
 
268
 
                case 9: /* printable ASCII except # and " */
269
 
                        return dwm_is_instring(in) ? 1 : -1;
270
 
 
271
 
                case 14: /* 0-9 */
272
 
                        return dwm_is_number(in) ? 1 : -1;
273
 
 
274
 
                case 18: /* \r */
275
 
                        return (in == '\r') ? 1 : -1;
276
 
 
277
 
                case 19: /* A-Za-z0-9 */
278
 
                        return dwm_is_dnamestart(in) ? 1 : -1;
279
 
 
280
 
                case 20: /* \n */
281
 
                        return (in == '\n') ? 1 : -1;
282
 
 
283
 
                case 23: /* ' ' or \t */
284
 
                        return dwm_is_whitespace(in) ? 1 : -1;
285
 
 
286
 
                case 24: /* printable ASCII/hi-bit or \t */
287
 
                        return dwm_is_any(in) ? 1 : -1;
288
 
 
289
 
                case 25: /* A-Za-z */
290
 
                        return dwm_is_alphastart(in) ? 1 : -1;
291
 
 
292
 
                default:
293
 
                        return -1;
294
 
        }
295
 
}
296
 
 
297
 
/* Given an input character, and a state, return an action (upper 16 bits)
298
 
 * and a new state (lower 16 bits).
299
 
 * Input: An input character and a current state
300
 
 * Output: ((action << 16) | newstate) or -1 on error */
301
 
int32_t dwm_process_character(int32_t in, int32_t state) {
302
 
        uint16_t action = 0;
303
 
        uint16_t newstate = 0;
304
 
        int32_t match = -1;
305
 
        int a = 0, b = 0;
306
 
 
307
 
        /* Sanity checks */
308
 
        if(state >= DWM_MAX_STATES) {
309
 
                return -1;
310
 
        }
311
 
 
312
 
        if(fsm[state].pattern[0] == 0) { /* Invalid state */
313
 
                return -1;
314
 
        }
315
 
 
316
 
        for(a=0;a<DWM_MAX_PATTERNS && fsm[state].pattern[a] != 0;a++) {
317
 
                b = fsm[state].pattern[a];
318
 
                if(b == 0) {
319
 
                        return -1;
320
 
                /* patterns between 1 and 32 are multi-character classes,
321
 
                 * such as "letters" */
322
 
                } else if(b < 32) {
323
 
                        match = dwm_char_class(in,b);
324
 
                /* Higher numbered "patterns" are one-character patterns,
325
 
                 * with the value of the character being the ASCII character
326
 
                 * we match against */
327
 
                } else {
328
 
                        if(in == b) {
329
 
                                match = 1;
330
 
                        } else {
331
 
                                match = -1;
332
 
                        }
333
 
                }
334
 
                if(match == 1) {
335
 
                        action = fsm[state].action[a];
336
 
                        newstate = fsm[state].newstate[a];
337
 
                        break;
338
 
                }
339
 
        }
340
 
 
341
 
        if(fsm[state].pattern[a] == 0) { /* Invalid state */
342
 
                return -1;
343
 
        }
344
 
 
345
 
        if(newstate >= DWM_MAX_STATES || action > 4096) {
346
 
                return -1;
347
 
        }
348
 
 
349
 
        return (action << 16) | newstate;
350
 
}
351
 
 
352
 
/* Initialize the Mararc parameters */
353
 
 
354
 
/* Initialize the data used to store MaraRC dictionary parameters */
355
 
void dwm_dict_init() {
356
 
        int a;
357
 
        for(a=0; a < KEY_D_COUNT; a++) {
358
 
                key_d[a] = 0;
359
 
        }
360
 
}
361
 
 
362
 
/* Initialize all mararc params */
363
 
void dwm_init_mararc() {
364
 
        int a = 0;
365
 
        for(a = 0; a < KEY_S_COUNT; a++) {
366
 
                key_s[a] = 0;
367
 
        }
368
 
        dwm_dict_init();
369
 
        /* Numeric mararc variables have default values.  */
370
 
        key_n[DWM_N_maxprocs] = 32;
371
 
#ifndef FALLBACK_TIME
372
 
        key_n[DWM_N_timeout_seconds] = 1;
373
 
#else /* FALLBACK_TIME */
374
 
        key_n[DWM_N_timeout_seconds] = 2;
375
 
#endif /* FALLBACK_TIME */
376
 
        key_n[DWM_N_dns_port] = 53;
377
 
        key_n[DWM_N_upstream_port] = 53;
378
 
        key_n[DWM_N_handle_overload] = 1;
379
 
        key_n[DWM_N_handle_noreply] = 1;
380
 
        key_n[DWM_N_recurse_min_bind_port] = 15000;
381
 
        key_n[DWM_N_recurse_number_ports] = 4096;
382
 
        key_n[DWM_N_hash_magic_number] = 1; /* Not real default value */
383
 
        key_n[DWM_N_maximum_cache_elements] = 1024;
384
 
        key_n[DWM_N_maradns_uid] = 99;
385
 
        key_n[DWM_N_maradns_gid] = 99;
386
 
        key_n[DWM_N_resurrections] = 1;
387
 
        key_n[DWM_N_num_retries] = 5;
388
 
        key_n[DWM_N_verbose_level] = 3;
389
 
        key_n[DWM_N_max_tcp_procs] = 8;
390
 
        key_n[DWM_N_timeout_seconds_tcp] = 4;
391
 
        key_n[DWM_N_tcp_listen] = 0;
392
 
        key_n[DWM_N_max_ar_chain] = 1;
393
 
        key_n[DWM_N_ttl_age] = 1;
394
 
        key_n[DWM_N_max_inflights] = 8;
395
 
        key_n[DWM_N_deliver_all] = 1;
396
 
        key_n[DWM_N_filter_rfc1918] = 1;
397
 
        key_n[DWM_N_ns_glueless_type] = 1;
398
 
        key_n[DWM_N_reject_aaaa] = 0;
399
 
        key_n[DWM_N_reject_mx] = 1;
400
 
        key_n[DWM_N_truncation_hack] = 1;
401
 
        key_n[DWM_N_reject_ptr] = 0;
402
 
        key_n[DWM_N_min_ttl_incomplete_cname] = 3600;
403
 
        key_n[DWM_N_max_ttl] = 86400;
404
 
}
405
 
 
406
 
/* Look for a Mararc parameter; -1 if not found/error; 0-n if found
407
 
 * (0: First index, 1: second index, etc.) */
408
 
int32_t dwm_grep_params(dw_str *seek, char *list[], int max) {
409
 
        int e = 0;
410
 
        dw_str *look = 0;
411
 
        int ret = 0;
412
 
 
413
 
        if(seek == 0 || list == 0 || max < 1) {
414
 
                ret = -1;
415
 
                goto catch_dwm_grep_params;
416
 
        }
417
 
 
418
 
        for(e = 0; e < max; e++) {
419
 
                if(list[e] == 0) {
420
 
                        ret = -1;
421
 
                        goto catch_dwm_grep_params;
422
 
                }
423
 
                look = dw_create(64);
424
 
                dw_qrappend((uint8_t *)list[e],look,0);
425
 
                if(dw_issame(seek,look) == 1) {
426
 
                        ret = e;
427
 
                        goto catch_dwm_grep_params;
428
 
                }
429
 
                if(look != 0) {
430
 
                        dw_destroy(look);
431
 
                        look = 0;
432
 
                }
433
 
        }
434
 
 
435
 
        ret = -1;
436
 
 
437
 
catch_dwm_grep_params:
438
 
        if(look != 0) {
439
 
                dw_destroy(look);
440
 
                look = 0;
441
 
        }
442
 
        return ret;
443
 
}
444
 
 
445
 
/* Start to read another file to parse data from */
446
 
void dwm_execfile(dw_str *execfile, dw_str *fname) {
447
 
        char *name = 0, *a = 0;
448
 
        dw_str *cmp = 0;
449
 
        int counter = 0;
450
 
 
451
 
        cmp = dw_create(10);
452
 
        if(cmp == 0) {
453
 
                return;
454
 
        }
455
 
        if(dw_cstr_append((uint8_t *)"execfile",8,cmp) == -1) {
456
 
                dw_destroy(cmp);
457
 
                return;
458
 
        }
459
 
        if(dw_issame(cmp,execfile) != 1) {
460
 
                dwm_fatal("Should have execfile here");
461
 
                dw_destroy(cmp);
462
 
                return;
463
 
        }
464
 
        dw_destroy(cmp);
465
 
 
466
 
#ifndef MINGW
467
 
        if(chdir(EXECFILE_DIR) != 0) {
468
 
                dwm_fatal("Could not enter execfile directory");
469
 
                return;
470
 
        }
471
 
#endif /* MINGW */
472
 
 
473
 
        name = (char *)dw_to_cstr(fname);
474
 
        if(name == 0) {
475
 
                return;
476
 
        }
477
 
 
478
 
        a = name;
479
 
 
480
 
        /* Clean up path to filename */
481
 
        if(*a == '/') {
482
 
                *a = '_';
483
 
        }
484
 
        for(counter = 0; counter < 200; counter++) {
485
 
                if(*a == 0) {
486
 
                        break;
487
 
                }
488
 
                if((*a < 'a' || *a > 'z') && *a != '_' && *a != '/') {
489
 
                        *a = '_';
490
 
                }
491
 
                a++;
492
 
        }
493
 
 
494
 
        dwm_parse_file(name);
495
 
 
496
 
        free(name);
497
 
}
498
 
 
499
 
/* Based on the actions done, determine what to do (this is called from
500
 
 * dwm_set_keys()).
501
 
 * Output:
502
 
 * -1: Error (bad action)
503
 
 * 0: Do nothing
504
 
 * 1: Set normal string variable
505
 
 * 2: Append to normal string variable
506
 
 * 3: Set dictionary variable
507
 
 * 4: Append to dictionary variable
508
 
 * 5: Set numeric variable
509
 
 * 6: Init dictionary variable
510
 
 * 7: Read other file for more dwood2rc parameters
511
 
 */
512
 
 
513
 
int dwm_set_todo(dw_str **actions) {
514
 
        if(actions[1] == 0) { /* Do nothing */
515
 
                return 0;
516
 
        }
517
 
        if(actions[6] != 0 && actions[1] != 0 && actions[2] == 0) {
518
 
                /* Init dictionary variable */
519
 
                return 6;
520
 
        }
521
 
        if(actions[7] != 0) { /* Read and parse other file */
522
 
                dwm_execfile(actions[1],actions[7]);
523
 
                return 0;
524
 
        }
525
 
        if(actions[3] == 0) { /* No string to set */
526
 
                if(actions[4] == 0) { /* No number to set */
527
 
                        return -1;
528
 
                } else if(actions[2] != 0) { /* Dictionary variable */
529
 
                        return -1;
530
 
                } else if(actions[5] != 0) { /* += instead of = */
531
 
                        return -1; /* Not supported; should we support this? */
532
 
                } else {
533
 
                        return 5;
534
 
                }
535
 
        }
536
 
        if(actions[2] != 0) { /* Dictionary variable */
537
 
                if(actions[6] != 0) { /* foo["."] = {} line */
538
 
                        return 0;
539
 
                }
540
 
                if(actions[5] != 0) { /* += instead of = */
541
 
                        return 4;
542
 
                }
543
 
                return 3;
544
 
        }
545
 
        if(actions[5] != 0) { /* += instead of = */
546
 
                return 2;
547
 
        }
548
 
        return 1;
549
 
}
550
 
 
551
 
/* Add a dictionary key/value pair to the compiled list of MaraRC
552
 
 * parameters.
553
 
 *
554
 
 * Input: Number of MaraRC parameter to modify
555
 
 *        Dictionary key index to modify
556
 
 *        Value for said key index
557
 
 *
558
 
 * Output: Void finction
559
 
 *
560
 
 * Global variables modified: key_d
561
 
 */
562
 
void dwm_dict_add(int num, dw_str *key, dw_str *value, int todo) {
563
 
        dw_str *temp = 0;
564
 
        dw_str *check = 0;
565
 
 
566
 
        if(num >= KEY_D_COUNT || num < 0) { /* Sanity check */
567
 
                dwm_fatal("Unknown dictionary variable");
568
 
        }
569
 
 
570
 
        if(todo == 6 && (key != 0 || value != 0)) {
571
 
                dwm_fatal("Illegal dictionary initialization");
572
 
        }
573
 
 
574
 
        /* Initialize dictionary if needed*/
575
 
        if(key_d[num] == 0 && todo == 6) { /* Initialized with {} */
576
 
                key_d[num] = dwd_init();
577
 
                return;
578
 
#ifndef TINY_BINARY
579
 
        } else if(key_d[num] != 0 && todo == 6) { /* Only initialize once */
580
 
                dwm_fatal("Dictionary variable already initialized");
581
 
#endif /* TINY_BINARY */
582
 
        } else if(key_d[num] == 0) {
583
 
                dwm_fatal("Uninitialized dictionary variable");
584
 
        }
585
 
 
586
 
        if(todo != 4) { /* =, create new dictionary element */
587
 
#ifndef TINY_BINARY
588
 
                check = dwd_fetch(key_d[num],key);
589
 
                if(check != 0) {
590
 
                        dw_log_dwstr_str("Warning: Dictionary element \"",
591
 
                                        key,"\" defined more than once",0);
592
 
                        dw_destroy(check);
593
 
                        /* I am tempted to make this fatal but will not since
594
 
                         * it could make managing large anti-phish/malware
595
 
                         * blacklists harder */
596
 
                        /*dw_fatal(
597
 
                            "Dictionary elements must be defined only once");*/
598
 
                }
599
 
#endif /* TINY_BINARY */
600
 
                key_d[num] = dwd_add(key_d[num],key,value);
601
 
                return;
602
 
        }
603
 
 
604
 
        /* OK, += so we append an already existing element */
605
 
        temp = dwd_fetch(key_d[num],key);
606
 
        if(temp == 0) {
607
 
                dwm_fatal("Appending unset dictionary index");
608
 
        }
609
 
 
610
 
        dw_append(value,temp);
611
 
 
612
 
        dwd_add(key_d[num],key,temp);
613
 
 
614
 
        dw_destroy(temp);
615
 
 
616
 
}
617
 
 
618
 
/* Fetch a value from a given dictionary variable (num is the number for
619
 
 * the dictionary variable we are seeking a given value for, given the
620
 
 * dictionary variable and the key inside that variable) */
621
 
dw_str *dwm_dict_fetch(int num, dw_str *key) {
622
 
        if(num >= KEY_D_COUNT) {
623
 
                return 0;
624
 
        }
625
 
 
626
 
        return dwd_fetch(key_d[num],key);
627
 
 
628
 
}
629
 
 
630
 
/* For a given dictionary variable, and a key, return (as a *copied* dw_str
631
 
 * object) the next key or 0 if we're at the last key.  If the key given to
632
 
 * this function is 0, return the first key. */
633
 
dw_str *dwm_dict_nextkey(int num, dw_str *key) {
634
 
        if(num >= KEY_D_COUNT) {
635
 
                return 0;
636
 
        }
637
 
        return dwd_nextkey(key_d[num],key);
638
 
}
639
 
 
640
 
/* Based on the actions done, set the appropriate Mararc parameters */
641
 
void dwm_set_keys(dw_str **actions) {
642
 
        int todo = 0, num = 0;
643
 
        dw_str **list = 0;
644
 
 
645
 
        todo = dwm_set_todo(actions);
646
 
        if(todo == 0) {
647
 
                return;
648
 
        } else if(todo == -1) {
649
 
                dwm_fatal("Bad deadwoodrc action");
650
 
        }
651
 
 
652
 
        if(todo == 1 || todo == 2) { /* Normal variable */
653
 
                num = dwm_grep_params(actions[1],key_s_names,KEY_S_COUNT);
654
 
                list = key_s;
655
 
        } else if(todo == 3 || todo == 4 || todo == 6) { /* Dict. variable */
656
 
                num = dwm_grep_params(actions[1],key_d_names,KEY_D_COUNT);
657
 
                if(num < 0) { /* Make sure the parameter is a legal one */
658
 
                        dwm_fatal("Unknown dwood3rc dictionary parameter");
659
 
                }
660
 
                dwm_dict_add(num, actions[2], actions[3], todo);
661
 
                return;
662
 
        } else if(todo == 5) { /* Numeric variable */
663
 
                int32_t val;
664
 
                num = dwm_grep_params(actions[1],key_n_names,KEY_N_COUNT);
665
 
                val = dw_atoi(actions[4],0,10);
666
 
                if(val == -1) {
667
 
                        dwm_fatal("Invalid numeric value");
668
 
                }
669
 
                if(num < 0) { /* Make sure the parameter is a legal one */
670
 
                        dwm_fatal("Unknown dwood3rc numeric parameter");
671
 
                }
672
 
                key_n[num] = val;
673
 
                return;
674
 
        } else { /* Shouldn't get here */
675
 
                return;
676
 
        }
677
 
 
678
 
        if(list == 0) { /* Sanity check */
679
 
                dwm_fatal("Unknown dwood3rc action");
680
 
        }
681
 
        if(num < 0) { /* Make sure the parameter is a legal one */
682
 
                dwm_fatal("Unknown dwood3rc string parameter");
683
 
        }
684
 
 
685
 
        if(list[num] == 0 && (todo & 1) == 0) {
686
 
                dwm_fatal("Appending to unset string parameter");
687
 
        } else if(list[num] != 0 && (todo & 1) == 0 /* append */) {
688
 
                dw_append(actions[3],list[num]);
689
 
                return;
690
 
        } else if(list[num] != 0) {
691
 
                dwm_fatal("Deadwoodrc parameter set twice");
692
 
        }
693
 
 
694
 
        list[num] = dw_copy(actions[3]);
695
 
}
696
 
 
697
 
/* If there is an action to perform, perform the action */
698
 
void dwm_do_action(int32_t ch, int32_t action, dw_str **actions) {
699
 
        if(actions[action] == 0) {
700
 
                /* This function is *only* called from dwm_parse_line,
701
 
                 * and the destructor for these strings is at the
702
 
                 * end of that function */
703
 
                actions[action] = dw_create(384);
704
 
        }
705
 
        dw_addchar(ch, actions[action]);
706
 
}
707
 
 
708
 
/* Parse a line in a MaraRC (Dwood#RC) file */
709
 
int dwm_parse_line(FILE *look) {
710
 
        dw_str *actions[11];
711
 
        int a = 0;
712
 
        int32_t action = 0, state = 0, mix = 0, ch = 0, last = 0;
713
 
        int ret = 0;
714
 
 
715
 
        for(a = 0; a < 11; a++) {
716
 
                actions[a] = 0;
717
 
        }
718
 
 
719
 
        ch = fgetc(look);
720
 
        if(feof(look)) {
721
 
                ret = 1; /* End of file reached */
722
 
                goto catch_dwm_parse_line;
723
 
        }
724
 
 
725
 
        while(action != 10) {
726
 
                mix = dwm_process_character(ch,state);
727
 
                if(mix < 0) {
728
 
                        ret = -1;
729
 
                        goto catch_dwm_parse_line;
730
 
                }
731
 
                action = (mix >> 16) & 0x7fff;
732
 
                state = mix & 0x7fff;
733
 
                if(action == 10) { /* Terminate */
734
 
                        ret = 0; /* Line parsed */
735
 
                        break; /* Now we need to set the keys */
736
 
                } else if(action == 8) {
737
 
                        ret = -4; /* Fatal: No leading whitespace */
738
 
                        goto catch_dwm_parse_line;
739
 
                } else if(action > 0 && action < 10) {
740
 
                        dwm_do_action(ch,action,actions);
741
 
                }
742
 
                last = ch;
743
 
                ch = fgetc(look);
744
 
                if(feof(look) && last != '\r' && last != '\n') {
745
 
                        ret = -3; /* Premature EOF; incomplete last line */
746
 
                        goto catch_dwm_parse_line;
747
 
                }
748
 
        }
749
 
 
750
 
        dwm_set_keys(actions); /* Sets mararc parameters based on actions */
751
 
 
752
 
catch_dwm_parse_line: /* Actions strings destructor */
753
 
        for(a = 0; a < 11; a++) {
754
 
                if(actions[a] != 0) {
755
 
                        dw_destroy(actions[a]);
756
 
                        actions[a] = 0;
757
 
                }
758
 
        }
759
 
        return ret;
760
 
}
761
 
 
762
 
/* Parse a single filename; used by dwm_parse_mararc and dwm_execfile to
763
 
 * parse the contents of a single file */
764
 
int dwm_parse_file(char *name) {
765
 
        FILE *look;
766
 
        int a = 0;
767
 
 
768
 
        if(dwm_file_depth > 8 || name == 0) {
769
 
                return -1;
770
 
        }
771
 
 
772
 
        dwm_file_depth++;
773
 
 
774
 
        look = fopen(name,"rb");
775
 
        if(look == NULL) {
776
 
                return -1; /* File open error */
777
 
        }
778
 
 
779
 
        do {
780
 
                a = dwm_parse_line(look);
781
 
                if(a == -3) {
782
 
                        dwm_fatal("incomplete last line");
783
 
                } else if(a == -4) {
784
 
                        dwm_fatal("leading whitespace not allowed");
785
 
                }
786
 
                if(a != 0 && a != 1) {
787
 
                        dwm_fatal("deadwoodrc parse error");
788
 
                }
789
 
                if(dwm_file_depth == 1) {
790
 
                        dwm_linenum++;
791
 
                }
792
 
        } while (a == 0);
793
 
 
794
 
        fclose(look);
795
 
 
796
 
        dwm_file_depth--;
797
 
 
798
 
        return 1;
799
 
}
800
 
 
801
 
/* Parse a mararc file; this should only be called once when executing
802
 
 * deadwood.  Note that this is the *only* public method in this entire
803
 
 * file; all other functions in this file should only be called from
804
 
 * other functions in this file.
805
 
 * Input: c string that points to mararc file
806
 
 * Output: 1 on success; program exits on mararc parse error */
807
 
int dwm_parse_mararc(char *name) {
808
 
        dwm_linenum = 1;
809
 
 
810
 
        dwm_init_fsm();
811
 
        dwm_init_mararc();
812
 
 
813
 
        return dwm_parse_file(name);
814
 
}
815
 
 
816
 
#ifdef HAVE_MAIN
817
 
 
818
 
/* Debugging function to make sure fsm is correctly set up */
819
 
 
820
 
void show_fsm() {
821
 
        int a = 0, b = 0, q = 0;
822
 
        for(a = 0; a < DWM_MAX_STATES; a++) {
823
 
                if(fsm[a].pattern[0] != 0) {
824
 
                        printf("State %d\n",a);
825
 
                }
826
 
                for(b = 0; b < DWM_MAX_PATTERNS; b++) {
827
 
                        q = fsm[a].pattern[b];
828
 
                        if(q > 0 && q < 32 && fsm[a].action[b] != 10) {
829
 
                                printf("Pattern @%d action %d newstate %d\n",
830
 
                                        fsm[a].pattern[b],
831
 
                                        fsm[a].action[b],
832
 
                                        fsm[a].newstate[b]);
833
 
                        } else if(q >= '!' && fsm[a].action[b] != 10) {
834
 
                                printf("Pattern %c action %d newstate %d\n",
835
 
                                        fsm[a].pattern[b],
836
 
                                        fsm[a].action[b],
837
 
                                        fsm[a].newstate[b]);
838
 
 
839
 
                        } else if(q > 0 && q < 32) {
840
 
                                printf("Pattern @%d action %d (terminate)\n",
841
 
                                        fsm[a].pattern[b],
842
 
                                        fsm[a].action[b]);
843
 
                        } else if(q >= '!') {
844
 
                                printf("Pattern %c action %d (terminate)\n",
845
 
                                        fsm[a].pattern[b],
846
 
                                        fsm[a].action[b]);
847
 
                        } else {
848
 
                                break;
849
 
                        }
850
 
                }
851
 
                if(fsm[a].pattern[0] != 0) {
852
 
                        printf("\n");
853
 
                }
854
 
        }
855
 
}
856
 
 
857
 
int main() {
858
 
        int a = 0;
859
 
 
860
 
        dwm_parse_mararc("deadwoodrc");
861
 
 
862
 
        show_fsm();
863
 
 
864
 
        for(a=0;a<KEY_S_COUNT;a++) {
865
 
                printf("%s is ",key_s_names[a]);
866
 
                if(key_s[a] == 0) {
867
 
                        printf("not set.\n");
868
 
                } else {
869
 
                        dw_stdout(key_s[a]);
870
 
                }
871
 
        }
872
 
 
873
 
        for(a=0;a<KEY_D_COUNT;a++) {
874
 
                printf("%s is ",key_d_names[a]);
875
 
                if(key_s[a] == 0) {
876
 
                        printf(" not set.\n");
877
 
                } else {
878
 
                        dw_stdout(key_d[a]);
879
 
                }
880
 
        }
881
 
 
882
 
        return 0;
883
 
}
884
 
 
885
 
#endif /* HAVE_MAIN */
886