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
         |