mucgly 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|