/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *	Ohio Trollius
 *	Copyright 1996 The Ohio State University
 *	GDB
 *
 *	$Id: pdi_parse.c,v 6.5 1999/08/27 22:33:10 jsquyres Exp $
 *
 *	Function:	- node identifier parsing package
 *			- id_range() based in part on Trollius 2.0,
 *			  Copyright 1990 The Ohio State University and Cornell
 *			  Research Foundation
 */

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

#include <all_list.h>
#include <args.h>
#include <net.h>
#include <pdi.h>
#include <portable.h>
#include <preq.h>
#include <terror.h>
#include <typical.h>

#define NEW		1
#define ONE		2
#define MANY		3

/*
 * global functions
 */
LIST *			pdi_parse();

/*
 * local functions
 */
static int		id_range();	/* parse a range of identifiers */

/*
 *	pdi_parse
 *
 *	Functions:	- parses process identifier mnemonics
 *	Accepts:	- command line count
 *			- command line vector
 *			- leftover vector (returned)
 *	Returns:	- process list or null
 */
LIST *
pdi_parse(argc, argv, othersv)

int			argc;
char **			argv;
char ***		othersv;

{
	int		index = 0;		/* current index */
	int		othersc;		/* leftover count */
	LIST *		proclist;		/* node ID list */
/*
 * Initialize the list.
 */
	proclist = al_init(sizeof(struct pdi), 0);
	if (proclist == 0) return(0);
/*
 * Pass argument 0 through.
 */
	if (othersv) {
		othersc = 0;
		*othersv = 0;

		if (argvadd(&othersc, othersv, argv[0])) {
			al_free(proclist);
			return(0);
		}
	}

	argc--;
	argv++;
/*
 * Loop through all the arguments.
 */
	while (argc) {
/*
 * Is it a generic node identifier?
 */
		if ((**argv == 'p') && isdigit((int) *(*argv + 1))) {

			if (id_range(*argv + 1, SELECT_PID, &index, proclist)) {
				al_free(proclist);
				argvfree(*othersv);
				return(0);
			}
		}
/*
 * Is it an index identifier?
 */
		else if (((**argv == '%') || (**argv == 'i')) &&
				isdigit((int) *(*argv + 1))) {

			if (id_range(*argv + 1,
					SELECT_INDEX, &index, proclist)) {
				al_free(proclist);
				argvfree(*othersv);
				return(0);
			}
		}
/*
 * Bump the non-id pointer and counter.
 */
		else if (othersv) {

			if (argvadd(&othersc, othersv, argv[0])) {
				al_free(proclist);
				argvfree(*othersv);
				return(0);
			}
		}

		argc--;
		argv++;
	}

	return(proclist);
}

/*
 *	id_range
 *
 *	Function:	- parses the ID range format
 *			- example: 1,3-5,7
 *	Accepts:	- range string
 *			- flags to use with every value found
 *			- current index ptr
 *			- list descriptor ptr
 *	Returns:	- 0 or ERROR
 */
static int
id_range(s, flags, ixp, lp)

char			*s;
int4			flags;
int			*ixp;
LIST			*lp;

{
	int		c;			/* current character */
	int4		id;			/* current identifier */
	int4		oldid = 0;		/* previous identifier */
	int		mode;			/* parsing state */
	struct pdi	newpdi;			/* new list entry */
	char		*t;			/* bumped up s */

	mode = NEW;

	while ((c = *s) != '\0') {

		if (c == ',') {

			if (mode == NEW) {
				errno = EBADIDSPEC;
				return(LAMERROR);
			}

			++s;
			mode = NEW;
		}

		else if (c == '-') {

			if (mode != ONE) {
				errno = EBADIDSPEC;
				return(LAMERROR);
			}

			++s;
			mode = MANY;
		}

		else {
			id = strtol(s, &t, 0);

			if ((id == 0) && (s == t)) {
				errno = EBADIDSPEC;
				return(LAMERROR);
			}

			s = t;

			if (mode == NEW) {
				newpdi.pdi_node = id;
				newpdi.pdi_flags = flags;
				newpdi.pdi_count = 1;
				newpdi.pdi_index = (*ixp)++;

				if (al_append(lp, &newpdi) == 0) return(LAMERROR);

				oldid = id;
				mode = ONE;
			}

			else if (mode == MANY) {

				if (id < oldid) {
					errno = EBADIDSPEC;
					return(LAMERROR);
				}

				while (++oldid <= id) {
					newpdi.pdi_node = oldid;
					newpdi.pdi_flags = flags;
					newpdi.pdi_count = 1;
					newpdi.pdi_index = (*ixp)++;

					if (al_append(lp, &newpdi) == 0)
							return(LAMERROR);
				}
			}

			else {
				errno = EIMPOSSIBLE;
				return(LAMERROR);
			}
		}
	} /* while() */

	return (0);
}
