[project @ 2003-11-03 12:25:39 by simonmar]
[ghc-hetmet.git] / ghc / utils / unlit / unlit.c
index ff9c678..52e6415 100644 (file)
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <ctype.h>
 
-#define NULLSTR       ((char *)0)
-#define DEFNCHAR      '>'
-#define MISSINGBLANK  "unlit: Program line next to comment"
-#define EMPTYSCRIPT   "unlit: No definitions in file (perhaps you forgot the '>'s?)"
-#define USAGE         "usage: unlit [-q] [-n] [-c] file1 file2\n"
-#define CANNOTOPEN    "unlit: cannot open \"%s\"\n"
-#define DISTINCTNAMES "unlit: input and output filenames must differ\n"
-#define MISSINGCODE   "unlit: missing %s\n"
+#define NULLSTR        ((char *)0)
+#define DEFNCHAR       '>'
+#define MISSINGBLANK   "unlit: Program line next to comment"
+#define EMPTYSCRIPT    "unlit: No definitions in file (perhaps you forgot the '>'s?)"
+#define USAGE          "usage: unlit [-q] [-n] [-c] file1 file2\n"
+#define CANNOTOPEN     "unlit: cannot open \"%s\"\n"
+#define CANNOTWRITE    "unlit: error writing \"%s\"\n"
+#define CANNOTWRITESTDOUT "unlit: error writing standard output\n"
+#define DISTINCTNAMES  "unlit: input and output filenames must differ\n"
+#define MISSINGENDCODE "unlit: missing \\end{code}\n"
 
 #define BEGINCODE "\\begin{code}"
 #define LENBEGINCODE 12
 #define LENENDCODE 10
 #ifdef PSEUDOCODE
 /* According to Will Partain, the inventor of pseudocode, this gone now. */
+#define MISSINGENDPSEUDOCODE "unlit: missing \\end{pseudocode}\n"
 #define BEGINPSEUDOCODE "\\begin{pseudocode}"
 #define LENBEGINPSEUDOCODE 18
 #define ENDPSEUDOCODE "\\end{pseudocode}"
 #define LENENDPSEUDOCODE 16
 #endif
 
-typedef enum { START, BLANK, TEXT, DEFN, BEGIN, /*PSEUDO,*/ END, HASH } line;
+typedef enum { START, BLANK, TEXT, DEFN, BEGIN, /*PSEUDO,*/ END, HASH, SHEBANG } line;
 #define isWhitespace(c)  (c==' '  || c=='\t')
 #define isLineTerm(c)    (c=='\n' || c==EOF)
 
@@ -72,6 +76,11 @@ static int noisy  = 1;   /* 0 => keep quiet about errors, 1 => report errors */
 static int errors = 0;   /* count the number of errors reported              */
 static int crunchnl = 0; /* don't print \n for removed lines                 */
 static int leavecpp = 1; /* leave preprocessor lines */
+static int ignore_shebang = 1; /* Leave out shebang (#!) lines */
+
+static char* prefix_str = NULL; /* Prefix output with a string */
+
+static char *ofilename = NULL;
 
 /* complain(file,line,what)
  *
@@ -91,6 +100,24 @@ int lin; {
     }
 }
 
+writeerror()
+{
+    if (!strcmp(ofilename,"-")) {
+       fprintf(stderr, CANNOTWRITESTDOUT);
+    } else {
+       fprintf(stderr, CANNOTWRITE, ofilename);
+    }
+    exit(1);
+}
+
+myputc(c, ostream)
+char c;
+FILE *ostream; {
+    if (putc(c,ostream) == EOF) {
+       writeerror();
+    }  
+}
+
 #define TABPOS 8
 
 /* As getc, but does TAB expansion */
