/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"@(#)parse.c	1.14	96/04/10 SMI"	/* SVr4.0 1.10	*/

#include "string.h"
#include "sys/types.h"
#include "stdlib.h"

#include "lp.h"
#include "printers.h"

#define	WHO_AM_I	I_AM_LPSTAT
#include "oam.h"

#include "lpstat.h"
#include <locale.h>

typedef struct execute {
	char			*list;
	void			(*func)();
	int			inquire_type;
	struct execute		*forward;
}			EXECUTE;

static int		r		= 0;
int			D		= 0,
			remote_cmd	= 0;

unsigned int		verbosity	= 0;

extern char		*optarg;

extern int		getopt(),
			optind,
			opterr,
			optopt;


static void		usage ( void );

#if	defined(CAN_DO_MODULES)
#define OPT_LIST	"a:c:do:p:rstu:v:f:TDS:lLRHP:"
#else
#define OPT_LIST	"a:c:do:p:rstu:v:f:TDS:lLRP:"
#endif

#define	QUEUE(LIST, FUNC, TYPE) \
	{ \
		next->list = LIST; \
		next->func = FUNC; \
		next->inquire_type = TYPE; \
		next->forward = (EXECUTE *)Malloc(sizeof(EXECUTE)); \
		(next = next->forward)->forward = 0; \
	}

/**
 ** parse() - PARSE COMMAND LINE OPTIONS
 **/

/*
 * This routine parses the command line, builds a linked list of
 * function calls desired, then executes them in the order they 
 * were received. This is necessary as we must apply -l to all 
 * options. So, we could either stash the calls away, or go
 * through parsing twice. I chose to build the linked list.
 */

void
parse(int argc, char **argv)
{
	int			optsw;
	int			ac;
	int			need_mount	= 0;

	char **			av;
	char *			p;
	char **			list;

	EXECUTE			linked_list;

	register EXECUTE *	next		= &linked_list;


	next->forward = 0;

	/*
	 * Add a fake value to the end of the "argv" list, to
	 * catch the case that a valued-option comes last.
	 */
	av = (char **)Malloc((argc + 2) * sizeof(char *));
	for (ac = 0; ac < argc; ac++)
		av[ac] = argv[ac];
	av[ac++] = "--";

	opterr = 0;

	while ((optsw = getopt(ac, (char * const *)av, OPT_LIST)) != -1) {

		switch(optsw) {

		/*
		 * These option letters MAY take a value. Check the value;
		 * if it begins with a '-', assume it's really the next
		 * argument.
		 */
		case 'a':
		case 'c':
		case 'o':
		case 'p':
		case 'u':
		case 'v':
		case 'f':
		case 'P':
		case 'S':
			if (*optarg == '-') {
				/*
				 * This will work if we were given
				 *
				 *	-x -foo
				 *
				 * but would fail if we were given
				 *
				 *	-x-foo
				 */
				optind--;
				optarg = NAME_ALL;
			}
			break;
		}
	
		switch(optsw) {
		case 'a':	/* acceptance status */
			QUEUE (optarg, do_accept, INQ_ACCEPT);
			break;

		case 'c':	/* class to printer mapping */
			QUEUE (optarg, do_class, 0);
			break;

		case 'd':	/* default destination */
			QUEUE (0, def, 0);
			break;

		case 'D':	/* Description of printers */
			D = 1;
			break;

		case 'f':	/* do forms */
			QUEUE (optarg, do_form, 0);
			need_mount = 1;
			break;

		case 'P':	/* do forms */
			QUEUE (optarg, do_paper, 0);
			break;

#if	defined(CAN_DO_MODULES)
		case 'H':	/* show modules pushed for printer */
			verbosity |= V_MODULES;
			break;
#endif

		case 'l':	/* verbose output */
			verbosity |= V_LONG;
			verbosity &= ~V_BITS;
			break;

		case 'L':	/* Local only */
			remote_cmd = 0;
			break;

		case 'o':	/* output for destinations */
			QUEUE (optarg, do_request, 0);
			break;

		case 'p':	/* printer status */
			QUEUE (optarg, do_printer, INQ_PRINTER);
			break;

		case 'R':	/* show rank in queue */
			verbosity |= V_RANK;
			break;

		case 'r':	/* is scheduler running? */
			QUEUE (0, running, 0);
			r = 1;
			break;

		case 's':	/* configuration summary */
			QUEUE (0, running, 0);
			QUEUE (0, def, 0);
			QUEUE (NAME_ALL, do_class, 0);
			QUEUE (NAME_ALL, do_device, 0);
			QUEUE (NAME_ALL, do_form, 0);
			QUEUE (NAME_ALL, do_charset, 0);
			r = 1;
			need_mount = 1;
			break;

		case 'S':	/* character set info */
			QUEUE (optarg, do_charset, 0);
			need_mount = 1;
			break;

		case 't':	/* print all info */
			QUEUE (0, running, 0);
			QUEUE (0, def, 0);
			QUEUE (NAME_ALL, do_class, 0);
			QUEUE (NAME_ALL, do_device, 0);
			QUEUE (NAME_ALL, do_accept, INQ_ACCEPT);
			QUEUE (NAME_ALL, do_printer, INQ_PRINTER);
			QUEUE (NAME_ALL, do_form, 0);
			QUEUE (NAME_ALL, do_charset, 0);
			QUEUE (NAME_ALL, do_request, 0);
			r = 1;
			need_mount = 1;
			break;

		case 'T':	/* (trace) special debugging output */
			verbosity |= V_BITS;
			verbosity &= ~V_LONG;
			break;

		case 'u':	/* output by user */
			QUEUE (optarg, do_user, INQ_USER);
			break;

		case 'v':	/* printers to devices mapping */
			QUEUE (optarg, do_device, 0);
			break;

		default:
			if (optopt == '?') {
				usage ();
				done (0);
			}

			(p = "-X")[1] = optopt;

			if (strchr(OPT_LIST, optopt))
				LP_ERRMSG1 (ERROR, E_LP_OPTARG, p);
			else
				LP_ERRMSG1 (ERROR, E_LP_USAGE, p);
			done(1);
			break;
		}

	}

#ifdef NEVER
	if (getenv("LPSTAT_NO_REMOTE"))
		remote_cmd = 0;
#endif NEVER

	/*
	 * Note: "argc" here, not "ac", to skip our fake option.
	 * We could use either "argv" or "av", since for the range
	 * of interest they're the same.
	 */

	list = 0;
	while (optind < argc)
		if (addlist(&list, av[optind++]) == -1) {
			LP_ERRMSG (ERROR, E_LP_MALLOC);
			done(1);
		}
	if (list)
		QUEUE (sprintlist(list), do_request, 0);

	if (argc == 1 || (verbosity & V_RANK) && argc == 2)
		QUEUE (getname(), do_user, INQ_USER);

	startup ();

	/*
		Linked list is completed, load up mount info if
		needed then do the requests
	*/

	if (need_mount) {
		inquire_type = INQ_STORE;
		do_printer (alllist);
	}

	for (next = &linked_list; next->forward; next = next->forward) {
		inquire_type = next->inquire_type;
		if (!next->list)
			(*next->func) ();
		else if (!*next->list)
			(*next->func) (alllist);
		else
			(*next->func) (getlist(next->list, LP_WS, LP_SEP));
	}

	return;
}

