Home Libraries Author Links

cuglify.c

Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the SysToMath C Libraries package (LibStmC).
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Tom Michaelis, SysToMath.
00018  * Portions created by the Initial Developer are Copyright (C) 1993-2006
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /******************************************************************************
00038  *                       First Release 1993-12-27
00039  ******************************************************************************/
00040 
00041 
00074 const char *Copyright = "(C) 1993-2006 Tom Michaelis, SysToMath";
00075 const char *Version   = "1.12-r341";
00076 
00081 static const char *man [] =
00082 {
00083 "NAME                                                                         ",
00084 "       cuglify - c or c++ source code uglifier                               ",
00085 "                                                                             ",
00086 "SYNOPSIS                                                                     ",
00087 "       cuglify [--keep-comments] [--c-plus-plus|--slash-slash-comments]      ",
00088 "               [--line-length=<linelen>] [--output=<outfile>] [<file>]       ",
00089 "       cuglify --help                                                        ",
00090 "       cuglify --version                                                     ",
00091 "                                                                             ",
00092 "DESCRIPTION                                                                  ",
00093 "       The command cuglify transforms the source code given by the <file>    "
00094 "       argument, or if no <file> argument is supplied, by standard input into"
00095 "       an ugly and for a human viewer almost unreadable form which, however, "
00096 "       compiles without errors.                                              ",
00097 "       Unless option --help or --version is supplied, the command returns    "
00098 "       with an exit code 0 on success and with an exit code 1, if any error  "
00099 "       did occur.                                                            ",
00100 "                                                                             ",
00101 "OPTIONS                                                                      ",
00102 "       --help                                                                ",
00103 "       -h     Print this man page on standard output and exit with exit code "
00104 "              2.                                                             ",
00105 "                                                                             ",
00106 "       --version                                                             ",
00107 "       -V     Print version info on standard output and exit with exit code  ",
00108 "              2.                                                             ",
00109 "                                                                             ",
00110 "       --keep-comments                                                       ",
00111 "       -c     Retain comments in the output.                                 ",
00112 "                                                                             ",
00113 "       --cpp                                                                 ",
00114 "       --c-plus-plus                                                         ",
00115 "       -C     Assume c++ input. The default is c input.                      ",
00116 "                                                                             ",
00117 "       --slash-slash-comments                                                ",
00118 "       -D     Assume c input with c++ one line comments.                     ",
00119 "                                                                             ",
00120 "       --line-length=<linelen>                                               ",
00121 "       -l <linelen>                                                          ",
00122 "              Define the line length of the output, which defaults to 78.    "
00123 "              The argument <linelen> shall be greater than 15 and less than  "
00124 "              32768 or 0.  If it is 0, the length of output lines is         "
00125 "              unlimited.                                                     ",
00126 "                                                                             ",
00127 "       --output=<outfile>                                                    ",
00128 "       --output-file=<outfile>                                               ",
00129 "       -o <outfile>                                                          ",
00130 "              Direct the output to <outfile>.  By default the output goes to "
00131 "              standard output.                                               "
00132 };
00133 
00134 
00135 #include <assert.h>
00136 #include <stdio.h>
00137 #include <stdlib.h>
00138 #include <string.h>
00139 #include <ctype.h>
00140 #include <limits.h>
00141 #include <errno.h>
00142 
00143 #include <stm/basetype.h>
00144 #include <stm/match.h>
00145 #include <stm/dvec.h>
00146 #include <stm/getopts.h>
00147 
00148 
00152 typedef enum LastChar LastChar;
00153 
00154 
00158 enum LastChar
00159 {
00160     NORMAL,     
00161     PLUS,       
00162     MINUS,      
00163     GREATER,    
00164     TIMES,      
00165     AMPERSAND,  
00166     POUND,      
00167     IDCHAR      
00168 };
00169 
00170 
00174 typedef struct CuglifyEnv CuglifyEnv;
00175 
00176 
00180 struct CuglifyEnv
00181 {
00182     StmBool init;               
00183     StmBool bsep;               
00186     StmBool lbeg;               
00189     StmBool clbeg;              
00192     StmBool cnl;                
00195     StmBool comments;           
00197     StmBool cplusplus ;         
00199     StmBool cplusplusComments;  
00200     StmBool incomment;          
00201     int linelen;                
00202     int iflevel;                
00203     int lnr;                    
00204     const char *filename;       
00205     const char *prog;           
00206     char *str;                  
00207     char *clbegstr;             
00208     char *outstr;               
00210     int outlen;                 
00212     StmBool ppline;             
00214     FILE *instream;             
00215     FILE *outstream;            
00216     FILE *debug;                
00217     jmp_buf jmpbuf;             
00218     LastChar last;              
00219 };
00220 
00221 
00240 int main (int argc, char **argv);
00241 
00242 
00249 static int out (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00250 
00251 
00259 static int errout (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00260 
00261 
00268 static int pout (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00269 
00270 
00277 static int bout (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00278 
00279 
00287 static int pnlout (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00288 
00289 
00297 static int cnlout (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00298 
00299 
00307 static int commout (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00308 
00309 
00317 static int setclbeg (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00318 
00319 
00327 static int cmode (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00328 
00329 
00336 static int incif (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00337 
00338 
00347 static int chkif (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00348 
00349 
00358 static int decif (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00359 
00360 
00368 static int newlnr (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00369 
00370 
00378 static int newfile (StmMtcFctCmd cmd, StmQreMtc qreMtc);
00379 
00380 
00393 static void defsreact (StmReCtrl reCtrl, CuglifyEnv *env);
00394 
00395 
00410 static StmBool readline (CuglifyEnv *env);
00411 
00412 
00425 static void flushout (CuglifyEnv *env);
00426 
00427 
00450 static void gatherout (CuglifyEnv *env, const char *str, int len);
00451 
00452 
00456 int main (int argc, char **argv)
00457 {
00458     int ret;
00459     StmDword optId;
00460     StmCmdOptSpec optSpec [] =
00461     {
00462         {StmId (h), "h\0help\0"},
00463         {StmId (V), "V\0version\0"},
00464         {StmId (c), "c\0keep-comments\0"},
00465         {StmId (C), "C\0cpp\0c-plus-plus\0"},
00466         {StmId (D), "D\0slash-slash-comments\0"},
00467         {StmId (l), "l\0line-length\0", StmCmdOptSpecRequiresArg},
00468         {StmId (o), "o\0output\0output-file\0", StmCmdOptSpecRequiresArg},
00469         {0, NULL}
00470     };
00471     StmCmdLine cmdLine = stmCmdLineCreate (argc, (const char **) argv, optSpec);
00472     StmReCtrl reCtrl = NULL;
00473     StmRe re1 = NULL, re2 = NULL, re3 = NULL;
00474     CuglifyEnv env;
00475     env.init = StmFalse;
00476     env.bsep = StmFalse;
00477     env.lbeg = StmFalse;
00478     env.clbeg = StmFalse;
00479     env.cnl = StmFalse;
00480     env.comments = StmFalse;
00481     env.cplusplus = StmFalse;
00482     env.cplusplusComments = StmFalse;
00483     env.incomment = StmFalse;
00484     env.linelen = 78;
00485     env.iflevel = 0;
00486     env.lnr = 0;
00487     env.filename = "-stdin-";
00488     env.prog = stmCmdLineGetProg (cmdLine);
00489     env.str = NULL;
00490     env.clbegstr = NULL;
00491     env.outstr = NULL;
00492     env.outlen = 0;
00493     env.ppline = StmFalse;
00494     env.instream = stdin;
00495     env.outstream = stdout;
00496     env.debug = stderr;
00497     env.last = NORMAL;
00498     stmCmdLineSetErrfp (cmdLine, stderr);
00499     for (optId = stmCmdLineGetFirstOptionId (cmdLine);
00500          optId;
00501          optId = stmCmdLineGetNextOptionId (cmdLine))
00502     {
00503         if (optId == StmId (h))
00504         {
00505             FILE *pp;
00506             if (! (pp = popen ("more", "w")))
00507             {
00508                 fprintf (stderr,
00509                          "system error in line %d: %s: aborted\n",
00510                          __LINE__, strerror (errno));
00511                 exit (1);
00512             }
00513             stmPrintManual (pp, 79,
00514                             Version, Copyright, StmElements (man), man);
00515             switch (pclose (pp))
00516             {
00517             case 0:
00518                 break;
00519             case EOF:
00520                 fprintf (stderr,
00521                          "system error in line %d: %s: aborted\n",
00522                          __LINE__, strerror (errno));
00523                 exit (1);
00524             default:
00525                 fprintf (stderr,
00526                          "system error in line %d: pipe failed: aborted\n",
00527                          __LINE__, strerror (errno));
00528                 exit (1);
00529             }
00530             exit (2);
00531             continue;
00532         }
00533         if (optId == StmId (V))
00534         {
00535             fprintf (stdout, "%s\n", Version);
00536             exit (2);
00537             continue;
00538         }
00539         if (optId == StmId (c))
00540         {
00541             env.comments = StmTrue;
00542             continue;
00543         }
00544         if (optId == StmId (C))
00545         {
00546             if (env.cplusplusComments)
00547             {
00548                 stmCmdLineSetError (cmdLine, StmCmdLineOptionArgError);
00549             }
00550             else env.cplusplus = StmTrue;
00551             continue;
00552         }
00553         if (optId == StmId (D))
00554         {
00555             if (env.cplusplus)
00556             {
00557                 stmCmdLineSetError (cmdLine, StmGetoptsOptionArgError);
00558             }
00559             else env.cplusplusComments = StmTrue;
00560             continue;
00561         }
00562         if (optId == StmId (l))
00563         {
00564             const char *optarg = stmCmdLineGetCurrentOptionArg (cmdLine);
00565             char *end;
00566             long ll;
00567             assert (optarg);
00568             ll = strtol (optarg, &end, 10);
00569             if (*end || (ll < 16 || ll > 32767) && ll)
00570             {
00571                 fprintf (stderr,
00572                          "%s: option -l: illegal value: %s\n",
00573                          env.prog,
00574                          optarg);
00575                 stmCmdLineSetError (cmdLine, StmCmdLineOptionArgError);
00576             }
00577             env.linelen = (int) ll;
00578             continue;
00579         }
00580         if (optId == StmId (o))
00581         {
00582             const char *optarg = stmCmdLineGetCurrentOptionArg (cmdLine);
00583             assert (optarg);
00584             if (strcmp (optarg, "-"))
00585             {
00586                 if (! (env.outstream = fopen (optarg, "w")))
00587                 {
00588                     fprintf (stderr,
00589                              "%s: option -o: cannot open output file %s\n",
00590                              env.prog,
00591                              optarg);
00592                     stmCmdLineSetError (cmdLine, StmCmdLineOptionArgError);
00593                 }
00594             }
00595             else env.outstream = stdout;
00596             continue;
00597         }
00598     }
00599     if (!stmCmdLineGetError (cmdLine) &&
00600         stmCmdLineGetArgCount (cmdLine) - stmCmdLineGetCurrentArgIndex (cmdLine) > 1)
00601     {
00602         fprintf (stderr,
00603                  "%s: at most one input file can be supplied\n",
00604                  env.prog);
00605         stmCmdLineSetError (cmdLine, StmCmdLineArgumentError);
00606     }
00607     if (!stmCmdLineGetError (cmdLine) &&
00608         stmCmdLineGetArgCount (cmdLine) - stmCmdLineGetCurrentArgIndex (cmdLine) == 1 &&
00609         ! (env.instream =
00610                fopen
00611                (
00612                    env.filename =
00613                        stmCmdLineGetArg
00614                        (
00615                            cmdLine,
00616                            stmCmdLineGetCurrentArgIndex (cmdLine)
00617                        ),
00618                    "r"
00619                )))
00620     {
00621         fprintf (stderr,
00622                  "%s: cannot open input file %s\n",
00623                  env.prog,
00624                  stmCmdLineGetArg (cmdLine, stmCmdLineGetCurrentArgIndex (cmdLine)));
00625         stmCmdLineSetError (cmdLine, StmCmdLineArgumentError);
00626     }
00627     if (stmCmdLineGetError (cmdLine))
00628     {
00629         stmPrintSynopsis (stderr, 79, StmElements (man), man);
00630         exit (1);
00631     }
00632     if (! (ret = setjmp (env.jmpbuf)))
00633     {
00634         reCtrl = stmReCtrlCreate (env.debug, &env.jmpbuf, NULL, NULL);
00635         re1 = stmReCreate (reCtrl,
00636                            "incommline",
00637                            "&commend&&progLine&||&commline&",
00638                            NULL);
00639         re2 = stmReCreate (reCtrl,
00640                            "line",
00641                            "&ws&(&controlLine&||&progLine&)",
00642                            NULL);
00643         re3 = stmReCreate (reCtrl,
00644                            "cwsline",
00645                            "&cws&&line&",
00646                            NULL);
00647         defsreact (reCtrl, &env);
00648         while (readline (&env))
00649         {
00650             if (env.incomment ?
00651                     !stmReMatch (re1, env.str, &env, NULL) :
00652                     env.lnr > 1 ?
00653                         !stmReMatch (re2, env.str, &env, NULL) :
00654                         !stmReMatch (re3, env.str, &env, NULL))
00655             {
00656                 fprintf (stderr,
00657                          "%s: internal error in file %s, line %d:\n\"%s\"\n",
00658                          env.prog, env.filename, env.lnr, env.str);
00659                 longjmp (env.jmpbuf, -1);
00660             }
00661         }
00662         flushout (&env);
00663         if (env.iflevel)
00664         {
00665             fprintf (stderr,
00666                      "%s: %d #endif line%s missing at end of input\n",
00667                      env.prog, env.iflevel, env.iflevel == 1 ? "" : "s");
00668             longjmp (env.jmpbuf, 1);
00669         }
00670     }
00671     else
00672     {
00673         if (ret > 0)
00674         {
00675             fprintf (stderr,
00676                      "%s: %s\n",
00677                      env.prog, stmReCtrlGetErrorMsg (reCtrl));
00678         }
00679         ret = 1;
00680     }
00681     stmReCtrlDestroy (reCtrl);
00682     stmCmdLineDestroy (cmdLine);
00683     return ret;
00684 }
00685 
00686 
00687 static int out (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00688 {
00689     if (cmd.action)
00690     {
00691         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00692         char ch;
00693         if (env -> lbeg) flushout (env);
00694         else if (stmQreMtcLen (qreMtc) && env -> bsep)
00695         {
00696             switch (ch = stmQreMtcStr (qreMtc) [0])
00697             {
00698             case '+':
00699                 if (env -> last == PLUS) gatherout (env, " ", 1);
00700                 break;
00701             case '-':
00702                 if (env -> last == MINUS) gatherout (env, " ", 1);
00703                 break;
00704             case '>':
00705                 if (env -> cplusplus && env -> last == GREATER)
00706                 {
00707                     gatherout (env, " ", 1);
00708                 }
00709                 break;
00710             case '&':
00711                 if (env -> last == AMPERSAND) gatherout (env, " ", 1);
00712                 break;
00713             case '=':
00714                 if (env -> last == AMPERSAND || env -> last == TIMES)
00715                 {
00716                     gatherout (env, " ", 1);
00717                 }
00718                 break;
00719             case '#':
00720                 if (env -> last == POUND) gatherout (env, " ", 1);
00721                 break;
00722             default:
00723                 if ((ch == '_' || isalnum (ch)) && env -> last == IDCHAR)
00724                 {
00725                     gatherout (env, " ", 1);
00726                 }
00727                 break;
00728             }
00729         }
00730         gatherout (env, stmQreMtcStr (qreMtc), stmQreMtcLen (qreMtc));
00731         if (stmQreMtcLen (qreMtc) &&
00732             ((ch = stmQreMtcStr (qreMtc) [stmQreMtcLen (qreMtc) - 1]) == '_' ||
00733              isalnum (ch)))
00734         {
00735             env -> last = IDCHAR;
00736         }
00737         else if (stmQreMtcLen (qreMtc) == 1) switch (ch)
00738         {
00739         case '+':
00740             env -> last = PLUS;
00741             break;
00742         case '-':
00743             env -> last = MINUS;
00744             break;
00745         case '>':
00746             env -> last = env -> cplusplus ? GREATER : NORMAL;
00747             break;
00748         case '*':
00749             env -> last = TIMES;
00750             break;
00751         case '&':
00752             env -> last = AMPERSAND;
00753             break;
00754         case '#':
00755             env -> last = POUND;
00756             break;
00757         default:
00758             env -> last = NORMAL;
00759             break;
00760         }
00761         else env -> last = NORMAL;
00762         env -> bsep = env -> lbeg = env -> clbeg = env -> cnl = StmFalse;
00763         env -> clbegstr = stmDstrDel (env -> clbegstr, 0, 0);
00764         env -> init = StmTrue;
00765     }
00766     if (cmd.rollback)
00767     {
00768         fprintf (stderr, "out (rollback): str [%.*s]\n",
00769                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00770     }
00771     return 0;
00772 }
00773 
00774 
00775 static int errout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00776 {
00777     if (cmd.action)
00778     {
00779         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00780         fprintf
00781         (
00782             stderr,
00783             "%s: syntax error near '%.*s' in file %s, line %d:\n\"%.*s\"\n",
00784             env -> prog, stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc),
00785             env -> filename, env -> lnr,
00786             strcspn (env -> str, "\n"), env -> str
00787         );
00788     }
00789     if (cmd.rollback)
00790     {
00791         fprintf (stderr, "errout (rollback): str [%.*s]\n",
00792                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00793     }
00794     return 0;
00795 }
00796 
00797 
00798 static int pout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00799 {
00800     if (cmd.action)
00801     {
00802         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00803         if (env -> init) flushout (env);
00804         gatherout (env, "#", 1);
00805         env -> last = POUND;
00806         env -> init = StmTrue;
00807         env -> ppline = StmTrue;
00808         env -> bsep = env -> lbeg = env -> clbeg = env -> cnl = StmFalse;
00809         env -> clbegstr = stmDstrDel (env -> clbegstr, 0, 0);
00810     }
00811     if (cmd.rollback)
00812     {
00813         fprintf (stderr, "pout (rollback): str [%.*s]\n",
00814                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00815     }
00816     return 0;
00817 }
00818 
00819 
00820 static int bout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00821 {
00822     if (cmd.action)
00823     {
00824         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00825         if (stmQreMtcSimpleReMtcCount (qreMtc)) env -> bsep = StmTrue;
00826     }
00827     if (cmd.rollback)
00828     {
00829         fprintf (stderr, "bout (rollback): str [%.*s]\n",
00830                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00831     }
00832     return 0;
00833 }
00834 
00835 
00836 static int pnlout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00837 {
00838     if (cmd.action)
00839     {
00840         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00841         env -> ppline = StmFalse;
00842         env -> lbeg = StmTrue;
00843     }
00844     if (cmd.rollback)
00845     {
00846         fprintf (stderr, "pnlout (rollback): str [%.*s]\n",
00847                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00848     }
00849     return 0;
00850 }
00851 
00852 
00853 static int cnlout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00854 {
00855     if (cmd.action)
00856     {
00857         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00858         if (env -> cnl) env -> lbeg = StmTrue;
00859         env -> clbegstr = stmDstrDel (env -> clbegstr, 0, 0);
00860         if (stmQreMtcLen (qreMtc) &&
00861             ! (env -> clbegstr = stmDstrApp (env -> clbegstr,
00862                                              stmQreMtcStr (qreMtc),
00863                                              (unsigned) stmQreMtcLen (qreMtc))))
00864         {
00865             if (env -> debug)
00866             {
00867                 fprintf (env -> debug,
00868                          "%s: line %d: %s: aborted\n",
00869                          env -> prog, __LINE__, strerror (errno));
00870             }
00871             else perror (env -> prog);
00872             longjmp (env -> jmpbuf, -1);
00873         }
00874     }
00875     if (cmd.rollback)
00876     {
00877         fprintf (stderr, "cnlout (rollback): str [%.*s]\n",
00878                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00879     }
00880     return 0;
00881 }
00882 
00883 
00884 static int commout (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00885 {
00886     if (cmd.action)
00887     {
00888         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00889         if (env -> comments)
00890         {
00891             if (env -> clbeg || env -> lbeg) flushout (env);
00892             if (env -> clbegstr) gatherout (env, env -> clbegstr, 0);
00893             gatherout (env, stmQreMtcStr (qreMtc), stmQreMtcLen (qreMtc));
00894             env -> bsep = env -> lbeg = env -> clbeg = StmFalse;
00895             env -> clbegstr = stmDstrDel (env -> clbegstr, 0, 0);
00896             env -> cnl = StmTrue;
00897             env -> init = StmTrue;
00898             env -> last = NORMAL;
00899         }
00900         else env -> bsep = StmTrue;
00901     }
00902     if (cmd.rollback)
00903     {
00904         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00905         fprintf (stderr, "commout (rollback): line %d: [%.*s]\n",
00906                  env -> lnr, stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00907     }
00908     return 0;
00909 }
00910 
00911 
00912 static int setclbeg (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00913 {
00914     if (cmd.action)
00915     {
00916         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00917         env -> clbeg = StmTrue;
00918     }
00919     if (cmd.rollback)
00920     {
00921         fprintf (stderr, "setclbeg (rollback): str [%.*s]\n",
00922                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00923     }
00924     return 0;
00925 }
00926 
00927 
00928 static int cmode (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00929 {
00930     if (cmd.action)
00931     {
00932         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00933         env -> incomment = stmQreMtcStr (qreMtc) [0] == '\n';
00934     }
00935     if (cmd.rollback)
00936     {
00937         fprintf (stderr, "cmode (rollback): str [%.*s]\n",
00938                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00939     }
00940     return 0;
00941 }
00942 
00943 
00944 static int incif (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00945 {
00946     if (cmd.action)
00947     {
00948         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00949         env -> iflevel ++;
00950     }
00951     if (cmd.rollback)
00952     {
00953         fprintf (stderr, "incif (rollback): str [%.*s]\n",
00954                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00955     }
00956     return 0;
00957 }
00958 
00959 
00960 static int chkif (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00961 {
00962     if (cmd.action)
00963     {
00964         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00965         if (!env -> iflevel)
00966         {
00967             fprintf (stderr,
00968                      "%s: #%.*s without #if in file %s, line %d:\n\"%s\"\n",
00969                      env -> prog, stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc),
00970                      env -> filename, env -> lnr, env -> str);
00971             return StmMtcFctFail;
00972         }
00973     }
00974     if (cmd.rollback)
00975     {
00976         fprintf (stderr, "chkif (rollback): str [%.*s]\n",
00977                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
00978     }
00979     return 0;
00980 }
00981 
00982 
00983 static int decif (StmMtcFctCmd cmd, StmQreMtc qreMtc)
00984 {
00985     if (cmd.action)
00986     {
00987         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
00988         if (!env -> iflevel)
00989         {
00990             fprintf (stderr,
00991                      "%s: #endif without #if in file %s, line %d:\n\"%s\"\n",
00992                      env -> prog, env -> filename, env -> lnr, env -> str);
00993             return StmMtcFctFail;
00994         }
00995         env -> iflevel --;
00996     }
00997     if (cmd.rollback)
00998     {
00999         fprintf (stderr, "decif (rollback): str [%.*s]\n",
01000                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
01001     }
01002     return 0;
01003 }
01004 
01005 
01006 static int newlnr (StmMtcFctCmd cmd, StmQreMtc qreMtc)
01007 {
01008     if (cmd.action)
01009     {
01010         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
01011         long ll = strtol (stmQreMtcStr (qreMtc), NULL, 0);
01012         if (ll > 0 && ll < INT_MAX) env -> lnr = (int) (ll - 1);
01013     }
01014     if (cmd.rollback)
01015     {
01016         fprintf (stderr, "newlnr (rollback): str [%.*s]\n",
01017                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
01018     }
01019     return 0;
01020 }
01021 
01022 
01023 static int newfile (StmMtcFctCmd cmd, StmQreMtc qreMtc)
01024 {
01025     if (cmd.action)
01026     {
01027         CuglifyEnv *env = stmQreMtcEnv (qreMtc);
01028         env -> filename =
01029             stmDstrSave (stmQreMtcStr (qreMtc), stmQreMtcLen (qreMtc));
01030     }
01031     if (cmd.rollback)
01032     {
01033         fprintf (stderr, "newfile (rollback): str [%.*s]\n",
01034                  stmQreMtcLen (qreMtc), stmQreMtcStr (qreMtc));
01035     }
01036     return 0;
01037 }
01038 
01039 
01040 static void defsreact (StmReCtrl reCtrl, CuglifyEnv *env)
01041 {
01042     stmReCreate (reCtrl,
01043                  "controlLine",
01044                  "#:pout:&ws&((line):out:&sep&&integerConstant&:newlnr,out:"
01045                                      "(&ws&&stringLiteral&:newfile,out:)?||"
01046                              "(include||line):out:&ws&&ppToken&+||"
01047                              "(error||pragma):out:&ws&&ppToken&*||"
01048                              "(define&_&&identifier&[( \t]?):out:"
01049                                                           "&ws&&ppToken&*||"
01050                              "(undef):out:&sep&&identifier&:out:||"
01051                              "(ifn?def):incif,out:&sep&&identifier&:out:||"
01052                              "(if):incif,out:&ws&&ppToken&+||"
01053                              "(elif):chkif,out:&ws&&ppToken&+||"
01054                              "(else):chkif,out:||"
01055                              "(endif):decif,out:||"
01056                              "(!&sep&[^\n]*):errout:"
01057                             ")?&ws&&nl&:pnlout:",
01058                  NULL);
01059     stmReCreate (reCtrl,
01060                  "progLine",
01061                  "&ppToken&*&cnl&",
01062                  NULL);
01063     stmReCreate (reCtrl,
01064                  "ppToken",
01065                  env -> cplusplus || env -> cplusplusComments ?
01066                      "!(%/[*/])'(&identifier&||"
01067                                 "&floatingConstant&||"
01068                                 "&integerConstant&||"
01069                                 "&characterConstant&||"
01070                                 "&stringLiteral&||"
01071                                 "&punctuator&||"
01072                                 "&operator&||"
01073                                 "[^ \t\n\f\v]):out:&ws&" :
01074                      "!(%/%*)'(&identifier&||"
01075                               "&floatingConstant&||"
01076                               "&integerConstant&||"
01077                               "&characterConstant&||"
01078                               "&stringLiteral&||"
01079                               "&punctuator&||"
01080                               "&operator&||"
01081                               "[^ \t\n\f\v]):out:&ws&",
01082                  NULL);
01083     stmReCreate (reCtrl,
01084                  "identifier",
01085                  "[_a-zA-Z][_0-9a-zA-Z]*",
01086                  NULL);
01087     stmReCreate (reCtrl,
01088                  "floatingConstant",
01089                  "(([0-9]*%.[0-9]+||[0-9]+%.)([eE][-+]?[0-9]+)?||"
01090                  "[0-9]+[eE][-+]?[0-9])[flFL]?",
01091                  NULL);
01092     stmReCreate (reCtrl,
01093                  "integerConstant",
01094                  "([1-9][0-9]*||"
01095                  "0[xX][0-9a-fA-F]*||"
01096                  "0[0-7]*)([uU][lL]?||[lL][uU]?)?",
01097                  NULL);
01098     stmReCreate (reCtrl,
01099                  "characterConstant",
01100                  "L?%'([^'\\\n]||&escapeSequence&)+%'",
01101                  NULL);
01102     stmReCreate (reCtrl,
01103                  "stringLiteral",
01104                  "L?\"([^\"\\\n]||&escapeSequence&)*\"",
01105                  NULL);
01106     stmReCreate (reCtrl,
01107                  "escapeSequence",
01108                  "\\(['\"?\\abfnrtv]||[0-7]{1,3}||[xX][0-9a-fA-F]{1,2})",
01109                  NULL);
01110     stmReCreate (reCtrl,
01111                  "punctuator",
01112                  "%.%.%.||[{};]",
01113                  NULL);
01114     stmReCreate (reCtrl,
01115                  "operator",
01116                  "sizeof||"
01117                  "%<%<=||"
01118                  "%>%>=||"
01119                  "%.%*||"
01120                  "-%>%*||"
01121                  "-%>||"
01122                  "%+%+||"
01123                  "--||"
01124                  "%<%<||"
01125                  "%>%>||"
01126                  "%<=||"
01127                  "%>=||"
01128                  "==||"
01129                  "%!=||"
01130                  "%&%&||"
01131                  "%|%|||"
01132                  "%*=||"
01133                  "%/=||"
01134                  "%%=||"
01135                  "%+=||"
01136                  "-=||"
01137                  "%&=||"
01138                  "^=||"
01139                  "%|=||"
01140                  "##||"
01141                  "%:%:||"
01142                  "-||"
01143                  "[][().&*+~!/%%<>^|?:=,#]",
01144                  NULL);
01145     stmReCreate (reCtrl,
01146                  "nl",
01147                  env -> cplusplus || env -> cplusplusComments ?
01148                      (env -> comments ?
01149                          "((%/%/[^\n]*):out:\n:pnlout:||\n:setclbeg:)&cws&" :
01150                          "(%/%/[^\n]*)?\n:setclbeg:&cws&") :
01151                      "\n:setclbeg:&cws&",
01152                  NULL);
01153     stmReCreate (reCtrl,
01154                  "cnl",
01155                  "&nl&||&commbeg&",
01156                  NULL);
01157     stmReCreate (reCtrl,
01158                  "ws",
01159                  "([ \t\v\f]:bout:||&comment&)*",
01160                  NULL);
01161     stmReCreate (reCtrl,
01162                  "sep",
01163                  "([ \t\v\f]:bout:||&comment&)+",
01164                  NULL);
01165     stmReCreate (reCtrl,
01166                  "cws",
01167                  "[ \t]*:cnlout:",
01168                  NULL);
01169     stmReCreate (reCtrl,
01170                  "_",
01171                  "[ \t]+:bout:",
01172                  NULL);
01173     stmReCreate (reCtrl,
01174                  "comment",
01175                  "(%/%*!(%*%/)*%*%/):commout:",
01176                  NULL);
01177     stmReCreate (reCtrl,
01178                  "commbeg",
01179                  "([ \t\v\f]*)(%/%*[^\n]*):commout:\n:setclbeg,cmode:&cws&",
01180                  NULL);
01181     stmReCreate (reCtrl,
01182                  "commline",
01183                  "[^\n]*:commout:\n:setclbeg:&cws&",
01184                  NULL);
01185     stmReCreate (reCtrl,
01186                  "commend",
01187                  "(!(%*%/)*%*%/:cmode:):commout:&ws&",
01188                  NULL);
01189     stmQreActDef (reCtrl, "out", out);
01190     stmQreActDef (reCtrl, "errout", errout);
01191     stmQreActDef (reCtrl, "pout", pout);
01192     stmQreActDef (reCtrl, "bout", bout);
01193     stmQreActDef (reCtrl, "pnlout", pnlout);
01194     stmQreActDef (reCtrl, "cnlout", cnlout);
01195     stmQreActDef (reCtrl, "commout", commout);
01196     stmQreActDef (reCtrl, "setclbeg", setclbeg);
01197     stmQreActDef (reCtrl, "cmode", cmode);
01198     stmQreActDef (reCtrl, "incif", incif);
01199     stmQreActDef (reCtrl, "chkif", chkif);
01200     stmQreActDef (reCtrl, "decif", decif);
01201     stmQreActDef (reCtrl, "newlnr", newlnr);
01202     stmQreActDef (reCtrl, "newfile", newfile);
01203     return;
01204 }
01205 
01206 
01207 static StmBool readline (CuglifyEnv *env)
01208 {
01209     StmBool splice = StmFalse;
01210     StmBool tws = StmFalse;
01211     int ch;
01212     env -> str = stmDstrDel (env -> str, 0, 0);
01213     while ((ch = fgetc (env -> instream)) != EOF)
01214     {
01215         if (tws) switch (ch)
01216         {
01217         case ' ':
01218         case '\t':
01219             env -> str = stmDstrChApp (env -> str, (char) ch);
01220             break;
01221         default:
01222             ungetc (ch, env -> instream);
01223             ch = 0;
01224             break;
01225         }
01226         else
01227         {
01228             int r = stmDstrLen (env -> str) - 2;
01229             if (r >= 0 && !strncmp (env -> str + r, "??", 2)) switch (ch)
01230             {
01231             case '=':
01232                 env -> str = stmDstrDel (env -> str, r, 2);
01233                 ch = '#';
01234                 break;
01235             case '/':
01236                 env -> str = stmDstrDel (env -> str, r, 2);
01237                 ch = '\\';
01238                 break;
01239             case '\'':
01240                 env -> str = stmDstrDel (env -> str, r, 2);
01241                 ch = '^';
01242                 break;
01243             case '(':
01244                 env -> str = stmDstrDel (env -> str, r, 2);
01245                 ch = '[';
01246                 break;
01247             case ')':
01248                 env -> str = stmDstrDel (env -> str, r, 2);
01249                 ch = ']';
01250                 break;
01251             case '!':
01252                 env -> str = stmDstrDel (env -> str, r, 2);
01253                 ch = '|';
01254                 break;
01255             case '<':
01256                 env -> str = stmDstrDel (env -> str, r, 2);
01257                 ch = '{';
01258                 break;
01259             case '>':
01260                 env -> str = stmDstrDel (env -> str, r, 2);
01261                 ch = '}';
01262                 break;
01263             case '-':
01264                 env -> str = stmDstrDel (env -> str, r, 2);
01265                 ch = '~';
01266                 break;
01267             }
01268             switch (ch)
01269             {
01270             case '\n':
01271                 if (++ r >= 0 && env -> str [r] == '\r')
01272                 {
01273                     env -> str = stmDstrDel (env -> str, r, 1);
01274                 }
01275                 env -> lnr ++;
01276                 if (splice) splice = StmFalse;
01277                 else
01278                 {
01279                     int i;
01280                     for (i = stmDstrLen (env -> str) - 1; i >= 0; -- i)
01281                     {
01282                         if (!strchr (" \t", env -> str [i])) break;
01283                     }
01284                     env -> str = stmDstrDel (env -> str, i + 1, 0);
01285                     env -> str = stmDstrChApp (env -> str, (char) ch);
01286                     tws = StmTrue;
01287                 }
01288                 break;
01289             case '\\':
01290                 if (!splice)
01291                 {
01292                     splice = StmTrue;
01293                     break;
01294                 }
01295                 /* fall through */
01296             default:
01297                 if (splice)
01298                 {
01299                     splice = StmFalse;
01300                     env -> str = stmDstrChApp (env -> str, '\\');
01301                 }
01302                 env -> str = stmDstrChApp (env -> str, (char) ch);
01303                 break;
01304             }
01305         }
01306         if (!env -> str)
01307         {
01308             errno = ENOMEM;
01309             break;
01310         }
01311         if (!ch) break;
01312     }
01313     if (ch == EOF && stmDstrLen (env -> str) && !tws)
01314     {
01315         env -> lnr ++;
01316         env -> str = stmDstrChApp (env -> str, '\n');
01317     }
01318     if (!env -> str || ferror (env -> instream))
01319     {
01320         if (env -> debug)
01321         {
01322             fprintf (env -> debug,
01323                      "%s: line %d: %s: aborted\n",
01324                      env -> prog, __LINE__, strerror (errno));
01325         }
01326         else perror (env -> prog);
01327         longjmp (env -> jmpbuf, -1);
01328     }
01329     return env -> str [0] != '\0';
01330 }
01331 
01332 
01333 static void flushout (CuglifyEnv *env)
01334 {
01335     if (env -> linelen)
01336     {
01337         if (env -> outlen)
01338         {
01339             fprintf (env -> outstream, "%s\n", env -> outstr);
01340             env -> outstr = stmDstrDel (env -> outstr, 0, 0);
01341             env -> outlen = 0;
01342         }
01343     }
01344     else fprintf (env -> outstream, "\n");
01345     return;
01346 }
01347 
01348 
01349 static void gatherout (CuglifyEnv *env, const char *str, int len)
01350 {
01351     if (!len) len = (int) strlen (str);
01352     if (env -> linelen)
01353     {
01354         if (!env -> outlen && env -> bsep && len && str [0] == ' ')
01355         {
01356             str ++;
01357             len --;
01358         }
01359         env -> bsep = StmFalse;
01360         if (len)
01361         {
01362             env -> outstr = stmDstrApp (env -> outstr, str, len);
01363             env -> outlen += len;
01364             while (env -> outlen >= env -> linelen)
01365             {
01366                 int l = env -> outlen == env -> linelen && !env -> ppline ?
01367                             env -> linelen :
01368                             env -> linelen - 1;
01369                 fprintf (env -> outstream, "%.*s", l, env -> outstr);
01370                 env -> outstr = stmDstrDel (env -> outstr, 0, l);
01371                 env -> outlen -= l;
01372                 if (l < env -> linelen) fprintf (env -> outstream, "\\");
01373                 fprintf (env -> outstream, "\n");
01374             }
01375         }
01376     }
01377     else if (len) fprintf (env -> outstream, "%.*s", len, str);
01378     return;
01379 }

© Copyright Tom Michaelis 2002-2007

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