Home Libraries Author Links

cuglify.c

This example is a CLI based console C program demonstrating the usage and testing the implementation of pattern matching in strings by means of regular expressions (see Match: Pattern Matching with Regular Expressions).

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the SysToMath C Libraries package (LibStmC).
 *
 * The Initial Developer of the Original Code is
 * Tom Michaelis, SysToMath.
 * Portions created by the Initial Developer are Copyright (C) 1993-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

/******************************************************************************
 *                       First Release 1993-12-27
 ******************************************************************************/


const char *Copyright = "(C) 1993-2006 Tom Michaelis, SysToMath";
const char *Version   = "1.12-r341";

static const char *man [] =
{
"NAME                                                                         ",
"       cuglify - c or c++ source code uglifier                               ",
"                                                                             ",
"SYNOPSIS                                                                     ",
"       cuglify [--keep-comments] [--c-plus-plus|--slash-slash-comments]      ",
"               [--line-length=<linelen>] [--output=<outfile>] [<file>]       ",
"       cuglify --help                                                        ",
"       cuglify --version                                                     ",
"                                                                             ",
"DESCRIPTION                                                                  ",
"       The command cuglify transforms the source code given by the <file>    "
"       argument, or if no <file> argument is supplied, by standard input into"
"       an ugly and for a human viewer almost unreadable form which, however, "
"       compiles without errors.                                              ",
"       Unless option --help or --version is supplied, the command returns    "
"       with an exit code 0 on success and with an exit code 1, if any error  "
"       did occur.                                                            ",
"                                                                             ",
"OPTIONS                                                                      ",
"       --help                                                                ",
"       -h     Print this man page on standard output and exit with exit code "
"              2.                                                             ",
"                                                                             ",
"       --version                                                             ",
"       -V     Print version info on standard output and exit with exit code  ",
"              2.                                                             ",
"                                                                             ",
"       --keep-comments                                                       ",
"       -c     Retain comments in the output.                                 ",
"                                                                             ",
"       --cpp                                                                 ",
"       --c-plus-plus                                                         ",
"       -C     Assume c++ input. The default is c input.                      ",
"                                                                             ",
"       --slash-slash-comments                                                ",
"       -D     Assume c input with c++ one line comments.                     ",
"                                                                             ",
"       --line-length=<linelen>                                               ",
"       -l <linelen>                                                          ",
"              Define the line length of the output, which defaults to 78.    "
"              The argument <linelen> shall be greater than 15 and less than  "
"              32768 or 0.  If it is 0, the length of output lines is         "
"              unlimited.                                                     ",
"                                                                             ",
"       --output=<outfile>                                                    ",
"       --output-file=<outfile>                                               ",
"       -o <outfile>                                                          ",
"              Direct the output to <outfile>.  By default the output goes to "
"              standard output.                                               "
};


#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>

#include <stm/basetype.h>
#include <stm/match.h>
#include <stm/dvec.h>
#include <stm/getopts.h>


typedef enum LastChar LastChar;


enum LastChar
{
    NORMAL,     
    PLUS,       
    MINUS,      
    GREATER,    
    TIMES,      
    AMPERSAND,  
    POUND,      
    IDCHAR      
};


typedef struct CuglifyEnv CuglifyEnv;


struct CuglifyEnv
{
    StmBool init;               
    StmBool bsep;               
    StmBool lbeg;               
    StmBool clbeg;              
    StmBool cnl;                
    StmBool comments;           
    StmBool cplusplus ;         
    StmBool cplusplusComments;  
    StmBool incomment;          
    int linelen;                
    int iflevel;                
    int lnr;                    
    const char *filename;       
    const char *prog;           
    char *str;                  
    char *clbegstr;             
    char *outstr;               
    int outlen;                 
    StmBool ppline;             
    FILE *instream;             
    FILE *outstream;            
    FILE *debug;                
    jmp_buf jmpbuf;             
    LastChar last;              
};


int main (int argc, char **argv);