/**
 ** usage() - PRINT USAGE MESSAGE
 **/

static void
usage(void)
{

#if	defined(CAN_DO_MODULES)

	(void) printf (gettext(
"usage:\n"
"    lpstat [options] [request-ids]\n"
"	[-a printers,classes]		(show acceptance status)\n"
"	[-c classes]			(show available classes)\n"
"	[-d]				(show default destination)\n"
"	[-D]				(-p only: describe printers)\n"
"	[-f forms]			(show available forms)\n"
"	[-l]				(be verbose)\n"
"	[-o printers,classes,req-ids]	(show status of requests)\n"
"	[-p printers]			(show available printers)\n"
"	[-P]				(show paper types)\n"
"	[-R]				(show rank in queue)\n"
"	[-r]				(show status of Spooler)\n"
"	[-s]				(show summary status)\n"
"	[-S char-sets,print-wheels]	(show available \"fonts\")\n"
"	[-t]				(show status of everything)\n"
"	[-u users]			(show status of user requests)\n"
"	[-v printers [-H]]		(show devices used by printers)\n"
"		(\"all\" allowed with -a,-c,-f,-o,-p,-S,-u,-v options)\n"));
#else
 
        (void) printf (gettext(
"usage:\n"
"    lpstat [options] [request-ids]\n"
"        [-a printers,classes]           (show acceptance status)\n"
"        [-c classes]                    (show available classes)\n"
"        [-d]                            (show default destination)\n"
"        [-D]                            (-p only: describe printers)\n"
"        [-f forms]                      (show available forms)\n"
"        [-l]                            (be verbose)\n"
"        [-o printers,classes,req-ids]   (show status of requests)\n"
"        [-p printers]                   (show available printers)\n"
"        [-P]                            (show paper types)\n"
"        [-R]                            (show rank in queue)\n"
"        [-r]                            (show status of Spooler)\n"
"        [-s]                            (show summary status)\n"
"        [-S char-sets,print-wheels]     (show available \"fonts\")\n"
"        [-t]                            (show status of everything)\n"
"        [-u users]                      (show status of user requests)\n"
"        [-v printers]                   (show devices used by printers)\n"
"                (\"all\" allowed with -a,-c,-f,-o,-p,-S,-u,-v options)\n"));  
#endif
	return;
}
