/*
 * PostScript text formatter
 *
 * Copyright (C) 1989 Geoffrey H. Cooper, All Rights Reserved.
 * Permission is granted to copy and use this program so long as [1] this
 * copyright notice is preserved, and [2] no financial gain is involved
 * in copying the program.  This program may not be sold as "shareware"
 * or "public domain" software without the express, written permission
 * of the author.
 *
 * $Log: pstext.c,v $
 * Revision 1.2  1992/11/05  11:36:53  ckclark
 * Fixed path to pstext.ps.
 *
 * Revision 1.1  1992/11/05  11:13:39  ckclark
 * Initial revision
 *
 * Revision 1.1  90/01/18  18:21:26  geof
 * Initial revision
 * 
 */

#include <stdio.h>
#include <ctype.h>

#ifdef UNIX
char mfile[] = "/mit/postscript/lib/pstext.ps";
#else /* MSDOS */
char mfile[] = "\\bin\\pstext.ps";
#endif
char *ctime();

/*
 * Global flags
 */
char showH;
char doligatures;

char buf[1024];
char qbuf[1024];
char *strstr();
void ReplaceAll();

struct {
    char *lig, *rep;
} ligatures[] =
{
     { "fi", "\\256" }
    ,{ "fl", "\\257" }
    ,{ "--", "\\320" }
    ,{ "``", "\\252" }
    ,{ "''", "\\272" }
    ,{ ",,", "\\271" }
    ,{ "...", "\\274" }
    ,{ "<<", "\\253" }
    ,{ ">>", "\\273" }
    ,{ "\\/", "" }
};
#define NumLigatures ((sizeof ligatures)/sizeof(ligatures[0]))

main(argc, argv)
    char **argv;
{
    FILE *f, *outf;
    char *ts;
    int c, n;
    long clock;
    char timestamp, header;

    doligatures = 1;
    showH = 0;
    header = 1;
    timestamp = 0;
    outf = stdout;
    while ( argc > 1 && argv[1][0] == '-' ) {
        if ( strcmp(argv[1], "-n") == 0 ) header = 0;
        else if ( strcmp(argv[1], "-t") == 0 ) timestamp = 1;
        else if ( strcmp(argv[1], "-h") == 0 ) showH = 1;
        else if ( strcmp(argv[1], "-l") == 0 ) doligatures = 0;
        else
            fprintf(stderr, "bad flag %s, ignored\n", argv[1]);
        argv++; argc--;
    }

    if ( header ) {
        f = fopen(mfile, "r");
        if ( f == NULL ) {
            fprintf(stderr, "Warning: can't open header file \"%s\"\n", mfile);
            perror("on open");
            exit(1);
        }
        fprintf(outf, "%%!\n");
        while ( (c = getc(f)) != EOF ) {
            putc(c, outf);
        }
        fclose(f);
        fprintf(outf, "\n");
    } else {
        if ( argc > 1 ) argv++;
    }
    time(&clock);
    ts = ctime(&clock);
    for ( c = 0; ts[c] && ts[c] != '\n'; c++ )
        ;
    ts[c] = 0;
    if ( timestamp ) {
        fprintf(outf, "/TimeStamp (%s) def\n", ts);
    }
    n = 0;
    while ( *++argv ) {
        n++;
        f = fopen(*argv, "r");
        if ( f == NULL ) {
            perror(*argv);
        } else {
            text(f, stdout);
            fclose(f);
        }
    }
    if ( n == 0 ) {
        text(stdin, stdout);
    }
    exit(0);
}

