/*
 * file: pspages.c
 *
 * (c) Peter Kleiweg 1998
 *
 *  This 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 2,
 *  or (at your option) any later version.
 *
 */

#ifdef __MSDOS__
#  ifndef __SMALL__
#    error Memory model SMALL required
#  endif
#  include <dir.h>
#  include <io.h>
#else
#  include <unistd.h>
#endif
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 4096

typedef enum { BOTH, EVEN, ODD } PAGES;

char
    buffer [BUFSIZE + 1],
    *programname;

void
    get_programname (char const *argv0),
    errit (char const *format, ...),
    syntax (void);

char
    *get_arg (int argc, char *argv [], int *index);

int main (int argc, char *argv [])
{
    PAGES
        pages = BOTH;
    int
        first = 0,
        last = 0,
        i;
    FILE
        *fp;

    get_programname (argv [0]);

    for (i = 1; i < argc; i++)
        if (argv [i][0] == '-') {
            switch (argv [i][1]) {
                case 'f':
                    first = atoi (get_arg (argc, argv, &i));
                    if (first < 1)
                        errit ("Illegal value for first page: %i", first);
                    break;
                case 'l':
                    last = atoi (get_arg (argc, argv, &i));
                    if (last < 1)
                        errit ("Illegal value for last page: %i", last);
                    break;
                case 'p':
                    first = last = atoi (get_arg (argc, argv, &i));
                    if (first < 1)
                        errit ("Illegal value for page: %i", first);
                    break;
                case 'e':
                    pages = EVEN;
                    break;
                case 'o':
                    pages = ODD;
                    break;
                default:
                    errit ("Illegal option '%s'", *argv [i]);
	    }
        } else
            break;

    if ((! first) && (! last) && (pages == BOTH))
        syntax ();

    if (first && last && (first > last))
        errit ("First page (%i) greater than last page (%i)", first, last);

    if (first && last && (first == last))
        if (first % 2) {
	      if (pages == EVEN)
                  errit ("Page %i is not an even page", first);
        } else {
	      if (pages == ODD)
                  errit ("Page %i is not an odd page", first);
	}

    switch (argc - i) {
        case 0:
            if (isatty (fileno (stdin)))
	        syntax ();
            fp = stdin;
            break;
        case 1:
            fp = fopen (argv [i], "r");
            if (! fp)
                errit ("Opening file \"%s\": %s", argv [i], strerror (errno));
            break;
        default:
            syntax ();
    }

    fputs (
        "%!PS\n"
        "\n"
        "<<\n"
        "    /EndPage {\n"
        "        dup 0 eq {\n"
        "            pop\n"
        "\n"
        "            1 add\n"
        "            true\n",
        stdout
    );

    if (pages == ODD) fputs (
        "            1 index 2 mod 1 ne { pop false } if\n",
        stdout
    );

    if (pages == EVEN) fputs (
        "            1 index 2 mod 0 ne { pop false } if\n",
        stdout
    );

    if (first) printf (
        "            1 index %i lt { pop false } if\n",
        first
    );

    if (last) printf (
        "            1 index %i gt { pop false } if\n",
        last
    );

    fputs (
        "            dup not { erasepage } if\n"
        "\n"
        "        } {\n"
        "	    1 eq\n"
        "	} ifelse\n"
        "	exch pop\n"
        "    }\n"
        ">> setpagedevice\n"
        "\n",
        stdout
    );

    while (fgets (buffer, BUFSIZE, fp))
        if (memcmp (buffer, "%%Page", 6) && memcmp (buffer, "%!PS", 4))
            fputs (buffer, stdout);

    if (fp != stdin)
        fclose (fp);

    return 0;
}

char *get_arg (int argc, char *argv [], int *index)
{
    if (argv [*index][2])
        return argv [*index] + 2;

    if (*index == argc - 1)
        errit ("Missing argument for '%s'", argv [*index]);

    return argv [++*index];
}

void errit (char const *format, ...)
{
    va_list
	list;

    fprintf (stderr, "\nError %s: ", programname);

    va_start (list, format);
    vfprintf (stderr, format, list);

    fprintf (stderr, "\n\n");

    exit (1);
}

void get_programname (char const *argv0)
{
#ifdef __MSDOS__
    char
        name [MAXFILE];
    fnsplit (argv0, NULL, NULL, name, NULL);
    programname = strdup (name);
#else   /* unix */
    char
        *p;
    p = strrchr (argv0, '/');
    if (p)
        programname = strdup (p + 1);
    else
        programname = strdup (argv0);
#endif    
}

void syntax ()
{
    fprintf (
	stderr,
        "\nPrinting selected pages from a PostScript document\n\n"
        "Useful for documents without page number comments\n"
        "Requires PostScript Level 2 (should understand setpagedevice operator)\n\n"
	"Usage: %s options [psfile]\n\n"
        "Options:\n"
        "  -p #  page number to print\n"
        "  -f #  first page number to print\n"
        "  -l #  last page number to print\n"
        "  -e    print even pages\n"
        "  -o    print odd pages\n\n"
        "(c) P. Kleiweg 1998\n\n",
	programname
    );
    exit (1);
}
