mucgly 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,11 @@
1
1
  = Version history
2
2
 
3
+ [0.2.1] Suspension feature for language mode compliance.
4
+ Character eater.
5
+ Mucgly.sethook method added.
6
+ Mucgly.seteater method added.
7
+ Checks for argument types in Mucgly methods.
8
+
3
9
  [0.2.0] Multihook feature.
4
10
  Remote escape feature.
5
11
  Block output feature.
@@ -63,6 +63,8 @@ For all command line options, see:
63
63
 
64
64
  * Multiple, concurrent macro start and end limiters (multihook).
65
65
 
66
+ * Compatible with editor's language sensitive mode.
67
+
66
68
  * Multiple sources for configuration: default config, environment
67
69
  variable, command line.
68
70
 
@@ -165,6 +167,65 @@ happen multiple times. If a single hook set is performed (again),
165
167
  singlehook mode is entered. This can also be used as method for
166
168
  resetting the current set of multihooks.
167
169
 
170
+ === Suspension
171
+
172
+ Suspension is a feature that helps in implementing macros that are
173
+ compliant with the text editor's language sensitive mode.
174
+
175
+ By default Mucgly macros do not look like part of the host language,
176
+ e.g. C language. However macros can be made to emulate the host
177
+ language.
178
+
179
+ For example the user might want to make the macro to look like a
180
+ function call in the host language.
181
+
182
+ The macro could be used like this:
183
+
184
+ c = rx( inline_mult( "c", "a1" ) );
185
+
186
+ Here hookbeg is "rx(" and hookend is ")". From the C language point of
187
+ view, this looks like two nested function calls. "rx" is called and
188
+ its argument is a return value from "inline_mult" function. From Ruby
189
+ point of view, we want "inline_mult" to be called as a Ruby
190
+ method. However, by default the macro would terminate to the first
191
+ closing parenthesis, which would cause a syntax error in the end.
192
+
193
+ The solution is to declare "(" as suspension character. Suspension
194
+ character means that for each occurence of the suspension character,
195
+ one hookend will be suspended, i.e. de-activated. Hence the first "("
196
+ after starting the macro with "rx(", will suspend the next ")",
197
+ i.e. hookend. Since there is only one "(", there will be only one
198
+ suspension performed, and the final ")" will terminate the macro. The
199
+ suspended hookend will be taken as part of the macro body.
200
+
201
+ In order to get suspension, a multihook is declared including a
202
+ suspension character/string.
203
+
204
+ /*-<+Mucgly.multihook( [ "rx(", ")", "(" ] )>-*/
205
+
206
+ Suspensions could be replaced with simple escape of the first ")"
207
+ within the macro call, but this is inconvenient, and might potentially
208
+ cause issues with language mode of the host language.
209
+
210
+ Suspension mechanism is not bullet proof, and thus does not always
211
+ guarantee language mode compatibility. Languages with C based syntax
212
+ work well since they use the same style of function argument lists and
213
+ string conventions as in Ruby. Other type of languages might not
214
+ benefit from this feature.
215
+
216
+
217
+ === Eater
218
+
219
+ Eater is character/string which follows hookesc and designates that
220
+ the following char should be removed. This applies to both inside and
221
+ outside macros. The reason for adding "extra" characters to input
222
+ could be for example to trick the language mode of the host language
223
+ to change coloring.
224
+
225
+ Eater can be set with ":eater" or with "Mucgly.seteater". If
226
+ "Mucgly.seteater" is passed a nil, the Eater feature is disabled and
227
+ hookesc behaves as by default.
228
+
168
229
 
169
230
  == Special commands
170
231
 
@@ -280,6 +341,8 @@ Complete list of Mucgly module methods:
280
341
 
281
342
  [hookesc] Get hookesc value.
282
343
 
344
+ [sethook] Set hookbeg and hookend values.
345
+
283
346
  [sethookbeg] Set hookbeg value.
284
347
 
285
348
  [sethookend] Set hookend value.
@@ -92,7 +92,7 @@
92
92
  <dt id="VERSION-constant" class="">VERSION =
93
93
 
94
94
  </dt>
95
- <dd><pre class="code"><span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>0.2.0</span><span class='tstring_end'>&quot;</span></span></pre></dd>
95
+ <dd><pre class="code"><span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>0.2.1</span><span class='tstring_end'>&quot;</span></span></pre></dd>
96
96
 
97
97
  </dl>
98
98
 
@@ -177,9 +177,9 @@
177
177
  </div>
178
178
 
179
179
  <div id="footer">
180
- Generated on Sun Apr 24 19:00:00 2016 by
180
+ Generated on Mon Oct 24 20:35:30 2016 by
181
181
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
182
- 0.8.7.6 (ruby-2.1.2).
182
+ 0.8.7.6 (ruby-2.3.1).
183
183
  </div>
184
184
 
185
185
  </body>
@@ -104,9 +104,9 @@
104
104
  </div>
105
105
 
106
106
  <div id="footer">
107
- Generated on Sun Apr 24 19:00:00 2016 by
107
+ Generated on Mon Oct 24 20:35:29 2016 by
108
108
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
109
- 0.8.7.6 (ruby-2.1.2).
109
+ 0.8.7.6 (ruby-2.3.1).
110
110
  </div>
111
111
 
112
112
  </body>
@@ -63,7 +63,12 @@
63
63
 
64
64
  <div id="content"><div id='filecontents'>
65
65
  <h1 id="label-Version+history">Version history</h1>
66
- <dl class="rdoc-list label-list"><dt>0.2.0
66
+ <dl class="rdoc-list label-list"><dt>0.2.1
67
+ <dd>
68
+ <p>Suspension feature for language mode compliance. Character eater.
69
+ Mucgly.sethook method added. Mucgly.seteater method added. Checks for
70
+ argument types in Mucgly methods.</p>
71
+ </dd><dt>0.2.0
67
72
  <dd>
68
73
  <p>Multihook feature. Remote escape feature. Block output feature. Fix for
69
74
  hook at EOF parsing.</p>
@@ -89,9 +94,9 @@ compatible with older versions.</p>
89
94
  </div></div>
90
95
 
91
96
  <div id="footer">
92
- Generated on Sun Apr 24 19:00:00 2016 by
97
+ Generated on Mon Oct 24 20:35:30 2016 by
93
98
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
94
- 0.8.7.6 (ruby-2.1.2).
99
+ 0.8.7.6 (ruby-2.3.1).
95
100
  </div>