@@ -146,31 +173,44 @@ FILE *istream;
 
 line readline(istream,ostream)
 FILE *istream, *ostream; {
-    int c = egetc(istream);
+    int c, c1;
     char buf[100];
     int i;
 
+    c = egetc(istream);
+
     if (c==EOF)
         return END;
-
-    if (leavecpp && c=='#') {
-       putc(c, ostream);
+  
+    if ( c == '#' ) {
+      if ( ignore_shebang ) {
+         c1 = egetc(istream);
+         if ( c1 == '!' ) {
+           while (c=egetc(istream), !isLineTerm(c)) ;
+           return SHEBANG;
+        }
+        myputc(c, ostream);
+        c=c1;
+      }
+      if ( leavecpp ) {
+       myputc(c, ostream);
         while (c=egetc(istream), !isLineTerm(c))
-            putc(c,ostream);
-        putc('\n',ostream);
+            myputc(c,ostream);
+        myputc('\n',ostream);
         return HASH;
+      }
     }
 
     if (c==DEFNCHAR) {
-/*     putc(' ',ostream);*/
+/*     myputc(' ',ostream);*/
         while (c=egetc(istream), !isLineTerm(c))
-            putc(c,ostream);
-        putc('\n',ostream);
+            myputc(c,ostream);
+        myputc('\n',ostream);
         return DEFN;
     }
 
     if (!crunchnl)
-       putc('\n',ostream);
+       myputc('\n',ostream);
 
     while (isWhitespace(c))
         c=egetc(istream);
@@ -228,12 +268,12 @@ FILE *ostream; {
            char lineb[1000];
            for(;;) {
                if (fgets(lineb, sizeof lineb, istream) == NULL) {
-                   fprintf(stderr, MISSINGCODE, ENDCODE);
+                   complain(file, linesread, MISSINGENDCODE);
                    exit(1);
                }
                linesread++;
                if (strncmp(lineb,ENDCODE,LENENDCODE) == 0) {
-                   putc('\n', ostream);
+                   myputc('\n', ostream);
                    break;
                }
                fputs(lineb, ostream);
@@ -245,11 +285,11 @@ FILE *ostream; {
            char lineb[1000];
            for(;;) {
                if (fgets(lineb, sizeof lineb, istream) == NULL) {
-                   fprintf(stderr, MISSINGCODE, ENDPSEUDOCODE);
+                   complain(file, linesread, MISSINGENDPSEUDOCODE);
                    exit(1);
                }
                linesread++;
-               putc('\n', ostream);
+               myputc('\n', ostream);
                if (strncmp(lineb,ENDPSEUDOCODE,LENENDPSEUDOCODE) == 0) {
                    break;
                }
@@ -266,7 +306,8 @@ FILE *ostream; {
  *
  * Main program.  Processes command line arguments, looking for leading:
  *  -q  quiet mode - do not complain about bad literate script files
- *  -n  noisy mpde - complain about bad literate script files.
+ *  -n  noisy mode - complain about bad literate script files.
+ *  -r  remove cpp droppings in output.
  * Expects two additional arguments, a file name for the input and a file
  * name for the output file.  These two names must normally be distinct.
  * An exception is made for the special name "-" which can be used in either
@@ -286,6 +327,17 @@ char **argv; {
             noisy = 0;
         else if (strcmp(*argv,"-c")==0)
            crunchnl = 1;
+        else if (strcmp(*argv,"-h")==0) {
+         if (argc > 1) {
+           argc--; argv++;
+           if (prefix_str) 
+             free(prefix_str);
+           prefix_str = (char*)malloc(sizeof(char)*(1+strlen(*argv)));
+           if (prefix_str) 
+             strcpy(prefix_str, *argv);
+         }
+        } else if (strcmp(*argv,"-#")==0)
+           ignore_shebang = 0;
         else
             break;
 
@@ -310,6 +362,7 @@ char **argv; {
             exit(1);
         }
 
+    ofilename=argv[1];
     if (strcmp(argv[1], "-")==0) 
         ostream = stdout; 
     else
@@ -318,10 +371,26 @@ char **argv; {
             exit(1);
         }
 
+    /* Prefix the output with line pragmas */
+    if (prefix_str) {
+      /* Both GHC and CPP understand the #line pragma.
+       * We used to throw in both a #line and a {-# LINE #-} pragma
+       * here, but CPP doesn't understand {-# LINE #-} so it thought
+       * the line numbers were off by one.  We could put the {-# LINE
+       * #-} before the #line, but there's no point since GHC
+       * understands #line anyhow.  --SDM 8/2003
+       */
+      fprintf(ostream, "#line 1 \"%s\"\n", prefix_str, prefix_str);
+    }
+
     unlit(file, istream, ostream);
 
-    fclose(istream);
-    fclose(ostream);
+    if (istream != stdin) fclose(istream);
+    if (ostream != stdout) {
+       if (fclose(ostream) == EOF) {
+           writeerror();
+       }
+    }
 
     exit(errors==0 ? 0 : 1);
 }