/* */
/* art2ps -- converts ASCII art to encapsulated PostScript. Handles
** CR overstrike. Forces newline-delimited files to CR/LF delimited.
*/

/*

mru 29 Aug 1999 [tomj] Tom Jennings <tomj@wps.com>
added forced-CR/LF when a line is found terminated with newline only.
added maximum-buffer-length check when reading from the input file.
stopped escaping % character in EPS data (why?!)
introduced new bug, _E END causes gagging when EPS file loaded in Illustrator 8.

*/

/*
Read a line, determine max line length.
Emit overstrike lines so they overlap.
Emit non-overstrike lines on new lines.

Search to find the form feeds.
Join following lines to the right of previous page.

*/

#include <stdio.h>
#include <string.h>


/* Error codes */

#define TE_NOERROR  0
#define TE_BADFILE  1


/* Copy the file art2ps.pre to stdout */

int emitHeader( void )
{
FILE *infp;
int ch;
int lerr;


    infp = NULL;

    infp = fopen( "art2ps.pre", "r" );
    if (infp == NULL) {
        lerr = TE_BADFILE;
        goto out;
    }

    /* Copy file to stdout */
    while ((ch=fgetc(infp)) != EOF) {
        putchar(ch);
    }
    lerr = TE_NOERROR;
out:
    if (infp != NULL) {
        fclose( infp );
        infp = NULL;
    }

    return lerr;
}


/* Read a line, removing line ending chars */

int getLine( FILE *infp, char *buff, unsigned size )
{
char *ptr;
int ch;
int chb;
int lerr;


    /* Read chars until CR, CR/LF or FF */
    ptr = buff;
    while ((ch=fgetc(infp)) != EOF) {

	/* [tomj] If we find LF before CR, assume there is no CR; 
	force this into a CR LF sequence. */
	if (ch == 0x0A) {
		ungetc(ch, infp);
		goto forceCR;
	}

        /* If CR, lookahead for LF or FF */
        if (ch == 0x0D) {

            /* Always keep the CR */
forceCR:    *ptr ++ = 0x0D;	/* [tomj] */

            /* If next char is LF or FF, use it */
            chb = fgetc(infp);
            if (chb == 0x0A || chb == 0x0C) {
                *ptr ++ = chb;
                break; /* exit while */
            }
            /* Else push it back and leave lone CR or FF */
            else {
                ungetc( chb, infp );
                break; /* exit while */
            }
        }

	/* [tomj] Don't exceed buff length! */
	if (--size <= 0) break;

        /* Else copy chars to buff */
        *ptr ++ = ch;
    }

    *ptr = '\0';

    lerr = TE_NOERROR;
/* out: */
    return lerr;
}


/* Emit the buffer as Illustrator EPS */

int emitLine( float x, float y, char *str, 
             float fontHeight, float lineSpace, float xScale, int last )
{
char *ptr;


    /* printf( "/_Courier %g %g 0 0 z\n", fontHeight, lineSpace ); */

    printf( "[%g 0 0 1 %g %g]e\n", xScale, x, y );
    printf( "(" );

    /* Escape all chars with meaning to Postscript */
    ptr = str;
    while (*ptr != '\0') {

        switch (*ptr) {

            case '(':
            case ')':
            case '\\':
         /* case '%': [tomj] */
                putchar('\\');
                putchar(*ptr);
                break;

            /* Emit everything else */
            default:
                putchar(*ptr);
        }

        ptr ++;
    }

    printf( ")t\nT\nU\n" );

    /* Only emit if not at end of file */
    if (!last) {
        printf( "u\n" );
    }

    return 0;
}



/* */

int main( int argc, char **argv )
{
FILE *infp;
char buff[2048];
int len;
char lastChar;
char penultChar;
float xPos;
float yPos;
float xStart;
float yStart;
float fontHeight;
float lineSpace;
int maxLen;
int formCount;
int lineCount;
int last;
float xScale;


    infp = NULL;

    /* Now open and convert the file */
    if (argc < 2) {
        printf( "Usage: %s filename >out.eps \n", argv[0] );
        goto out;
    }

    /* Parse command line options */

    /* Open the file */
    infp = fopen( argv[1], "rb" );
    if (infp == NULL) {
        printf( "Can't open file '%s'\n", argv[1] );
        goto out;
    }

    /* Check the line length ?? */
    /* Search for form feeds ?? */

    /* Emit the EPS header as-is */
    if (emitHeader() != TE_NOERROR) {
        goto out;
    }

    /* Starting position on the page : upper left */
    xStart = 5.0f;
    yStart = 725.0f;
    xPos = xStart;
    yPos = yStart;

    xScale = 1.28f;

    /* Font size 10 points, on 120% spacing */
    fontHeight = 2.75f;
    lineSpace = fontHeight * 1.0f;

    /* Default font and line spacing */
    printf( "/_Courier %g %g 0 0 z\n", fontHeight, lineSpace );

    /* Watch maximum line length */
    maxLen = -1;
    lineCount = 0;
    formCount = 0;

    /* Read lines, ending in CR or CR/LF, convert to EPS */
    while (!feof(infp)) {

        /* Read a line ending in CR/LF or just CR */
        if (getLine( infp, buff, sizeof(buff) ) != TE_NOERROR) {
            break;
        }
        lineCount ++;

        /* Last line detection */
        last = 0;
        if (feof(infp)) {
            last = 1;
        }

        /* Last char */
        len = strlen(buff);
        if (len >= 2) {

            penultChar = buff[len-2];
            lastChar = buff[len-1];

            /* If just CR, emit a strikeover line */
            if (penultChar != 0x0A && lastChar == 0x0D) {

                /* Clear the CR */
                buff[len-1] = '\0';

                len --;

                emitLine( xPos, yPos, buff, fontHeight, lineSpace, xScale, last );
            }
            /* Else if CR/FF, emit a strikeover line, begin new section */
            else if (penultChar == 0x0D && lastChar == 0x0C) {

                /* Clear the CR/FF */
                buff[len-2] = '\0';
                buff[len-1] = '\0';

                len -= 2;

                formCount ++;

                emitLine( xPos, yPos, buff, fontHeight, lineSpace, xScale, last );

                fprintf( stderr, "form hit: lineCount %d, formCount %d, maxLen %d\n",
                    lineCount, formCount, maxLen );

                /* Reposition the next section */
                /* xPos = xStart + ((float)maxLen * (5.0f/8.0f) * fontHeight); */
                xPos = xStart + ((float)maxLen * (0.6f) * fontHeight * xScale);
                yPos = yStart;

                xStart = xPos;
            }
            /* If CR/LF, emit a line and move to next */
            else if (penultChar == 0x0D && lastChar == 0x0A) {

                /* Clear the CR/LF */
                buff[len-2] = '\0';
                buff[len-1] = '\0';

                len -= 2;

                emitLine( xPos, yPos, buff, fontHeight, lineSpace, xScale, last );

                /* Move to start of next line */
                xPos = xStart;
                yPos -= lineSpace;
            }
            /* Else if form feed */
            else if (lastChar == 0x0C) {
                ;
            }

            /* Watch line length */
            if (len > maxLen) {
                maxLen = len;
            }
        }
    }
    /* Trailer */
    printf( "%%PageTrailer\n" );
    printf( "%%Trailer\n" );
    printf( "_E end\n" );
    printf( "%%EOF\n\n" );

    fprintf( stderr, "lineCount %d, formCount %d, maxLen %d\n",
        lineCount, formCount, maxLen );

out:

    if (infp != NULL) {
        fclose( infp );
        infp = NULL;
    }

    return 0;
}