static int out (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int errout (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int pout (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int bout (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int pnlout (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int cnlout (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int commout (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int setclbeg (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int cmode (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int incif (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int chkif (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int decif (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int newlnr (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static int newfile (StmMtcFctCmd cmd, StmQreMtc qreMtc);


static void defsreact (StmReCtrl reCtrl, CuglifyEnv *env);


static StmBool readline (CuglifyEnv *env);


static void flushout (CuglifyEnv *env);


static void gatherout (CuglifyEnv *env, const char *str, int len);


int main (int argc, char **argv)
{
    int ret;
    StmDword optId;
    StmCmdOptSpec optSpec [] =
    {
        {StmId (h), "h\0help\0"},
        {StmId (V), "V\0version\0"},
        {StmId (c), "c\0keep-comments\0"},
        {StmId (C), "C\0cpp\0c-plus-plus\0"},
        {StmId (D), "D\0slash-slash-comments\0"},
        {StmId (l), "l\0line-length\0", StmCmdOptSpecRequiresArg},
        {StmId (o), "o\0output\0output-file\0", StmCmdOptSpecRequiresArg},
        {0, NULL}
    };
    StmCmdLine cmdLine = stmCmdLineCreate (argc, (const char **) argv, optSpec);
    StmReCtrl reCtrl = NULL;
    StmRe re1 = NULL, re2 = NULL, re3 = NULL;
    CuglifyEnv env;
    env.init = StmFalse;
    env.bsep = StmFalse;
    env.lbeg = StmFalse;
    env.clbeg = StmFalse;
    env.cnl = StmFalse;
    env.comments = StmFalse;
    env.cplusplus = StmFalse;
    env.cplusplusComments = StmFalse;
    env.incomment = StmFalse;
    env.linelen = 78;
    env.iflevel = 0;
    env.lnr = 0;
    env.filename = "-stdin-";
    env.prog = stmCmdLineGetProg (cmdLine);
    env.str = NULL;
    env.clbegstr = NULL;
    env.outstr = NULL;
    env.outlen = 0;
    env.ppline = StmFalse;
    env.instream = stdin;
    env.outstream = stdout;
    env.debug = stderr;
    env.last = NORMAL;
    stmCmdLineSetErrfp (cmdLine, stderr);
    for (optId = stmCmdLineGetFirstOptionId (cmdLine);
         optId;
         optId = stmCmdLineGetNextOptionId (cmdLine))
    {
        if (optId == StmId (h))
        {
            FILE *pp;
            if (! (pp = popen ("more", "w")))
            {
                fprintf (stderr,
                         "system error in line %d: %s: aborted\n",
                         __LINE__, strerror (errno));
                exit (1);
            }
            stmPrintManual (pp, 79,
                            Version, Copyright, StmElements (man), man);
            switch (pclose (pp))
            {
            case 0:
                break;
            case EOF:
                fprintf (stderr,
                         "system error in line %d: %s: aborted\n",
                         __LINE__, strerror (errno));
                exit (1);
            default:
                fprintf (stderr,
                         "system error in line %d: pipe failed: aborted\n",
                         __LINE__, strerror (errno));
                exit (1);
            }
            exit (2);
            continue;
        }
        if (optId == StmId (V))
        {
            fprintf (stdout, "%s\n", Version);
            exit (2);
            continue;
        }
        if (optId == StmId (c))
        {
            env.comments = StmTrue;
            continue;
        }
        if (optId == StmId (C))
        {
            if (env.cplusplusComments)
            {
                stmCmdLineSetError (cmdLine, StmCmdLineOptionArgError);
            }
            else env.cplusplus = StmTrue;
            continue;
        }
        if (optId == StmId (D))
        {
            if (env.cplusplus)
            {
                stmCmdLineSetError (cmdLine, StmGetoptsOptionArgError);
            }
            else env.cplusplusComments = StmTrue;
            continue;
        }
        if (optId == StmId (l))
        {
            const char *optarg = stmCmdLineGetCurrentOptionArg (cmdLine);
            char *end;
            long ll;
            assert (optarg);
            ll = strtol (optarg, &end, 10);
            if (*end || (ll < 16 || ll > 32767) && ll)
            {
                fprintf (stderr,
                         "%s: option -l: illegal value: %s\n",
                         env.prog,
                         optarg);
                stmCmdLineSetError (cmdLine, StmCmdLineOptionArgError);
            }
            env.linelen = (int) ll;
            continue;
        }
        if (optId == StmId (o))
        {
            const char *optarg = stmCmdLineGetCurrentOptionArg (cmdLine);
            assert (optarg);
            if (strcmp (optarg, "-"))
            {
                if (! (env.outstream = fopen (optarg, "w")))
                {
                    fprintf (stderr,
                             "%s: option -o: cannot open output file %s\n",
                             env.prog,
                             optarg);
                    stmCmdLineSetError (cmdLine, StmCmdLineOptionArgError);
                }
            }
            else env.outstream = stdout;
            continue;
        }
    }
    if (!stmCmdLineGetError (cmdLine) &&
        stmCmdLineGetArgCount (cmdLine) - stmCmdLineGetCurrentArgIndex (cmdLine) > 1)
    {
        fprintf (stderr,
                 "%s: at most one input file can be supplied\n",
                 env.prog);
        stmCmdLineSetError (cmdLine, StmCmdLineArgumentError);
    }
    if (!stmCmdLineGetError (cmdLine) &&
        stmCmdLineGetArgCount (cmdLine) - stmCmdLineGetCurrentArgIndex (cmdLine) == 1 &&
        ! (env.instream =
               fopen
               (
                   env.filename =
                       stmCmdLineGetArg
                       (
                           cmdLine,
                           stmCmdLineGetCurrentArgIndex (cmdLine)
                       ),
                   "r"
               )))
    {
        fprintf (stderr,
                 "%s: cannot open input file %s\n",
                 env.prog,
                 stmCmdLineGetArg (cmdLine, stmCmdLineGetCurrentArgIndex (cmdLine)));
        stmCmdLineSetError (cmdLine, StmCmdLineArgumentError);
    }
    if (stmCmdLineGetError (cmdLine))
    {
        stmPrintSynopsis (stderr, 79, StmElements (man), man);
        exit (1);
    }
    if (! (ret = setjmp (env.jmpbuf)))
    {
        reCtrl = stmReCtrlCreate (env.debug, &env.jmpbuf, NULL, NULL);
        re1 = stmReCreate (reCtrl,
                           "incommline",
                           "&commend&&progLine&||&commline&",
                           NULL);
        re2 = stmReCreate (reCtrl,
                           "line",
                           "&ws&(&controlLine&||&progLine&)",
                           NULL);
        re3 = stmReCreate (reCtrl,
                           "cwsline",
                           "&cws&&line&",
                           NULL);
        defsreact (reCtrl, &env);
        while (readline (&env))
        {
            if (env.incomment ?
                    !stmReMatch (re1, env.str, &env, NULL) :
                    env.lnr > 1 ?
                        !stmReMatch (re2, env.str, &env, NULL) :
                        !stmReMatch (re3, env.str, &env, NULL))
            {
                fprintf (stderr,
                         "%s: internal error in file %s, line %d:\n\"%s\"\n",
                         env.prog, env.filename, env.lnr, env.str);
                longjmp (env.jmpbuf, -1);
            }
        }
        flushout (&env);
        if (env.iflevel)
        {
            fprintf (stderr,
                     "%s: %d #endif line%s missing at end of input\n",
                     env.prog, env.iflevel, env.iflevel == 1 ? "" : "s");
            longjmp (env.jmpbuf, 1);
        }
    }
    else
    {
        if (ret > 0)
        {
            fprintf (stderr,
                     "%s: %s\n",
                     env.prog, stmReCtrlGetErrorMsg (reCtrl));
        }
        ret = 1;
    }
    stmReCtrlDestroy (reCtrl);
    stmCmdLineDestroy (cmdLine);
    return ret;
}


static int out (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        char ch;
        if (env -> lbeg) flushout (env);
        else if (stmQreMtcLen (qreMtc) && env -> bsep)
        {
            switch (ch = stmQreMtcStr (qreMtc) [0])
            {
            case '+':
                if (env -> last == PLUS) gatherout (env, " ", 1);
                break;
            case '-':
                if (env -> last == MINUS) gatherout (env, " ", 1);
                break;
            case '>':
                if (env -> cplusplus && env -> last == GREATER)
                {
                    gatherout (env, " ", 1);
                }
                break;
            case '&':
                if (env -> last == AMPERSAND) gatherout (env, " ", 1);
                break;
            case '=':
                if (env -> last == AMPERSAND || env -> last == TIMES)
                {
                    gatherout (env, " ", 1);
                }
                break;
            case '#':
                if (env -> last == POUND) gatherout (env, " ", 1);
                break;
            default:
                if ((ch == '_' || isalnum (ch)) && env -> last == IDCHAR)
                {
                    gatherout (env, " ", 1);
                }
                break;
            }
        }
        gatherout (env, stmQreMtcStr (qreMtc), stmQreMtcLen (qreMtc));
        if (stmQreMtcLen (qreMtc) &&
            ((ch = stmQreMtcStr (qreMtc) [stmQreMtcLen (qreMtc) - 1]) == '_' ||
             isalnum (ch)))
        {
            env -> last = IDCHAR;
        }
        else if (stmQreMtcLen (qreMtc) == 1) switch (ch)
        {
        case '+':
            env -> last = PLUS;
            break;
        case '-':
            env -> last = MINUS;
            break;
        case '>':
            env -> last = env -> cplusplus ? GREATER : NORMAL;
            break;
        case '*':
            env -> last = TIMES;
            break;
        case '&':
            env -> last = AMPERSAND;
            break;
        case '#':
            env -> last = POUND;
            break;
        default:
            env -> last = NORMAL;
            break;
        }
        else env -> last = NORMAL;
        env -> bsep = env -> lbeg = env -> clbeg = env -> cnl = StmFalse;
        env -> clbegstr = stmDstrDel (env -> clbegstr, 0, 0);
        env -> init = StmTrue;
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "out (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int errout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        fprintf
        (
            stderr,
            "%s: syntax error near '%.*s' in file %s, line %d:\n\"%.*s\"\n",
            env -> prog, stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc),
            env -> filename, env -> lnr,
            strcspn (env -> str, "\n"), env -> str
        );
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "errout (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int pout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        if (env -> init) flushout (env);
        gatherout (env, "#", 1);
        env -> last = POUND;
        env -> init = StmTrue;
        env -> ppline = StmTrue;
        env -> bsep = env -> lbeg = env -> clbeg = env -> cnl = StmFalse;
        env -> clbegstr = stmDstrDel (env -> clbegstr, 0, 0);
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "pout (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int bout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        if (stmQreMtcSimpleReMtcCount (qreMtc)) env -> bsep = StmTrue;
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "bout (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int pnlout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        env -> ppline = StmFalse;
        env -> lbeg = StmTrue;
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "pnlout (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int cnlout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        if (env -> cnl) env -> lbeg = StmTrue;
        env -> clbegstr = stmDstrDel (env -> clbegstr, 0, 0);
        if (stmQreMtcLen (qreMtc) &&
            ! (env -> clbegstr = stmDstrApp (env -> clbegstr,
                                             stmQreMtcStr (qreMtc),
                                             (unsigned) stmQreMtcLen (qreMtc))))
        {
            if (env -> debug)
            {
                fprintf (env -> debug,
                         "%s: line %d: %s: aborted\n",
                         env -> prog, __LINE__, strerror (errno));
            }
            else perror (env -> prog);
            longjmp (env -> jmpbuf, -1);
        }
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "cnlout (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int commout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        if (env -> comments)
        {
            if (env -> clbeg || env -> lbeg) flushout (env);
            if (env -> clbegstr) gatherout (env, env -> clbegstr, 0);
            gatherout (env, stmQreMtcStr (qreMtc), stmQreMtcLen (qreMtc));
            env -> bsep = env -> lbeg = env -> clbeg = StmFalse;
            env -> clbegstr = stmDstrDel (env -> clbegstr, 0, 0);
            env -> cnl = StmTrue;
            env -> init = StmTrue;
            env -> last = NORMAL;
        }
        else env -> bsep = StmTrue;
    }
    if (cmd.rollback)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        fprintf (stderr, "commout (rollback): line %d: [%.*s]\n",
                 env -> lnr, stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int setclbeg (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        env -> clbeg = StmTrue;
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "setclbeg (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int cmode (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        env -> incomment = stmQreMtcStr (qreMtc) [0] == '\n';
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "cmode (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int incif (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        env -> iflevel ++;
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "incif (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int chkif (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        if (!env -> iflevel)
        {
            fprintf (stderr,
                     "%s: #%.*s without #if in file %s, line %d:\n\"%s\"\n",
                     env -> prog, stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc),
                     env -> filename, env -> lnr, env -> str);
            return StmMtcFctFail;
        }
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "chkif (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int decif (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        if (!env -> iflevel)
        {
            fprintf (stderr,
                     "%s: #endif without #if in file %s, line %d:\n\"%s\"\n",
                     env -> prog, env -> filename, env -> lnr, env -> str);
            return StmMtcFctFail;
        }
        env -> iflevel --;
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "decif (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int newlnr (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        long ll = strtol (stmQreMtcStr (qreMtc), NULL, 0);
        if (ll > 0 && ll < INT_MAX) env -> lnr = (int) (ll - 1);
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "newlnr (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static int newfile (StmMtcFctCmd cmd, StmQreMtc qreMtc)
{
    if (cmd.action)
    {
        CuglifyEnv *env = stmQreMtcEnv (qreMtc);
        env -> filename =
            stmDstrSave (stmQreMtcStr (qreMtc), stmQreMtcLen (qreMtc));
    }
    if (cmd.rollback)
    {
        fprintf (stderr, "newfile (rollback): str [%.*s]\n",
                 stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
    }
    return 0;
}


static void defsreact (StmReCtrl reCtrl, CuglifyEnv *env)
{
    stmReCreate (reCtrl,
                 "controlLine",
                 "#:pout:&ws&((line):out:&sep&&integerConstant&:newlnr,out:"
                                     "(&ws&&stringLiteral&:newfile,out:)?||"
                             "(include||line):out:&ws&&ppToken&+||"
                             "(error||pragma):out:&ws&&ppToken&*||"
                             "(define&_&&identifier&[( \t]?):out:"
                                                          "&ws&&ppToken&*||"
                             "(undef):out:&sep&&identifier&:out:||"
                             "(ifn?def):incif,out:&sep&&identifier&:out:||"
                             "(if):incif,out:&ws&&ppToken&+||"
                             "(elif):chkif,out:&ws&&ppToken&+||"
                             "(else):chkif,out:||"
                             "(endif):decif,out:||"
                             "(!&sep&[^\n]*):errout:"
                            ")?&ws&&nl&:pnlout:",
                 NULL);
    stmReCreate (reCtrl,
                 "progLine",
                 "&ppToken&*&cnl&",
                 NULL);
    stmReCreate (reCtrl,
                 "ppToken",
                 env -> cplusplus || env -> cplusplusComments ?
                     "!(%/[*/])'(&identifier&||"
                                "&floatingConstant&||"
                                "&integerConstant&||"
                                "&characterConstant&||"
                                "&stringLiteral&||"
                                "&punctuator&||"
                                "&operator&||"
                                "[^ \t\n\f\v]):out:&ws&" :
                     "!(%/%*)'(&identifier&||"
                              "&floatingConstant&||"
                              "&integerConstant&||"
                              "&characterConstant&||"
                              "&stringLiteral&||"
                              "&punctuator&||"
                              "&operator&||"
                              "[^ \t\n\f\v]):out:&ws&",
                 NULL);
    stmReCreate (reCtrl,
                 "identifier",
                 "[_a-zA-Z][_0-9a-zA-Z]*",
                 NULL);
    stmReCreate (reCtrl,
                 "floatingConstant",
                 "(([0-9]*%.[0-9]+||[0-9]+%.)([eE][-+]?[0-9]+)?||"
                 "[0-9]+[eE][-+]?[0-9])[flFL]?",
                 NULL);
    stmReCreate (reCtrl,
                 "integerConstant",
                 "([1-9][0-9]*||"
                 "0[xX][0-9a-fA-F]*||"
                 "0[0-7]*)([uU][lL]?||[lL][uU]?)?",
                 NULL);
    stmReCreate (reCtrl,
                 "characterConstant",
                 "L?%'([^'\\\n]||&escapeSequence&)+%'",
                 NULL);
    stmReCreate (reCtrl,
                 "stringLiteral",
                 "L?\"([^\"\\\n]||&escapeSequence&)*\"",
                 NULL);
    stmReCreate (reCtrl,
                 "escapeSequence",
                 "\\(['\"?\\abfnrtv]||[0-7]{1,3}||[xX][0-9a-fA-F]{1,2})",
                 NULL);
    stmReCreate (reCtrl,
                 "punctuator",
                 "%.%.%.||[{};]",
                 NULL);
    stmReCreate (reCtrl,
                 "operator",
                 "sizeof||"
                 "%<%<=||"
                 "%>%>=||"
                 "%.%*||"
                 "-%>%*||"
                 "-%>||"
                 "%+%+||"
                 "--||"
                 "%<%<||"
                 "%>%>||"
                 "%<=||"
                 "%>=||"
                 "==||"
                 "%!=||"
                 "%&%&||"
                 "%|%|||"
                 "%*=||"
                 "%/=||"
                 "%%=||"
                 "%+=||"
                 "-=||"
                 "%&=||"
                 "^=||"
                 "%|=||"
                 "##||"
                 "%:%:||"
                 "-||"
                 "[][().&*+~!/%%<>^|?:=,#]",
                 NULL);
    stmReCreate (reCtrl,
                 "nl",
                 env -> cplusplus || env -> cplusplusComments ?
                     (env -> comments ?
                         "((%/%/[^\n]*):out:\n:pnlout:||\n:setclbeg:)&cws&" :
                         "(%/%/[^\n]*)?\n:setclbeg:&cws&") :
                     "\n:setclbeg:&cws&",
                 NULL);
    stmReCreate (reCtrl,
                 "cnl",
                 "&nl&||&commbeg&",
                 NULL);
    stmReCreate (reCtrl,
                 "ws",
                 "([ \t\v\f]:bout:||&comment&)*",
                 NULL);
    stmReCreate (reCtrl,
                 "sep",
                 "([ \t\v\f]:bout:||&comment&)+",
                 NULL);
    stmReCreate (reCtrl,
                 "cws",
                 "[ \t]*:cnlout:",
                 NULL);
    stmReCreate (reCtrl,
                 "_",
                 "[ \t]+:bout:",
                 NULL);
    stmReCreate (reCtrl,
                 "comment",
                 "(%/%*!(%*%/)*%*%/):commout:",
                 NULL);
    stmReCreate (reCtrl,
                 "commbeg",
                 "([ \t\v\f]*)(%/%*[^\n]*):commout:\n:setclbeg,cmode:&cws&",
                 NULL);
    stmReCreate (reCtrl,
                 "commline",
                 "[^\n]*:commout:\n:setclbeg:&cws&",
                 NULL);
    stmReCreate (reCtrl,
                 "commend",
                 "(!(%*%/)*%*%/:cmode:):commout:&ws&",
                 NULL);
    stmQreActDef (reCtrl, "out", out);
    stmQreActDef (reCtrl, "errout", errout);
    stmQreActDef (reCtrl, "pout", pout);
    stmQreActDef (reCtrl, "bout", bout);
    stmQreActDef (reCtrl, "pnlout", pnlout);
    stmQreActDef (reCtrl, "cnlout", cnlout);
    stmQreActDef (reCtrl, "commout", commout);
    stmQreActDef (reCtrl, "setclbeg", setclbeg);
    stmQreActDef (reCtrl, "cmode", cmode);
    stmQreActDef (reCtrl, "incif", incif);
    stmQreActDef (reCtrl, "chkif", chkif);
    stmQreActDef (reCtrl, "decif", decif);
    stmQreActDef (reCtrl, "newlnr", newlnr);
    stmQreActDef (reCtrl, "newfile", newfile);
    return;
}


static StmBool readline (CuglifyEnv *env)
{
    StmBool splice = StmFalse;
    StmBool tws = StmFalse;
    int ch;
    env -> str = stmDstrDel (env -> str, 0, 0);
    while ((ch = fgetc (env -> instream)) != EOF)
    {
        if (tws) switch (ch)
        {
        case ' ':
        case '\t':
            env -> str = stmDstrChApp (env -> str, (char) ch);
            break;
        default:
            ungetc (ch, env -> instream);
            ch = 0;
            break;
        }
        else
        {
            int r = stmDstrLen (env -> str) - 2;
            if (r >= 0 && !strncmp (env -> str + r, "??", 2)) switch (ch)
            {
            case '=':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = '#';
                break;
            case '/':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = '\\';
                break;
            case '\'':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = '^';
                break;
            case '(':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = '[';
                break;
            case ')':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = ']';
                break;
            case '!':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = '|';
                break;
            case '<':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = '{';
                break;
            case '>':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = '}';
                break;
            case '-':
                env -> str = stmDstrDel (env -> str, r, 2);
                ch = '~';
                break;
            }
            switch (ch)
            {
            case '\n':
                if (++ r >= 0 && env -> str [r] == '\r')
                {
                    env -> str = stmDstrDel (env -> str, r, 1);
                }
                env -> lnr ++;
                if (splice) splice = StmFalse;
                else
                {
                    int i;
                    for (i = stmDstrLen (env -> str) - 1; i >= 0; -- i)
                    {
                        if (!strchr (" \t", env -> str [i])) break;
                    }
                    env -> str = stmDstrDel (env -> str, i + 1, 0);
                    env -> str = stmDstrChApp (env -> str, (char) ch);
                    tws = StmTrue;
                }
                break;
            case '\\':
                if (!splice)
                {
                    splice = StmTrue;
                    break;
                }
                /* fall through */
            default:
                if (splice)
                {
                    splice = StmFalse;
                    env -> str = stmDstrChApp (env -> str, '\\');
                }
                env -> str = stmDstrChApp (env -> str, (char) ch);
                break;
            }
        }
        if (!env -> str)
        {
            errno = ENOMEM;
            break;
        }
        if (!ch) break;
    }
    if (ch == EOF && stmDstrLen (env -> str) && !tws)
    {
        env -> lnr ++;
        env -> str = stmDstrChApp (env -> str, '\n');
    }
    if (!env -> str || ferror (env -> instream))
    {
        if (env -> debug)
        {
            fprintf (env -> debug,
                     "%s: line %d: %s: aborted\n",
                     env -> prog, __LINE__, strerror (errno));
        }
        else perror (env -> prog);
        longjmp (env -> jmpbuf, -1);
    }
    return env -> str [0] != '\0';
}


static void flushout (CuglifyEnv *env)
{
    if (env -> linelen)
    {
        if (env -> outlen)
        {
            fprintf (env -> outstream, "%s\n", env -> outstr);
            env -> outstr = stmDstrDel (env -> outstr, 0, 0);
            env -> outlen = 0;
        }
    }
    else fprintf (env -> outstream, "\n");
    return;
}


static void gatherout (CuglifyEnv *env, const char *str, int len)
{
    if (!len) len = (int) strlen (str);
    if (env -> linelen)
    {
        if (!env -> outlen && env -> bsep && len && str [0] == ' ')
        {
            str ++;
            len --;
        }
        env -> bsep = StmFalse;
        if (len)
        {
            env -> outstr = stmDstrApp (env -> outstr, str, len);
            env -> outlen += len;
            while (env -> outlen >= env -> linelen)
            {
                int l = env -> outlen == env -> linelen && !env -> ppline ?
                            env -> linelen :
                            env -> linelen - 1;
                fprintf (env -> outstream, "%.*s", l, env -> outstr);
                env -> outstr = stmDstrDel (env -> outstr, 0, l);
                env -> outlen -= l;
                if (l < env -> linelen) fprintf (env -> outstream, "\\");
                fprintf (env -> outstream, "\n");
            }
        }
    }
    else if (len) fprintf (env -> outstream, "%.*s", len, str);
    return;
}

© Copyright Tom Michaelis 2002-2007

Distributed under the SysToMath Software License (See the accompanying file license.txt or a copy at www.SysToMath.com).