text(f, outf)
    FILE *f, *outf;
{
    char *b, *limit, *q;
    int c;
    char eof, breakpara, someoutput;
    int numSpaces, numNewLines;
    int i;

    b = buf;
    limit = &buf[(sizeof buf) - 3];
    eof = 0;
    breakpara = 0;
    numSpaces = 0;
    numNewLines = 0;
    qbuf[0] = 0;
    if ( showH )
        fprintf(outf, "H %% initial header\n");
    c = getc(f);
    if ( c == EOF ) {
        fprintf(stderr, "Warning: null input\n");
        return;
    }
    if ( c == '.' || c == '\'' )
        goto docmd;
    ungetc(c, f);
    do {
        while ( b < limit && (c = getc(f)) != EOF && c != ' ' && c != '\n' ) {
            if ( c == '\\' ) {
                c = getc(f);
                switch ( c ) {

                case '\\':
                case '0': case '1': case '2': case '3':
                case '4': case '5': case '6': case '7':
                case '/':
                    *b++ = '\\';
                case '.':
                case '\'':
                    break;

                /* switch fonts */
                case 'f':
                    *b = 0;
                    c = getc(f);
                    c = toupper(c);
                    if ( c == 'R' || c == 'I' || c == 'P' || c == 'B' || c == 'L' || c == 'F' || c == 'S' ) {
                        sprintf(qbuf, "/%c f\n", c);
                        c = 0;
                        goto break2;
                    }
                    fprintf(stderr, "Warning: \\f%c illegal, ignored.\n", c);
                    continue;

                case '(':
                    q = qbuf;
                    while ( (c = getc(f)) != EOF && c != '\n' && c != ')' ) {
                        *q++ = c;
                    }
                    sprintf(q, "%%()\n");
                    if ( c != ')' ) 
                        fprintf(stderr, "Warning: unterminated \\(...) construct, terminated at code 0x%02x\n", c);
                    c = 0;
                    goto break2;

                default:
                    fprintf(stderr, "Warning, \\%c illegal, treating it as text\n", c);
                    *b++ = '\\';
                    *b++ = '\\';
                }
            } else {
                if ( c == '(' || c == ')' )
                    *b++ = '\\';
            }
            *b++ = c;
        }
  break2:
        someoutput = 0;
        *b = 0;
        if ( b > buf ) {
            someoutput = 1;
            if ( doligatures ) {
                for ( i = 0; i < NumLigatures; i++ )
                    ReplaceAll(ligatures[i].lig, ligatures[i].rep, buf);
            }
            fprintf(outf, "(%s)W ", buf);
        }
        numSpaces = 1;
        if ( c == '\n' ) {
            c = getc(f);
            if ( c == '\n' ) {
                numNewLines = 1;
                breakpara = 1;
                while ( (c = getc(f)) != EOF && c == '\n' ) {
                    numNewLines++;
                }
                if ( c == EOF ) eof = 1;
                if ( c != '.' && c != '\'' ) {
                    ungetc(c, f);
                    c = '\n';
                }
            } else if ( c == '.' ) {
                numNewLines = 0;
                breakpara = 1;
            } else if ( c == EOF ) eof = 1;
            else
                ungetc(c, f);
        } else if ( c == ' ' ) {
            while ( (c = getc(f)) != EOF && c == ' ' ) {
                numSpaces++;
            }
            if ( c == EOF ) eof = 1;
            else ungetc(c, f);
            c = ' ';
        } else if ( c == EOF ) {
            numSpaces = 0;
            breakpara = 1;
            eof = 1;
        } else
            numSpaces = 0;
        if ( numSpaces > 0 ) {
            someoutput = 1;
            if ( numSpaces == 1 )
                fprintf(outf, "S ");
            else
                fprintf(outf, "%d Ss", numSpaces);
        }
        if ( breakpara ) {
            someoutput = 1;
            fprintf(outf, "BK ");
        }
        while ( numNewLines-- > 0 ) {
            someoutput = 1;
            fprintf(outf, "NL ");
        }
        if ( someoutput )
            putc('\n', outf);
        numSpaces = 0;
        numNewLines = 0;
        breakpara = 0;
        if ( c == '.' || c == '\'' ) {
 docmd:     for (;;) {
                b = buf;
                while ( (c = getc(f)) != EOF && c != '\n' ) 
                    *b++ = c;
                *b = 0;
                if ( c == EOF ) goto doeof;
                if ( buf[0] == '+' ) {
                    fprintf(outf, "%s %%.+\n", &buf[1]);
                    if ( ! verbatim(f, outf) ) goto doeof;
                } else {
                    for ( b = buf; *b; b++ ) {
                        putc(*b, outf);
                    }
                    fprintf(outf, " %%.\n");
                }
                c = getc(f);
                if ( c == EOF ) goto doeof;
                if ( c != '.' && c != '\'' ) {
                    ungetc(c, f);
                    break;
                }
            }
        }
        b = buf;
        for ( q = qbuf; *q; q++ )
            putc(*q, outf);
        qbuf[0] = 0;
    } while ( ! eof );
 doeof:
    fprintf(outf, "BK showpage\n");
}

