/*
 * args.c
 */

/*
 * mpage:    a program to reduce pages of print so that several pages
 *           of output appear on one printed page.
 *
 * Copyright (c) 1994-2004 Marcel J.E. Mol, The Netherlands
 * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia
 *  
 *     Permission is granted to anyone to make or distribute verbatim
 *     copies of this document as received, in any medium, provided
 *     that this copyright notice is preserved, and that the
 *     distributor grants the recipient permission for further
 *     redistribution as permitted by this notice.
 *
 */

#include "mpage.h"
#include <ctype.h>
#include <string.h>

/*
 * Function declarations
 */
static char **slice(char *string, int *cntp);



int
do_args(int argc, char **argv, int envflag)
{
    char *optstr;
    int consumed;
    int finished;
    int currarg;
    int opterrors;

    int i;

    opt_jarg = 0;
    for (i = 0; i < MAXJARG; i++) {
        opt_first[i] = 1;
        opt_last[i]  = MAXINT;
        opt_alt[i]   = 1;
    }

#define OPTARG()  \
    { char opt = *optstr; \
      consumed = 1; if(*++optstr == '\0') optstr = argv[++currarg]; \
      if (!optstr) { fprintf (stderr, "%s: -%c: option requires argument\n", \
                    MPAGE, opt); return -1; } \
    }


    opterrors = 0;
    finished = 0;
    for (currarg = 1; !finished && currarg < argc; currarg++) {
        if (*argv[currarg] != '-') {
            if (envflag)
                opterrors++;
            break;
        }
        optstr = argv[currarg];
        consumed = 0;
        while (!consumed && *++optstr) {
            switch (*optstr) {
                default:
                        fprintf(stderr, "%s: unknown option -%c\n",
                                        MPAGE, *optstr);
                        opterrors++;
                        break;
                case '-':
                        finished = 1;
                        break;
                case '1':
                        sheetindex = 0;
                        break;
                case '2':
                        sheetindex = 1;
                        break;
                case '4':
                        sheetindex = 2;
                        break;
                case '8':
                        sheetindex = 3;
                        break;
                case 'a':    /* toggle between accross and updown */
                        sheetorder = sheetorder == LEFTRIGHT ?
                                     UPDOWN : LEFTRIGHT;
                        break;
                case 'A':    /* A4 sized, european paper */
                        opt_page = "A4"; /* deprecated */
                        break;
                case 'b':     /* base paper type */
                        OPTARG();
                        /* see if user wants help */
                        if (!strcmp(optstr, "?") || !strcmp(optstr, "l")) {
                            show_pagetypes();
                            exit(0);
                        }
                        /* set opt_page */
                        select_pagetype(optstr);
                        break;
                case 'B': {
                        int pb = 0; /* set a default */

                        consumed = 1;
                        opt_textbox = 1 - opt_textbox;
                        if (*++optstr == '\0') {
                            break;
                        }
                                
                        while (*optstr) {
                            int sign;
                            if (*optstr == '-') {
                                sign = -1;
                                optstr++;
                            }
                            else
                                sign = 1;
                            if (isdigit((int)*optstr)) {
                                pb = *optstr - '0';
                                while (*++optstr && isdigit((int)*optstr))
                                    pb = pb*10 + *optstr - '0';
                            }
                            pb *= sign;
                            switch (*optstr) { 
                                case 'l': textmargin_left = pb;
                                          break;
                                case 'r': textmargin_right = pb;
                                          break;
                                case 't': textmargin_top = pb;
                                          break;
                                case 'b': textmargin_bottom = pb;
                                          break;
                                case '\0':textbox.thick = pb;
                                          break;
                                default:  fprintf(stderr,
                                           "%s: Unknown -B box specifier: %c\n",
                                           MPAGE, *optstr);
                                          break;
                            }
                            if (*optstr)
                                optstr++;
                        }
                        break;
                    }
                case 'c':    /* concat pages from different files on sheet */
                        opt_file = 1 - opt_file;
                        break;
                case 'C':    /* select character definitions */
                        consumed = 1;
                        if (*++optstr) { /* did we get a encoding name ? */
                            if ((charvec_file = (char *) malloc(strlen(libdir) +
                                                                strlen(optstr) +
                                                                2)) == NULL) {
                                perror(optstr);
                                fprintf(stderr,
                                    "ignoring character encoding definition\n");
                            }
                            else {
                                (void) strcpy(charvec_file, libdir);
                                (void) strcat(charvec_file, "/");
                                (void) strcat(charvec_file, optstr);
                                opt_encoding = 1;
                            }
                        }
                        else /* no encoding name, toggle default one */
                            opt_encoding = 1 - opt_encoding;
                        break;
                case 'd':
                        OPTARG();
                        switch (*optstr) {
			    case 'a': opt_input = IN_ASCII; break;
			    case 'p': opt_input = IN_PS; break;
			    default :
                                fprintf(stderr,
                                        "ignoring input file type -d%c\n",
                                        *optstr);
				break;
			}
                        break;
                case 'D':
                        OPTARG();
                        dateformat = optstr;
                        break;
                case 'e': /* GPN. for coli, 2,3,4,1(all) pages */
                        Coli = 3;
                        opt_duplex = 1 - opt_duplex;
                        break;
	        case 'E': /* GPN. for coli, 2,3(inside) pages */
	                Coli = 2;
                        break;
                case 'f':    /* fold long lines */
                        opt_fold = 1 - opt_fold;
                        break;
                case 'F':
                        OPTARG();
                        fontname = optstr;
                        break;
                case 'h':
                        OPTARG();
                        opt_header = optstr;
                        break;
                case 'H':
                        opt_mp_header = 1;
                        break;
                case 'I':
                        OPTARG();
                        opt_indent = atoi(optstr);
                        break;
                case 'j':    /* Just these sheets */
                        OPTARG();
                        if (opt_jarg >= MAXJARG) {
                            fprintf(stderr,
                                    "%s: to many j args (%d), ignoring %s\n", 
                                    MPAGE, MAXJARG, optstr);
                            break;
                        }
                        opt_first[opt_jarg] = isdigit((int)*optstr) ? 
                                    strtol(optstr, &optstr, 10) : 1;
                        if (*optstr == '-') {
                            if (isdigit((int)*++optstr))
                                opt_last[opt_jarg] = strtol(optstr, &optstr, 10);
                        }
                        else
                            opt_last[opt_jarg] = MAXINT;
                        if (*optstr == '/' || *optstr == '%')
                            opt_alt[opt_jarg] = atoi(++optstr);
                        opt_jarg++;
                        break;
                case 'J':
                        OPTARG();
                        ps_pagenum = atoi(optstr) - 1;
                        break;
                case 'k':    /* toggle kill on trailer */
                        opt_killtrail = 1 - opt_killtrail;
                        break;
                case 'l':    /* landscape */
                        sheetaspect = sheetaspect == LANDSCAPE ?
                                      PORTRAIT : LANDSCAPE;
                        break;
                case 'L':
                        OPTARG();
                        opt_lines = atoi(optstr);
                        break;
                case 'm': {
                        int sm = 2*DEFAULTSMARGIN; /* set a default */

                        consumed = 1;
                        if (*++optstr == '\0') {
                            sheetmargin_left = sm;
#if defined(ALL_MARGINS)
                            sheetmargin_right = sm;
                            sheetmargin_top = sm;
                            sheetmargin_bottom = sm;
#endif
                            break;
                        }
                                
                        while (*optstr) {
                            int sign;
                            if (*optstr == '-') {
                                sign = -1;
                                optstr++;
                            }
                            else
                                sign = 1;
                            if (isdigit((int)*optstr)) {
                                sm = *optstr - '0';
                                while (*++optstr && isdigit((int)*optstr))
                                    sm = sm*10 + *optstr - '0';
                            }
                            sm *= sign;
                            switch (*optstr) { 
                                case 'l': sheetmargin_left = sm;
                                          break;
                                case 'r': sheetmargin_right = sm;
                                          break;
                                case 't': sheetmargin_top = sm;
                                          break;
                                case 'b': sheetmargin_bottom = sm;
                                          break;
                                case '\0':sheetmargin_left = sm;
                                          sheetmargin_right = sm;
                                          sheetmargin_top = sm;
                                          sheetmargin_bottom = sm;
                                          break;
                                default:  fprintf(stderr,
                                        "%s: Unknown -m margin specifier: %c\n",
                                        MPAGE, *optstr);
                                          break;
                            }
                            if (*optstr)
                                optstr++;
                        }
                        break;
                    }
                case 'M': {
                        int pm = 2*DEFAULTPMARGIN; /* set a default */

                        consumed = 1;
                        if (*++optstr == '\0') {
                            pagemargin_left = pm;
#if defined(ALL_MARGINS)
                            pagemargin_right = pm;
                            pagemargin_top = pm;
                            pagemargin_bottom = pm;
#endif
                            break;
                        }
                                
                        while (*optstr) {
                            int sign;
                            if (*optstr == '-') {
                                sign = -1;
                                optstr++;
                            }
                            else
                                sign = 1;
                            if (isdigit((int)*optstr)) {
                                pm = *optstr - '0';
                                while (isdigit((int)*++optstr))
                                    pm = pm*10 + *optstr - '0';
                            }
                            pm *= sign;
                            switch (*optstr) { 
                                case 'l': pagemargin_left = pm;
                                          break;
                                case 'r': pagemargin_right = pm;
                                          break;
                                case 't': pagemargin_top = pm;
                                          break;
                                case 'b': pagemargin_bottom = pm;
                                          break;
                                case '\0':pagemargin_left = pm;
                                          pagemargin_right = pm;
                                          pagemargin_top = pm;
                                          pagemargin_bottom = pm;
                                          break;
                                default:  fprintf(stderr,
                                        "%s: Unknown -M margin specifier: %c\n",
                                           MPAGE, *optstr);
                                          break;
                            }
                            if (*optstr)
                                optstr++;
                        }
                        break;
                    }
                case 'o':    /* toggle print outlines */
                        opt_outline = 1 - opt_outline;
                        break;
	        case 'O': /* GPN. for coli, 4,1(outside) pages */
	                Coli = 1;
                        break;
                case 'p':    /* pr */
                        opt_pr = 1;
                        consumed = 1;
                        if (*++optstr)
                            prprog = optstr;
                        break;
                case 'P':    /* Printer */
                        consumed = 1;
                        doprint = 1;
                        if (*++optstr) {
                            if (*optstr == '-' && *(optstr+1) == '\0')
                                doprint = 0; /* kill MPAGE envvar que setting*/
                            else
                                printque = optstr;
                        }
                        break;
                case 'r':
                        opt_reverse = 1;
                        break;
                case 'R':    /* reorient  */
                        sheetaspect = LANDSCAPE_PORTRAIT;
                        break;
                case 's': /* tab Stops */
                        OPTARG();
                        if ((opt_tabstop = atoi(optstr)) < 2)
                            opt_tabstop = DEFAULTTABSTOP;
                        break;
                case 'S':
                        opt_square = 0;
                        break;
                case 't':
                        opt_duplex = 1 - opt_duplex;
                        break;
                case 'T':
                        opt_tumble = 1 - opt_tumble;
                        break;
                case 'u':
                        check_utf8 = 1 - check_utf8;
                        break;
                case 'U':    /* Letter sized, US paper */
                        opt_page = "Letter"; /* deprecated */
                        break;
                case 'v':    /* verbose (print page count) */
                        opt_verbose = 1 - opt_verbose;
                        break;
                case 'V':    /* Version */
                        fprintf(stderr, "mpage version %s\n", VERSION);
                        exit(0);
                        break;
                case 'W':
                        OPTARG();
                        opt_width = atoi(optstr);
                        break;
                case 'x': /* force usage. Could be extended to usagelevel */
                        opterrors = 1;
                        break;
                case 'X':
                        opt_sheetheader = 1;
                        consumed = 1;
                        if (*++optstr)
                            sheethead = optstr;
                        break;
                case 'z':
                        OPTARG();
                        printprog = optstr;
                        break;
                case 'Z':
                        OPTARG();
                        printarg = optstr;
                        break;

            }
        }
    }
    /*
     * Just NOW set the page size parameters
     */
    set_page();

    if (opterrors)
        return -1;

    return currarg;

} /* do_args */



