OpenSolaris_b135/lib/libeti/form/common/ty_enum.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*	Copyright (c) 1988 AT&T	*/
/*	  All Rights Reserved  	*/


/*
 *      Copyright (c) 1997, by Sun Microsystems, Inc.
 *      All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.2	*/

/*LINTLIBRARY*/

#include <sys/types.h>
#include <stdlib.h>
#include "utility.h"

/*
 *	TYPE_ENUM standard type
 *
 *	usage:
 *		set_field_type(f, TYPE_ENUM, list, checkcase, checkuniq);
 *
 *		char ** list;	list of acceptable strings
 *		int checkcase;	TRUE - upper/lower case is significant
 *		int checkuniq;	TRUE - unique match required
 *
 */
typedef struct {

	char **	list;
	int	checkcase;
	int	checkuniq;
	int	count;
} ENUM;

static char * make_enum(va_list *);
static char * copy_enum(char *);
static void free_enum(char *);
static int fcheck_enum(FIELD *, char *);
static int next_enum(FIELD *, char *);
static int prev_enum(FIELD *, char *);

static FIELDTYPE typeENUM =
{
				ARGS | CHOICE,		/* status	*/
				1,			/* ref		*/
				(FIELDTYPE *) 0,	/* left		*/
				(FIELDTYPE *) 0,	/* right	*/
				make_enum,		/* makearg	*/
				copy_enum,		/* copyarg	*/
				free_enum,		/* freearg	*/
				fcheck_enum,		/* fcheck	*/
				(PTF_int) 0,		/* ccheck	*/
				next_enum,		/* next		*/
				prev_enum,		/* prev		*/
};

FIELDTYPE * TYPE_ENUM = &typeENUM;

static char *
make_enum(va_list *ap)
{
	ENUM * n;

	if (Alloc(n, ENUM)) {
		char **		v;

		n -> list	= va_arg(*ap, char **);
		n -> checkcase	= va_arg(*ap, int);
		n -> checkuniq	= va_arg(*ap, int);

		for (v = n -> list; *v; ++v)
			;
		n -> count = (int) (v - n -> list);
	}
	return ((char *) n);
}

static char *
copy_enum(char *arg)
{
	ENUM * n;

	if (Alloc(n, ENUM))
		*n = *((ENUM *) arg);
	return ((char *) n);
}

static void
free_enum(char *arg)
{
	Free(arg);
}

#define	NO_MATCH		0
#define	PARTIAL_MATCH		1
#define	EXACT_MATCH		2

static int
cmp(char *x, char *v, int checkcase)
{
	while (*v && *v == ' ')			/* remove leading blanks */
		++v;
	while (*x && *x == ' ')			/* remove leading blanks */
		++x;

	if (*v == '\0')
		return (*x == '\0' ? EXACT_MATCH : NO_MATCH);

	if (checkcase) {			/* case is significant */
		while (*x++ == *v)
			if (*v++ == '\0')
				return (EXACT_MATCH);
	} else {				/* ignore case */
		while (toupper (*x++) == toupper (*v))
			if (*v++ == '\0')
				return (EXACT_MATCH);
	}
	while (*v && *v == ' ')			/* remove trailing blanks */
		++v;
	if (*v)
		return (NO_MATCH);
	else
		return (*--x ? PARTIAL_MATCH : EXACT_MATCH);
}

static int
fcheck_enum(FIELD *f, char *arg)
{
	ENUM *		n		= (ENUM *) arg;
	char **		list		= n -> list;
	int		checkcase	= n -> checkcase;
	int		checkuniq	= n -> checkuniq;
	int		m;
	char *		v		= field_buffer(f, 0);
	char *		x;

	while (x = *list++)
		if (m = cmp(x, v, checkcase)) {
			char * value = x;

			if (checkuniq && m != EXACT_MATCH)
				while (x = *list++)
					if (m = cmp(x, v, checkcase)) {
						if (m == EXACT_MATCH) {
							value = x;
							break;
						}
						else
							value = (char *) 0;
					}
			if (! value)
				return (FALSE);

			(void) set_field_buffer(f, 0, value);
			return (TRUE);
		}

	return (FALSE);
}

static int
next_enum(FIELD *f, char *arg)
{
	ENUM *		n		= (ENUM *) arg;
	char **		list		= n -> list;
	int		checkcase	= n -> checkcase;
	int		count		= n -> count;
	char *		v		= field_buffer(f, 0);

	while (count--)
		if (cmp(*list++, v, checkcase) == EXACT_MATCH)
			break;
	if (count <= 0)
		list = n -> list;

	if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) {
		(void) set_field_buffer(f, 0, *list);
		return (TRUE);
	}
	return (FALSE);
}

static int
prev_enum(FIELD *f, char *arg)
{
	ENUM *		n		= (ENUM *) arg;
	char **		list		= n -> list + n -> count - 1;
	int		checkcase	= n -> checkcase;
	int		count		= n -> count;
	char *		v		= field_buffer(f, 0);

	while (count--)
		if (cmp(*list--, v, checkcase) == EXACT_MATCH)
			break;
	if (count <= 0)
		list = n -> list + n -> count - 1;

	if (count >= 0 || cmp("", v, checkcase) == EXACT_MATCH) {
		(void) set_field_buffer(f, 0, *list);
		return (TRUE);
	}
	return (FALSE);
}