// crm_main.c - Controllable Regex Mutilator, version v1.0
// Copyright 2001-2006 William S. Yerazunis, all rights reserved.
//
// This software is licensed to the public under the Free Software
// Foundation's GNU GPL, version 2. You may obtain a copy of the
// GPL by visiting the Free Software Foundations web site at
// www.fsf.org, and a copy is included in this distribution.
//
// Other licenses may be negotiated; contact the
// author for details.
//
// include some standard files
#include "crm114_sysincludes.h"
// include any local crm114 configuration file
#include "crm114_config.h"
// include the crm114 data structures file
#include "crm114_structs.h"
// include the routine declarations file
#include "crm114.h"
// and include OSBF declarations
#include "crm114_osbf.h"
// the command line argc, argv
int prog_argc;
char **prog_argv;
// the auxilliary input buffer (for WINDOW input)
char *newinputbuf;
// the globals used when we need a big buffer - allocated once, used
// wherever needed. These are sized to the same size as the data window.
char *inbuf;
char *outbuf;
char *tempbuf;
int main (int argc, char **argv)
{
int i; // some random counters, when we need a loop
int status;
int openbracket; // if there's a command-line program...
int openparen = -1; // if there's a list of acceptable arguments
int user_cmd_line_vars = 0; // did the user specify --vars on cmdline?
// printf (" args: %d \n", argc);
// for (i = 0; i < argc; i++)
// fprintf (stderr, " argi: %d, argv: %s \n", i, argv[i]);
// copy argc and argv into global statics...
prog_argc = argc;
prog_argv = argv;
vht_size = DEFAULT_VHT_SIZE;
cstk_limit = DEFAULT_CSTK_LIMIT;
max_pgmlines = DEFAULT_MAX_PGMLINES;
max_pgmsize = DEFAULT_MAX_PGMLINES * 128;
data_window_size = DEFAULT_DATA_WINDOW;
user_trace = DEFAULT_USER_TRACE_LEVEL;
internal_trace = DEFAULT_INTERNAL_TRACE_LEVEL;
sparse_spectrum_file_length = 0;
microgroom_chain_length = 0;
microgroom_stop_after = 0;
min_pmax_pmin_ratio = OSBF_MIN_PMAX_PMIN_RATIO;
ignore_environment_vars = 0;
debug_countdown = -1;
cycle_counter = 0;
cmdline_break = -1;
profile_execution = 0;
prettyprint_listing = 0;
engine_exit_base = 0;
q_expansion_mode = 0;
// allcate and initialize the initial root csl (control stack
// level) cell. We do this first, before command-line parsing,
// because the command line parse fills in a lot of the first level csl.
csl = (CSL_CELL *) malloc (sizeof (CSL_CELL));
if (!csl)
untrappableerror ("Couldn't malloc the csl. Big problem!\n","");
csl -> filename = NULL;
csl -> filedes = -1;
csl -> rdwr = 0; // 0 means readonly, 1 means read/write
csl -> nchars = 0;
csl -> mct = 0;
csl -> cstmt = 0;
csl -> nstmts = 0;
csl -> preload_window = 1;
csl -> caller = NULL;
csl -> calldepth = 0;
csl -> aliusstk[0] = 0; // this gets initted later.
openbracket = -1;
openparen = -1;
// and allocate the argparse block
apb = (ARGPARSE_BLOCK *) malloc (sizeof (ARGPARSE_BLOCK));
if (!apb)
untrappableerror ("Couldn't malloc apb. This is very bad.\n","");
// Parse the input command arguments
// user_trace = 1;
//internal_trace = 1;
for (i = 1; i < argc; i++)
{
// fprintf (stderr, "Arg %d = '%s' \n", i, argv[i]);
// is this a plea for help?
if (
(strncmp (argv[i], "-?", 2) == 0)
|| (strncmp (argv[i], "-h", 2) == 0)
|| (argc == 1) )
{
fprintf (stderr, " CRM114 version %s (regex engine: %s)\n ",
VERSION,
crm_regversion());
fprintf (stderr, " Copyright 2001-2006 William S. Yerazunis\n");
fprintf (stderr, " This software is licensed under the GPL "
"with ABSOLUTELY NO WARRANTY\n");
fprintf (stderr, " For language help, RTFRM. \n");
fprintf (stderr, " Command Line Options:\n");
fprintf (stderr, " -{statements} executes statements\n");
fprintf (stderr, " -b nn sets a breakpoint on stmt nn\n");
fprintf (stderr, " -d nn run nn statements, then drop to debug\n");
fprintf (stderr, " -e ignore environment variables\n");
fprintf (stderr, " -E set base for engine exit values\n");
fprintf (stderr, " -h this help\n");
fprintf (stderr, " -l n listing (detail level 1 through 5)\n");
fprintf (stderr, " -m nn max number of microgroomed buckets in a chain\n");
fprintf (stderr, " -M nn max chain length - triggers microgrooming if enabled\n");
fprintf (stderr, " -p profile statement times \n");
fprintf (stderr, " -P nn max program lines @ 128 chars/line\n");
fprintf (stderr, " -q m mathmode (0,1 alg/RPN in EVAL,"
"2,3 alg/RPN everywhere)\n");
fprintf (stderr, " -r nn set OSBF min pmax/pmin ratio (default=9)\n");
fprintf (stderr, " -s nn sparse spectra (.css) featureslots \n");
fprintf (stderr, " -S nn round up to 2^N+1 .css featureslots \n");
fprintf (stderr, " -C use env. locale (default POSIX)\n");
fprintf (stderr, " -t user trace mode on\n");
fprintf (stderr, " -T implementors trace mode on\n");
fprintf (stderr, " -u dir chdir to directory before starting\n");
fprintf (stderr, " -v print version ID and exit \n");
fprintf (stderr, " -w nn max data window size ( bytes ) \n");
fprintf (stderr, " -- end of CRM114 flags; start of user args\n");
fprintf (stderr, " --foo creates var :foo: with value 'SET'\n");
fprintf (stderr, " --x=y creates var :x: with value 'y'\n");
if (openparen > 0)
{
fprintf (stderr, "\n This program also claims to accept these command line args:" );
fprintf (stderr, "\n %s\n", &argv[openparen][1] );
};
if (engine_exit_base != 0)
{
exit (engine_exit_base + 14);
}
else
exit (EXIT_SUCCESS);
}
// -- means "end of crm114 flags" - remainder of args goes to
// the program alone.
if (strncmp (argv[i], "--", 2) == 0 && strlen (argv[i]) == 2)
{
if (user_trace > 0)
fprintf (stderr, "system flag processing ended at arg %d .\n", i);
i = argc;
goto end_command_line_parse_loop;
}
if (strncmp (argv[i], "--", 2) == 0 && strlen (argv[i]) > 2)
{
if (user_trace > 0)
fprintf (stderr, "Commandline set of user variable at %d '%s'.\n",
i, argv[i]);
if (user_cmd_line_vars == 0) user_cmd_line_vars = i;
goto end_command_line_parse_loop;
};
// set debug levels
if (strncmp (argv[i], "-t", 2) == 0 && strlen(argv[i]) == 2)
{
user_trace++;
if (user_trace > 0)
{
fprintf (stderr, "Setting usertrace level to %ld\n", user_trace);
};
goto end_command_line_parse_loop;
};
if (strncmp (argv[i], "-T", 2) == 0 && strlen(argv[i]) == 2)
{
internal_trace++;
if (user_trace > 0 )
fprintf (stderr, "Setting internaltrace to %ld\n", internal_trace);
goto end_command_line_parse_loop;
};
if (strncmp (argv[i], "-p", 2) == 0 && strlen(argv[i]) == 2)
{
profile_execution = 1;
if (user_trace > 0 )
fprintf (stderr, "Setting profile_execution to 1" );
goto end_command_line_parse_loop;
};
// is this a change to the maximum number of program lines?
if (strncmp (argv[i], "-P", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
{
sscanf (argv[i], "%ld", &max_pgmlines);
max_pgmsize = 128 * max_pgmlines;
}
if (user_trace > 0)
fprintf (stderr, "Setting max prog lines to %ld (%ld bytes)\n",
max_pgmlines, max_pgmsize);
goto end_command_line_parse_loop;
};
// is this a "gimme a listing" flag?
if (strncmp (argv[i], "-l", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
{
sscanf (argv[i], "%ld", &prettyprint_listing);
}
if (user_trace > 0)
fprintf (stderr, "Setting listing level to %ld \n",
prettyprint_listing);
goto end_command_line_parse_loop;
};
// is this a "Use Local Country Code" flag?
if (strncmp (argv[i], "-C", 2) == 0 && strlen(argv[i]) == 2)
{
if (user_trace > 0)
fprintf (stderr, "Setting locale to local\n");
setlocale (LC_ALL, "");
goto end_command_line_parse_loop;
};
// is this a change to the math mode (0,1 for alg/RPN but only in EVAL,
// 2,3 for alg/RPN everywhere.
if (strncmp (argv[i], "-q", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
sscanf (argv[i], "%ld", &q_expansion_mode);
if (user_trace > 0)
{
fprintf (stderr, "Setting math mode to %ld ", q_expansion_mode);
if (q_expansion_mode == 0)
fprintf (stderr, "(algebraic, only in EVAL\n");
if (q_expansion_mode == 1)
fprintf (stderr, "(RPN, only in EVAL\n");
if (q_expansion_mode == 2)
fprintf (stderr, "(algebraic, in all expressions)\n");
if (q_expansion_mode == 3)
fprintf (stderr, "(RPN, in all expressions)\n");
};
goto end_command_line_parse_loop;
};
// change the size of the maximum data window we'll allow
if (strncmp (argv[i], "-w", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
sscanf (argv[i], "%ld", &data_window_size);
if (data_window_size < 8192)
{
fprintf (stderr, "Sorry, but the min data window is 8192 bytes");
data_window_size = 8192;
};
if (user_trace > 0)
fprintf (stderr, "Setting max data window to %ld chars\n",
data_window_size);
goto end_command_line_parse_loop;
};
// change the size of the sparse spectrum file default.
if (strncasecmp (argv[i], "-s", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc &&
sscanf (argv[i], "%ld", &sparse_spectrum_file_length))
{
if (strcmp (argv[i-1], "-S") == 0)
{
long k;
k=(long) floor(log10(sparse_spectrum_file_length-1)
/ log10(2));
while ( (2<<k)+1 < sparse_spectrum_file_length)
{
k++;
};
sparse_spectrum_file_length=(2<<k)+1;
};
}
else
{
fprintf (stderr, "On -s flag: Missing or incomprehensible"
".CSS file length.\n");
if (engine_exit_base != 0)
{
exit (engine_exit_base + 15);
}
else
exit (EXIT_FAILURE);
};
if (user_trace > 0)
fprintf (stderr, "Setting sparse spectrum length to %ld bins\n",
sparse_spectrum_file_length );
goto end_command_line_parse_loop;
};
// set a break from the command line
if (strncmp (argv[i], "-b", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
sscanf (argv[i], "%ld", &cmdline_break);
if (user_trace > 0)
fprintf (stderr, "Setting the command-line break to line %ld\n",
cmdline_break);
goto end_command_line_parse_loop;
};
// set base value for detailed engine exit values
if (strncmp (argv[i], "-E", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
sscanf (argv[i], "%ld", &engine_exit_base);
if (user_trace > 0)
fprintf (stderr, "Setting the engine exit base value to %ld\n",
engine_exit_base);
goto end_command_line_parse_loop;
};
// set countdown cycles before dropping to debugger
if (strncmp (argv[i], "-d", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
debug_countdown = 0;
if (i < argc)
sscanf (argv[i], "%ld", &debug_countdown);
if (user_trace > 0)
fprintf (stderr, "Setting debug countdown to %ld statements\n",
debug_countdown);
if (debug_countdown == 0) // if next arg wasn't numeric, back up
i-- ;
goto end_command_line_parse_loop;
};
// ignore environment variables?
if (strncmp (argv[i], "-e", 2) == 0 && strlen(argv[i]) == 2)
{
ignore_environment_vars++;
if (user_trace > 0)
fprintf (stderr, "Ignoring environment variables\n");
goto end_command_line_parse_loop;
};
// is this to set the cwd?
if (strncmp (argv[i], "-u", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (user_trace)
fprintf (stderr, "Setting WD to %s\n",argv[i]);
if ( i >= argc )
{
fprintf (stderr, "The -u working-directory change needs an arg");
goto end_command_line_parse_loop;
};
if ( chdir(argv[i] ))
{
fprintf (stderr, "Sorry, couldn't chdir to %s \n", argv[i]);
};
goto end_command_line_parse_loop;
};
if (strncmp (argv[i], "-v", 2) == 0 && strlen(argv[i]) == 2)
{
// NOTE - version info goes to stdout, not stderr, just like GCC does
fprintf (stdout,
" This is CRM114, version %s (%s)\n",
VERSION,
crm_regversion());
fprintf (stdout, " Copyright 2001-2006 William S. Yerazunis\n");
fprintf (stdout, " This software is licensed under the GPL with ABSOLUTELY NO WARRANTY\n");
if (engine_exit_base != 0)
{
exit (engine_exit_base + 16);
}
else
exit( EXIT_SUCCESS );
};
if (strncmp (argv[i], "-{", 2) == 0) // don't care about the "}"
{
if (user_trace)
fprintf (stderr, "Command line program at arg %d\n", i);
openbracket = i;
goto end_command_line_parse_loop;
};
//
// What about -( var var var ) cmdline var restrictions?
if (strncmp (argv[i], "-(", 2) == 0 )
{
if (user_trace)
fprintf (stderr, "Allowed command line arg list at arg %d\n", i);
openparen = i;
//
// If there's a -- at the end of the arg, lock out system
// flags as though we hit a '--' flag.
// (i.e. no debugger. Minimal security. No doubt this is
// circumventable by a sufficiently skilled user, but
// at least it's a start.)
if ( strncmp ("--", &argv[i][strlen(argv[i])-2], 2) == 0)
{
if (user_trace)
fprintf (stderr, "cmdline arglist also locks out sysflags.\n");
i = argc;
};
goto end_command_line_parse_loop;
};
// set microgroom_stop_after
if (strncmp (argv[i], "-m", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
sscanf (argv[i], "%ld", µgroom_stop_after);
if (user_trace > 0)
fprintf (stderr, "Setting microgroom_stop_after to %ld\n",
microgroom_stop_after);
if (microgroom_stop_after <= 0) // if value <= 0 set it to default
microgroom_stop_after = MICROGROOM_STOP_AFTER;
goto end_command_line_parse_loop;
};
// set microgroom_chain_length length
if (strncmp (argv[i], "-M", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
sscanf (argv[i], "%ld", µgroom_chain_length);
if (user_trace > 0)
fprintf (stderr, "Setting microgroom_chain_length to %ld\n",
microgroom_chain_length);
if (microgroom_chain_length < 5) // if value <= 5 set it to default
microgroom_chain_length = MICROGROOM_CHAIN_LENGTH;
goto end_command_line_parse_loop;
};
// set min_pmax_pmin_ratio
if (strncmp (argv[i], "-r", 2) == 0 && strlen(argv[i]) == 2)
{
i++; // move to the next arg
if (i < argc)
sscanf (argv[i], "%f", &min_pmax_pmin_ratio);
if (user_trace > 0)
fprintf (stderr, "Setting min pmax/pmin of a feature to %f\n",
min_pmax_pmin_ratio);
if (min_pmax_pmin_ratio < 0) // if value < 0 set it to 0
min_pmax_pmin_ratio = OSBF_MIN_PMAX_PMIN_RATIO ;
goto end_command_line_parse_loop;
};
// that's all of the flags. Anything left must be
// the name of the file we want to use as a program
// BOGOSITUDE - only the FIRST such thing is the name of the
// file we want to use as a program. The rest of the args
// should just be passed along
if (csl->filename == NULL)
{
if (strlen(argv[i]) > MAX_FILE_NAME_LEN)
untrappableerror ("Invalid filename, ", "filename too long.");
csl->filename = argv[i];
if (user_trace > 0)
fprintf (stderr, "Using program file %s\n", csl->filename);
};
end_command_line_parse_loop:
if (internal_trace)
fprintf (stderr, "End of pass %d through cmdline parse loop\n",
i);
}
//
// Did we get a program filename? If not, look for one.
// At this point, accept any arg that doesn't start with a - sign
//
if (csl->filename == NULL && openbracket < 1)
{
if (internal_trace)
fprintf (stderr, "Looking for _some_ program to run...\n");
for (i = 1; i < argc; i++)
if (argv[i][0] != '-')
{
if (strlen(argv[i]) > MAX_FILE_NAME_LEN)
untrappableerror ("Couldn't open the file, ",
"filename too long.");
csl->filename = argv[i];
i = argc;
}
if (user_trace > 0)
fprintf (stderr, "Using program file %s\n", csl->filename);
};
// If we still don't have a program, we're done. Squalk an
// error.
if (csl->filename == NULL && openbracket < 0)
{
fprintf (stderr, "\nCan't find a file to run,"
"or a command-line to execute. \n"
"I give up... (exiting)\n");
if (engine_exit_base != 0)
{
exit (engine_exit_base + 17);
}
else
exit (EXIT_SUCCESS);
};
// open, stat and load the program file
if (openbracket < 0 )
{
{
if (argc <= 1)
{
fprintf (stderr, "CRM114 version %s \n", VERSION);
fprintf (stderr, "Try 'crm <progname>', or 'crm -h' for help\n");
if (engine_exit_base != 0)
{
exit (engine_exit_base + 18);
}
else
exit (EXIT_SUCCESS);
}
else
{
if (user_trace)
fprintf (stderr, "Loading program from file %s\n",
csl->filename);
crm_load_csl (csl);
};
};
}
else
{
// if we got here, then it's a command-line program, and
// we should just assemble the proggie from the argv [openbracket]
if (strlen (&(argv[openbracket][1])) + 2048 > max_pgmsize)
untrappableerror ("The command line program is too big. \n",
"Try increasing the max program size with -P. \n");
csl->filename = "(from command line)";
csl->filetext = (char *) malloc (sizeof (char) * max_pgmsize);
if (!csl->filetext)
untrappableerror ("Couldn't malloc csl->filetext space (where I was going to put your program.\nWithout program space, we can't run. Sorry.","");
strcpy (csl->filetext, "\n");
// the [1] below gets rid of the leading - sign
strcat (csl->filetext, &(argv[openbracket][1]));
strcat (csl->filetext, "\n");
strcat (csl->filetext, "\n");
csl->nchars = strlen (csl->filetext);
csl->hash = strnhash (csl->filetext, csl->nchars);
if (user_trace)
fprintf (stderr, "Hash of program: %lX, length is %ld bytes\n",
csl->hash, csl->nchars);
};
// We get another csl-like data structure,
// which we'll call the cdw, which has all the fields we need, and
// simply allocate the data window of "adequate size" and read
// stuff in on stdin.
cdw = malloc (sizeof (CSL_CELL));
if (!cdw)
untrappableerror ("Couldn't malloc cdw.\nThis is very bad.","");
cdw->filename = NULL;
cdw->rdwr = 1;
cdw->filedes = -1;
cdw->filetext = malloc (sizeof (char) * data_window_size);
if (!cdw->filetext)
untrappableerror ("Couldn't malloc cdw->filetext.\nWithout this space, you have no place for data. Thus, we cannot run.","");
// also allocate storage for the windowed data input
newinputbuf = malloc (sizeof (char) * data_window_size);
// and our three big work buffers - these are used ONLY inside
// of a single statement's execution and do NOT ever contain state
// that has to exist across statements.
inbuf = malloc (sizeof (char) * data_window_size);
outbuf = malloc (sizeof (char) * data_window_size);
tempbuf = malloc (sizeof (char) * data_window_size);
if (!tempbuf || !outbuf || !inbuf || !newinputbuf)
untrappableerror (
"Couldn't malloc one or more of"
"newinputbuf,inbuf,outbuf,tempbuf.\n"
"These are all necessary for operation."
"We can't run.","");
// Initialize the VHT, add in a few predefined variables
//
crm_vht_init(argc, argv);
// Call the pre-processor on the program
//
status = crm_preprocessor (csl, 0);
// Now, call the microcompiler on the program file.
status = crm_microcompiler ( csl, vht);
// Great - program file is now mapped via csl->mct
// Put a copy of the preprocessor-result text into
// the isolated variable ":_pgm_text:"
crm_set_temp_var (":_pgm_text:", csl->filetext);
// If the windowflag == 0, we should preload the data window. Now,
// let's get some data in.
// and preload the data window with stdin until we hit EOF
i = 0;
if (csl->preload_window)
{
// GROT GROT GROT This is slow
//
//while (!feof (stdin) && i < data_window_size - 1)
// {
// cdw->filetext[i] = fgetc (stdin);
// i++;
// };
//i-- ; // get rid of the extra ++ on i from the loop; this is the
// EOF "character" which prints like an umlauted-Y.
//
//
// This is the much faster way.
//
// i = fread (cdw->filetext, 1, data_window_size -1, stdin);
//
// JesusFreke suggests this instead- retry with successively
// smaller readsizes on systems that can't handle full
// POSIX-style massive block transfers.
int readsize = data_window_size - 1;
while (! feof (stdin) && i < data_window_size - 1)
{
//i += fread (cdw->filetext + i, 1, readsize-1, stdin);
int rs;
rs = i + readsize < data_window_size - 1 ?
readsize : data_window_size - i - 1;
i+= fread (cdw->filetext + i, 1, rs, stdin);
if (feof (stdin))
{
break;
};
if (ferror (stdin))
{
if (errno == ENOMEM && readsize > 1) // insufficient memory?
{
readsize = readsize / 2; // try a smaller block
clearerr (stdin);
}
else
{
fprintf (stderr, "Error while trying to get startup input. "
"This is usually pretty much hopeless, but "
"I'll try to keep running anyway. ");
break;
};
};
};
};
// data window is now preloaded (we hope), set the cdwo up.
cdw->filetext[i] = '\000';
cdw->nchars = i;
cdw->hash = strnhash (cdw->filetext, cdw->nchars);
cdw->mct = NULL;
cdw->nstmts = -1;
cdw->cstmt = -1;
cdw->caller = NULL;
// and put the initial data window suck-in contents into the vht
// with the special name :_dw:
//
// GROT GROT GROT will have to change this when we get rid of separate
// areas for the data window and the temporary area. In particular, the
// "start" will no longer be zero. Note to self: get rid of this comment
// when it gets fixed. Second note to self - since most of the insert
// and delete action happens in :_dw:, for efficiency reasons perhaps
// we don't want to merge these areas.
//
{
long dwname;
long dwlen;
tdw->filetext[tdw->nchars] = '\n';
tdw->nchars++;
dwlen = strlen (":_dw:");
dwname = tdw->nchars;
//strcat (tdw->filetext, ":_dw:");
memmove (&tdw->filetext[dwname], ":_dw:", dwlen);
tdw->nchars = tdw->nchars + dwlen;
// strcat (tdw->filetext, "\n");
memmove (&tdw->filetext[tdw->nchars], "\n", strlen ("\n"));
tdw->nchars++;
crm_setvar ( NULL,
0,
tdw->filetext,
dwname,
dwlen,
cdw->filetext,
0,
cdw->nchars,
-1);
};
//
// We also set up the :_iso: to hold the isolated variables.
// Note that we must specifically NOT use this var during reclamation
// or GCing the isolated var storage area.
//
// HACK ALERT HACK ALERT - note that :_iso: starts out with a zero
// length and must be updated
//
#define USE_COLON_ISO_COLON
#ifdef USE_COLON_ISO_COLON
{
long isoname;
long isolen;
isolen = strlen (":_iso:");
isoname = tdw->nchars;
//strcat (tdw->filetext, ":_dw:");
memmove (&tdw->filetext[isoname], ":_iso:", isolen);
tdw->nchars = tdw->nchars + isolen;
// strcat (tdw->filetext, "\n");
memmove (&tdw->filetext[tdw->nchars], "\n", strlen ("\n"));
tdw->nchars++;
crm_setvar ( NULL,
0,
tdw->filetext,
isoname,
isolen,
tdw->filetext,
0,
0,
-1);
};
#endif
// Now we're here, we can actually run!
// set up to start at the 0'th statement (the start)
csl->cstmt = 0;
status = crm_invoke ();
// This is the *real* exit from the engine, so we do not override
// the engine's exit status with an engine_exit_base value.
exit ( (char) status);
}
syntax highlighted by Code2HTML, v. 0.9.1