96
101
 
97
102
  </body>
@@ -130,6 +130,8 @@ line, configuration files, or from macro input file.</p>
130
130
  </li><li>
131
131
  <p>Multiple, concurrent macro start and end limiters (multihook).</p>
132
132
  </li><li>
133
+ <p>Compatible with editor&#39;s language sensitive mode.</p>
134
+ </li><li>
133
135
  <p>Multiple sources for configuration: default config, environment variable,
134
136
  command line.</p>
135
137
  </li><li>
@@ -229,6 +231,63 @@ happen multiple times. If a single hook set is performed (again),
229
231
  singlehook mode is entered. This can also be used as method for resetting
230
232
  the current set of multihooks.</p>
231
233
 
234
+ <h3 id="label-Suspension">Suspension</h3>
235
+
236
+ <p>Suspension is a feature that helps in implementing macros that are
237
+ compliant with the text editor&#39;s language sensitive mode.</p>
238
+
239
+ <p>By default Mucgly macros do not look like part of the host language, e.g. C
240
+ language. However macros can be made to emulate the host language.</p>
241
+
242
+ <p>For example the user might want to make the macro to look like a function
243
+ call in the host language.</p>
244
+
245
+ <p>The macro could be used like this:</p>
246
+
247
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_c'>c</span> <span class='op'>=</span> <span class='id identifier rubyid_rx'>rx</span><span class='lparen'>(</span> <span class='id identifier rubyid_inline_mult'>inline_mult</span><span class='lparen'>(</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>c</span><span class='tstring_end'>&quot;</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>a1</span><span class='tstring_end'>&quot;</span></span> <span class='rparen'>)</span> <span class='rparen'>)</span><span class='semicolon'>;</span>
248
+ </code></pre>
249
+
250
+ <p>Here hookbeg is “rx(” and hookend is “)”. From the C language point of
251
+ view, this looks like two nested function calls. “rx” is called and its
252
+ argument is a return value from “inline_mult” function. From Ruby point of
253
+ view, we want “inline_mult” to be called as a Ruby method. However, by
254
+ default the macro would terminate to the first closing parenthesis, which
255
+ would cause a syntax error in the end.</p>
256
+
257
+ <p>The solution is to declare “(” as suspension character. Suspension
258
+ character means that for each occurence of the suspension character, one
259
+ hookend will be suspended, i.e. de-activated. Hence the first “(” after
260
+ starting the macro with “rx(”, will suspend the next “)”, i.e. hookend.
261
+ Since there is only one “(”, there will be only one suspension performed,
262
+ and the final “)” will terminate the macro. The suspended hookend will be
263
+ taken as part of the macro body.</p>
264
+
265
+ <p>In order to get suspension, a multihook is declared including a suspension
266
+ character/string.</p>
267
+
268
+ <pre class="code ruby"><code class="ruby"><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>*-&lt;+Mucgly.multihook( [ &quot;rx(&quot;, &quot;)&quot;, &quot;(&quot; ] )&gt;-*</span><span class='regexp_end'>/</span></span></code></pre>
269
+
270
+ <p>Suspensions could be replaced with simple escape of the first “)” within
271
+ the macro call, but this is inconvenient, and might potentially cause
272
+ issues with language mode of the host language.</p>
273
+
274
+ <p>Suspension mechanism is not bullet proof, and thus does not always
275
+ guarantee language mode compatibility. Languages with C based syntax work
276
+ well since they use the same style of function argument lists and string
277
+ conventions as in Ruby. Other type of languages might not benefit from this
278
+ feature.</p>
279
+
280
+ <h3 id="label-Eater">Eater</h3>
281
+
282
+ <p>Eater is character/string which follows hookesc and designates that the
283
+ following char should be removed. This applies to both inside and outside
284
+ macros. The reason for adding “extra” characters to input could be for
285
+ example to trick the language mode of the host language to change coloring.</p>
286
+
287
+ <p>Eater can be set with “:eater” or with “Mucgly.seteater”. If
288
+ “Mucgly.seteater” is passed a nil, the Eater feature is disabled and
289
+ hookesc behaves as by default.</p>
290
+
232
291
  <h2 id="label-Special+commands">Special commands</h2>
233
292
 
234
293
  <p>In addition to regular Ruby code the macros are allowed to include so
@@ -355,6 +414,9 @@ Hook-commands change the current hook values.</p>
355
414
  </dd><dt>hookesc
356
415
  <dd>
357
416
  <p>Get hookesc value.</p>
417
+ </dd><dt>sethook
418
+ <dd>
419
+ <p>Set hookbeg and hookend values.</p>
358
420
  </dd><dt>sethookbeg
359
421
  <dd>
360
422
  <p>Set hookbeg value.</p>
@@ -466,9 +528,9 @@ GEM executable (i.e. same command line options).</p>
466
528
  </div></div>
467
529
 
468
530
  <div id="footer">
469
- Generated on Sun Apr 24 19:00:00 2016 by
531
+ Generated on Mon Oct 24 20:35:30 2016 by
470
532
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
471
- 0.8.7.6 (ruby-2.1.2).
533
+ 0.8.7.6 (ruby-2.3.1).
472
534
  </div>
473
535
 
474
536
  </body>
@@ -130,6 +130,8 @@ line, configuration files, or from macro input file.</p>
130
130
  </li><li>
131
131
  <p>Multiple, concurrent macro start and end limiters (multihook).</p>
132
132
  </li><li>
133
+ <p>Compatible with editor&#39;s language sensitive mode.</p>
134
+ </li><li>
133
135
  <p>Multiple sources for configuration: default config, environment variable,
134
136
  command line.</p>
135
137
  </li><li>
@@ -229,6 +231,63 @@ happen multiple times. If a single hook set is performed (again),
229
231
  singlehook mode is entered. This can also be used as method for resetting
230
232
  the current set of multihooks.</p>
231
233
 
234
+ <h3 id="label-Suspension">Suspension</h3>
235
+
236
+ <p>Suspension is a feature that helps in implementing macros that are
237
+ compliant with the text editor&#39;s language sensitive mode.</p>
238
+
239
+ <p>By default Mucgly macros do not look like part of the host language, e.g. C
240
+ language. However macros can be made to emulate the host language.</p>
241
+
242
+ <p>For example the user might want to make the macro to look like a function
243
+ call in the host language.</p>
244
+
245
+ <p>The macro could be used like this:</p>
246
+
247
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_c'>c</span> <span class='op'>=</span> <span class='id identifier rubyid_rx'>rx</span><span class='lparen'>(</span> <span class='id identifier rubyid_inline_mult'>inline_mult</span><span class='lparen'>(</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>c</span><span class='tstring_end'>&quot;</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>a1</span><span class='tstring_end'>&quot;</span></span> <span class='rparen'>)</span> <span class='rparen'>)</span><span class='semicolon'>;</span>
248
+ </code></pre>
249
+
250
+ <p>Here hookbeg is “rx(” and hookend is “)”. From the C language point of
251
+ view, this looks like two nested function calls. “rx” is called and its
252
+ argument is a return value from “inline_mult” function. From Ruby point of
253
+ view, we want “inline_mult” to be called as a Ruby method. However, by
254
+ default the macro would terminate to the first closing parenthesis, which
255
+ would cause a syntax error in the end.</p>
256
+
257
+ <p>The solution is to declare “(” as suspension character. Suspension
258
+ character means that for each occurence of the suspension character, one
259
+ hookend will be suspended, i.e. de-activated. Hence the first “(” after
260
+ starting the macro with “rx(”, will suspend the next “)”, i.e. hookend.
261
+ Since there is only one “(”, there will be only one suspension performed,
262
+ and the final “)” will terminate the macro. The suspended hookend will be
263
+ taken as part of the macro body.</p>
264
+
265
+ <p>In order to get suspension, a multihook is declared including a suspension
266
+ character/string.</p>
267
+
268
+ <pre class="code ruby"><code class="ruby"><span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>*-&lt;+Mucgly.multihook( [ &quot;rx(&quot;, &quot;)&quot;, &quot;(&quot; ] )&gt;-*</span><span class='regexp_end'>/</span></span></code></pre>
269
+
270
+ <p>Suspensions could be replaced with simple escape of the first “)” within
271
+ the macro call, but this is inconvenient, and might potentially cause
272
+ issues with language mode of the host language.</p>
273
+
274
+ <p>Suspension mechanism is not bullet proof, and thus does not always
275
+ guarantee language mode compatibility. Languages with C based syntax work
276
+ well since they use the same style of function argument lists and string
277
+ conventions as in Ruby. Other type of languages might not benefit from this
278
+ feature.</p>
279
+
280
+ <h3 id="label-Eater">Eater</h3>
281
+
282
+ <p>Eater is character/string which follows hookesc and designates that the
283
+ following char should be removed. This applies to both inside and outside
284
+ macros. The reason for adding “extra” characters to input could be for
285
+ example to trick the language mode of the host language to change coloring.</p>
286
+
287
+ <p>Eater can be set with “:eater” or with “Mucgly.seteater”. If
288
+ “Mucgly.seteater” is passed a nil, the Eater feature is disabled and
289
+ hookesc behaves as by default.</p>
290
+
232
291
  <h2 id="label-Special+commands">Special commands</h2>
233
292
 
234
293
  <p>In addition to regular Ruby code the macros are allowed to include so
@@ -355,6 +414,9 @@ Hook-commands change the current hook values.</p>
355
414
  </dd><dt>hookesc
356
415
  <dd>
357
416
  <p>Get hookesc value.</p>
417
+ </dd><dt>sethook
418
+ <dd>
419
+ <p>Set hookbeg and hookend values.</p>
358
420
  </dd><dt>sethookbeg
359
421
  <dd>
360
422
  <p>Set hookbeg value.</p>
@@ -466,9 +528,9 @@ GEM executable (i.e. same command line options).</p>
466
528
  </div></div>
467
529
 
468
530
  <div id="footer">
469
- Generated on Sun Apr 24 19:00:00 2016 by
531
+ Generated on Mon Oct 24 20:35:30 2016 by
470
532
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
471
- 0.8.7.6 (ruby-2.1.2).
533
+ 0.8.7.6 (ruby-2.3.1).
472
534
  </div>
473
535
 
474
536
  </body>
@@ -103,9 +103,9 @@
103
103
  </div>
104
104
 
105
105
  <div id="footer">
106
- Generated on Sun Apr 24 19:00:00 2016 by
106
+ Generated on Mon Oct 24 20:35:30 2016 by
107
107
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
- 0.8.7.6 (ruby-2.1.2).
108
+ 0.8.7.6 (ruby-2.3.1).
109
109
  </div>
110
110
 
111
111
  </body>
@@ -81,11 +81,13 @@ void mucgly_debug( void ) {}
81
81
 
82
82
 
83
83
  /**
84
- * Pair of hooks for macro beginning and end.
84
+ * Pair of hooks for macro beginning and end. Plus optional suspension
85
+ * marker.
85
86
  */
86
87
  typedef struct hookpair_s {
87
- gchar* beg; /**< Hookbeg for input file. */
88
- gchar* end; /**< Hookend for input file. */
88
+ gchar* beg; /**< Hookbeg for macro. */
89
+ gchar* end; /**< Hookend for macro. */
90
+ gchar* susp; /**< Suspender for macro. */
89
91
  } hookpair_t;
90
92
 
91
93
 
@@ -110,6 +112,7 @@ typedef struct stackfile_s {
110
112
 
111
113
  hookpair_t hook; /**< Pair of hooks for macro boundary. */
112
114
  gchar* hookesc; /**< Hookesc for input file. */
115
+ gchar* eater; /**< Eater. */
113
116
 
114
117
  hookpair_t* multi; /**< Pairs of hooks for multi-hooking. */
115
118
  int multi_cnt; /**< Number of pairs in multi-hooking. */
@@ -117,10 +120,10 @@ typedef struct stackfile_s {
117
120
  /** Current hook, as stack to support nesting macros. */
118
121
  GList* curhook;
119
122
 
120
- /** Hookesc is same as hookbeg. Speeds up input processing. */
123
+ /** Hookesc is same as hookbeg. Speed-up for input processing. */
121
124
  gboolean hook_esc_eq_beg;
122
125
 
123
- /** Hookesc is same as hookend. Speeds up input processing. */
126
+ /** Hookesc is same as hookend. Speed-up for input processing. */
124
127
  gboolean hook_esc_eq_end;
125
128
 
126
129
  /** Lookup-table for the first chars of hooks. Speeds up input processing. */
@@ -169,6 +172,7 @@ typedef struct pstate_s {
169
172
  GString* match_buf; /**< Match str buffer. */
170
173
 
171
174
  int in_macro; /**< Processing within macro. */
175
+ int suspension; /**< Suspension level. */
172
176
 
173
177
  GList* output; /**< Stack of output streams. */
174
178
 
@@ -215,8 +219,9 @@ pstate_t* ruby_ps;
215
219
  * ------------------------------------------------------------ */
216
220
 
217
221
  void sf_update_hook_cache( stackfile_t* sf );
218
- void sf_multi_hook( stackfile_t* sf, const char* beg, const char* end );
222
+ void sf_multi_hook( stackfile_t* sf, const char* beg, const char* end, const char* susp );
219
223
  gchar* ps_current_hookend( pstate_t* ps );
224
+ gchar* ps_current_hooksusp( pstate_t* ps );
220
225
 
221
226
 
222
227
 
@@ -236,7 +241,7 @@ gchar* ps_current_hookend( pstate_t* ps );
236
241
  int len_str_cmp( char* str1, char* str2 )
237
242
  {
238
243
  int len = strlen( str1 );
239
-
244
+
240
245
  if ( !strncmp( str1, str2, len ) )
241
246
  return len;
242
247
  else
@@ -339,17 +344,18 @@ void mucgly_fatal( stackfile_t* sf, char* format, ... )
339
344
 
340
345
 
341
346
  /**
342
- * Duplicate hookpair content.
347
+ * Copy hookpair content.
343
348
  *
344
349
  * @param from Source.
345
350
  * @param to Destination.
346
351
  *
347
352
  * @return Destination.
348
353
  */
349
- hookpair_t* hookpair_dup( hookpair_t* from, hookpair_t* to )
354
+ hookpair_t* hookpair_cpy( hookpair_t* from, hookpair_t* to )
350
355
  {
351
356
  to->beg = g_strdup( from->beg );
352
357
  to->end = g_strdup( from->end );
358
+ to->susp = g_strdup( from->susp );
353
359
  return to;
354
360
  }
355
361
 
@@ -363,6 +369,7 @@ void hookpair_del( hookpair_t* pair )
363
369
  {
364
370
  g_free( pair->beg );
365
371
  g_free( pair->end );
372
+ g_free( pair->susp );
366
373
  }
367
374
 
368
375
 
@@ -424,7 +431,7 @@ stackfile_t* sf_new( gchar* filename, stackfile_t* inherit )
424
431
  if ( inherit )
425
432
  {
426
433
  /* Inherited hook values. */
427
- hookpair_dup( &inherit->hook, &sf->hook );
434
+ hookpair_cpy( &inherit->hook, &sf->hook );
428
435
  sf->hookesc = g_strdup( inherit->hookesc );
429
436
 
430
437
  /* Setup fast-lookup caches. */
@@ -434,7 +441,7 @@ stackfile_t* sf_new( gchar* filename, stackfile_t* inherit )
434
441
  {
435
442
  for ( int i = 0; i < inherit->multi_cnt; i++ )
436
443
  {
437
- sf_multi_hook( sf, inherit->multi[i].beg, inherit->multi[i].end );
444
+ sf_multi_hook( sf, inherit->multi[i].beg, inherit->multi[i].end, inherit->multi[i].susp );
438
445
  }
439
446
  }
440
447
  }
@@ -495,7 +502,7 @@ void sf_rem( stackfile_t* sf )
495
502
 
496
503
  hookpair_del( &sf->hook );
497
504
  g_free( sf->hookesc );
498
-
505
+
499
506
  if ( sf->multi )
500
507
  {
501
508
  for ( int i = 0; i < sf->multi_cnt; i++ )
@@ -517,7 +524,7 @@ void sf_rem( stackfile_t* sf )
517
524
  int sf_get( stackfile_t* sf )
518
525
  {
519
526
  int ret;
520
-
527
+
521
528
  re_read:
522
529
  if ( sf->buf->len > 0 )
523
530
  {
@@ -615,6 +622,8 @@ void sf_update_hook_cache( stackfile_t* sf )
615
622
  /* Add the latest addition to 1st char lookup. */
616
623
  sf->hook_1st_chars[ sf->multi[ sf->multi_cnt-1 ].beg[0] ] = 1;
617
624
  sf->hook_1st_chars[ sf->multi[ sf->multi_cnt-1 ].end[0] ] = 1;
625
+ if ( sf->multi[ sf->multi_cnt-1 ].susp )
626
+ sf->hook_1st_chars[ sf->multi[ sf->multi_cnt-1 ].susp[0] ] = 1;
618
627
 
619
628
  sf->hook_1st_chars[ sf->hookesc[0] ] = 1;
620
629
  }
@@ -681,6 +690,24 @@ void sf_set_hook( stackfile_t* sf, hook_t hook, char* value )
681
690
  }
682
691
 
683
692
 
693
+ /**
694
+ * Set eater value.
695
+ *
696
+ * @param sf Stackfile.
697
+ * @param value New eater value.
698
+ */
699
+ void sf_set_eater( stackfile_t* sf, char* value )
700
+ {
701
+ if ( sf->eater )
702
+ g_free( sf->eater );
703
+
704
+ sf->eater = NULL;
705
+ if ( value )
706
+ sf->eater = g_strdup( value );
707
+ }
708
+
709
+
710
+
684
711
  /**
685
712
  * Add multi-hook pair.
686
713
  *
@@ -688,7 +715,7 @@ void sf_set_hook( stackfile_t* sf, hook_t hook, char* value )
688
715
  * @param beg Hookbeg of pair.
689
716
  * @param end Hookend of pair.
690
717
  */
691
- void sf_multi_hook( stackfile_t* sf, const char* beg, const char* end )
718
+ void sf_multi_hook( stackfile_t* sf, const char* beg, const char* end, const char* susp )
692
719
  {
693
720
  /* Check that hooks don't match escape. */
694
721
  if ( !g_strcmp0( sf->hookesc, beg )
@@ -702,7 +729,7 @@ void sf_multi_hook( stackfile_t* sf, const char* beg, const char* end )
702
729
  {
703
730
  /* Allocate enough pairs. */
704
731
  sf->multi = g_new0( hookpair_t, MULTI_LIMIT );
705
- sf->multi[0] = (hookpair_t) {0,0};
732
+ sf->multi[0] = (hookpair_t) {0,0,0};
706
733
  sf->multi_cnt = 0;
707
734
 
708
735
  /* Clear non-multi-mode lookups. */
@@ -717,8 +744,10 @@ void sf_multi_hook( stackfile_t* sf, const char* beg, const char* end )
717
744
 
718
745
  sf->multi[sf->multi_cnt].beg = g_strdup( beg );
719
746
  sf->multi[sf->multi_cnt].end = g_strdup( end );
747
+ sf->multi[sf->multi_cnt].susp = g_strdup( susp );
748
+
720
749
  sf->multi_cnt++;
721
- sf->multi[sf->multi_cnt] = (hookpair_t) {0,0};
750
+ sf->multi[sf->multi_cnt] = (hookpair_t) {0,0,0};
722
751
 
723
752
  sf_update_hook_cache( sf );
724
753
  }
@@ -1040,10 +1069,11 @@ pstate_t* ps_new( gchar* outfile )
1040
1069
  ps->fs = fs_new();
1041
1070
 
1042
1071
  ps->in_macro = 0;
1072
+ ps->suspension = 0;
1043
1073
 
1044
1074
  /* Preview input buffer. */
1045
1075
  ps->check_buf = g_string_sized_new( 0 );
1046
-
1076
+
1047
1077
  /* Top level input buffer. */
1048
1078
  ps->macro_buf = g_string_sized_new( 0 );
1049
1079
 
@@ -1068,7 +1098,7 @@ pstate_t* ps_new( gchar* outfile )
1068
1098
  void ps_rem( pstate_t* ps )
1069
1099
  {
1070
1100
  fs_rem( ps->fs );
1071
-
1101
+
1072
1102
  g_string_free( ps->check_buf, TRUE );
1073
1103
  g_string_free( ps->macro_buf, TRUE );
1074
1104
 
@@ -1121,10 +1151,10 @@ gboolean ps_check( pstate_t* ps, gchar* match, gboolean erase )
1121
1151
  GString* input;
1122
1152
  int len;
1123
1153
  gboolean ret;
1124
-
1154
+
1125
1155
  /* Dup match string since it might disappear if Filestack stack is
1126
1156
  popped. */
1127
-
1157
+
1128
1158
  g_string_assign( ps->match_buf, match );
1129
1159
 
1130
1160
  len = strlen( match );
@@ -1178,7 +1208,7 @@ void ps_push_curhook( stackfile_t* sf, hookpair_t* pair )
1178
1208
  {
1179
1209
  sf->curhook = g_list_prepend(
1180
1210
  sf->curhook,
1181
- hookpair_dup( pair, g_new0( hookpair_t, 1 ) ) );
1211
+ hookpair_cpy( pair, g_new0( hookpair_t, 1 ) ) );
1182
1212
  }
1183
1213
 
1184
1214
 
@@ -1252,12 +1282,51 @@ gboolean ps_check_hookend( pstate_t* ps )
1252
1282
  }
1253
1283
 
1254
1284
 
1285
+ /**
1286
+ * Check input for hooksusp.
1287
+ *
1288
+ * @param ps Pstate.
1289
+ *
1290
+ * @return TRUE on match.
1291
+ */
1292
+ gboolean ps_check_hooksusp( pstate_t* ps )
1293
+ {
1294
+ gchar* susp;
1295
+
1296
+ if ( !ps_has_file(ps) )
1297
+ return FALSE;
1298
+ else if ( susp = ps_current_hooksusp(ps) )
1299
+ return ps_check( ps, susp, TRUE );
1300
+ else
1301
+ return FALSE;
1302
+ }
1303
+
1304
+
1305
+ /**
1306
+ * Check input for eater.
1307
+ *
1308
+ * @param ps Pstate.
1309
+ *
1310
+ * @return TRUE on match.
1311
+ */
1312
+ gboolean ps_check_eater( pstate_t* ps )
1313
+ {
1314
+ if ( !ps_has_file(ps) )
1315
+ return FALSE;
1316
+
1317
+ if ( ps_topfile(ps)->eater )
1318
+ return ps_check( ps, ps_topfile(ps)->eater, TRUE );
1319
+ else
1320
+ return FALSE;
1321
+ }
1322
+
1323
+
1255
1324
  /**
1256
1325
  * Return hookbeg string that opened the current macro.
1257
1326
  *
1258
1327
  * @param ps PState.
1259
1328
  *
1260
- * @return
1329
+ * @return
1261
1330
  */
1262
1331
  gchar* ps_current_hookbeg( pstate_t* ps )
1263
1332
  {
@@ -1268,11 +1337,11 @@ gchar* ps_current_hookbeg( pstate_t* ps )
1268
1337
 
1269
1338
 
1270
1339
  /**
1271
- * Return hookend string that opened the current macro.
1340
+ * Return hookend string that closes the current macro.
1272
1341
  *
1273
1342
  * @param ps PState.
1274
1343
  *
1275
- * @return
1344
+ * @return
1276
1345
  */
1277
1346
  gchar* ps_current_hookend( pstate_t* ps )
1278
1347
  {
@@ -1282,6 +1351,20 @@ gchar* ps_current_hookend( pstate_t* ps )
1282
1351
  }
1283
1352
 
1284
1353
 
1354
+ /**
1355
+ * Return hooksusp string that suspends the current hookend.
1356
+ *
1357
+ * @param ps PState.
1358
+ *
1359
+ * @return
1360
+ */
1361
+ gchar* ps_current_hooksusp( pstate_t* ps )
1362
+ {
1363
+ hookpair_t* h;
1364
+ h = ps_topfile(ps)->curhook->data;
1365
+ return h->susp;
1366
+ }
1367
+
1285
1368
 
1286
1369
  /**
1287
1370
  * Get char (through Filestack).
@@ -1310,7 +1393,7 @@ void ps_out( pstate_t* ps, int c )
1310
1393
  {
1311
1394
  if ( c == '\n' )
1312
1395
  of->lineno++;
1313
-
1396
+
1314
1397
  fputc( c, of->fh );
1315
1398
  if ( ps->flush )
1316
1399
  fflush( of->fh );
@@ -1432,6 +1515,18 @@ void ps_collect( pstate_t* ps, int c )
1432
1515
  }
1433
1516
 
1434
1517
 
1518
+ /**
1519
+ * Add str content to macro.
1520
+ *
1521
+ * @param ps Pstate.
1522
+ * @param str String to add.
1523
+ */
1524
+ void ps_collect_str( pstate_t* ps, gchar* str )
1525
+ {
1526
+ g_string_append( ps->macro_buf, str );
1527
+ }
1528
+
1529
+
1435
1530
  /**
1436
1531
  * Enter first level macro and setup state accordingly.
1437
1532
  *
@@ -1444,7 +1539,7 @@ void ps_enter_macro( pstate_t* ps )
1444
1539
 
1445
1540
  /* Store macro start info. */
1446
1541
  sf_mark_macro( ps_topfile( ps ) );
1447
-
1542
+
1448
1543
  ps_start_collect( ps );
1449
1544
  }
1450
1545
 
@@ -1553,7 +1648,7 @@ void ps_load_ruby_file( pstate_t* ps, gchar* filename )
1553
1648
  gboolean ps_eval_cmd( pstate_t* ps )
1554
1649
  {
1555
1650
  char* cmd;
1556
-
1651
+
1557
1652
  cmd = ps_get_macro( ps );
1558
1653
 
1559
1654
  if ( cmd[0] == ':' )
@@ -1570,6 +1665,8 @@ gboolean ps_eval_cmd( pstate_t* ps )
1570
1665
  sf_set_hook( ps_topfile(ps), hook_end, &cmd[ len+1 ] );
1571
1666
  else if ( ( len = len_str_cmp( ":hookesc", cmd ) ) )
1572
1667
  sf_set_hook( ps_topfile(ps), hook_esc, &cmd[ len+1 ] );
1668
+ else if ( ( len = len_str_cmp( ":eater", cmd ) ) )
1669
+ sf_set_eater( ps_topfile(ps), &cmd[ len+1 ] );
1573
1670
 
1574
1671
  else if ( ( len = len_str_cmp( ":hookall", cmd ) ) )
1575
1672
  {
@@ -1581,7 +1678,7 @@ gboolean ps_eval_cmd( pstate_t* ps )
1581
1678
  else if ( ( len = len_str_cmp( ":hook", cmd ) ) )
1582
1679
  {
1583
1680
  gchar** pieces;
1584
-
1681
+
1585
1682
  pieces = g_strsplit( &cmd[ len+1 ], " ", 2 );
1586
1683
  if ( g_strv_length( pieces ) == 2 )
1587
1684
  {
@@ -1629,13 +1726,13 @@ gboolean ps_eval_cmd( pstate_t* ps )
1629
1726
  mucgly_error( ps_topfile(ps), "Unknown internal command: \"%s\"", &cmd[len+1] );
1630
1727
  }
1631
1728
  }
1632
-
1729
+
1633
1730
  else if ( cmd[0] == '.' )
1634
1731
  {
1635
1732
  /* Mucgly variable output. */
1636
1733
  ps_out_str( ps, ps_eval_ruby_str( ps, &cmd[1], TRUE, NULL ) );
1637
1734
  }
1638
-
1735
+
1639
1736
  else if ( cmd[0] == '/' )
1640
1737
  {
1641
1738
  /* Mucgly comment, do nothing. */
@@ -1652,7 +1749,7 @@ gboolean ps_eval_cmd( pstate_t* ps )
1652
1749
 
1653
1750
  ps_out_str( ps, ps_current_hookend( ps ) );
1654
1751
  }
1655
-
1752
+
1656
1753
  else
1657
1754
  {
1658
1755
  /* Ruby code execution. */
@@ -1703,7 +1800,7 @@ void ps_process_hook_end_seq( pstate_t* ps, gboolean* do_break )
1703
1800
  ps->post_pop = FALSE;
1704
1801
  fs_pop_file( ps->fs );
1705
1802
  }
1706
- }
1803
+ }
1707
1804
  }
1708
1805
 
1709
1806
 
@@ -1770,7 +1867,7 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
1770
1867
 
1771
1868
  for (;;)
1772
1869
  {
1773
-
1870
+
1774
1871
  /* For each input char, we must explicitly read it since
1775
1872
  otherwise the Filestack does not operate correctly, i.e. we
1776
1873
  are not allowed to put back to stream after EOF has been
@@ -1804,7 +1901,6 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
1804
1901
  }
1805
1902
  else
1806
1903
  {
1807
-
1808
1904
  if ( ( c == ' ' || c == '\n' ) &&
1809
1905
  ps_topfile(ps)->hook_esc_eq_end )
1810
1906
  {
@@ -1813,6 +1909,15 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
1813
1909
  if ( do_break )
1814
1910
  break;
1815
1911
  }
1912
+ else if ( ps_topfile(ps)->eater
1913
+ && ps_topfile(ps)->eater[0] == c )
1914
+ {
1915
+ fs_put( ps->fs, c );
1916
+ if ( ps_check_eater( ps ) )
1917
+ ps_in( ps );
1918
+ else
1919
+ ps_collect( ps, c );
1920
+ }
1816
1921
  else
1817
1922
  {
1818
1923
  ps_collect( ps, c );
@@ -1832,6 +1937,15 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
1832
1937
  /* EOF */
1833
1938
  break;
1834
1939
  }
1940
+ else if ( ps_topfile(ps)->eater
1941
+ && ps_topfile(ps)->eater[0] == c )
1942
+ {
1943
+ fs_put( ps->fs, c );
1944
+ if ( ps_check_eater( ps ) )
1945
+ ps_in( ps );
1946
+ else
1947
+ ps_out( ps, c );
1948
+ }
1835
1949
  else
1836
1950
  {
1837
1951
 
@@ -1862,7 +1976,7 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
1862
1976
  {
1863
1977
  /* Escape is same as hookbeg and escape is
1864
1978
  not used to eat out spaces. */
1865
-
1979
+
1866
1980
  /* Put back the extra char (for safety/clarity). */
1867
1981
  fs_put( ps->fs, c );
1868
1982
 
@@ -1871,7 +1985,7 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
1871
1985
  hook. */
1872
1986
  ps_push_curhook( ps_topfile(ps), &ps_topfile(ps)->hook );
1873
1987
 
1874
- /* Start collect the macro content. */
1988
+ /* Start to collect the macro content. */
1875
1989
  ps_enter_macro( ps );
1876
1990
  }
1877
1991
  }
@@ -1882,16 +1996,29 @@ void ps_process_file( pstate_t* ps, gchar* infile, gchar* outfile )
1882
1996
  }
1883
1997
  }
1884
1998
  }
1885
-
1999
+
1886
2000
  }
1887
2001
  }
2002
+ else if ( ps->in_macro && ps_check_hooksusp( ps ) )
2003
+ {
2004
+ ps->suspension++;
2005
+ ps_collect_str( ps, ps_current_hooksusp( ps ) );
2006
+ }
1888
2007
  else if ( ps->in_macro && ps_check_hookend( ps ) )
1889
2008
  {
1890
2009
  /* Hookend has priority over hookbeg if we are in
1891
2010
  macro. Also hookend is ignored when outside macro. */
1892
- ps_process_hook_end_seq( ps, &do_break );
1893
- if ( do_break )
1894
- break;
2011
+ if ( ps->suspension == 0 )
2012
+ {
2013
+ ps_process_hook_end_seq( ps, &do_break );
2014
+ if ( do_break )
2015
+ break;
2016
+ }
2017
+ else
2018
+ {
2019
+ ps->suspension--;
2020
+ ps_collect_str( ps, ps_current_hookend( ps ) );
2021
+ }
1895
2022
  }
1896
2023
  else if ( ps_check_hookbeg( ps ) )
1897
2024
  {
@@ -1958,7 +2085,7 @@ VALUE mucgly_write( VALUE obj, VALUE rstr )
1958
2085
  else
1959
2086
  /* Convert to Ruby String. */
1960
2087
  tmp = rb_inspect( rstr );
1961
-
2088
+
1962
2089
  str = RSTRING_PTR( tmp );
1963
2090
  ps_out_str( ruby_ps, str );
1964
2091
  return Qnil;
@@ -1983,7 +2110,7 @@ VALUE mucgly_puts( VALUE obj, VALUE rstr )
1983
2110
  else
1984
2111
  /* Convert to Ruby String. */
1985
2112
  tmp = rb_inspect( rstr );
1986
-
2113
+
1987
2114
  str = RSTRING_PTR( tmp );
1988
2115
 
1989
2116
  ps_out_str( ruby_ps, str );
@@ -2031,6 +2158,31 @@ VALUE mucgly_hookesc( VALUE obj )
2031
2158
  }
2032
2159
 
2033
2160
 
2161
+ /**
2162
+ * Mucgly.sethook method. Set both hookben and hookend.
2163
+ *
2164
+ * @param obj Not used.
2165
+ * @param ary Array of hookpairs.
2166
+ *
2167
+ * @return Qnil.
2168
+ */
2169
+ VALUE mucgly_sethook( VALUE obj, VALUE hookbeg, VALUE hookend )
2170
+ {
2171
+ char* beg, *end;
2172
+
2173
+ Check_Type( hookbeg, T_STRING );
2174
+ Check_Type( hookend, T_STRING );
2175
+
2176
+ beg = RSTRING_PTR( hookbeg );
2177
+ sf_set_hook( ps_topfile( ruby_ps ), hook_beg, beg );
2178
+
2179
+ end = RSTRING_PTR( hookend );
2180
+ sf_set_hook( ps_topfile( ruby_ps ), hook_end, end );
2181
+
2182
+ return Qnil;
2183
+ }
2184
+
2185
+
2034
2186
  /**
2035
2187
  * Mucgly.sethookbeg method. Set hookbeg.
2036
2188
  *
@@ -2042,6 +2194,7 @@ VALUE mucgly_hookesc( VALUE obj )
2042
2194
  VALUE mucgly_sethookbeg( VALUE obj, VALUE rstr )
2043
2195
  {
2044
2196
  char* str;
2197
+ Check_Type( rstr, T_STRING );
2045
2198
  str = RSTRING_PTR( rstr );
2046
2199
  sf_set_hook( ps_topfile( ruby_ps ), hook_beg, str );
2047
2200
  return Qnil;
@@ -2059,6 +2212,7 @@ VALUE mucgly_sethookbeg( VALUE obj, VALUE rstr )
2059
2212
  VALUE mucgly_sethookend( VALUE obj, VALUE rstr )
2060
2213
  {
2061
2214
  char* str;
2215
+ Check_Type( rstr, T_STRING );
2062
2216
  str = RSTRING_PTR( rstr );
2063
2217
  sf_set_hook( ps_topfile( ruby_ps ), hook_end, str );
2064
2218
  return Qnil;
@@ -2076,33 +2230,130 @@ VALUE mucgly_sethookend( VALUE obj, VALUE rstr )
2076
2230
  VALUE mucgly_sethookesc( VALUE obj, VALUE rstr )
2077
2231
  {
2078
2232
  char* str;
2233
+ Check_Type( rstr, T_STRING );
2079
2234
  str = RSTRING_PTR( rstr );
2080
2235
  sf_set_hook( ps_topfile( ruby_ps ), hook_esc, str );
2081
2236
  return Qnil;
2082
2237
  }
2083
2238
 
2084
2239
 
2240
+ /**
2241
+ * Mucgly.seteater method. Set eater.
2242
+ *
2243
+ * @param obj Not used.
2244
+ * @param rstr Eater string (Ruby String).
2245
+ *
2246
+ * @return Qnil.
2247
+ */
2248
+ VALUE mucgly_seteater( VALUE obj, VALUE rstr )
2249
+ {
2250
+ char* str;
2251
+
2252
+ if ( RB_TYPE_P( rstr, T_NIL ) )
2253
+ {
2254
+ sf_set_eater( ps_topfile( ruby_ps ), NULL );
2255
+ }
2256
+ else
2257
+ {
2258
+ Check_Type( rstr, T_STRING );
2259
+ str = RSTRING_PTR( rstr );
2260
+ sf_set_eater( ps_topfile( ruby_ps ), str );
2261
+ }
2262
+
2263
+ return Qnil;
2264
+ }
2265
+
2266
+
2085
2267
  /**
2086
2268
  * Mucgly.multihook method. Add multihook pairs.
2087
2269
  *
2270
+ * Arg options:
2271
+ * [ hb1, he1, su1 ], [ hb2, he2, su2 ], [ hb3, he3 ], ...
2272
+ * [ hb1, he1, hb2, he2, hb3, he3 ]
2273
+ * hb1, he1, hb2, he2, hb3, he3, ...
2274
+ *
2088
2275
  * @param obj Not used.
2089
2276
  * @param ary Array of hookpairs.
2090
2277
  *
2091
2278
  * @return Qnil.
2092
2279
  */
2093
- VALUE mucgly_multihook( VALUE obj, VALUE ary )
2280
+ VALUE mucgly_multihook( int argc, VALUE* argv, VALUE obj )
2094
2281
  {
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 )
2282
+ char* beg, *end, *susp;
2283
+
2284
+ if ( RB_TYPE_P( argv[0], T_STRING ) )
2102
2285
  {
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 );
2286
+ if ( ( argc % 2 ) == 0 )
2287
+ {
2288
+ for ( int i = 0; i < argc; i += 2 )
2289
+ {
2290
+ beg = RSTRING_PTR( argv[i] );
2291
+ end = RSTRING_PTR( argv[i+1] );
2292
+ sf_multi_hook( ps_topfile( ruby_ps ), beg, end, NULL );
2293
+ }
2294
+ }
2295
+ else
2296
+ {
2297
+ rb_raise( rb_eRuntimeError,
2298
+ "mucgly: Argument count must be even!" );
2299
+ }
2300
+ }
2301
+ else if ( RB_TYPE_P( argv[0], T_ARRAY ) )
2302
+ {
2303
+ VALUE ary;
2304
+
2305
+ if ( argc > 1 )
2306
+ {
2307
+ /* Using suspensions. */
2308
+
2309
+ for ( int i = 0; i < argc; i++ )
2310
+ {
2311
+ ary = argv[i];
2312
+ if ( RARRAY_LEN(ary) == 3 )
2313
+ {
2314
+ beg = RSTRING_PTR( RARRAY_PTR(ary)[0] );
2315
+ end = RSTRING_PTR( RARRAY_PTR(ary)[1] );
2316
+ susp = RSTRING_PTR( RARRAY_PTR(ary)[2] );
2317
+ sf_multi_hook( ps_topfile( ruby_ps ), beg, end, susp );
2318
+ }
2319
+ else if ( RARRAY_LEN(ary) == 2 )
2320
+ {
2321
+ beg = RSTRING_PTR( RARRAY_PTR(ary)[0] );
2322
+ end = RSTRING_PTR( RARRAY_PTR(ary)[1] );
2323
+ sf_multi_hook( ps_topfile( ruby_ps ), beg, end, NULL );
2324
+ }
2325
+ else
2326
+ {
2327
+ rb_raise( rb_eRuntimeError,
2328
+ "mucgly: Array argument must either two or three long, i.e. beg, end, [susp]!" );
2329
+ }
2330
+ }
2331
+ }
2332
+ else
2333
+ {
2334
+ ary = argv[0];
2335
+ if ( RARRAY_LEN(ary) == 3 )
2336
+ {
2337
+ beg = RSTRING_PTR( RARRAY_PTR(ary)[0] );
2338
+ end = RSTRING_PTR( RARRAY_PTR(ary)[1] );
2339
+ susp = RSTRING_PTR( RARRAY_PTR(ary)[2] );
2340
+ sf_multi_hook( ps_topfile( ruby_ps ), beg, end, susp );
2341
+ }
2342
+ else if ( (RARRAY_LEN(ary) % 2) == 0 )
2343
+ {
2344
+ for ( int i = 0; i < RARRAY_LEN(ary); i += 2 )
2345
+ {
2346
+ beg = RSTRING_PTR( RARRAY_PTR(ary)[i] );
2347
+ end = RSTRING_PTR( RARRAY_PTR(ary)[i+1] );
2348
+ sf_multi_hook( ps_topfile( ruby_ps ), beg, end, NULL );
2349
+ }
2350
+ }
2351
+ else
2352
+ {
2353
+ rb_raise( rb_eRuntimeError,
2354
+ "mucgly: Array argument must have either three or even items!" );
2355
+ }
2356
+ }
2106
2357
  }
2107
2358
 
2108
2359
  return Qnil;
@@ -2177,6 +2428,7 @@ VALUE mucgly_pushinput( VALUE obj, VALUE rstr )
2177
2428
  {
2178
2429
  char* str;
2179
2430
 
2431
+ Check_Type( rstr, T_STRING );
2180
2432
  str = RSTRING_PTR( rstr );
2181
2433
  fs_push_file_delayed( ruby_ps->fs, str );
2182
2434
  ruby_ps->post_push = TRUE;
@@ -2210,8 +2462,10 @@ VALUE mucgly_pushoutput( VALUE obj, VALUE rstr )
2210
2462
  {
2211
2463
  char* str;
2212
2464
 
2465
+ Check_Type( rstr, T_STRING );
2213
2466
  str = RSTRING_PTR( rstr );
2214
2467
  ps_push_file( ruby_ps, str );
2468
+
2215
2469
  return Qnil;
2216
2470
  }
2217
2471
 
@@ -2307,10 +2561,12 @@ void Init_mucgly( void )
2307
2561
  rb_define_module_function( mMucgly, "hookbeg", mucgly_hookbeg, 0 );
2308
2562
  rb_define_module_function( mMucgly, "hookend", mucgly_hookend, 0 );
2309
2563
  rb_define_module_function( mMucgly, "hookesc", mucgly_hookesc, 0 );
2564
+ rb_define_module_function( mMucgly, "sethook", mucgly_sethook, -1 );
2310
2565
  rb_define_module_function( mMucgly, "sethookbeg", mucgly_sethookbeg, 1 );
2311
2566
  rb_define_module_function( mMucgly, "sethookend", mucgly_sethookend, 1 );
2312
2567
  rb_define_module_function( mMucgly, "sethookesc", mucgly_sethookesc, 1 );
2313
- rb_define_module_function( mMucgly, "multihook", mucgly_multihook, 1 );
2568
+ rb_define_module_function( mMucgly, "seteater", mucgly_seteater, 1 );
2569
+ rb_define_module_function( mMucgly, "multihook", mucgly_multihook, -1 );
2314
2570
  rb_define_module_function( mMucgly, "ifilename", mucgly_ifilename, 0 );
2315
2571
  rb_define_module_function( mMucgly, "ilinenumber", mucgly_ilinenumber, 0 );
2316
2572
  rb_define_module_function( mMucgly, "ofilename", mucgly_ofilename, 0 );
@@ -2369,7 +2625,7 @@ gchar* infile_to_outfile( gchar* infile, gchar* outfile_tag )
2369
2625
  */
2370
2626
  void mucgly_main( int argc, char** argv )
2371
2627
  {
2372
-
2628
+
2373
2629
  /* Setup default hooks etc. */
2374
2630
  stack_default = sf_new( NULL, NULL );
2375
2631
 
@@ -2535,7 +2791,8 @@ void mucgly_main( int argc, char** argv )
2535
2791
  {
2536
2792
  sf_multi_hook( stack_default,
2537
2793
  opt_multi_sep[ cnt ],
2538
- opt_multi_sep[ cnt+1 ] );
2794
+ opt_multi_sep[ cnt+1 ],
2795
+ NULL );
2539
2796
  cnt += 2;
2540
2797
  }
2541
2798
  }