mucgly 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.rdoc +5 -0
- data/README.rdoc +49 -4
- data/bin/mucgly +1 -1
- data/doc/Mucgly.html +2 -2
- data/doc/_index.html +1 -1
- data/doc/file.CHANGELOG.html +6 -2
- data/doc/file.README.html +55 -5
- data/doc/index.html +55 -5
- data/doc/top-level-namespace.html +1 -1
- data/ext/mucgly/mucgly.c +785 -288
- data/lib/version.rb +1 -1
- data/test/doit +5 -0
- data/test/golden/test_block.txt +4 -0
- data/test/golden/test_multihook.txt +4 -0
- data/test/golden/test_multihook_cli.txt +4 -0
- data/test/result/test_block.txt +4 -0
- data/test/result/test_multihook.txt +4 -0
- data/test/result/test_multihook_cli.txt +4 -0
- data/test/test_block.rx.txt +11 -0
- data/test/test_mucgly.rb +11 -4
- data/test/test_multihook.rx.c +17 -0
- data/test/test_multihook_cli.rx.c +16 -0
- metadata +22 -2
data/ext/mucgly/mucgly.c
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
/**
|
2
|
+
* @file mucgly.c
|
3
|
+
* @author Tero Isannainen <tero.isannainen@gmail.com>
|
4
|
+
* @date Sat Apr 23 12:41:02 2016
|
5
|
+
*
|
6
|
+
* @brief Inline macro processor.
|
7
|
+
*
|
8
|
+
* See README.rdoc for full documentation of Mucgly.
|
9
|
+
*/
|
10
|
+
|
11
|
+
|
1
12
|
#include <glib.h>
|
2
13
|
#include <glib/gstdio.h>
|
3
14
|
#include <ruby.h>
|
@@ -18,10 +29,14 @@ void mucgly_main( int argc, char** argv );
|
|
18
29
|
* Debugging:
|
19
30
|
* ------------------------------------------------------------ */
|
20
31
|
|
21
|
-
|
22
|
-
|
32
|
+
/**
|
33
|
+
* Enable the define if input char based debugging is required. Set
|
34
|
+
* GDB breakpoint at mucgly_debug.
|
35
|
+
*/
|
23
36
|
void mucgly_debug( void ) {}
|
37
|
+
|
24
38
|
#if 0
|
39
|
+
/** Special char for invoking the debugger. */
|
25
40
|
# define DEBUG_CHAR '~'
|
26
41
|
#endif
|
27
42
|
|
@@ -52,33 +67,55 @@ void mucgly_debug( void ) {}
|
|
52
67
|
*/
|
53
68
|
|
54
69
|
|
70
|
+
/** Default value for hookbeg. */
|
55
71
|
#define HOOKBEG_DEFAULT "-<"
|
72
|
+
|
73
|
+
/** Default value for hookend. */
|
56
74
|
#define HOOKEND_DEFAULT ">-"
|
75
|
+
|
76
|
+
/** Default value for hookesc. */
|
57
77
|
#define HOOKESC_DEFAULT "\\"
|
58
78
|
|
79
|
+
/** Multihook count limit, also array size. */
|
80
|
+
#define MULTI_LIMIT 128
|
81
|
+
|
82
|
+
|
83
|
+
/**
|
84
|
+
* Pair of hooks for macro beginning and end.
|
85
|
+
*/
|
86
|
+
typedef struct hookpair_s {
|
87
|
+
gchar* beg; /**< Hookbeg for input file. */
|
88
|
+
gchar* end; /**< Hookend for input file. */
|
89
|
+
} hookpair_t;
|
59
90
|
|
60
91
|
|
61
92
|
/**
|
62
93
|
* Stackfile is an entry in the Filestack. Stackfile is the input file
|
63
94
|
* for Mucgly.
|
64
95
|
*/
|
65
|
-
struct stackfile_s {
|
96
|
+
typedef struct stackfile_s {
|
66
97
|
|
67
|
-
gchar* filename;
|
68
|
-
FILE* fh;
|
69
|
-
GString* buf;
|
98
|
+
gchar* filename; /**< Filename. */
|
99
|
+
FILE* fh; /**< IO stream handle. */
|
100
|
+
GString* buf; /**< Put-back buffer (oldest-is-last). */
|
70
101
|
|
71
|
-
int lineno;
|
72
|
-
int column;
|
73
|
-
int old_column;
|
102
|
+
int lineno; /**< Line number (0->). */
|
103
|
+
int column; /**< Line column (0->). */
|
104
|
+
int old_column; /**< Prev column (used with putback). */
|
105
|
+
|
106
|
+
gboolean macro; /**< Macro active. */
|
107
|
+
int macro_line; /**< Macro start line. */
|
108
|
+
int macro_col; /**< Macro start column. */
|
109
|
+
gboolean eat_tail; /**< Eat the char after macro (if not EOF). */
|
110
|
+
|
111
|
+
hookpair_t hook; /**< Pair of hooks for macro boundary. */
|
112
|
+
gchar* hookesc; /**< Hookesc for input file. */
|
74
113
|
|
75
|
-
|
76
|
-
int
|
77
|
-
int macro_col; /**< Macro start column. */
|
114
|
+
hookpair_t* multi; /**< Pairs of hooks for multi-hooking. */
|
115
|
+
int multi_cnt; /**< Number of pairs in multi-hooking. */
|
78
116
|
|
79
|
-
|
80
|
-
|
81
|
-
gchar* hookesc; /**< Hookesc for input file. */
|
117
|
+
/** Current hook, as stack to support nesting macros. */
|
118
|
+
GList* curhook;
|
82
119
|
|
83
120
|
/** Hookesc is same as hookbeg. Speeds up input processing. */
|
84
121
|
gboolean hook_esc_eq_beg;
|
@@ -86,11 +123,10 @@ struct stackfile_s {
|
|
86
123
|
/** Hookesc is same as hookend. Speeds up input processing. */
|
87
124
|
gboolean hook_esc_eq_end;
|
88
125
|
|
89
|
-
/**
|
126
|
+
/** Lookup-table for the first chars of hooks. Speeds up input processing. */
|
90
127
|
guchar hook_1st_chars[ 256 ];
|
91
128
|
|
92
|
-
};
|
93
|
-
typedef struct stackfile_s stackfile_t;
|
129
|
+
} stackfile_t;
|
94
130
|
|
95
131
|
|
96
132
|
|
@@ -102,10 +138,9 @@ typedef struct stackfile_s stackfile_t;
|
|
102
138
|
* EOF is encountered, it is popped of the stack. This makes the
|
103
139
|
* character flow continuous from the parser point of view.
|
104
140
|
*/
|
105
|
-
struct filestack_s {
|
141
|
+
typedef struct filestack_s {
|
106
142
|
GList* file; /**< Stack of files. */
|
107
|
-
};
|
108
|
-
typedef struct filestack_s filestack_t;
|
143
|
+
} filestack_t;
|
109
144
|
|
110
145
|
|
111
146
|
|
@@ -114,19 +149,19 @@ typedef struct filestack_s filestack_t;
|
|
114
149
|
* from the default output to another output file temporarely. Note
|
115
150
|
* that the diverted output stream has to be closed as well.
|
116
151
|
*/
|
117
|
-
struct outfile_s {
|
118
|
-
gchar* filename;
|
119
|
-
FILE* fh;
|
120
|
-
int lineno;
|
121
|
-
|
122
|
-
|
152
|
+
typedef struct outfile_s {
|
153
|
+
gchar* filename; /**< Filename. */
|
154
|
+
FILE* fh; /**< Stream handle. */
|
155
|
+
int lineno; /**< Line number (0->). */
|
156
|
+
gboolean blocked; /**< Blocked output for IO stream. */
|
157
|
+
} outfile_t;
|
123
158
|
|
124
159
|
|
125
160
|
|
126
161
|
/**
|
127
162
|
* Parser state for Mucgly.
|
128
163
|
*/
|
129
|
-
struct pstate_s {
|
164
|
+
typedef struct pstate_s {
|
130
165
|
filestack_t* fs; /**< Stack of input streams. */
|
131
166
|
|
132
167
|
GString* check_buf; /**< Preview buffer. */
|
@@ -138,8 +173,11 @@ struct pstate_s {
|
|
138
173
|
GList* output; /**< Stack of output streams. */
|
139
174
|
|
140
175
|
gboolean flush; /**< Flush out-stream immediately. */
|
141
|
-
|
142
|
-
|
176
|
+
|
177
|
+
gboolean post_push; /**< Move up in fs after macro processing. */
|
178
|
+
gboolean post_pop; /**< Move down in fs after macro processing. */
|
179
|
+
|
180
|
+
} pstate_t;
|
143
181
|
|
144
182
|
|
145
183
|
/** Hook type enum. */
|
@@ -149,11 +187,9 @@ typedef enum hook_e { hook_none, hook_end, hook_beg, hook_esc } hook_t;
|
|
149
187
|
/** Current filestack from pstate_t (for convenience). */
|
150
188
|
#define ps_has_file(ps) ((stackfile_t*)(ps)->fs->file)
|
151
189
|
|
152
|
-
|
153
190
|
/** Current stackfile from pstate_t (for convenience). */
|
154
191
|
#define ps_topfile(ps) ((stackfile_t*)(ps)->fs->file->data)
|
155
192
|
|
156
|
-
|
157
193
|
/** Current stackfile from filestack_t (for convenience). */
|
158
194
|
#define fs_topfile(fs) ((stackfile_t*)(fs)->file->data)
|
159
195
|
|
@@ -166,7 +202,7 @@ typedef enum hook_e { hook_none, hook_end, hook_beg, hook_esc } hook_t;
|
|
166
202
|
/** Default hook settings. */
|
167
203
|
stackfile_t* stack_default = NULL;
|
168
204
|
|
169
|
-
/** Pointer to current file.
|
205
|
+
/** Pointer to current file. Useful for debugging. */
|
170
206
|
stackfile_t* csf;
|
171
207
|
|
172
208
|
/** Ruby side reference to parser. */
|
@@ -178,7 +214,9 @@ pstate_t* ruby_ps;
|
|
178
214
|
* Function declarations:
|
179
215
|
* ------------------------------------------------------------ */
|
180
216
|
|
181
|
-
void
|
217
|
+
void sf_update_hook_cache( stackfile_t* sf );
|
218
|
+
void sf_multi_hook( stackfile_t* sf, const char* beg, const char* end );
|
219
|
+
gchar* ps_current_hookend( pstate_t* ps );
|
182
220
|
|
183
221
|
|
184
222
|
|
@@ -189,10 +227,10 @@ void sf_set_hook( stackfile_t* sf, hook_t hook, char* value );
|
|
189
227
|
|
190
228
|
/**
|
191
229
|
* Compare two strings upto length of str1.
|
192
|
-
*
|
230
|
+
*
|
193
231
|
* @param str1 String 1.
|
194
232
|
* @param str2 String 2.
|
195
|
-
*
|
233
|
+
*
|
196
234
|
* @return Match length (0 for no match).
|
197
235
|
*/
|
198
236
|
int len_str_cmp( char* str1, char* str2 )
|
@@ -208,7 +246,7 @@ int len_str_cmp( char* str1, char* str2 )
|
|
208
246
|
|
209
247
|
/**
|
210
248
|
* Common routine for user info message output.
|
211
|
-
*
|
249
|
+
*
|
212
250
|
* @param sf Currently processed file (or NULL).
|
213
251
|
* @param infotype Severity type.
|
214
252
|
* @param format Message (printf) formatter.
|
@@ -255,7 +293,7 @@ void mucgly_user_info( stackfile_t* sf, char* infotype, char* format, va_list ap
|
|
255
293
|
|
256
294
|
/**
|
257
295
|
* Report warning to user (no exit).
|
258
|
-
*
|
296
|
+
*
|
259
297
|
* @param sf Current input file.
|
260
298
|
* @param format Message formatter.
|
261
299
|
*/
|
@@ -270,7 +308,7 @@ void mucgly_warn( stackfile_t* sf, char* format, ... )
|
|
270
308
|
|
271
309
|
/**
|
272
310
|
* Report error to user (and exit).
|
273
|
-
*
|
311
|
+
*
|
274
312
|
* @param sf Current input file.
|
275
313
|
* @param format Message formatter.
|
276
314
|
*/
|
@@ -286,7 +324,7 @@ void mucgly_error( stackfile_t* sf, char* format, ... )
|
|
286
324
|
|
287
325
|
/**
|
288
326
|
* Report fatal error to user (and exit).
|
289
|
-
*
|
327
|
+
*
|
290
328
|
* @param sf Current input file.
|
291
329
|
* @param format Message formatter.
|
292
330
|
*/
|
@@ -300,12 +338,40 @@ void mucgly_fatal( stackfile_t* sf, char* format, ... )
|
|
300
338
|
}
|
301
339
|
|
302
340
|
|
341
|
+
/**
|
342
|
+
* Duplicate hookpair content.
|
343
|
+
*
|
344
|
+
* @param from Source.
|
345
|
+
* @param to Destination.
|
346
|
+
*
|
347
|
+
* @return Destination.
|
348
|
+
*/
|
349
|
+
hookpair_t* hookpair_dup( hookpair_t* from, hookpair_t* to )
|
350
|
+
{
|
351
|
+
to->beg = g_strdup( from->beg );
|
352
|
+
to->end = g_strdup( from->end );
|
353
|
+
return to;
|
354
|
+
}
|
355
|
+
|
356
|
+
|
357
|
+
/**
|
358
|
+
* Free allocated hookpair memory.
|
359
|
+
*
|
360
|
+
* @param pair Pair to dealloc.
|
361
|
+
*/
|
362
|
+
void hookpair_del( hookpair_t* pair )
|
363
|
+
{
|
364
|
+
g_free( pair->beg );
|
365
|
+
g_free( pair->end );
|
366
|
+
}
|
367
|
+
|
368
|
+
|
303
369
|
/**
|
304
370
|
* Create new Stackfile.
|
305
|
-
*
|
371
|
+
*
|
306
372
|
* @param filename Filename (NULL for stdin).
|
307
373
|
* @param inherit Inherit hooks source (NULL for defaults).
|
308
|
-
*
|
374
|
+
*
|
309
375
|
* @return Stackfile.
|
310
376
|
*/
|
311
377
|
stackfile_t* sf_new( gchar* filename, stackfile_t* inherit )
|
@@ -347,25 +413,41 @@ stackfile_t* sf_new( gchar* filename, stackfile_t* inherit )
|
|
347
413
|
sf->macro = FALSE;
|
348
414
|
sf->macro_line = 0;
|
349
415
|
sf->macro_col = 0;
|
416
|
+
sf->eat_tail = FALSE;
|
417
|
+
|
418
|
+
sf->multi = NULL;
|
419
|
+
sf->multi_cnt = 0;
|
420
|
+
|
421
|
+
sf->curhook = NULL;
|
350
422
|
|
351
423
|
|
352
424
|
if ( inherit )
|
353
425
|
{
|
354
426
|
/* Inherited hook values. */
|
355
|
-
|
356
|
-
sf->hookend = g_strdup( inherit->hookend );
|
427
|
+
hookpair_dup( &inherit->hook, &sf->hook );
|
357
428
|
sf->hookesc = g_strdup( inherit->hookesc );
|
429
|
+
|
430
|
+
/* Setup fast-lookup caches. */
|
431
|
+
sf_update_hook_cache( sf );
|
432
|
+
|
433
|
+
if ( inherit->multi )
|
434
|
+
{
|
435
|
+
for ( int i = 0; i < inherit->multi_cnt; i++ )
|
436
|
+
{
|
437
|
+
sf_multi_hook( sf, inherit->multi[i].beg, inherit->multi[i].end );
|
438
|
+
}
|
439
|
+
}
|
358
440
|
}
|
359
441
|
else
|
360
442
|
{
|
361
443
|
/* Default hook values. */
|
362
|
-
sf->
|
363
|
-
sf->
|
444
|
+
sf->hook.beg = g_strdup( HOOKBEG_DEFAULT );
|
445
|
+
sf->hook.end = g_strdup( HOOKEND_DEFAULT );
|
364
446
|
sf->hookesc = g_strdup( HOOKESC_DEFAULT );
|
365
|
-
}
|
366
447
|
|
367
|
-
|
368
|
-
|
448
|
+
/* Setup fast-lookup caches. */
|
449
|
+
sf_update_hook_cache( sf );
|
450
|
+
}
|
369
451
|
|
370
452
|
return sf;
|
371
453
|
}
|
@@ -373,7 +455,7 @@ stackfile_t* sf_new( gchar* filename, stackfile_t* inherit )
|
|
373
455
|
|
374
456
|
/**
|
375
457
|
* Store macro start info.
|
376
|
-
*
|
458
|
+
*
|
377
459
|
* @param sf Stackfile.
|
378
460
|
*/
|
379
461
|
void sf_mark_macro( stackfile_t* sf )
|
@@ -386,7 +468,7 @@ void sf_mark_macro( stackfile_t* sf )
|
|
386
468
|
|
387
469
|
/**
|
388
470
|
* Reset macro start info.
|
389
|
-
*
|
471
|
+
*
|
390
472
|
* @param sf Stackfile.
|
391
473
|
*/
|
392
474
|
void sf_unmark_macro( stackfile_t* sf )
|
@@ -397,7 +479,7 @@ void sf_unmark_macro( stackfile_t* sf )
|
|
397
479
|
|
398
480
|
/**
|
399
481
|
* Free Stackfile and close the file stream.
|
400
|
-
*
|
482
|
+
*
|
401
483
|
* @param sf Stackfile.
|
402
484
|
*/
|
403
485
|
void sf_rem( stackfile_t* sf )
|
@@ -411,42 +493,44 @@ void sf_rem( stackfile_t* sf )
|
|
411
493
|
|
412
494
|
g_free( sf->filename );
|
413
495
|
|
414
|
-
|
415
|
-
g_free( sf->hookend );
|
496
|
+
hookpair_del( &sf->hook );
|
416
497
|
g_free( sf->hookesc );
|
417
498
|
|
499
|
+
if ( sf->multi )
|
500
|
+
{
|
501
|
+
for ( int i = 0; i < sf->multi_cnt; i++ )
|
502
|
+
hookpair_del( &sf->multi[i] );
|
503
|
+
g_free( sf->multi );
|
504
|
+
}
|
505
|
+
|
418
506
|
g_free( sf );
|
419
507
|
}
|
420
508
|
|
421
509
|
|
422
510
|
/**
|
423
511
|
* Get char from Stackfile.
|
424
|
-
*
|
512
|
+
*
|
425
513
|
* @param sf Stackfile.
|
426
|
-
*
|
514
|
+
*
|
427
515
|
* @return Char or EOF.
|
428
516
|
*/
|
429
517
|
int sf_get( stackfile_t* sf )
|
430
518
|
{
|
431
519
|
int ret;
|
432
|
-
|
520
|
+
|
521
|
+
re_read:
|
433
522
|
if ( sf->buf->len > 0 )
|
434
523
|
{
|
435
|
-
|
436
524
|
/* Pending chars in buffer, don't need to read file (yet). */
|
437
|
-
|
438
525
|
int pos = sf->buf->len-1;
|
439
526
|
|
440
527
|
/* Use buffer as stack with oldest (first to use) on right. */
|
441
528
|
ret = sf->buf->str[ pos ];
|
442
529
|
g_string_truncate( sf->buf, pos );
|
443
|
-
|
444
530
|
}
|
445
531
|
else
|
446
532
|
{
|
447
|
-
|
448
533
|
/* Read from actual file stream. */
|
449
|
-
|
450
534
|
#ifdef DEBUG_CHAR
|
451
535
|
ret = fgetc( sf->fh );
|
452
536
|
if ( DEBUG_CHAR == (char) ret )
|
@@ -475,16 +559,24 @@ int sf_get( stackfile_t* sf )
|
|
475
559
|
}
|
476
560
|
}
|
477
561
|
|
562
|
+
if ( sf->eat_tail == TRUE )
|
563
|
+
{
|
564
|
+
/* Eat tail if not in EOF. */
|
565
|
+
sf->eat_tail = FALSE;
|
566
|
+
if ( ret != EOF )
|
567
|
+
goto re_read;
|
568
|
+
}
|
569
|
+
|
478
570
|
return ret;
|
479
571
|
}
|
480
572
|
|
481
573
|
|
482
574
|
/**
|
483
575
|
* Put char back to Stackfile.
|
484
|
-
*
|
576
|
+
*
|
485
577
|
* @param sf Stackfile.
|
486
578
|
* @param c char.
|
487
|
-
*
|
579
|
+
*
|
488
580
|
* @return TRUE.
|
489
581
|
*/
|
490
582
|
gboolean sf_put( stackfile_t* sf, char c )
|
@@ -508,48 +600,133 @@ gboolean sf_put( stackfile_t* sf, char c )
|
|
508
600
|
|
509
601
|
|
510
602
|
/**
|
511
|
-
*
|
512
|
-
*
|
603
|
+
* Update the hooks related cache/lookup entries.
|
604
|
+
*
|
513
605
|
* @param sf Stackfile.
|
514
|
-
|
606
|
+
*/
|
607
|
+
void sf_update_hook_cache( stackfile_t* sf )
|
608
|
+
{
|
609
|
+
if ( sf->multi )
|
610
|
+
{
|
611
|
+
/* Esc can never match multihooks. */
|
612
|
+
sf->hook_esc_eq_beg = FALSE;
|
613
|
+
sf->hook_esc_eq_end = FALSE;
|
614
|
+
|
615
|
+
/* Add the latest addition to 1st char lookup. */
|
616
|
+
sf->hook_1st_chars[ sf->multi[ sf->multi_cnt-1 ].beg[0] ] = 1;
|
617
|
+
sf->hook_1st_chars[ sf->multi[ sf->multi_cnt-1 ].end[0] ] = 1;
|
618
|
+
|
619
|
+
sf->hook_1st_chars[ sf->hookesc[0] ] = 1;
|
620
|
+
}
|
621
|
+
else
|
622
|
+
{
|
623
|
+
/* Store these equalities for speed-up. */
|
624
|
+
if ( !g_strcmp0( sf->hookesc, sf->hook.beg ) )
|
625
|
+
sf->hook_esc_eq_beg = TRUE;
|
626
|
+
else
|
627
|
+
sf->hook_esc_eq_beg = FALSE;
|
628
|
+
|
629
|
+
if ( !g_strcmp0( sf->hookesc, sf->hook.end ) )
|
630
|
+
sf->hook_esc_eq_end = TRUE;
|
631
|
+
else
|
632
|
+
sf->hook_esc_eq_end = FALSE;
|
633
|
+
|
634
|
+
/* Initialize 1st char lookup. */
|
635
|
+
memset( sf->hook_1st_chars, 0, 256 * sizeof( guchar ) );
|
636
|
+
|
637
|
+
/* Hook 1st char lookup. */
|
638
|
+
sf->hook_1st_chars[ sf->hook.beg[0] ] = 1;
|
639
|
+
sf->hook_1st_chars[ sf->hook.end[0] ] = 1;
|
640
|
+
sf->hook_1st_chars[ sf->hookesc[0] ] = 1;
|
641
|
+
}
|
642
|
+
}
|
643
|
+
|
644
|
+
|
645
|
+
/**
|
646
|
+
* Set hook value.
|
647
|
+
*
|
648
|
+
* @param sf Stackfile.
|
649
|
+
* @param hook Hook type.
|
515
650
|
* @param value New hook value.
|
516
651
|
*/
|
517
652
|
void sf_set_hook( stackfile_t* sf, hook_t hook, char* value )
|
518
653
|
{
|
654
|
+
/* Check that we are not in multi-hook mode. */
|
655
|
+
if ( sf->multi && hook != hook_esc )
|
656
|
+
{
|
657
|
+
/* Disable multi-hook mode. */
|
658
|
+
for ( int i = 0; i < sf->multi_cnt; i++ )
|
659
|
+
hookpair_del( &sf->multi[i] );
|
660
|
+
g_free( sf->multi );
|
661
|
+
sf->multi_cnt = 0;
|
662
|
+
}
|
519
663
|
|
520
664
|
/* Set values. */
|
521
665
|
switch ( hook )
|
522
666
|
{
|
523
|
-
case hook_beg: g_free( sf->
|
524
|
-
case hook_end: g_free( sf->
|
525
|
-
case hook_esc:
|
667
|
+
case hook_beg: g_free( sf->hook.beg ); sf->hook.beg = g_strdup( value ); break;
|
668
|
+
case hook_end: g_free( sf->hook.end ); sf->hook.end = g_strdup( value ); break;
|
669
|
+
case hook_esc:
|
670
|
+
{
|
671
|
+
/* Remove old esc from 1st char lookup. */
|
672
|
+
sf->hook_1st_chars[ sf->hookesc[0] ] = 0;
|
673
|
+
g_free( sf->hookesc );
|
674
|
+
sf->hookesc = g_strdup( value );
|
675
|
+
break;
|
676
|
+
}
|
526
677
|
default: break;
|
527
678
|
}
|
528
679
|
|
680
|
+
sf_update_hook_cache( sf );
|
681
|
+
}
|
529
682
|
|
530
|
-
/* Store these equalities for speed-up. */
|
531
683
|
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
684
|
+
/**
|
685
|
+
* Add multi-hook pair.
|
686
|
+
*
|
687
|
+
* @param sf Stackfile.
|
688
|
+
* @param beg Hookbeg of pair.
|
689
|
+
* @param end Hookend of pair.
|
690
|
+
*/
|
691
|
+
void sf_multi_hook( stackfile_t* sf, const char* beg, const char* end )
|
692
|
+
{
|
693
|
+
/* Check that hooks don't match escape. */
|
694
|
+
if ( !g_strcmp0( sf->hookesc, beg )
|
695
|
+
|| !g_strcmp0( sf->hookesc, end ) )
|
696
|
+
{
|
697
|
+
g_print( "mucgly: Esc hook is not allowed to match multihooks\n" );
|
698
|
+
exit( EXIT_FAILURE );
|
699
|
+
}
|
536
700
|
|
537
|
-
if (
|
538
|
-
|
539
|
-
|
540
|
-
|
701
|
+
if ( sf->multi == NULL )
|
702
|
+
{
|
703
|
+
/* Allocate enough pairs. */
|
704
|
+
sf->multi = g_new0( hookpair_t, MULTI_LIMIT );
|
705
|
+
sf->multi[0] = (hookpair_t) {0,0};
|
706
|
+
sf->multi_cnt = 0;
|
707
|
+
|
708
|
+
/* Clear non-multi-mode lookups. */
|
709
|
+
memset( sf->hook_1st_chars, 0, 256 * sizeof( guchar ) );
|
710
|
+
}
|
541
711
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
712
|
+
if ( sf->multi_cnt >= (MULTI_LIMIT-1) )
|
713
|
+
{
|
714
|
+
g_print( "mucgly: Too many multihooks, 127 allowed!\n" );
|
715
|
+
exit( EXIT_FAILURE );
|
716
|
+
}
|
717
|
+
|
718
|
+
sf->multi[sf->multi_cnt].beg = g_strdup( beg );
|
719
|
+
sf->multi[sf->multi_cnt].end = g_strdup( end );
|
720
|
+
sf->multi_cnt++;
|
721
|
+
sf->multi[sf->multi_cnt] = (hookpair_t) {0,0};
|
722
|
+
|
723
|
+
sf_update_hook_cache( sf );
|
547
724
|
}
|
548
725
|
|
549
726
|
|
550
727
|
/**
|
551
728
|
* Create new Filestack.
|
552
|
-
*
|
729
|
+
*
|
553
730
|
* @return Filestack.
|
554
731
|
*/
|
555
732
|
filestack_t* fs_new( void )
|
@@ -564,9 +741,9 @@ filestack_t* fs_new( void )
|
|
564
741
|
|
565
742
|
/**
|
566
743
|
* Free Filestack and close all Stackfiles.
|
567
|
-
*
|
744
|
+
*
|
568
745
|
* @param fs Filestack.
|
569
|
-
*
|
746
|
+
*
|
570
747
|
* @return NULL.
|
571
748
|
*/
|
572
749
|
filestack_t* fs_rem( filestack_t* fs )
|
@@ -587,7 +764,7 @@ filestack_t* fs_rem( filestack_t* fs )
|
|
587
764
|
|
588
765
|
/**
|
589
766
|
* Push file on top of Filestack.
|
590
|
-
*
|
767
|
+
*
|
591
768
|
* @param fs Filestack.
|
592
769
|
* @param filename New top file.
|
593
770
|
*/
|
@@ -596,7 +773,7 @@ void fs_push_file( filestack_t* fs, gchar* filename )
|
|
596
773
|
stackfile_t* sf;
|
597
774
|
|
598
775
|
if ( fs->file )
|
599
|
-
/*
|
776
|
+
/* Additional file. */
|
600
777
|
sf = sf_new( filename, fs_topfile(fs) );
|
601
778
|
else
|
602
779
|
/* First file, i.e. inherit stack_default hooks. */
|
@@ -610,9 +787,23 @@ void fs_push_file( filestack_t* fs, gchar* filename )
|
|
610
787
|
}
|
611
788
|
|
612
789
|
|
790
|
+
/**
|
791
|
+
* Push file on top of Filestack for later use (i.e. current macro is
|
792
|
+
* completely processed).
|
793
|
+
*
|
794
|
+
* @param fs Filestack.
|
795
|
+
* @param filename New top file.
|
796
|
+
*/
|
797
|
+
void fs_push_file_delayed( filestack_t* fs, gchar* filename )
|
798
|
+
{
|
799
|
+
fs_push_file( fs, filename );
|
800
|
+
fs->file = fs->file->next;
|
801
|
+
}
|
802
|
+
|
803
|
+
|
613
804
|
/**
|
614
805
|
* Pop file from top of Filestack. File is closed.
|
615
|
-
*
|
806
|
+
*
|
616
807
|
* @param fs Filestack.
|
617
808
|
*/
|
618
809
|
void fs_pop_file( filestack_t* fs )
|
@@ -632,13 +823,31 @@ void fs_pop_file( filestack_t* fs )
|
|
632
823
|
|
633
824
|
|
634
825
|
/**
|
635
|
-
* Get char from (through) Filestack (i.e. top file).
|
636
|
-
*
|
826
|
+
* Get char from (through) Filestack (i.e. top file). Stop at EOF, and
|
827
|
+
* don't pop the file in order to allow putback to the file.
|
828
|
+
*
|
637
829
|
* @param fs Filestack.
|
638
|
-
*
|
830
|
+
*
|
639
831
|
* @return Char or EOF.
|
640
832
|
*/
|
641
833
|
int fs_get( filestack_t* fs )
|
834
|
+
{
|
835
|
+
if ( fs->file != NULL )
|
836
|
+
return sf_get( fs_topfile(fs) );
|
837
|
+
else
|
838
|
+
return EOF;
|
839
|
+
}
|
840
|
+
|
841
|
+
|
842
|
+
/**
|
843
|
+
* Get char from (through) Filestack (i.e. top file). If EOF is
|
844
|
+
* encountered, continue with lower file if possible.
|
845
|
+
*
|
846
|
+
* @param fs Filestack.
|
847
|
+
*
|
848
|
+
* @return Char or EOF.
|
849
|
+
*/
|
850
|
+
int fs_get_one( filestack_t* fs )
|
642
851
|
{
|
643
852
|
int ret;
|
644
853
|
|
@@ -666,10 +875,10 @@ int fs_get( filestack_t* fs )
|
|
666
875
|
|
667
876
|
/**
|
668
877
|
* Put back char.
|
669
|
-
*
|
878
|
+
*
|
670
879
|
* @param fs Filestack.
|
671
880
|
* @param c Char.
|
672
|
-
*
|
881
|
+
*
|
673
882
|
* @return TRUE.
|
674
883
|
*/
|
675
884
|
gboolean fs_put( filestack_t* fs, char c )
|
@@ -682,11 +891,11 @@ gboolean fs_put( filestack_t* fs, char c )
|
|
682
891
|
/**
|
683
892
|
* Get n chars from Filestack. If ret is non-null, use that for
|
684
893
|
* storage.
|
685
|
-
*
|
894
|
+
*
|
686
895
|
* @param fs Filestack.
|
687
896
|
* @param n Number of chars to get.
|
688
897
|
* @param ret Storage for data.
|
689
|
-
*
|
898
|
+
*
|
690
899
|
* @return Return data.
|
691
900
|
*/
|
692
901
|
GString* fs_get_n( filestack_t* fs, int n, GString* ret )
|
@@ -732,11 +941,11 @@ GString* fs_get_n( filestack_t* fs, int n, GString* ret )
|
|
732
941
|
/**
|
733
942
|
* Put chars in str back to Filestack. If n is 0, then use strlen to
|
734
943
|
* get the count.
|
735
|
-
*
|
944
|
+
*
|
736
945
|
* @param fs Filestack.
|
737
946
|
* @param str Content to add.
|
738
947
|
* @param n Number of chars from content.
|
739
|
-
*
|
948
|
+
*
|
740
949
|
* @return True if success.
|
741
950
|
*/
|
742
951
|
gboolean fs_put_n( filestack_t* fs, gchar* str, int n )
|
@@ -757,9 +966,9 @@ gboolean fs_put_n( filestack_t* fs, gchar* str, int n )
|
|
757
966
|
|
758
967
|
/**
|
759
968
|
* Create new Outfile. If filename is NULL, then stream is stdout.
|
760
|
-
*
|
969
|
+
*
|
761
970
|
* @param filename File name (or NULL for stdout).
|
762
|
-
*
|
971
|
+
*
|
763
972
|
* @return Outfile.
|
764
973
|
*/
|
765
974
|
outfile_t* outfile_new( gchar* filename )
|
@@ -768,10 +977,10 @@ outfile_t* outfile_new( gchar* filename )
|
|
768
977
|
|
769
978
|
of = g_new0( outfile_t, 1 );
|
770
979
|
of->lineno = 0;
|
980
|
+
of->blocked = FALSE;
|
771
981
|
|
772
982
|
if ( filename )
|
773
983
|
{
|
774
|
-
|
775
984
|
/* Disk file output. */
|
776
985
|
|
777
986
|
of->filename = g_strdup( filename );
|
@@ -787,15 +996,12 @@ outfile_t* outfile_new( gchar* filename )
|
|
787
996
|
|
788
997
|
mucgly_fatal( err_sf, "Can't open \"%s\"", err_sf->filename );
|
789
998
|
}
|
790
|
-
|
791
999
|
}
|
792
1000
|
else
|
793
1001
|
{
|
794
|
-
|
795
1002
|
/* STDOUT output. */
|
796
1003
|
of->filename = g_strdup( "<STDOUT>" );
|
797
1004
|
of->fh = stdout;
|
798
|
-
|
799
1005
|
}
|
800
1006
|
|
801
1007
|
return of;
|
@@ -804,7 +1010,7 @@ outfile_t* outfile_new( gchar* filename )
|
|
804
1010
|
|
805
1011
|
/**
|
806
1012
|
* Free Outfile and close output stream if non-stdout.
|
807
|
-
*
|
1013
|
+
*
|
808
1014
|
* @param of Outfile.
|
809
1015
|
*/
|
810
1016
|
void outfile_rem( outfile_t* of )
|
@@ -820,9 +1026,9 @@ void outfile_rem( outfile_t* of )
|
|
820
1026
|
/**
|
821
1027
|
* Create Pstate. Create input file stack and output file
|
822
1028
|
* stack. Initialize parsing state.
|
823
|
-
*
|
1029
|
+
*
|
824
1030
|
* @param outfile Initial input file name.
|
825
|
-
*
|
1031
|
+
*
|
826
1032
|
* @return Pstate.
|
827
1033
|
*/
|
828
1034
|
pstate_t* ps_new( gchar* outfile )
|
@@ -844,17 +1050,19 @@ pstate_t* ps_new( gchar* outfile )
|
|
844
1050
|
/* Match string buffer. */
|
845
1051
|
ps->match_buf = g_string_sized_new( 0 );
|
846
1052
|
|
847
|
-
|
848
1053
|
ps->output = g_list_prepend( ps->output, outfile_new( outfile ) );
|
849
1054
|
ps->flush = FALSE;
|
850
1055
|
|
1056
|
+
ps->post_push = FALSE;
|
1057
|
+
ps->post_pop = FALSE;
|
1058
|
+
|
851
1059
|
return ps;
|
852
1060
|
}
|
853
1061
|
|
854
1062
|
|
855
1063
|
/**
|
856
1064
|
* Free Pstate. Close all input and output files.
|
857
|
-
*
|
1065
|
+
*
|
858
1066
|
* @param ps Pstate.
|
859
1067
|
*/
|
860
1068
|
void ps_rem( pstate_t* ps )
|
@@ -876,9 +1084,10 @@ void ps_rem( pstate_t* ps )
|
|
876
1084
|
/**
|
877
1085
|
* Fast check for current input char being first char of any of the
|
878
1086
|
* hooks.
|
879
|
-
*
|
1087
|
+
*
|
880
1088
|
* @param ps Pstate.
|
881
|
-
*
|
1089
|
+
* @param c Char to check.
|
1090
|
+
*
|
882
1091
|
* @return TRUE if next char matches 1st char of any hook.
|
883
1092
|
*/
|
884
1093
|
gboolean ps_check_hook( pstate_t* ps, int c )
|
@@ -900,11 +1109,11 @@ gboolean ps_check_hook( pstate_t* ps, int c )
|
|
900
1109
|
/**
|
901
1110
|
* Check if input has the match string coming next. Erase the matched
|
902
1111
|
* string if erase is true and input is matched.
|
903
|
-
*
|
1112
|
+
*
|
904
1113
|
* @param ps Pstate.
|
905
1114
|
* @param match Match string.
|
906
1115
|
* @param erase Erase matched string (but only if matched).
|
907
|
-
*
|
1116
|
+
*
|
908
1117
|
* @return True if match.
|
909
1118
|
*/
|
910
1119
|
gboolean ps_check( pstate_t* ps, gchar* match, gboolean erase )
|
@@ -920,21 +1129,34 @@ gboolean ps_check( pstate_t* ps, gchar* match, gboolean erase )
|
|
920
1129
|
|
921
1130
|
len = strlen( match );
|
922
1131
|
input = fs_get_n( ps->fs, len, ps->check_buf );
|
923
|
-
ret = !g_strcmp0( input->str, ps->match_buf->str );
|
924
1132
|
|
925
|
-
if (
|
926
|
-
|
927
|
-
|
1133
|
+
if ( input->len == 0 )
|
1134
|
+
{
|
1135
|
+
/* We are at end-of-file. Let's give up and pop the file from
|
1136
|
+
filestack. */
|
1137
|
+
fs_pop_file( ps->fs );
|
1138
|
+
return FALSE;
|
1139
|
+
}
|
1140
|
+
else
|
1141
|
+
{
|
1142
|
+
/* At least partial match string was received. */
|
928
1143
|
|
929
|
-
|
1144
|
+
ret = !g_strcmp0( input->str, ps->match_buf->str );
|
1145
|
+
|
1146
|
+
if ( !ret || !erase )
|
1147
|
+
/* Put back checked chars. */
|
1148
|
+
fs_put_n( ps->fs, input->str, input->len );
|
1149
|
+
|
1150
|
+
return ret;
|
1151
|
+
}
|
930
1152
|
}
|
931
1153
|
|
932
1154
|
|
933
1155
|
/**
|
934
1156
|
* Check input for hookesc.
|
935
|
-
*
|
1157
|
+
*
|
936
1158
|
* @param ps Pstate.
|
937
|
-
*
|
1159
|
+
*
|
938
1160
|
* @return TRUE on match.
|
939
1161
|
*/
|
940
1162
|
gboolean ps_check_hookesc( pstate_t* ps )
|
@@ -946,11 +1168,37 @@ gboolean ps_check_hookesc( pstate_t* ps )
|
|
946
1168
|
}
|
947
1169
|
|
948
1170
|
|
1171
|
+
/**
|
1172
|
+
* Save hookpair on top of stack.
|
1173
|
+
*
|
1174
|
+
* @param sf Stackfile (as context).
|
1175
|
+
* @param pair Hookpair to store.
|
1176
|
+
*/
|
1177
|
+
void ps_push_curhook( stackfile_t* sf, hookpair_t* pair )
|
1178
|
+
{
|
1179
|
+
sf->curhook = g_list_prepend(
|
1180
|
+
sf->curhook,
|
1181
|
+
hookpair_dup( pair, g_new0( hookpair_t, 1 ) ) );
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
|
1185
|
+
/**
|
1186
|
+
* Pop of top of stack hookpair.
|
1187
|
+
*
|
1188
|
+
* @param sf Stackfile (as context).
|
1189
|
+
*/
|
1190
|
+
void ps_pop_curhook( stackfile_t* sf )
|
1191
|
+
{
|
1192
|
+
hookpair_del( (hookpair_t*) sf->curhook->data );
|
1193
|
+
sf->curhook = g_list_delete_link( sf->curhook, sf->curhook );
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
|
949
1197
|
/**
|
950
1198
|
* Check input for hookbeg.
|
951
|
-
*
|
1199
|
+
*
|
952
1200
|
* @param ps Pstate.
|
953
|
-
*
|
1201
|
+
*
|
954
1202
|
* @return TRUE on match.
|
955
1203
|
*/
|
956
1204
|
gboolean ps_check_hookbeg( pstate_t* ps )
|
@@ -958,42 +1206,99 @@ gboolean ps_check_hookbeg( pstate_t* ps )
|
|
958
1206
|
if ( !ps_has_file(ps) )
|
959
1207
|
return FALSE;
|
960
1208
|
|
961
|
-
|
1209
|
+
gboolean ret;
|
1210
|
+
stackfile_t* sf = ps_topfile(ps);
|
1211
|
+
|
1212
|
+
if ( sf->multi )
|
1213
|
+
{
|
1214
|
+
ret = FALSE;
|
1215
|
+
|
1216
|
+
/* Check all hookbegs for match. */
|
1217
|
+
for ( int i = 0; i < sf->multi_cnt; i++ )
|
1218
|
+
{
|
1219
|
+
ret = ps_check( ps, sf->multi[i].beg, TRUE );
|
1220
|
+
if ( ret )
|
1221
|
+
{
|
1222
|
+
ps_push_curhook( sf, &sf->multi[i] );
|
1223
|
+
break;
|
1224
|
+
}
|
1225
|
+
}
|
1226
|
+
}
|
1227
|
+
else
|
1228
|
+
{
|
1229
|
+
ret = ps_check( ps, sf->hook.beg, TRUE );
|
1230
|
+
|
1231
|
+
if ( ret )
|
1232
|
+
ps_push_curhook( sf, &sf->hook );
|
1233
|
+
}
|
1234
|
+
|
1235
|
+
return ret;
|
962
1236
|
}
|
963
1237
|
|
964
1238
|
|
965
1239
|
/**
|
966
1240
|
* Check input for hookend.
|
967
|
-
*
|
1241
|
+
*
|
968
1242
|
* @param ps Pstate.
|
969
|
-
*
|
1243
|
+
*
|
970
1244
|
* @return TRUE on match.
|
971
1245
|
*/
|
972
1246
|
gboolean ps_check_hookend( pstate_t* ps )
|
973
1247
|
{
|
974
1248
|
if ( !ps_has_file(ps) )
|
975
1249
|
return FALSE;
|
1250
|
+
else
|
1251
|
+
return ps_check( ps, ps_current_hookend(ps), TRUE );
|
1252
|
+
}
|
976
1253
|
|
977
|
-
|
1254
|
+
|
1255
|
+
/**
|
1256
|
+
* Return hookbeg string that opened the current macro.
|
1257
|
+
*
|
1258
|
+
* @param ps PState.
|
1259
|
+
*
|
1260
|
+
* @return
|
1261
|
+
*/
|
1262
|
+
gchar* ps_current_hookbeg( pstate_t* ps )
|
1263
|
+
{
|
1264
|
+
hookpair_t* h;
|
1265
|
+
h = ps_topfile(ps)->curhook->data;
|
1266
|
+
return h->beg;
|
1267
|
+
}
|
1268
|
+
|
1269
|
+
|
1270
|
+
/**
|
1271
|
+
* Return hookend string that opened the current macro.
|
1272
|
+
*
|
1273
|
+
* @param ps PState.
|
1274
|
+
*
|
1275
|
+
* @return
|
1276
|
+
*/
|
1277
|
+
gchar* ps_current_hookend( pstate_t* ps )
|
1278
|
+
{
|
1279
|
+
hookpair_t* h;
|
1280
|
+
h = ps_topfile(ps)->curhook->data;
|
1281
|
+
return h->end;
|
978
1282
|
}
|
979
1283
|
|
980
1284
|
|
1285
|
+
|
981
1286
|
/**
|
982
1287
|
* Get char (through Filestack).
|
983
|
-
*
|
1288
|
+
*
|
984
1289
|
* @param ps Pstate.
|
985
|
-
*
|
1290
|
+
*
|
986
1291
|
* @return Char or EOF.
|
987
1292
|
*/
|
988
1293
|
int ps_in( pstate_t* ps )
|
989
1294
|
{
|
990
|
-
return
|
1295
|
+
return fs_get_one( ps->fs );
|
991
1296
|
}
|
992
1297
|
|
993
1298
|
|
994
1299
|
/**
|
995
1300
|
* Output char to current output stream.
|
996
|
-
*
|
1301
|
+
*
|
997
1302
|
* @param ps Pstate.
|
998
1303
|
* @param c Char.
|
999
1304
|
*/
|
@@ -1001,18 +1306,21 @@ void ps_out( pstate_t* ps, int c )
|
|
1001
1306
|
{
|
1002
1307
|
outfile_t* of = ps->output->data;
|
1003
1308
|
|
1004
|
-
if (
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1309
|
+
if ( of->blocked == FALSE )
|
1310
|
+
{
|
1311
|
+
if ( c == '\n' )
|
1312
|
+
of->lineno++;
|
1313
|
+
|
1314
|
+
fputc( c, of->fh );
|
1315
|
+
if ( ps->flush )
|
1316
|
+
fflush( of->fh );
|
1317
|
+
}
|
1010
1318
|
}
|
1011
1319
|
|
1012
1320
|
|
1013
1321
|
/**
|
1014
1322
|
* Output chars with ps_out.
|
1015
|
-
*
|
1323
|
+
*
|
1016
1324
|
* @param ps Pstate.
|
1017
1325
|
* @param str Output string (or NULL for no output).
|
1018
1326
|
*/
|
@@ -1030,9 +1338,33 @@ void ps_out_str( pstate_t* ps, gchar* str )
|
|
1030
1338
|
}
|
1031
1339
|
|
1032
1340
|
|
1341
|
+
/**
|
1342
|
+
* Block output stream.
|
1343
|
+
*
|
1344
|
+
* @param ps Pstate.
|
1345
|
+
*/
|
1346
|
+
void ps_block_output( pstate_t* ps )
|
1347
|
+
{
|
1348
|
+
outfile_t* of = ps->output->data;
|
1349
|
+
of->blocked = TRUE;
|
1350
|
+
}
|
1351
|
+
|
1352
|
+
|
1353
|
+
/**
|
1354
|
+
* Unblock output stream.
|
1355
|
+
*
|
1356
|
+
* @param ps Pstate.
|
1357
|
+
*/
|
1358
|
+
void ps_unblock_output( pstate_t* ps )
|
1359
|
+
{
|
1360
|
+
outfile_t* of = ps->output->data;
|
1361
|
+
of->blocked = FALSE;
|
1362
|
+
}
|
1363
|
+
|
1364
|
+
|
1033
1365
|
/**
|
1034
1366
|
* Push new output stream on top of output file stack.
|
1035
|
-
*
|
1367
|
+
*
|
1036
1368
|
* @param ps Pstate.
|
1037
1369
|
* @param filename File name.
|
1038
1370
|
*/
|
@@ -1045,7 +1377,7 @@ void ps_push_file( pstate_t* ps, gchar* filename )
|
|
1045
1377
|
|
1046
1378
|
/**
|
1047
1379
|
* Pop file from output file stack. Close the stream.
|
1048
|
-
*
|
1380
|
+
*
|
1049
1381
|
* @param ps Pstate.
|
1050
1382
|
*/
|
1051
1383
|
void ps_pop_file( pstate_t* ps )
|
@@ -1060,9 +1392,9 @@ void ps_pop_file( pstate_t* ps )
|
|
1060
1392
|
|
1061
1393
|
/**
|
1062
1394
|
* Return current Stackfile (input stream).
|
1063
|
-
*
|
1395
|
+
*
|
1064
1396
|
* @param ps Pstate.
|
1065
|
-
*
|
1397
|
+
*
|
1066
1398
|
* @return Stackfile (or NULL if none).
|
1067
1399
|
*/
|
1068
1400
|
stackfile_t* ps_current_file( pstate_t* ps )
|
@@ -1076,9 +1408,10 @@ stackfile_t* ps_current_file( pstate_t* ps )
|
|
1076
1408
|
}
|
1077
1409
|
|
1078
1410
|
|
1411
|
+
|
1079
1412
|
/**
|
1080
1413
|
* Initialize macro content collection.
|
1081
|
-
*
|
1414
|
+
*
|
1082
1415
|
* @param ps Pstate.
|
1083
1416
|
*/
|
1084
1417
|
void ps_start_collect( pstate_t* ps )
|
@@ -1089,7 +1422,7 @@ void ps_start_collect( pstate_t* ps )
|
|
1089
1422
|
|
1090
1423
|
/**
|
1091
1424
|
* Add content to macro.
|
1092
|
-
*
|
1425
|
+
*
|
1093
1426
|
* @param ps Pstate.
|
1094
1427
|
* @param c Char to add.
|
1095
1428
|
*/
|
@@ -1099,16 +1432,42 @@ void ps_collect( pstate_t* ps, int c )
|
|
1099
1432
|
}
|
1100
1433
|
|
1101
1434
|
|
1435
|
+
/**
|
1436
|
+
* Enter first level macro and setup state accordingly.
|
1437
|
+
*
|
1438
|
+
* @param ps Pstate.
|
1439
|
+
*/
|
1440
|
+
void ps_enter_macro( pstate_t* ps )
|
1441
|
+
{
|
1442
|
+
/* New macro starting. */
|
1443
|
+
ps->in_macro++;
|
1444
|
+
|
1445
|
+
/* Store macro start info. */
|
1446
|
+
sf_mark_macro( ps_topfile( ps ) );
|
1447
|
+
|
1448
|
+
ps_start_collect( ps );
|
1449
|
+
}
|
1450
|
+
|
1451
|
+
|
1102
1452
|
/**
|
1103
1453
|
* Get current macro content.
|
1104
|
-
*
|
1454
|
+
*
|
1105
1455
|
* @param ps Pstate.
|
1106
|
-
*
|
1456
|
+
*
|
1107
1457
|
* @return Macro content.
|
1108
1458
|
*/
|
1109
1459
|
char* ps_get_macro( pstate_t* ps )
|
1110
1460
|
{
|
1111
|
-
|
1461
|
+
if ( ps->macro_buf->str[0] == '+' )
|
1462
|
+
{
|
1463
|
+
/* Eat the next char after macro. */
|
1464
|
+
ps_topfile(ps)->eat_tail = TRUE;
|
1465
|
+
return &ps->macro_buf->str[1];
|
1466
|
+
}
|
1467
|
+
else
|
1468
|
+
{
|
1469
|
+
return ps->macro_buf->str;
|
1470
|
+
}
|
1112
1471
|
}
|
1113
1472
|
|
1114
1473
|
|
@@ -1116,12 +1475,12 @@ char* ps_get_macro( pstate_t* ps )
|
|
1116
1475
|
* Evaluate str as Ruby code and convert result to string. Conversion
|
1117
1476
|
* is performed if execution was successful and conversion was
|
1118
1477
|
* requested.
|
1119
|
-
*
|
1120
|
-
* @param ps
|
1121
|
-
* @param str
|
1478
|
+
*
|
1479
|
+
* @param ps Pstate.
|
1480
|
+
* @param str Ruby code string.
|
1122
1481
|
* @param to_str Result convert enable.
|
1123
|
-
* @param ctxt
|
1124
|
-
*
|
1482
|
+
* @param ctxt Context (name) for execution.
|
1483
|
+
*
|
1125
1484
|
* @return Ruby code execution as string (or NULL).
|
1126
1485
|
*/
|
1127
1486
|
gchar* ps_eval_ruby_str( pstate_t* ps, gchar* str, gboolean to_str, char* ctxt )
|
@@ -1168,8 +1527,9 @@ gchar* ps_eval_ruby_str( pstate_t* ps, gchar* str, gboolean to_str, char* ctxt )
|
|
1168
1527
|
|
1169
1528
|
|
1170
1529
|
/**
|
1171
|
-
* Load file Ruby intepreter.
|
1172
|
-
*
|
1530
|
+
* Load file with Ruby intepreter.
|
1531
|
+
*
|
1532
|
+
* @param ps Pstate.
|
1173
1533
|
* @param filename Source file.
|
1174
1534
|
*/
|
1175
1535
|
void ps_load_ruby_file( pstate_t* ps, gchar* filename )
|
@@ -1185,9 +1545,9 @@ void ps_load_ruby_file( pstate_t* ps, gchar* filename )
|
|
1185
1545
|
|
1186
1546
|
/**
|
1187
1547
|
* Execute Mucgly command/macro.
|
1188
|
-
*
|
1548
|
+
*
|
1189
1549
|
* @param ps Pstate.
|
1190
|
-
*
|
1550
|
+
*
|
1191
1551
|
* @return TRUE if input processing should be aborted.
|
1192
1552
|
*/
|
1193
1553
|
gboolean ps_eval_cmd( pstate_t* ps )
|
@@ -1239,11 +1599,20 @@ gboolean ps_eval_cmd( pstate_t* ps )
|
|
1239
1599
|
}
|
1240
1600
|
|
1241
1601
|
else if ( ( len = len_str_cmp( ":include", cmd ) ) )
|
1242
|
-
|
1602
|
+
{
|
1603
|
+
fs_push_file_delayed( ps->fs, &cmd[ len+1 ] );
|
1604
|
+
ps->post_push = TRUE;
|
1605
|
+
}
|
1243
1606
|
|
1244
1607
|
else if ( ( len = len_str_cmp( ":source", cmd ) ) )
|
1245
1608
|
ps_load_ruby_file( ps, &cmd[ len+1 ] );
|
1246
1609
|
|
1610
|
+
else if ( ( len = len_str_cmp( ":block", cmd ) ) )
|
1611
|
+
ps_block_output( ps );
|
1612
|
+
|
1613
|
+
else if ( ( len = len_str_cmp( ":unblock", cmd ) ) )
|
1614
|
+
ps_unblock_output( ps );
|
1615
|
+
|
1247
1616
|
else if ( ( len = len_str_cmp( ":comment", cmd ) ) )
|
1248
1617
|
{
|
1249
1618
|
/* Do nothing. */
|
@@ -1276,12 +1645,12 @@ gboolean ps_eval_cmd( pstate_t* ps )
|
|
1276
1645
|
{
|
1277
1646
|
/* Postpone evaluation (to next round). */
|
1278
1647
|
|
1279
|
-
ps_out_str( ps,
|
1648
|
+
ps_out_str( ps, ps_current_hookbeg( ps ) );
|
1280
1649
|
|
1281
1650
|
/* Remove one # sign. */
|
1282
1651
|
ps_out_str( ps, &cmd[1] );
|
1283
1652
|
|
1284
|
-
ps_out_str( ps,
|
1653
|
+
ps_out_str( ps, ps_current_hookend( ps ) );
|
1285
1654
|
}
|
1286
1655
|
|
1287
1656
|
else
|
@@ -1294,51 +1663,90 @@ gboolean ps_eval_cmd( pstate_t* ps )
|
|
1294
1663
|
}
|
1295
1664
|
|
1296
1665
|
|
1297
|
-
/**
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1666
|
+
/**
|
1667
|
+
* Processing routine for hookend phase.
|
1668
|
+
*
|
1669
|
+
* @param ps Pstate.
|
1670
|
+
* @param do_break True if current processing phase is over.
|
1671
|
+
*/
|
1672
|
+
void ps_process_hook_end_seq( pstate_t* ps, gboolean* do_break )
|
1673
|
+
{
|
1674
|
+
ps->in_macro--;
|
1675
|
+
|
1676
|
+
if ( ps->in_macro < 0 )
|
1677
|
+
{
|
1678
|
+
mucgly_fatal( ps_topfile(ps), "Internal error in macro status..." );
|
1679
|
+
}
|
1680
|
+
else if ( ps->in_macro )
|
1681
|
+
{
|
1682
|
+
/* Multilevel macro decrement. */
|
1683
|
+
/* Output the consumed hookend. */
|
1684
|
+
ps_out_str( ps, ps_current_hookend( ps ) );
|
1685
|
+
ps_pop_curhook( ps_topfile(ps) );
|
1686
|
+
*do_break = FALSE;
|
1687
|
+
}
|
1688
|
+
else
|
1689
|
+
{
|
1690
|
+
/* Back to base level from macro, eval the macro. */
|
1691
|
+
*do_break = ps_eval_cmd( ps );
|
1692
|
+
sf_unmark_macro( ps_topfile( ps ) );
|
1693
|
+
ps_pop_curhook( ps_topfile(ps) );
|
1694
|
+
|
1695
|
+
if ( ps->post_push == TRUE )
|
1696
|
+
{
|
1697
|
+
ps->post_push = FALSE;
|
1698
|
+
ps->fs->file = ps->fs->file->prev;
|
1699
|
+
}
|
1700
|
+
|
1701
|
+
if ( ps->post_pop )
|
1702
|
+
{
|
1703
|
+
ps->post_pop = FALSE;
|
1704
|
+
fs_pop_file( ps->fs );
|
1705
|
+
}
|
1706
|
+
}
|
1707
|
+
}
|
1708
|
+
|
1709
|
+
|
1710
|
+
/**
|
1711
|
+
* Processing routine for non-hook chars.
|
1712
|
+
*
|
1713
|
+
* @param ps Pstate.
|
1714
|
+
* @param c Current char input.
|
1715
|
+
* @param do_break True if should break from current phase.
|
1716
|
+
*/
|
1717
|
+
void ps_process_non_hook_seq( pstate_t* ps, int c, gboolean* do_break )
|
1718
|
+
{
|
1719
|
+
/* Non-hook input. */
|
1720
|
+
if ( ps->in_macro )
|
1721
|
+
{
|
1722
|
+
*do_break = FALSE;
|
1723
|
+
|
1724
|
+
if ( c == EOF )
|
1725
|
+
mucgly_error( ps_current_file(ps), "Got EOF within macro!" );
|
1726
|
+
|
1727
|
+
/* Add content to macro. */
|
1728
|
+
ps_collect( ps, c );
|
1729
|
+
}
|
1730
|
+
else
|
1731
|
+
{
|
1732
|
+
if ( c == EOF )
|
1733
|
+
{
|
1734
|
+
*do_break = TRUE;
|
1735
|
+
}
|
1736
|
+
else
|
1737
|
+
{
|
1738
|
+
*do_break = FALSE;
|
1739
|
+
|
1740
|
+
/* Output to current output file. */
|
1741
|
+
ps_out( ps, c );
|
1742
|
+
}
|
1743
|
+
}
|
1744
|
+
}
|
1337
1745
|
|
1338
1746
|
|
1339
1747
|
/**
|
1340
1748
|
* Process input file (or stack of files).
|
1341
|
-
*
|
1749
|
+
*
|
1342
1750
|
* @param ps Pstate.
|
1343
1751
|
* @param infile Input file name.
|
1344
1752
|
* @param outfile Output file name (or NULL). Outfile string is freed.
|
@@ -1346,6 +1754,7 @@ gboolean ps_eval_cmd( pstate_t* ps )
|
|
1346
1754
|
void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
|
1347
1755
|
{
|
1348
1756
|
int c;
|
1757
|
+
gboolean do_break = FALSE;
|
1349
1758
|
|
1350
1759
|
fs_push_file( ps->fs, infile );
|
1351
1760
|
|
@@ -1399,24 +1808,10 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
|
|
1399
1808
|
if ( ( c == ' ' || c == '\n' ) &&
|
1400
1809
|
ps_topfile(ps)->hook_esc_eq_end )
|
1401
1810
|
{
|
1402
|
-
|
1403
1811
|
/* Space/newline and hookesc is same as hookbeg. */
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
if ( ps->in_macro )
|
1408
|
-
{
|
1409
|
-
/* Multilevel macro decrement. */
|
1410
|
-
|
1411
|
-
/* Output the consumed hookend. */
|
1412
|
-
ps_out_str( ps, ps_topfile(ps)->hookend );
|
1413
|
-
}
|
1414
|
-
else
|
1415
|
-
{
|
1416
|
-
/* Back to base level from macro, eval the macro. */
|
1417
|
-
if ( ps_eval_cmd( ps ) )
|
1418
|
-
break;
|
1419
|
-
}
|
1812
|
+
ps_process_hook_end_seq( ps, &do_break );
|
1813
|
+
if ( do_break )
|
1814
|
+
break;
|
1420
1815
|
}
|
1421
1816
|
else
|
1422
1817
|
{
|
@@ -1467,13 +1862,17 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
|
|
1467
1862
|
{
|
1468
1863
|
/* Escape is same as hookbeg and escape is
|
1469
1864
|
not used to eat out spaces. */
|
1470
|
-
ps->in_macro++;
|
1471
1865
|
|
1472
1866
|
/* Put back the extra char (for safety/clarity). */
|
1473
1867
|
fs_put( ps->fs, c );
|
1474
1868
|
|
1869
|
+
/* Push hook here. For non-esc hooks
|
1870
|
+
this is done while matching for
|
1871
|
+
hook. */
|
1872
|
+
ps_push_curhook( ps_topfile(ps), &ps_topfile(ps)->hook );
|
1873
|
+
|
1475
1874
|
/* Start collect the macro content. */
|
1476
|
-
|
1875
|
+
ps_enter_macro( ps );
|
1477
1876
|
}
|
1478
1877
|
}
|
1479
1878
|
else
|
@@ -1488,8 +1887,11 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
|
|
1488
1887
|
}
|
1489
1888
|
else if ( ps->in_macro && ps_check_hookend( ps ) )
|
1490
1889
|
{
|
1491
|
-
/* Hookend has priority over hookbeg if we are in
|
1492
|
-
|
1890
|
+
/* Hookend has priority over hookbeg if we are in
|
1891
|
+
macro. Also hookend is ignored when outside macro. */
|
1892
|
+
ps_process_hook_end_seq( ps, &do_break );
|
1893
|
+
if ( do_break )
|
1894
|
+
break;
|
1493
1895
|
}
|
1494
1896
|
else if ( ps_check_hookbeg( ps ) )
|
1495
1897
|
{
|
@@ -1502,33 +1904,26 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
|
|
1502
1904
|
ps->in_macro++;
|
1503
1905
|
|
1504
1906
|
/* Output the consumed hookbeg. */
|
1505
|
-
ps_out_str( ps,
|
1907
|
+
ps_out_str( ps, ps_current_hookbeg( ps ) );
|
1506
1908
|
}
|
1507
1909
|
else
|
1508
1910
|
{
|
1509
|
-
|
1510
|
-
ps->in_macro++;
|
1511
|
-
|
1512
|
-
/* Store macro start info. */
|
1513
|
-
sf_mark_macro( ps_topfile( ps ) );
|
1514
|
-
|
1515
|
-
ps_start_collect( ps );
|
1911
|
+
ps_enter_macro( ps );
|
1516
1912
|
}
|
1517
|
-
|
1518
|
-
}
|
1519
|
-
else if ( ps_check_hookend( ps ) )
|
1520
|
-
{
|
1521
|
-
HOOK_END_SEQ;
|
1522
1913
|
}
|
1523
1914
|
else
|
1524
1915
|
{
|
1525
1916
|
c = ps_in( ps );
|
1526
|
-
|
1917
|
+
ps_process_non_hook_seq( ps, c, &do_break );
|
1918
|
+
if ( do_break )
|
1919
|
+
break;
|
1527
1920
|
}
|
1528
1921
|
}
|
1529
1922
|
else
|
1530
1923
|
{
|
1531
|
-
|
1924
|
+
ps_process_non_hook_seq( ps, c, &do_break );
|
1925
|
+
if ( do_break )
|
1926
|
+
break;
|
1532
1927
|
}
|
1533
1928
|
}
|
1534
1929
|
|
@@ -1547,10 +1942,10 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
|
|
1547
1942
|
|
1548
1943
|
/**
|
1549
1944
|
* Mucgly.write method. Write output current output without NL.
|
1550
|
-
*
|
1945
|
+
*
|
1551
1946
|
* @param obj Not used.
|
1552
1947
|
* @param rstr Written string (Ruby String).
|
1553
|
-
*
|
1948
|
+
*
|
1554
1949
|
* @return Qnil.
|
1555
1950
|
*/
|
1556
1951
|
VALUE mucgly_write( VALUE obj, VALUE rstr )
|
@@ -1572,10 +1967,10 @@ VALUE mucgly_write( VALUE obj, VALUE rstr )
|
|
1572
1967
|
|
1573
1968
|
/**
|
1574
1969
|
* Mucgly.puts method. Write output current output with NL.
|
1575
|
-
*
|
1970
|
+
*
|
1576
1971
|
* @param obj Not used.
|
1577
1972
|
* @param rstr Written string (Ruby String).
|
1578
|
-
*
|
1973
|
+
*
|
1579
1974
|
* @return Qnil.
|
1580
1975
|
*/
|
1581
1976
|
VALUE mucgly_puts( VALUE obj, VALUE rstr )
|
@@ -1599,35 +1994,35 @@ VALUE mucgly_puts( VALUE obj, VALUE rstr )
|
|
1599
1994
|
|
1600
1995
|
/**
|
1601
1996
|
* Mucgly.hookbeg method. Get hookbeg.
|
1602
|
-
*
|
1997
|
+
*
|
1603
1998
|
* @param obj Not used.
|
1604
|
-
*
|
1999
|
+
*
|
1605
2000
|
* @return Hookbeg as Ruby String.
|
1606
2001
|
*/
|
1607
2002
|
VALUE mucgly_hookbeg( VALUE obj )
|
1608
2003
|
{
|
1609
|
-
return rb_str_new_cstr( ps_current_file( ruby_ps )->
|
2004
|
+
return rb_str_new_cstr( ps_current_file( ruby_ps )->hook.beg );
|
1610
2005
|
}
|
1611
2006
|
|
1612
2007
|
|
1613
2008
|
/**
|
1614
2009
|
* Mucgly.hookend method. Get hookend.
|
1615
|
-
*
|
2010
|
+
*
|
1616
2011
|
* @param obj Not used.
|
1617
|
-
*
|
2012
|
+
*
|
1618
2013
|
* @return Hookend as Ruby String.
|
1619
2014
|
*/
|
1620
2015
|
VALUE mucgly_hookend( VALUE obj )
|
1621
2016
|
{
|
1622
|
-
return rb_str_new_cstr( ps_current_file( ruby_ps )->
|
2017
|
+
return rb_str_new_cstr( ps_current_file( ruby_ps )->hook.end );
|
1623
2018
|
}
|
1624
2019
|
|
1625
2020
|
|
1626
2021
|
/**
|
1627
2022
|
* Mucgly.hookesc method. Get hookesc.
|
1628
|
-
*
|
2023
|
+
*
|
1629
2024
|
* @param obj Not used.
|
1630
|
-
*
|
2025
|
+
*
|
1631
2026
|
* @return Hookesc as Ruby String.
|
1632
2027
|
*/
|
1633
2028
|
VALUE mucgly_hookesc( VALUE obj )
|
@@ -1638,10 +2033,10 @@ VALUE mucgly_hookesc( VALUE obj )
|
|
1638
2033
|
|
1639
2034
|
/**
|
1640
2035
|
* Mucgly.sethookbeg method. Set hookbeg.
|
1641
|
-
*
|
2036
|
+
*
|
1642
2037
|
* @param obj Not used.
|
1643
2038
|
* @param rstr Hookbeg string (Ruby String).
|
1644
|
-
*
|
2039
|
+
*
|
1645
2040
|
* @return Qnil.
|
1646
2041
|
*/
|
1647
2042
|
VALUE mucgly_sethookbeg( VALUE obj, VALUE rstr )
|
@@ -1655,10 +2050,10 @@ VALUE mucgly_sethookbeg( VALUE obj, VALUE rstr )
|
|
1655
2050
|
|
1656
2051
|
/**
|
1657
2052
|
* Mucgly.sethookend method. Set hookend.
|
1658
|
-
*
|
2053
|
+
*
|
1659
2054
|
* @param obj Not used.
|
1660
2055
|
* @param rstr Hookend string (Ruby String).
|
1661
|
-
*
|
2056
|
+
*
|
1662
2057
|
* @return Qnil.
|
1663
2058
|
*/
|
1664
2059
|
VALUE mucgly_sethookend( VALUE obj, VALUE rstr )
|
@@ -1672,10 +2067,10 @@ VALUE mucgly_sethookend( VALUE obj, VALUE rstr )
|
|
1672
2067
|
|
1673
2068
|
/**
|
1674
2069
|
* Mucgly.sethookesc method. Set hookesc.
|
1675
|
-
*
|
2070
|
+
*
|
1676
2071
|
* @param obj Not used.
|
1677
2072
|
* @param rstr Hookesc string (Ruby String).
|
1678
|
-
*
|
2073
|
+
*
|
1679
2074
|
* @return Qnil.
|
1680
2075
|
*/
|
1681
2076
|
VALUE mucgly_sethookesc( VALUE obj, VALUE rstr )
|
@@ -1687,11 +2082,38 @@ VALUE mucgly_sethookesc( VALUE obj, VALUE rstr )
|
|
1687
2082
|
}
|
1688
2083
|
|
1689
2084
|
|
2085
|
+
/**
|
2086
|
+
* Mucgly.multihook method. Add multihook pairs.
|
2087
|
+
*
|
2088
|
+
* @param obj Not used.
|
2089
|
+
* @param ary Array of hookpairs.
|
2090
|
+
*
|
2091
|
+
* @return Qnil.
|
2092
|
+
*/
|
2093
|
+
VALUE mucgly_multihook( VALUE obj, VALUE ary )
|
2094
|
+
{
|
2095
|
+
if ( ( RARRAY_LEN(ary) % 2 ) != 0 )
|
2096
|
+
rb_raise( rb_eRuntimeError,
|
2097
|
+
"mucgly: Must have even number of multi hook args, had %d!",
|
2098
|
+
((int) RARRAY_LEN(ary)) );
|
2099
|
+
|
2100
|
+
char* beg, *end;
|
2101
|
+
for ( int i = 0; i < RARRAY_LEN(ary); i += 2 )
|
2102
|
+
{
|
2103
|
+
beg = RSTRING_PTR( RARRAY_PTR(ary)[i] );
|
2104
|
+
end = RSTRING_PTR( RARRAY_PTR(ary)[i+1] );
|
2105
|
+
sf_multi_hook( ps_topfile( ruby_ps ), beg, end );
|
2106
|
+
}
|
2107
|
+
|
2108
|
+
return Qnil;
|
2109
|
+
}
|
2110
|
+
|
2111
|
+
|
1690
2112
|
/**
|
1691
2113
|
* Mucgly.ifilename method. Gets current input file name.
|
1692
|
-
*
|
2114
|
+
*
|
1693
2115
|
* @param obj Not used.
|
1694
|
-
*
|
2116
|
+
*
|
1695
2117
|
* @return Input file name (Ruby String).
|
1696
2118
|
*/
|
1697
2119
|
VALUE mucgly_ifilename( VALUE obj )
|
@@ -1702,9 +2124,9 @@ VALUE mucgly_ifilename( VALUE obj )
|
|
1702
2124
|
|
1703
2125
|
/**
|
1704
2126
|
* Mucgly.ilinenumber method. Gets current input file line.
|
1705
|
-
*
|
2127
|
+
*
|
1706
2128
|
* @param obj Not used.
|
1707
|
-
*
|
2129
|
+
*
|
1708
2130
|
* @return Input file line number (Ruby Fixnum).
|
1709
2131
|
*/
|
1710
2132
|
VALUE mucgly_ilinenumber( VALUE obj )
|
@@ -1715,9 +2137,9 @@ VALUE mucgly_ilinenumber( VALUE obj )
|
|
1715
2137
|
|
1716
2138
|
/**
|
1717
2139
|
* Mucgly.ofilename method. Gets current output file name.
|
1718
|
-
*
|
2140
|
+
*
|
1719
2141
|
* @param obj Not used.
|
1720
|
-
*
|
2142
|
+
*
|
1721
2143
|
* @return Input file name (Ruby String).
|
1722
2144
|
*/
|
1723
2145
|
VALUE mucgly_ofilename( VALUE obj )
|
@@ -1730,9 +2152,9 @@ VALUE mucgly_ofilename( VALUE obj )
|
|
1730
2152
|
|
1731
2153
|
/**
|
1732
2154
|
* Mucgly.olinenumber method. Gets current output file line.
|
1733
|
-
*
|
2155
|
+
*
|
1734
2156
|
* @param obj Not used.
|
1735
|
-
*
|
2157
|
+
*
|
1736
2158
|
* @return Output file line number (Ruby Fixnum).
|
1737
2159
|
*/
|
1738
2160
|
VALUE mucgly_olinenumber( VALUE obj )
|
@@ -1745,10 +2167,10 @@ VALUE mucgly_olinenumber( VALUE obj )
|
|
1745
2167
|
|
1746
2168
|
/**
|
1747
2169
|
* Mucgly.pushinput method. Push new input stream.
|
1748
|
-
*
|
2170
|
+
*
|
1749
2171
|
* @param obj Not used.
|
1750
2172
|
* @param rstr Input file name (Ruby String).
|
1751
|
-
*
|
2173
|
+
*
|
1752
2174
|
* @return Qnil.
|
1753
2175
|
*/
|
1754
2176
|
VALUE mucgly_pushinput( VALUE obj, VALUE rstr )
|
@@ -1756,31 +2178,32 @@ VALUE mucgly_pushinput( VALUE obj, VALUE rstr )
|
|
1756
2178
|
char* str;
|
1757
2179
|
|
1758
2180
|
str = RSTRING_PTR( rstr );
|
1759
|
-
|
2181
|
+
fs_push_file_delayed( ruby_ps->fs, str );
|
2182
|
+
ruby_ps->post_push = TRUE;
|
1760
2183
|
return Qnil;
|
1761
2184
|
}
|
1762
2185
|
|
1763
2186
|
|
1764
2187
|
/**
|
1765
2188
|
* Mucgly.closeinput method. Pop input stream and close file stream.
|
1766
|
-
*
|
2189
|
+
*
|
1767
2190
|
* @param obj Not used.
|
1768
|
-
*
|
2191
|
+
*
|
1769
2192
|
* @return Qnil.
|
1770
2193
|
*/
|
1771
2194
|
VALUE mucgly_closeinput( VALUE obj )
|
1772
2195
|
{
|
1773
|
-
|
2196
|
+
ruby_ps->post_pop = TRUE;
|
1774
2197
|
return Qnil;
|
1775
2198
|
}
|
1776
2199
|
|
1777
2200
|
|
1778
2201
|
/**
|
1779
2202
|
* Mucgly.pushoutput method. Push new output stream.
|
1780
|
-
*
|
2203
|
+
*
|
1781
2204
|
* @param obj Not used.
|
1782
2205
|
* @param rstr Output file name (Ruby String).
|
1783
|
-
*
|
2206
|
+
*
|
1784
2207
|
* @return Qnil.
|
1785
2208
|
*/
|
1786
2209
|
VALUE mucgly_pushoutput( VALUE obj, VALUE rstr )
|
@@ -1795,9 +2218,9 @@ VALUE mucgly_pushoutput( VALUE obj, VALUE rstr )
|
|
1795
2218
|
|
1796
2219
|
/**
|
1797
2220
|
* Mucgly.closeoutput method. Pop output stream and close file stream.
|
1798
|
-
*
|
2221
|
+
*
|
1799
2222
|
* @param obj Not used.
|
1800
|
-
*
|
2223
|
+
*
|
1801
2224
|
* @return Qnil.
|
1802
2225
|
*/
|
1803
2226
|
VALUE mucgly_closeoutput( VALUE obj )
|
@@ -1807,14 +2230,42 @@ VALUE mucgly_closeoutput( VALUE obj )
|
|
1807
2230
|
}
|
1808
2231
|
|
1809
2232
|
|
2233
|
+
/**
|
2234
|
+
* Mucgly.block method. Block output.
|
2235
|
+
*
|
2236
|
+
* @param obj Not used.
|
2237
|
+
*
|
2238
|
+
* @return Qnil.
|
2239
|
+
*/
|
2240
|
+
VALUE mucgly_block( VALUE obj )
|
2241
|
+
{
|
2242
|
+
ps_block_output( ruby_ps );
|
2243
|
+
return Qnil;
|
2244
|
+
}
|
2245
|
+
|
2246
|
+
|
2247
|
+
/**
|
2248
|
+
* Mucgly.block method. Block output.
|
2249
|
+
*
|
2250
|
+
* @param obj Not used.
|
2251
|
+
*
|
2252
|
+
* @return Qnil.
|
2253
|
+
*/
|
2254
|
+
VALUE mucgly_unblock( VALUE obj )
|
2255
|
+
{
|
2256
|
+
ps_unblock_output( ruby_ps );
|
2257
|
+
return Qnil;
|
2258
|
+
}
|
2259
|
+
|
2260
|
+
|
1810
2261
|
#ifdef MUCGLY_LIB
|
1811
2262
|
/**
|
1812
2263
|
* Call mucgly C-side entry point. Convert Ruby ARGV array to C-array
|
1813
2264
|
* for C-side command line arg parsing.
|
1814
|
-
*
|
2265
|
+
*
|
1815
2266
|
* @param obj Not used.
|
1816
2267
|
* @param cli Ruby side ARGV.
|
1817
|
-
*
|
2268
|
+
*
|
1818
2269
|
* @return Qnil.
|
1819
2270
|
*/
|
1820
2271
|
VALUE mucgly_run_mucgly( VALUE obj, VALUE cli )
|
@@ -1839,7 +2290,7 @@ VALUE mucgly_run_mucgly( VALUE obj, VALUE cli )
|
|
1839
2290
|
|
1840
2291
|
/**
|
1841
2292
|
* Create Mucgly Ruby module and register all methods to it.
|
1842
|
-
*
|
2293
|
+
*
|
1843
2294
|
*/
|
1844
2295
|
void Init_mucgly( void )
|
1845
2296
|
{
|
@@ -1859,6 +2310,7 @@ void Init_mucgly( void )
|
|
1859
2310
|
rb_define_module_function( mMucgly, "sethookbeg", mucgly_sethookbeg, 1 );
|
1860
2311
|
rb_define_module_function( mMucgly, "sethookend", mucgly_sethookend, 1 );
|
1861
2312
|
rb_define_module_function( mMucgly, "sethookesc", mucgly_sethookesc, 1 );
|
2313
|
+
rb_define_module_function( mMucgly, "multihook", mucgly_multihook, 1 );
|
1862
2314
|
rb_define_module_function( mMucgly, "ifilename", mucgly_ifilename, 0 );
|
1863
2315
|
rb_define_module_function( mMucgly, "ilinenumber", mucgly_ilinenumber, 0 );
|
1864
2316
|
rb_define_module_function( mMucgly, "ofilename", mucgly_ofilename, 0 );
|
@@ -1867,6 +2319,8 @@ void Init_mucgly( void )
|
|
1867
2319
|
rb_define_module_function( mMucgly, "closeinput", mucgly_closeinput, 0 );
|
1868
2320
|
rb_define_module_function( mMucgly, "pushoutput", mucgly_pushoutput, 1 );
|
1869
2321
|
rb_define_module_function( mMucgly, "closeoutput", mucgly_closeoutput, 0 );
|
2322
|
+
rb_define_module_function( mMucgly, "block", mucgly_block, 0 );
|
2323
|
+
rb_define_module_function( mMucgly, "unblock", mucgly_unblock, 0 );
|
1870
2324
|
|
1871
2325
|
}
|
1872
2326
|
|
@@ -1874,10 +2328,10 @@ void Init_mucgly( void )
|
|
1874
2328
|
/**
|
1875
2329
|
* Generate outfile name from infile by removing the outfile_tag from
|
1876
2330
|
* infile name.
|
1877
|
-
*
|
2331
|
+
*
|
1878
2332
|
* @param infile Input file name.
|
1879
2333
|
* @param outfile_tag Tag to remove from infile to get outfile.
|
1880
|
-
*
|
2334
|
+
*
|
1881
2335
|
* @return Outfile name.
|
1882
2336
|
*/
|
1883
2337
|
gchar* infile_to_outfile( gchar* infile, gchar* outfile_tag )
|
@@ -1907,21 +2361,18 @@ gchar* infile_to_outfile( gchar* infile, gchar* outfile_tag )
|
|
1907
2361
|
* Main program:
|
1908
2362
|
* ------------------------------------------------------------ */
|
1909
2363
|
|
2364
|
+
/**
|
2365
|
+
* Mucgly entrypoint.
|
2366
|
+
*
|
2367
|
+
* @param argc Arg count.
|
2368
|
+
* @param argv Arg values.
|
2369
|
+
*/
|
1910
2370
|
void mucgly_main( int argc, char** argv )
|
1911
2371
|
{
|
1912
2372
|
|
1913
2373
|
/* Setup default hooks etc. */
|
1914
2374
|
stack_default = sf_new( NULL, NULL );
|
1915
2375
|
|
1916
|
-
/* ------------------------------------------------------------
|
1917
|
-
* Setup Ruby features:
|
1918
|
-
* ------------------------------------------------------------ */
|
1919
|
-
|
1920
|
-
#ifndef MUCGLY_LIB
|
1921
|
-
ruby_init();
|
1922
|
-
Init_mucgly();
|
1923
|
-
#endif
|
1924
|
-
|
1925
2376
|
|
1926
2377
|
/* ------------------------------------------------------------
|
1927
2378
|
* Command line parsing:
|
@@ -1936,6 +2387,7 @@ void mucgly_main( int argc, char** argv )
|
|
1936
2387
|
gchar* opt_end_sep = NULL;
|
1937
2388
|
gchar* opt_esc_sep = NULL;
|
1938
2389
|
gchar* opt_all_sep = NULL;
|
2390
|
+
gchar** opt_multi_sep = NULL;
|
1939
2391
|
gboolean opt_module = FALSE;
|
1940
2392
|
gboolean opt_interact = FALSE;
|
1941
2393
|
gboolean opt_no_init = FALSE;
|
@@ -1945,28 +2397,43 @@ void mucgly_main( int argc, char** argv )
|
|
1945
2397
|
{
|
1946
2398
|
{ "files", 'f', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_files,
|
1947
2399
|
"Input file(s) (default: stdin).", NULL },
|
2400
|
+
|
1948
2401
|
{ "configs", 'c', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_configs,
|
1949
2402
|
"Ruby configuration file(s).", NULL },
|
2403
|
+
|
1950
2404
|
{ "output", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output,
|
1951
2405
|
"Output file(s) (default: stdout).", NULL },
|
2406
|
+
|
1952
2407
|
{ "genout", 'g', 0, G_OPTION_ARG_STRING, &opt_genout,
|
1953
2408
|
"Generate output file names (remove arg from input filename).", NULL },
|
2409
|
+
|
1954
2410
|
{ "cli_cmds", 'l', 0, G_OPTION_ARG_STRING_ARRAY, &opt_cli_cmds,
|
1955
2411
|
"Command line configuration(s).", NULL },
|
2412
|
+
|
1956
2413
|
{ "beg_sep", 'b', 0, G_OPTION_ARG_STRING, &opt_beg_sep,
|
1957
2414
|
"Set hookbeg separator (default: '-<').", NULL },
|
2415
|
+
|
1958
2416
|
{ "end_sep", 'e', 0, G_OPTION_ARG_STRING, &opt_end_sep,
|
1959
2417
|
"Set hookend separator (default: '>-').", NULL },
|
2418
|
+
|
1960
2419
|
{ "esc_sep", 's', 0, G_OPTION_ARG_STRING, &opt_esc_sep,
|
1961
2420
|
"Set hookesc separator (default: '\\').", NULL },
|
2421
|
+
|
1962
2422
|
{ "all_sep", 'a', 0, G_OPTION_ARG_STRING, &opt_all_sep,
|
1963
2423
|
"Set all separators.", NULL },
|
2424
|
+
|
2425
|
+
{ "multi_sep", 'u', 0, G_OPTION_ARG_STRING_ARRAY, &opt_multi_sep,
|
2426
|
+
"Set multiple beg/end hook pairs.", NULL },
|
2427
|
+
|
1964
2428
|
{ "module", 'm', 0, G_OPTION_ARG_NONE, &opt_module,
|
1965
2429
|
"Include Mucgly module at startup.", NULL },
|
2430
|
+
|
1966
2431
|
{ "interact", 'i', 0, G_OPTION_ARG_NONE, &opt_interact,
|
1967
2432
|
"Flush output for convenient interaction.", NULL },
|
2433
|
+
|
1968
2434
|
{ "no_init", 'n', 0, G_OPTION_ARG_NONE, &opt_no_init,
|
1969
2435
|
"No init file (skip MUCGLY env var).", NULL },
|
2436
|
+
|
1970
2437
|
{ NULL }
|
1971
2438
|
};
|
1972
2439
|
|
@@ -2049,6 +2516,30 @@ void mucgly_main( int argc, char** argv )
|
|
2049
2516
|
sf_set_hook( stack_default, hook_esc, opt_all_sep );
|
2050
2517
|
}
|
2051
2518
|
|
2519
|
+
/* Set multi-hooks. */
|
2520
|
+
if ( opt_multi_sep )
|
2521
|
+
{
|
2522
|
+
int cnt = 0;
|
2523
|
+
|
2524
|
+
/* First check that we have even number of hooks. */
|
2525
|
+
while ( opt_multi_sep[ cnt ] ) cnt++;
|
2526
|
+
|
2527
|
+
if ( ( cnt % 2 ) != 0 )
|
2528
|
+
{
|
2529
|
+
g_print( "mucgly: Must have even number of multi hook args, had %d!\n", cnt );
|
2530
|
+
exit( EXIT_FAILURE );
|
2531
|
+
}
|
2532
|
+
|
2533
|
+
cnt = 0;
|
2534
|
+
while ( opt_multi_sep[ cnt ] )
|
2535
|
+
{
|
2536
|
+
sf_multi_hook( stack_default,
|
2537
|
+
opt_multi_sep[ cnt ],
|
2538
|
+
opt_multi_sep[ cnt+1 ] );
|
2539
|
+
cnt += 2;
|
2540
|
+
}
|
2541
|
+
}
|
2542
|
+
|
2052
2543
|
|
2053
2544
|
if ( opt_interact )
|
2054
2545
|
/* Flush output immediately in interactive mode. */
|
@@ -2084,14 +2575,20 @@ void mucgly_main( int argc, char** argv )
|
|
2084
2575
|
#ifndef MUCGLY_LIB
|
2085
2576
|
/**
|
2086
2577
|
* C-top entry point.
|
2087
|
-
*
|
2578
|
+
*
|
2088
2579
|
* @param argc Cli arg count.
|
2089
2580
|
* @param argv Cli arg values.
|
2090
|
-
*
|
2581
|
+
*
|
2091
2582
|
* @return Not used.
|
2092
2583
|
*/
|
2093
2584
|
int main( int argc, char** argv )
|
2094
2585
|
{
|
2586
|
+
|
2587
|
+
/* Setup Ruby and mucgly module. */
|
2588
|
+
ruby_init();
|
2589
|
+
Init_mucgly();
|
2590
|
+
|
2591
|
+
/* Enter mucgly. */
|
2095
2592
|
mucgly_main( argc, argv );
|
2096
2593
|
}
|
2097
2594
|
#endif
|