#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 100

#include "pcx.h"

typedef struct {
    int xpos;
    int ypos;
    int width;
    int height;
    int scale;
	int autoscale;
    int invert;
    int prt_res;
    int dumphdr;
} MAPPING;

/**** c o p y _ p s _ h e a d e r ****
    Abstract:   Opens the PS header file and copies it to the output.
    Parameters: Filename of the current file (the .PS extension is added
                here) and the output file pointer.
    Returns:    0 if successful, 1 if failure.
****************************/
char *copy_ps_header(char *name, FILE *outfile, char *stop)
{
    static char buf[BUFSIZE];
    char *bp;
    static FILE *f = NULL;
    if (f == NULL)
    {    
        strcpy(buf, name);
        if ((bp = strchr(buf, '.')) != NULL)
            *bp = 0;
        strcat(buf, ".ps");             /* open file with this name but .ps ext */
        if ((f = fopen(buf, "r")) == NULL)
        {
            fprintf(stderr, "Unable to open PostScript header file '%s'\n",
                buf);
            return(NULL);
        }
    }
    else
    {
        fputs(buf, outfile);
    }
    while (fgets(buf, BUFSIZE, f) != NULL)
    {
        if ((stop != NULL) && (strncmp(buf, stop, strlen(stop)) == 0))
            return(buf);                /* bail out right now */
        fputs(buf, outfile);
    }
    fclose(f);
    f = NULL;
    return(NULL);
}

/**** d o f i l e ****
    Abstract:   Processes a single PCX file.
    Parameters: char *filename - the input PCX filename (.PCX optional)
                MAPPING *map - the structure containing page position info
                char *psname - the PostScript prologue (.PS will be forced)
                FILE *outfile - the open output file
    Returns:    0 if successful, 1 if no file generated
****************************/
int dofile(char *filename, MAPPING *map, char *psname, FILE *outfile)
{
    FILE *f;
    PCX_HDR hdr;
    WORD i, j, xsize, ysize;
    BYTE *lineptr = NULL;
    char *t;
    char buf[BUFSIZE];
    long bbox_x, bbox_y;
    strcpy(buf, filename);
    if (strchr(buf, '.') == NULL)
        strcat(buf, ".pcx");     /* add .PCX if needed */
    if ((f = fopen(buf, "rb")) == NULL)
    {
        fprintf(stderr, "Unable to open '%s'\n", buf);
        return(1);
    }
    if (pcx_read_header(&hdr, f) == NULL)
    {
        fprintf(stderr, "Unable to read header for file '%s'.\n", buf);
        fclose(f);
        return(1);
    }
    if (map->dumphdr)
    {
        pcx_print_header(&hdr, stdout);
        return(1);
    }
    if (hdr.nplanes != 1)
    {
        fprintf(stderr, "Only able to read monochrome .PCX files.\n");
        fclose(f);
        return(1);
    }
    xsize = hdr.lorightx - hdr.upleftx + 1;
    ysize = hdr.lorighty - hdr.uplefty + 1;

	if (map->autoscale && hdr.display_xres)
	    map->width = (long)map->prt_res * (long)map->width / hdr.display_xres;
	if (map->autoscale && hdr.display_yres)
	    map->height = (long)map->prt_res * (long)map->height / hdr.display_yres;
    
    t = copy_ps_header(psname, outfile, "%%BoundingBox");
    bbox_x = (long)xsize * (long)map->width  * (long)map->scale / 10000L;
    bbox_y = (long)ysize * (long)map->height * (long)map->scale / 10000L;
    bbox_x += map->xpos;
    bbox_y += map->ypos;
    sprintf(t, "%%%%BoundingBox: %d %d %ld %ld\n", map->xpos, map->ypos,
            bbox_x, bbox_y);
    t = copy_ps_header(psname, outfile, NULL);
        
    fprintf(outfile, "/bmap_wid %d def\n", xsize);
    fprintf(outfile, "/bmap_hgt %d def\n", ysize);
    fprintf(outfile, "/bpp %d def\n", hdr.bpp);
    fprintf(outfile, "/res %d def\n\n", map->prt_res);
    fprintf(outfile, "/x %d def\n", map->xpos);
    fprintf(outfile, "/y %d def\n\n", map->ypos);
    fprintf(outfile, "/scy %d 100 div def\n", map->height);
    fprintf(outfile, "/scx %d 100 div def\n", map->width);
    fprintf(outfile, "/scg %d 100 div def\n\n", map->scale);
    fprintf(outfile, "scaleit\n");
    fprintf(outfile, "imagedata\n\n");

    for (i=0; i<ysize; i++)
    {
        lineptr = pcx_next_line(&hdr, lineptr, f);
        if (map->invert)                 /* invert if necessary */
            for (j=0; j < xsize/8; j++)
                lineptr[j] = ~lineptr[j];
        for (j=0; j < xsize/8; j++)
            fprintf(outfile, "%02X", lineptr[j]);
        fprintf(outfile, "\n");
    }
    fprintf(outfile, "\nshowit\n\004");
    free(lineptr);
    fclose(f);
    return(0);
}