int
do_env()
{
    int argc;
    char **argv;
    char *copy;
    char *env;

#if SPOOLER == ATT_SPOOLER
    if ((env = getenv("LPDEST")) != NULL)
#elif SPOOLER == BSD_SPOOLER
    if ((env = getenv("PRINTER")) != NULL)
#endif
        printque = env;

    if ((env = getenv("MPAGE_LIB")) != NULL)
        libdir = env;

    if ((env = getenv("MPAGE")) != NULL) {
        if ((copy = strdup(env)) == NULL) {
            fprintf(stderr, "%s: Unable to alloc memory for environment args\n",
                    MPAGE);
            return -1;
        }
        argv = slice(copy, &argc);
        if (do_args(argc, argv, 1) < 0) {
            fprintf(stderr, "%s: error in environment \"%s\"\n", MPAGE, env);
            return -1;
        }
    }

    return 0;

} /* do_env */

#define ARGCNT	20

char *slc_argv[ARGCNT+1];

static char **
slice(char *string, int *cntp)
{
    int count;

    /*
     * mimic the shell for conformity
     */
    slc_argv[0] = MPAGE;
    count = 1;
    /*
     * while there are still characters to be processed
     */
    while (*string && count < ARGCNT) {
        /*
         * skip any leading or leftover white space
         */
        while (*string == ' ')
            string++;
        /*
         * make sure we had more than just white space before
         * we believe we actually have an argument
         */
        if (*string) {
            /*
             * point the next slot in argv to this string
             */
            slc_argv[count++] = string;
            /*
             * and go looking for the end of this string
             * which is delienated by a space or NULL
             */
            while (*string && *string != ' ')
                string++;
            /*
             * if this not the end of the string, then convert
             * the space into a NULL and move forward one byte.
             * if this is the end of the string, we already have
             * a suitable NULL byte for the string and it also
             * drops us out of all the loops
             */
            if (*string) {
                *string = '\0';
                string++;
            }
        }
    }
    /*
     * return the count via the integer pointer we were given
     * and put a null pointer into the argv array for conformity
     */
    if (*string && count == ARGCNT)
        fprintf(stderr,
           "%s: to many options in MPAGE environment variable, skipping '%s'\n",
               MPAGE, string);
    slc_argv[count] = 0;
    *cntp = count;

    return slc_argv;

} /* slice */
