aboutsummaryrefslogtreecommitdiffstats
path: root/c2lout.c
diff options
context:
space:
mode:
Diffstat (limited to 'c2lout.c')
-rw-r--r--c2lout.c916
1 files changed, 916 insertions, 0 deletions
diff --git a/c2lout.c b/c2lout.c
new file mode 100644
index 0000000..e1f5bb1
--- /dev/null
+++ b/c2lout.c
@@ -0,0 +1,916 @@
+/*****************************************************************************/
+/* */
+/* C2LOUT: A PROGRAM TO CONVERT C AND C++ SOURCE INTO LOUT (VERSION 1.0) */
+/* COPYRIGHT (C) 1993 Jeffrey H. Kingston */
+/* */
+/* Jeffrey H. Kingston (jeff@cs.usyd.edu.au) */
+/* Basser Department of Computer Science */
+/* The University of Sydney 2006 */
+/* AUSTRALIA */
+/* */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 1, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* */
+/*****************************************************************************/
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define C2LOUT_VERSION "c2lout Version 3.15 (May 1999)"
+#define BOOLEAN unsigned
+#define FALSE 0
+#define TRUE 1
+#define MAX_LINE 1024
+
+/* print styles */
+#define NO_STYLE 0
+#define FIXED_STYLE 1
+#define VARYING_STYLE 2
+#define SYMBOL_STYLE 3
+
+static char file_name[MAX_LINE]; /* current input file name */
+static int line_num; /* current input line number */
+static int line_pos; /* current input column number */
+static FILE *err_fp; /* where error messages go */
+
+static BOOLEAN headers_option; /* TRUE if no -n option (headers) */
+static int style_option; /* value of -p option, or NO_STYLE */
+static char *font_option; /* value of -f option, else null */
+static char *size_option; /* value of -s option, else null */
+static char *line_option; /* value of -v option, else null */
+static char *tabin_option; /* value of -t option, else null */
+static char *tabout_option; /* value of -T option, else null */
+
+static BOOLEAN tab_by_spacing; /* TRUE if using space chars to tab */
+static int tab_in; /* tab interval, value of -t option */
+static float tab_out; /* tab interval width (-T option) */
+static char tab_unit; /* unit of measurement for tab */
+static BOOLEAN Scan();
+
+extern void ProcessStandAlone(char *fname, FILE *in_fp, FILE *out_fp);
+
+#define Error0(str) \
+{ \
+ if( line_num > 0 ) \
+ fprintf(err_fp, "c2lout %s %d,%d: ", file_name, line_num, line_pos);\
+ else \
+ fprintf(err_fp, "c2lout: "); \
+ fprintf(err_fp, str); \
+ fprintf(err_fp, "\n"); \
+}
+
+#define Error1(str, arg) \
+{ \
+ if( line_num > 0 ) \
+ fprintf(err_fp, "c2lout %s %d,%d: ", file_name, line_num, line_pos);\
+ else \
+ fprintf(err_fp, "c2lout: "); \
+ fprintf(err_fp, str, arg); \
+ fprintf(err_fp, "\n"); \
+}
+
+#define GetArg(arg, message, null_ok) \
+{ if( strcmp(argv[i]+2, "") != 0 ) \
+ arg = argv[i]+2; \
+ else if( !null_ok && i < argc-1 && *argv[i+1] != '-' ) \
+ arg = argv[++i]; \
+ else if( null_ok ) \
+ arg = (char *) NULL; \
+ else \
+ { Error0(message); \
+ exit(1); \
+ } \
+} /* end GetArg */
+
+
+/*****************************************************************************/
+/* */
+/* main(argc, argv) */
+/* */
+/* Read command line and process each file in turn. */
+/* */
+/*****************************************************************************/
+
+int main(int argc, char *argv[])
+{ FILE *in_fp, *out_fp = stdout;
+ BOOLEAN at_least_one_file, raw_seen; int i;
+ char *infilename, *outfilename, *errfilename, *str;
+
+ /* read command line */
+ in_fp = out_fp = NULL;
+ err_fp = stderr;
+ line_num = 0;
+ raw_seen = FALSE;
+ tab_by_spacing = TRUE;
+ style_option = NO_STYLE;
+ tab_in = 8;
+ tab_out = 3;
+ tab_unit = 'f';
+ at_least_one_file = FALSE;
+ headers_option = TRUE;
+ font_option = size_option = line_option =
+ tabin_option = tabout_option = (char *) NULL;
+ for( i = 1; i < argc; i++ )
+ { if( *argv[i] == '-' ) switch( *(argv[i]+1) )
+ {
+ case 'r':
+
+ if( i > 1 )
+ { Error0("-r must be first if it occurs at all");
+ exit(1);
+ }
+ raw_seen = TRUE;
+ break;
+
+
+ case 'i':
+
+ /* read name of input file */
+ if( !raw_seen )
+ { Error0("-i illegal without -r");
+ exit(1);
+ }
+ if( in_fp != NULL )
+ { Error0("-i seen twice");
+ exit(1);
+ }
+ GetArg(infilename, "usage: -i<filename>", FALSE);
+
+ /* open the file */
+ in_fp = fopen(infilename, "r");
+ if( in_fp == NULL )
+ { Error1("cannot open input file %s", infilename);
+ exit(1);
+ }
+
+ /* initialize file position */
+ strcpy(file_name, infilename);
+ line_num = 1;
+ line_pos = 0;
+ break;
+
+
+ case 'o':
+
+ /* read name of output file */
+ if( out_fp != NULL )
+ { Error0("-o seen twice");
+ exit(1);
+ }
+ GetArg(outfilename, "usage: -o<filename>", FALSE);
+ out_fp = fopen(outfilename, "w");
+ if( out_fp == NULL )
+ { Error1("cannot open output file %s", outfilename);
+ exit(1);
+ }
+ break;
+
+
+ case 'e':
+
+ /* read name of error file */
+ GetArg(errfilename, "usage: -e<filename>", FALSE);
+ err_fp = fopen(errfilename, "w");
+ if( err_fp == NULL )
+ { Error1("cannot open error file %s", errfilename);
+ exit(1);
+ }
+ break;
+
+
+ case 'p':
+
+ /* read print style */
+ if( raw_seen )
+ { Error0("-p illegal with -r option");
+ exit(1);
+ }
+ GetArg(str, "usage: -p<printstyle>", FALSE);
+ if( style_option != NO_STYLE )
+ { Error0("-p option appears twice");
+ exit(1);
+ }
+ else if( strcmp(str, "fixed") == 0 )
+ { style_option = FIXED_STYLE;
+ }
+ else if( strcmp(str, "varying") == 0 )
+ { style_option = VARYING_STYLE;
+ tab_by_spacing = FALSE;
+ }
+ else if( strcmp(str, "symbol") == 0 )
+ { style_option = SYMBOL_STYLE;
+ tab_by_spacing = FALSE;
+ }
+ else
+ { Error1("unknown -p option %s", str);
+ exit(1);
+ }
+ break;
+
+
+ case 'f':
+
+ /* read font family */
+ if( raw_seen )
+ { Error0("-f illegal with -r option");
+ exit(1);
+ }
+ GetArg(font_option, "usage: -f<font>", FALSE);
+ break;
+
+
+ case 's':
+
+ /* read font size */
+ if( raw_seen )
+ { Error0("-s illegal with -r option");
+ exit(1);
+ }
+ GetArg(size_option, "usage: -s<size>", FALSE);
+ break;
+
+
+ case 'v':
+
+ /* read line spacing */
+ if( raw_seen )
+ { Error0("-v illegal with -r option");
+ exit(1);
+ }
+ GetArg(line_option, "usage: -v<vsize>", FALSE);
+ break;
+
+
+ case 't':
+
+ /* read tab interval */
+ GetArg(tabin_option, "usage: -t<number>", TRUE);
+ if( tabin_option != NULL && sscanf(tabin_option,"%d",&tab_in) != 1 )
+ { Error0("usage: -t<number>\n");
+ exit(1);
+ }
+ if( tab_in <= 0 )
+ { Error0("-t: tab interval must be greater than 0\n");
+ exit(1);
+ }
+ break;
+
+
+ case 'T':
+
+ /* read tab_out and tab_unit */
+ GetArg(tabout_option, "usage: -T<number><unit>", TRUE);
+ if( tabout_option != NULL )
+ { if( sscanf(tabout_option, "%f%c",&tab_out,&tab_unit) != 2 )
+ { Error0("usage: -T<number><unit>\n");
+ exit(1);
+ }
+ if( tab_out <= 0 || tab_out >= 50 )
+ { Error0("-T: unreasonably large or small tab interval");
+ exit(1);
+ }
+ if( tab_unit != 'c' && tab_unit != 'i' && tab_unit != 'p' &&
+ tab_unit != 'm' && tab_unit != 'f' && tab_unit != 's' &&
+ tab_unit != 'v' )
+ { Error0("-T: tab unit must be one of cipmfsv\n");
+ exit(1);
+ }
+ tab_by_spacing = FALSE;
+ }
+ break;
+
+
+ case 'n':
+
+ if( raw_seen )
+ { Error0("-n illegal with -r option");
+ exit(1);
+ }
+ headers_option = FALSE;
+ break;
+
+
+ case 'V':
+
+ if( raw_seen )
+ { Error0("-V illegal with -r option");
+ exit(1);
+ }
+ Error1("%s", C2LOUT_VERSION);
+ exit(0);
+ break;
+
+
+ case 'u':
+
+ if( raw_seen )
+ { Error0("-u illegal with -r option");
+ exit(1);
+ }
+ Error0("usage: c2lout C-files or c2lout -r Lout-files");
+ exit(0);
+ break;
+
+
+ default:
+
+ Error1("unknown command line flag %s", argv[i]);
+ exit(1);
+ break;
+
+ }
+ else
+ {
+ /* argument is source file, so open it */
+ if( raw_seen )
+ { Error0("file parameter illegal with -r flag!");
+ exit(1);
+ }
+ at_least_one_file = TRUE;
+ in_fp = fopen(argv[i], "r");
+ if( in_fp == NULL )
+ { Error1("cannot open input file %s", argv[i]);
+ exit(1);
+ }
+
+ /* initialize file position */
+ strcpy(file_name, argv[i]);
+ line_num = 1;
+ line_pos = 0;
+
+ ProcessStandAlone(argv[i], in_fp, out_fp == NULL ? stdout : out_fp);
+ }
+ } /* for */
+
+ /* raw case: filter in_fp to out_fp using Scan() */
+ if( raw_seen )
+ {
+ /* check that input and output files are open */
+ if( in_fp == NULL )
+ { Error0("-r: missing -i option");
+ exit(1);
+ }
+ if( out_fp == NULL )
+ { Error0("-r: missing -o option");
+ exit(1);
+ }
+
+ /* scan the file and leave unchanged if an error occurred */
+ if( !Scan(in_fp, out_fp) ) exit(1);
+ }
+
+ /* finish of non-raw case with end text */
+ else if( at_least_one_file )
+ fprintf(out_fp == NULL ? stdout : out_fp, "@End @Text\n");
+
+ return 0;
+} /* end main */
+
+
+/*****************************************************************************/
+/* */
+/* ProcessStandAlone(fname, in_fp, out_fp) */
+/* */
+/* Process one file consisting completely of C code. */
+/* */
+/*****************************************************************************/
+
+void ProcessStandAlone(char *fname, FILE *in_fp, FILE *out_fp)
+{ static BOOLEAN first = TRUE;
+ char *style_str, *font_str, *size_str, *line_str, *face_str,
+ *tabin_str, *tabout_str;
+
+ /* print heading information on out_fp */
+ if( first )
+ {
+ /* sort out the options' values */
+ switch( style_option )
+ {
+
+ case NO_STYLE:
+ case FIXED_STYLE:
+
+ style_str = "fixed";
+ face_str = "Base";
+ font_str = font_option != NULL ? font_option : "Courier";
+ size_str = size_option != NULL ? size_option : "9p";
+ line_str = line_option != NULL ? line_option : "1.1fx";
+ tabin_str = tabin_option != NULL ? tabin_option : "8";
+ tabout_str = tabout_option != NULL ? tabout_option : "8s";
+ break;
+
+
+ case VARYING_STYLE:
+
+ style_str = "varying";
+ face_str = "Slope";
+ font_str = font_option != NULL ? font_option : "Times";
+ size_str = size_option != NULL ? size_option : "10p";
+ line_str = line_option != NULL ? line_option : "1.1fx";
+ tabin_str = tabin_option != NULL ? tabin_option : "8";
+ tabout_str = tabout_option != NULL ? tabout_option : "3f";
+ break;
+
+
+ case SYMBOL_STYLE:
+
+ style_str = "symbol";
+ face_str = "Slope";
+ font_str = font_option != NULL ? font_option : "Times";
+ size_str = size_option != NULL ? size_option : "10p";
+ line_str = line_option != NULL ? line_option : "1.1fx";
+ tabin_str = tabin_option != NULL ? tabin_option : "8";
+ tabout_str = tabout_option != NULL ? tabout_option : "3f";
+ break;
+
+
+ default:
+
+ Error0("internal error in -p option");
+ exit(1);
+ break;
+ }
+
+
+ /* now print the initial @Use clauses etc.*/
+ fprintf(out_fp, "@SysInclude { cprint }\n");
+ fprintf(out_fp, "@SysInclude { doc }\n");
+ fprintf(out_fp, "@Use { @CP\n");
+ fprintf(out_fp, " style { %s }\n", style_str);
+ fprintf(out_fp, " font { %s }\n", font_str);
+ fprintf(out_fp, " size { %s }\n", size_str);
+ fprintf(out_fp, " line { %s }\n", line_str);
+ fprintf(out_fp, " tabin { %s }\n", tabin_str);
+ fprintf(out_fp, " tabout { %s }\n", tabout_str);
+ fprintf(out_fp, "{}\n");
+ fprintf(out_fp, "}\n");
+ fprintf(out_fp, "@Document\n");
+ fprintf(out_fp, " @InitialFont { \"%s\" \"%s\" \"%s\" }\n",
+ font_str, face_str, size_str);
+ fprintf(out_fp, " @InitialBreak { lines \"%s\" nohyphen }\n", line_str);
+ fprintf(out_fp, "//\n");
+ fprintf(out_fp, "@Text @Begin\n\n");
+ first = FALSE;
+ }
+ else fprintf(out_fp, "@NP\n\n");
+
+ /* print file name and contents */
+ if( headers_option )
+ fprintf(out_fp, "{ Times Bold \"+3p\" } @Font \"%s\"\n@DP\n", fname);
+ if( !Scan(in_fp, out_fp) ) exit(1);
+
+} /* end ProcessStandAlone */
+
+
+/*****************************************************************************/
+/* */
+/* EmitTab(out_fp) */
+/* */
+/* Emit the equivalent of one tab character, depending on whether we */
+/* are using spaces or Lout tab operators to simulate it. */
+/* */
+/*****************************************************************************/
+
+void EmitTab(FILE *out_fp)
+{
+ if( tab_by_spacing )
+ { putc(' ', out_fp);
+ while( line_pos % tab_in != 0 )
+ { putc(' ', out_fp);
+ line_pos++;
+ }
+ }
+ else
+ { while( line_pos % tab_in != 0 )
+ { line_pos++;
+ }
+ fprintf(out_fp, " $>%.1f%ct ",
+ (line_pos/tab_in) * tab_out, tab_unit);
+ }
+} /* end EmitTab */
+
+
+/*****************************************************************************/
+/* */
+/* BOOLEAN Scan(in_fp, out_fp) */
+/* */
+/* Scan the C source beginning in file in_fp and write it in modified */
+/* Lout source form onto out_fp. Return TRUE if successful. */
+/* */
+/*****************************************************************************/
+
+/* states of scanner */
+#define C_REGULAR 1
+#define C_SLASH 2
+#define C_COMMENT 3
+#define CPP_COMMENT 4
+#define LOUT_INSERT 5
+#define CPP_LOUT_INSERT 6
+#define LOUT_INSERT_STAR 7
+#define C_COMMENT_STAR 8
+#define C_STRING 9
+#define C_STRING_BACKSLASH 10
+#define C_CHAR 11
+#define C_CHAR_BACKSLASH 12
+
+static BOOLEAN Scan(FILE *in_fp, FILE *out_fp)
+{ int state, ch;
+ state = C_REGULAR;
+ while( (ch = getc(in_fp)) != EOF )
+ {
+ if( ch == '\n' )
+ { line_num++;
+ line_pos = 0;
+ }
+ else line_pos++;
+
+ switch( state )
+ {
+
+ case C_REGULAR: /* in ordinary C code */
+
+ if( ch == '\f' )
+ { fprintf(out_fp, "\n@NP\n");
+ }
+ else if( ch == '\t' )
+ { EmitTab(out_fp);
+ }
+ else if( ch == '#' )
+ { fputs("$$", out_fp);
+ }
+ else if( ch == '\\' )
+ { fputs("\"\\\\\"", out_fp);
+ }
+ else if( ch == '{' ) /*}*/
+ { fputs("${", out_fp); /*}*/
+ }
+ else if( ch == /*{*/ '}' )
+ { /*{*/ fputs("$}", out_fp);
+ }
+ else if( ch == '@' )
+ { Error0("@ character in C program text");
+ return FALSE;
+ }
+ else if( ch == '/' )
+ { state = C_SLASH;
+ }
+ else if( ch == '\'' )
+ { fputs("{@L \"", out_fp);
+ state = C_CHAR;
+ }
+ else if( ch == '"' )
+ { fputs("{@S \"", out_fp); /*}*/
+ state = C_STRING;
+ }
+ else
+ { putc(ch, out_fp);
+ }
+ break;
+
+
+ case C_SLASH: /* in ordinary C code just after / */
+
+ if( ch == '*' )
+ { int nextch = getc(in_fp);
+ if( nextch == EOF )
+ { Error0("unexpected end-of-file");
+ return FALSE;
+ }
+ else if( nextch == '@' )
+ { state = LOUT_INSERT;
+ }
+ else
+ { ungetc(nextch, in_fp);
+ if( nextch == '\n' ) line_num--;
+ fputs("{@C \"/*", out_fp);
+ state = C_COMMENT;
+ }
+ }
+ else if( ch == '/' ) /* C++ comment */
+ { int nextch = getc(in_fp);
+ if( nextch == EOF )
+ { Error0("unexpected end-of-file");
+ return FALSE;
+ }
+ else if( nextch == '@' )
+ { state = CPP_LOUT_INSERT;
+ }
+ else
+ { ungetc(nextch, in_fp);
+ if( nextch == '\n' ) line_num--;
+ fputs("{@C \"//", out_fp);
+ state = CPP_COMMENT;
+ }
+ }
+ else
+ { putc('/', out_fp);
+ ungetc(ch, in_fp);
+ if( ch == '\n' ) line_num--;
+ state = C_REGULAR;
+ }
+ break;
+
+
+ case C_COMMENT: /* inside a C comment */
+
+ if( ch == '\t' )
+ { fputs("\"}", out_fp);
+ EmitTab(out_fp);
+ fputs("{@C \"", out_fp);
+ }
+ else if( ch == '\n' )
+ { int nextch = getc(in_fp);
+ if( nextch != EOF )
+ { fputs("\"}\n{@C \"", out_fp);
+ }
+ ungetc(nextch, in_fp);
+ if( ch == '\n' ) line_num--;
+ }
+ else if( ch == '\\' )
+ { fputs("\\\\", out_fp);
+ }
+ else if( ch == '"' )
+ { fputs("\\\"", out_fp);
+ }
+ else if( ch == '*' )
+ { putc(ch, out_fp);
+ state = C_COMMENT_STAR;
+ }
+ else
+ { putc(ch, out_fp);
+ }
+ break;
+
+
+ case CPP_COMMENT: /* inside a C++ comment */
+
+ if( ch == '\t' )
+ { fputs("\"}", out_fp);
+ EmitTab(out_fp);
+ fputs("{@C \"", out_fp);
+ }
+ else if( ch == '\n' )
+ { fputs("\"}\n", out_fp);
+ state = C_REGULAR;
+ }
+ else if( ch == '\\' )
+ { fputs("\\\\", out_fp);
+ }
+ else if( ch == '"' )
+ { fputs("\\\"", out_fp);
+ }
+ else
+ { putc(ch, out_fp);
+ }
+ break;
+
+
+ case LOUT_INSERT: /* inside C comment which is a Lout insert */
+
+ if( ch == '*' )
+ { state = LOUT_INSERT_STAR;
+ }
+ else
+ { putc(ch, out_fp);
+ }
+ break;
+
+
+ case LOUT_INSERT_STAR: /* inside Lout insert comment just after * */
+
+ if( ch == '/' )
+ { state = C_REGULAR;
+ }
+ else if( ch == '*' )
+ { putc('*', out_fp);
+ }
+ else
+ { putc('*', out_fp);
+ putc(ch, out_fp);
+ state = LOUT_INSERT;
+ }
+ break;
+
+
+ case CPP_LOUT_INSERT: /* inside C++ comment which is a Lout insert */
+
+ if( ch == '\n' )
+ { putc(ch, out_fp);
+ state = C_REGULAR;
+ }
+ else
+ { putc(ch, out_fp);
+ }
+ break;
+
+
+ case C_COMMENT_STAR: /* inside C comment just after * */
+
+ if( ch == '/' )
+ { fputs("/\"}", out_fp);
+ state = C_REGULAR;
+ }
+ else if( ch == '*' )
+ { putc(ch, out_fp);
+ }
+ else if( ch == '\t' )
+ { fputs("\"}", out_fp);
+ EmitTab(out_fp);
+ fputs("{@C \"", out_fp);
+ state = C_COMMENT;
+ }
+ else if( ch == '\n' )
+ { fputs("\"}\n{@C \"", out_fp);
+ state = C_COMMENT;
+ }
+ else if( ch == '\\' )
+ { fputs("\\\\", out_fp);
+ state = C_COMMENT;
+ }
+ else if( ch == '"' )
+ { fputs("\\\"", out_fp);
+ state = C_COMMENT;
+ }
+ else
+ { putc(ch, out_fp);
+ state = C_COMMENT;
+ }
+ break;
+
+
+ case C_STRING: /* inside a C string */
+
+ if( ch == '\t' )
+ { Error0("replaced tab character in string by \\t");
+ fputs("\\\\t", out_fp);
+ }
+ else if( ch == '\\' )
+ { fputs("\\\\", out_fp);
+ state = C_STRING_BACKSLASH;
+ }
+ else if( ch == '"' )
+ { /*{*/ fputs("\"}", out_fp);
+ state = C_REGULAR;
+ }
+ else if( ch == '\n' )
+ { Error0("unterminated C string");
+ /*{*/ fputs("\"}\n", out_fp);
+ state = C_REGULAR;
+ }
+ else putc(ch, out_fp);
+ break;
+
+
+ case C_STRING_BACKSLASH: /* inside a C string just after \ */
+
+ if( ch == '\t' )
+ { Error0("replacing literal tab character after \\ by t");
+ putc('t', out_fp);
+ state = C_STRING;
+ }
+ else if( ch == '\\' )
+ { fputs("\\\\", out_fp);
+ state = C_STRING;
+ }
+ else if( ch == '"' )
+ { fputs("\\\"", out_fp);
+ state = C_STRING;
+ }
+ else if( ch == '\n' )
+ { Error0("multi-line string printed as two strings, sorry");
+ fputs("\"}\n{@S \"", out_fp);
+ state = C_STRING;
+ }
+ else
+ { putc(ch, out_fp);
+ state = C_STRING;
+ }
+ break;
+
+
+ case C_CHAR: /* inside char literal */
+
+ if( ch == '\t' )
+ { Error0("replacing literal tab character by \\t");
+ fputs("\\\\t", out_fp);
+ }
+ else if( ch == '\\' )
+ { fputs("\\\\", out_fp);
+ state = C_CHAR_BACKSLASH;
+ }
+ else if( ch == '"' )
+ { fputs("\\\"", out_fp);
+ }
+ else if( ch == '\n' )
+ { Error0("unterminated C character constant");
+ fputs("\"}\n", out_fp);
+ state = C_REGULAR;
+ }
+ else if( ch == '\'' )
+ { /*{*/ fputs("\"}", out_fp);
+ state = C_REGULAR;
+ }
+ else putc(ch, out_fp);
+ break;
+
+
+
+ case C_CHAR_BACKSLASH: /* inside quoted char just after \ */
+
+ if( ch == '"' )
+ { fputs("\\\"", out_fp);
+ state = C_CHAR;
+ }
+ else if( ch == '\\' )
+ { fputs("\\\\", out_fp);
+ state = C_CHAR;
+ }
+ else if( ch == '\n' )
+ { Error0("unterminated C character constant");
+ /*{*/ fputs("\"}\n", out_fp);
+ state = C_REGULAR;
+ }
+ else
+ { putc(ch, out_fp);
+ state = C_CHAR;
+ }
+ break;
+
+
+ default:
+
+ Error1("unknown case %d", state);
+ exit(1);
+ break;
+
+ }
+ }
+
+ /* check that final state is reasonable */
+ switch( state )
+ {
+ case C_REGULAR: /* in ordinary C code */
+
+ break;
+
+
+ case C_SLASH: /* in ordinary C code just after / */
+
+ fputs("/\n", out_fp);
+ break;
+
+
+ case C_COMMENT: /* inside a C comment */
+ case CPP_COMMENT: /* inside a C++ comment */
+ case C_COMMENT_STAR: /* inside C comment just after * */
+
+ /*{*/ fputs("\"}\n", out_fp);
+ Error0("C text ended inside a comment");
+ break;
+
+
+ case LOUT_INSERT: /* inside C comment which is a Lout insert */
+ case CPP_LOUT_INSERT: /* inside C++ comment which is a Lout insert */
+ case LOUT_INSERT_STAR: /* inside Lout insert comment just after * */
+
+ Error0("C text ended inside a Lout inclusion");
+ exit(1);
+ break;
+
+
+ case C_STRING: /* inside a C string */
+ case C_STRING_BACKSLASH: /* inside a C string just after \ */
+
+ /*{*/ fputs("\"}\n", out_fp);
+ Error0("C text ended inside a string literal");
+ break;
+
+
+ case C_CHAR: /* inside char literal (has been quoted) */
+ case C_CHAR_BACKSLASH: /* inside quoted char just after \ */
+
+ /*{*/ fputs("\"}\n", out_fp);
+ Error0("C text ended inside a character literal");
+ break;
+
+
+ default:
+
+ Error0("unknown final state");
+ exit(1);
+ break;
+ }
+
+ return TRUE;
+} /* end Scan */