verbatim(f, outf)
    FILE *f, *outf;
{
    char nl, passthru;
    int c;

    nl = 1;
    passthru = 0;
    while ( (c = getc(f)) && c != EOF ) {
        switch ( c ) {
        case '\n':
            if ( !passthru ) {
                if ( ! nl ) fprintf(outf, ")show ");
                fprintf(outf, "NL");
            }
            putc('\n', outf);
            nl = 1;
            passthru = 0;
            break;


        case '\'':
        case '.':
            if ( nl ) {
                passthru = 1;
                nl = 0;
                c = getc(f);
                if ( c == EOF ) break;
                if ( c == '-' ) {
                    while ( (c = getc(f)) != EOF && c != '\n' )
                        putc(c, outf);
                    fprintf(outf, " %%.-\n");
                    return ( c != EOF );
                }
                ungetc(c, f);
                break;
            }
            /* fall thru */
        default:
            if ( !passthru ) {
                if ( nl )
                    putc('(', outf);
                if ( c == '(' || c == ')' )
                    putc('\\', outf);
                if ( c == '\\' ) {
                    c = getc(f);
                    switch ( c ) {

                    case '\\':
                        putc('\\', outf);
                        break;

                    /* switch fonts */
                    case 'f':
                        c = getc(f);
                        c = toupper(c);
                        if ( c == 'R' || c == 'I' || c == 'P' || c == 'B' || c == 'L' )
                            fprintf(outf, ")show /%c f (", c);
                        else
                            fprintf(stderr, "Warning: \\f%c illegal, ignored.\n", c);
                        nl = 0;
                        continue;

                    case '(':
                        fprintf(outf, ")show ");
                        while ( (c = getc(f)) != EOF && c != '\n' && c != ')' ) {
                            putc(c, outf);
                        }
                        fprintf(outf, "%%()\n(");
                        if ( c != ')' ) 
                            fprintf(stderr, "Warning: unterminated \\(...) construct, terminated at code 0x%02x\n", c);
                        break;

                    default:
                        fprintf(stderr, "Warning, \\%c illegal, treating it as text\n", c);
                        putc('\\', f);
                    }
                }
            }
            nl = 0;
            putc(c, outf);
        }
    }
    return ( c != EOF );
}

void
ReplaceAll(s, withs, ins)
    char *s, *withs, *ins;
{
    int diff;
    char *b;

    diff = strlen(withs) - strlen(s);
    while ( *ins ) {
        ins = strstr(s, ins);
        if ( ins == NULL )
            return;

        if ( diff > 0 ) {
            for ( b = ins; *b; b++ )
                ;
            while ( b > ins ) {
                b[diff] = *b;
                b--;
            }
        } else if ( diff < 0 ) {
            b = ins + (-diff);
            while ( b[diff] = *b )
                b++;
        }
        b = withs;
        while ( *b )
            *ins++ = *b++;
    }
}

char *
strstr(s, ins)
    char *s, *ins;
{
    char *ms, *mins;

    while ( *ins ) {
        if ( *s == *ins ) {
            ms = s+1;
            mins = ins+1;
            while ( *ms && *ms == *mins ) {
                ms++; mins++;
            }
            if ( *ms == 0 )
                return ( ins );
        }
        ins++;
    }
    return ( NULL );
}