/**** u s a g e ****
    Abstract:   Prints a usage message and dies.
    Parameters: None
    Returns:    Never returns.
****************************/
void usage(void)
{
    printf("PRPCX:  by Kent Quirk\n");
    printf("   Given a .PCX file, this program creates a PostScript file \n");
    printf("    which will print the image.\n");
    printf(" PRPCX [-wW] [-hH] [-xX] [-yY] [-sS] [-rR] [-d] [-i] filename\n");
    printf("   Options include:         (units) [default]\n");
    printf("   -sSCA  set overall scale factor (percent) [100]\n");
    printf("   -wWID  set horizontal scale factor (percent) [100]\n");
    printf("   -hHGT  set vertical scale factor (percent) [100]\n");
    printf("   -xPOS  set horizontal position (points from left) [0]\n");
    printf("   -yPOS  set vertical position (points from bottom) [0]\n");
    printf("   -rRES  set printer resolution (dpi) [300]\n");
    printf("   -a     auto-scale PCX dpi resolution to printer's [off]\n");
    printf("   -d     dump PCX file info to stdout [off]\n");
    printf("   -i     invert image [off]\n");
    printf("   -oFIL  set output filename, or use SET PRPCX=filename\n");
    printf("   The defaults print the image at one pixel per device pixel\n");
    printf("   at the lower left corner of the page.\n");
    printf("   PRPCX.PS must be in the same directory as PRPCX.EXE.\n");
    exit(1);
}

/**** m a i n ****
    The main routine for PRPCX.  Sets defaults, parses command line,
    and calls dofile().
****************************/
int main(int argc, char *argv[])
{
    int i;
    MAPPING map;
    FILE *outfile = stdout;
    char *outfname = NULL;
    char *filename = NULL;
    map.xpos = map.ypos = 0;
    map.width = map.height = map.scale = 100;
    map.autoscale = 0;
	map.invert = 0;
    map.prt_res = 300;
    map.dumphdr = 0;
    if (argc < 2)
        usage();
    for (i=1; i<argc; i++)
    {
        if (argv[i][0] == '-' || argv[i][0] == '/')
        {
            switch (argv[i][1]) 
            {
            case 'x':  case 'X':
                map.xpos = atoi(argv[i]+2);
                break;
            case 'y':  case 'Y':
                map.ypos = atoi(argv[i]+2);
                break;
            case 'h':  case 'H':
                map.height = atoi(argv[i]+2);
                break;
            case 'w':  case 'W':
                map.width = atoi(argv[i]+2);
                break;
            case 's':  case 'S':
                map.scale = atoi(argv[i]+2);
                break;
            case 'r': case 'R':
                map.prt_res = atoi(argv[i]+2);
                break;
            case 'a': case 'A':
                map.autoscale = !map.autoscale;
                break;
            case 'i': case 'I':
                map.invert = !map.invert;
                break;
            case 'd': case 'D':
                map.dumphdr = 1;
                break;
            case 'o': case 'O':
                outfname = argv[i]+2;
                break;
            case '?':
                usage();
                break;
            default:
                fprintf(stderr, "Unknown option %s\n", argv[i]);
                usage();
                break;
            }
        }
        else                    /* process a file */
        {
            filename = argv[i];
        }
    }
    if ((outfname != NULL) || ((outfname = getenv("PRPCX")) != NULL))
    {
        if ((outfile = fopen(outfname, "w")) == NULL)
        {
            fprintf(stderr,"Unable to open output file %s", outfname);
            exit(1);
        }
    }
    i = dofile(filename, &map, argv[0], outfile);
    fclose(outfile);
    return(i);
}


