12264Sjacobs /*
22264Sjacobs  * CDDL HEADER START
32264Sjacobs  *
42264Sjacobs  * The contents of this file are subject to the terms of the
52264Sjacobs  * Common Development and Distribution License (the "License").
62264Sjacobs  * You may not use this file except in compliance with the License.
72264Sjacobs  *
82264Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92264Sjacobs  * or http://www.opensolaris.org/os/licensing.
102264Sjacobs  * See the License for the specific language governing permissions
112264Sjacobs  * and limitations under the License.
122264Sjacobs  *
132264Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
142264Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152264Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
162264Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
172264Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
182264Sjacobs  *
192264Sjacobs  * CDDL HEADER END
202264Sjacobs  */
212264Sjacobs 
222264Sjacobs /*
23*6725Sjacobs  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242264Sjacobs  * Use is subject to license terms.
252264Sjacobs  *
262264Sjacobs  */
272264Sjacobs 
282264Sjacobs /* $Id: attribute.c 157 2006-04-26 15:07:55Z ktou $ */
292264Sjacobs 
302264Sjacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
312264Sjacobs 
322264Sjacobs /*LINTLIBRARY*/
332264Sjacobs 
342264Sjacobs #include <stdio.h>
352264Sjacobs #include <stdlib.h>
362264Sjacobs #include <stdarg.h>
372264Sjacobs #include <string.h>
38*6725Sjacobs #include <ctype.h>
392264Sjacobs #include <alloca.h>
402264Sjacobs #include <papi.h>
41*6725Sjacobs #include <regex.h>
422264Sjacobs 
432264Sjacobs static void papiAttributeFree(papi_attribute_t *attribute);
442264Sjacobs 
452264Sjacobs static void
462264Sjacobs papiAttributeValueFree(papi_attribute_value_type_t type,
472264Sjacobs 		    papi_attribute_value_t *value)
482264Sjacobs {
492264Sjacobs 	if (value != NULL) {
502264Sjacobs 		switch (type) {
512264Sjacobs 		case PAPI_STRING:
522264Sjacobs 			if (value->string != NULL)
532264Sjacobs 				free(value->string);
542264Sjacobs 			break;
552264Sjacobs 		case PAPI_COLLECTION:
562264Sjacobs 			if (value->collection != NULL) {
572264Sjacobs 				int i;
582264Sjacobs 
592264Sjacobs 				for (i = 0; value->collection[i] != NULL; i++)
602264Sjacobs 					papiAttributeFree(value->collection[i]);
612264Sjacobs 
622264Sjacobs 				free(value->collection);
632264Sjacobs 			}
642264Sjacobs 			break;
652264Sjacobs 		default: /* don't need to free anything extra */
662264Sjacobs 			break;
672264Sjacobs 		}
682264Sjacobs 
692264Sjacobs 		free(value);
702264Sjacobs 	}
712264Sjacobs }
722264Sjacobs 
732264Sjacobs static void
742264Sjacobs papiAttributeValuesFree(papi_attribute_value_type_t type,
752264Sjacobs 		    papi_attribute_value_t **values)
762264Sjacobs {
772264Sjacobs 	if (values != NULL) {
782264Sjacobs 		int i;
792264Sjacobs 
802264Sjacobs 		for (i = 0; values[i] != NULL; i++)
812264Sjacobs 			papiAttributeValueFree(type, values[i]);
822264Sjacobs 
832264Sjacobs 		free(values);
842264Sjacobs 	}
852264Sjacobs }
862264Sjacobs 
872264Sjacobs static void
882264Sjacobs papiAttributeFree(papi_attribute_t *attribute)
892264Sjacobs {
902264Sjacobs 	if (attribute != NULL) {
912264Sjacobs 		if (attribute->name != NULL)
922264Sjacobs 			free(attribute->name);
932264Sjacobs 		if (attribute->values != NULL)
942264Sjacobs 			papiAttributeValuesFree(attribute->type,
952264Sjacobs 						attribute->values);
962264Sjacobs 			free(attribute);
972264Sjacobs 	}
982264Sjacobs }
992264Sjacobs 
1002264Sjacobs void
1012264Sjacobs papiAttributeListFree(papi_attribute_t **list)
1022264Sjacobs {
1032264Sjacobs 	if (list != NULL) {
1042264Sjacobs 		int i;
1052264Sjacobs 
1062264Sjacobs 		for (i = 0; list[i] != NULL; i++)
1072264Sjacobs 			papiAttributeFree(list[i]);
1082264Sjacobs 
1092264Sjacobs 		free(list);
1102264Sjacobs 	}
1112264Sjacobs }
1122264Sjacobs 
1132264Sjacobs static papi_attribute_t **
1142264Sjacobs collection_dup(papi_attribute_t **collection)
1152264Sjacobs {
1162264Sjacobs 	papi_attribute_t **result = NULL;
1172264Sjacobs 
1182264Sjacobs 	/* allows a NULL collection that is "empty" or "no value" */
1192264Sjacobs 	if (collection != NULL) {
1202264Sjacobs 		papi_status_t status = PAPI_OK;
1212264Sjacobs 		int i;
1222264Sjacobs 
1232264Sjacobs 		for (i = 0; ((collection[i] != NULL) && (status == PAPI_OK));
1242264Sjacobs 		     i++) {
1252264Sjacobs 			papi_attribute_t *a = collection[i];
1262264Sjacobs 
1272264Sjacobs 			status = papiAttributeListAddValue(&result,
1282264Sjacobs 					PAPI_ATTR_APPEND, a->name, a->type,
1292264Sjacobs 					NULL);
1302264Sjacobs 			if ((status == PAPI_OK) && (a->values != NULL)) {
1312264Sjacobs 				int j;
1322264Sjacobs 
1332264Sjacobs 				for (j = 0; ((a->values[j] != NULL) &&
1342264Sjacobs 					     (status == PAPI_OK)); j++)
1352264Sjacobs 					status = papiAttributeListAddValue(
1362264Sjacobs 							&result,
1372264Sjacobs 							PAPI_ATTR_APPEND,
1382264Sjacobs 							a->name, a->type,
1392264Sjacobs 							a->values[j]);
1402264Sjacobs 			}
1412264Sjacobs 		}
1422264Sjacobs 		if (status != PAPI_OK) {
1432264Sjacobs 			papiAttributeListFree(result);
1442264Sjacobs 			result = NULL;
1452264Sjacobs 		}
1462264Sjacobs 	}
1472264Sjacobs 
1482264Sjacobs 	return (result);
1492264Sjacobs }
1502264Sjacobs 
1512264Sjacobs static papi_attribute_value_t *
1522264Sjacobs papiAttributeValueDup(papi_attribute_value_type_t type,
1532264Sjacobs 		papi_attribute_value_t *v)
1542264Sjacobs {
1552264Sjacobs 	papi_attribute_value_t *result = NULL;
1562264Sjacobs 
1572264Sjacobs 	if ((v != NULL) && ((result = calloc(1, sizeof (*result))) != NULL)) {
1582264Sjacobs 		switch (type) {
1592264Sjacobs 		case PAPI_STRING:
1602264Sjacobs 			if (v->string == NULL) {
1612264Sjacobs 				free(result);
1622264Sjacobs 				result = NULL;
1632264Sjacobs 			} else
1642264Sjacobs 				result->string = strdup(v->string);
1652264Sjacobs 			break;
1662264Sjacobs 		case PAPI_INTEGER:
1672264Sjacobs 			result->integer = v->integer;
1682264Sjacobs 			break;
1692264Sjacobs 		case PAPI_BOOLEAN:
1702264Sjacobs 			result->boolean = v->boolean;
1712264Sjacobs 			break;
1722264Sjacobs 		case PAPI_RANGE:
1732264Sjacobs 			result->range.lower = v->range.lower;
1742264Sjacobs 			result->range.upper = v->range.upper;
1752264Sjacobs 			break;
1762264Sjacobs 		case PAPI_RESOLUTION:
1772264Sjacobs 			result->resolution.xres = v->resolution.xres;
1782264Sjacobs 			result->resolution.yres = v->resolution.yres;
1792264Sjacobs 			result->resolution.units = v->resolution.units;
1802264Sjacobs 			break;
1812264Sjacobs 		case PAPI_DATETIME:
1822264Sjacobs 			result->datetime = v->datetime;
1832264Sjacobs 			break;
1842264Sjacobs 		case PAPI_COLLECTION:
1852264Sjacobs 			result->collection = collection_dup(v->collection);
1862264Sjacobs 			break;
1872264Sjacobs 		case PAPI_METADATA:
1882264Sjacobs 			result->metadata = v->metadata;
1892264Sjacobs 			break;
1902264Sjacobs 		default:	/* unknown type, fail to duplicate */
1912264Sjacobs 			free(result);
1922264Sjacobs 			result = NULL;
1932264Sjacobs 		}
1942264Sjacobs 	}
1952264Sjacobs 
1962264Sjacobs 	return (result);
1972264Sjacobs }
1982264Sjacobs 
1992264Sjacobs static papi_attribute_t *
2002264Sjacobs papiAttributeAlloc(char *name, papi_attribute_value_type_t type)
2012264Sjacobs {
2022264Sjacobs 	papi_attribute_t *result = NULL;
2032264Sjacobs 
2042264Sjacobs 	if ((result = calloc(1, sizeof (*result))) != NULL) {
2052264Sjacobs 		result->name = strdup(name);
2062264Sjacobs 		result->type = type;
2072264Sjacobs 	}
2082264Sjacobs 
2092264Sjacobs 	return (result);
2102264Sjacobs }
2112264Sjacobs 
2122264Sjacobs static papi_status_t
2132264Sjacobs papiAttributeListAppendValue(papi_attribute_value_t ***values,
2142264Sjacobs 		papi_attribute_value_type_t type,
2152264Sjacobs 		papi_attribute_value_t *value)
2162264Sjacobs {
2172264Sjacobs 
2182264Sjacobs 	if (values == NULL)
2192264Sjacobs 		return (PAPI_BAD_ARGUMENT);
2202264Sjacobs 
2212264Sjacobs 	if (value != NULL) {	/* this allows "empty" attributes */
2222264Sjacobs 		papi_attribute_value_t *tmp = NULL;
2232264Sjacobs 
2242264Sjacobs 		if ((tmp = papiAttributeValueDup(type, value)) == NULL)
2252264Sjacobs 			return (PAPI_TEMPORARY_ERROR);
2262264Sjacobs 
2272264Sjacobs 		list_append(values, tmp);
2282264Sjacobs 	}
2292264Sjacobs 
2302264Sjacobs 	return (PAPI_OK);
2312264Sjacobs }
2322264Sjacobs 
2332264Sjacobs papi_status_t
2342264Sjacobs papiAttributeListAddValue(papi_attribute_t ***list, int flgs,
2352264Sjacobs 		char *name, papi_attribute_value_type_t type,
2362264Sjacobs 		papi_attribute_value_t *value)
2372264Sjacobs {
2382264Sjacobs 	papi_status_t result;
2392264Sjacobs 	int flags = flgs;
2402264Sjacobs 	papi_attribute_t *attribute = NULL;
2412264Sjacobs 	papi_attribute_value_t **values = NULL;
2422264Sjacobs 
2432264Sjacobs 	if ((list == NULL) || (name == NULL))
2442264Sjacobs 		return (PAPI_BAD_ARGUMENT);
2452264Sjacobs 
2462264Sjacobs 	if ((type == PAPI_RANGE) && (value != NULL) &&
2472264Sjacobs 	    (value->range.lower > value->range.upper))
2482264Sjacobs 		return (PAPI_BAD_ARGUMENT);	/* RANGE must have min <= max */
2492264Sjacobs 
2502264Sjacobs 	if (flags == 0) /* if it wasn't set, set a default behaviour */
2512264Sjacobs 		flags = PAPI_ATTR_APPEND;
2522264Sjacobs 
2532264Sjacobs 	/* look for an existing one */
2542264Sjacobs 	attribute = papiAttributeListFind(*list, name);
2552264Sjacobs 
2562264Sjacobs 	if (((flags & PAPI_ATTR_EXCL) != 0) && (attribute != NULL))
2572264Sjacobs 		return (PAPI_CONFLICT); /* EXISTS */
2582264Sjacobs 
2592264Sjacobs 	if (((flags & PAPI_ATTR_REPLACE) == 0) && (attribute != NULL) &&
2602264Sjacobs 	    (attribute->type != type))
2612264Sjacobs 		return (PAPI_CONFLICT); /* TYPE CONFLICT */
2622264Sjacobs 
2632264Sjacobs 	/* if we don't have one, create it and add it to the list */
2642264Sjacobs 	if ((attribute == NULL) &&
2652264Sjacobs 	    ((attribute = papiAttributeAlloc(name, type)) != NULL))
2662264Sjacobs 		list_append(list, attribute);
2672264Sjacobs 
2682264Sjacobs 	/* if we don't have one by now, it's most likely an alloc fail */
2692264Sjacobs 	if (attribute == NULL)
2702264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
2712264Sjacobs 
2722264Sjacobs 	/*
2732264Sjacobs 	 * if we are replacing, clear any existing values, but don't free
2742264Sjacobs 	 * until after we have replaced the values, in case we are replacing
2752264Sjacobs 	 * a collection with a relocated version of the original collection.
2762264Sjacobs 	 */
2772264Sjacobs 	if (((flags & PAPI_ATTR_REPLACE) != 0) && (attribute->values != NULL)) {
2782264Sjacobs 		values = attribute->values;
2792264Sjacobs 		attribute->values = NULL;
2802264Sjacobs 	}
2812264Sjacobs 
2822264Sjacobs 	attribute->type = type;
2832264Sjacobs 
2842264Sjacobs 	result = papiAttributeListAppendValue(&attribute->values, type, value);
2852264Sjacobs 
2862264Sjacobs 	/* free old values if we replaced them */
2872264Sjacobs 	if (values != NULL)
2882264Sjacobs 		papiAttributeValuesFree(type, values);
2892264Sjacobs 
2902264Sjacobs 	return (result);
2912264Sjacobs }
2922264Sjacobs 
2932264Sjacobs papi_status_t
2942264Sjacobs papiAttributeListAddString(papi_attribute_t ***list, int flags,
2952264Sjacobs 			char *name, char *string)
2962264Sjacobs {
2972264Sjacobs 	papi_attribute_value_t v;
2982264Sjacobs 
2992264Sjacobs 	v.string = (char *)string;
3002264Sjacobs 	return (papiAttributeListAddValue(list, flags, name, PAPI_STRING, &v));
3012264Sjacobs }
3022264Sjacobs 
3032264Sjacobs papi_status_t
3042264Sjacobs papiAttributeListAddInteger(papi_attribute_t ***list, int flags,
3052264Sjacobs 			char *name, int integer)
3062264Sjacobs {
3072264Sjacobs 	papi_attribute_value_t v;
3082264Sjacobs 
3092264Sjacobs 	v.integer = integer;
3102264Sjacobs 	return (papiAttributeListAddValue(list, flags, name, PAPI_INTEGER, &v));
3112264Sjacobs }
3122264Sjacobs 
3132264Sjacobs papi_status_t
3142264Sjacobs papiAttributeListAddBoolean(papi_attribute_t ***list, int flags,
3152264Sjacobs 			char *name, char boolean)
3162264Sjacobs {
3172264Sjacobs 	papi_attribute_value_t v;
3182264Sjacobs 
3192264Sjacobs 	v.boolean = boolean;
3202264Sjacobs 	return (papiAttributeListAddValue(list, flags, name, PAPI_BOOLEAN, &v));
3212264Sjacobs }
3222264Sjacobs 
3232264Sjacobs papi_status_t
3242264Sjacobs papiAttributeListAddRange(papi_attribute_t ***list, int flags,
3252264Sjacobs 			char *name, int lower, int upper)
3262264Sjacobs {
3272264Sjacobs 	papi_attribute_value_t v;
3282264Sjacobs 
3292264Sjacobs 	v.range.lower = lower;
3302264Sjacobs 	v.range.upper = upper;
3312264Sjacobs 	return (papiAttributeListAddValue(list, flags, name, PAPI_RANGE, &v));
3322264Sjacobs }
3332264Sjacobs 
3342264Sjacobs papi_status_t
3352264Sjacobs papiAttributeListAddResolution(papi_attribute_t ***list, int flags,
3362264Sjacobs 			char *name, int xres, int yres,
3372264Sjacobs 			papi_resolution_unit_t units)
3382264Sjacobs {
3392264Sjacobs 	papi_attribute_value_t v;
3402264Sjacobs 
3412264Sjacobs 	v.resolution.xres = xres;
3422264Sjacobs 	v.resolution.yres = yres;
3432264Sjacobs 	v.resolution.units = units;
3442264Sjacobs 	return (papiAttributeListAddValue(list, flags, name,
3452264Sjacobs 				PAPI_RESOLUTION, &v));
3462264Sjacobs }
3472264Sjacobs 
3482264Sjacobs papi_status_t
3492264Sjacobs papiAttributeListAddDatetime(papi_attribute_t ***list, int flags,
3502264Sjacobs 			char *name, time_t datetime)
3512264Sjacobs {
3522264Sjacobs 	papi_attribute_value_t v;
3532264Sjacobs 
3542264Sjacobs 	v.datetime = datetime;
3552264Sjacobs 	return (papiAttributeListAddValue(list, flags, name,
3562264Sjacobs 				PAPI_DATETIME, &v));
3572264Sjacobs }
3582264Sjacobs 
3592264Sjacobs papi_status_t
3602264Sjacobs papiAttributeListAddCollection(papi_attribute_t ***list, int flags,
3612264Sjacobs 			char *name, papi_attribute_t **collection)
3622264Sjacobs {
3632264Sjacobs 	papi_attribute_value_t v;
3642264Sjacobs 
3652264Sjacobs 	v.collection = (papi_attribute_t **)collection;
3662264Sjacobs 	return (papiAttributeListAddValue(list, flags, name,
3672264Sjacobs 				PAPI_COLLECTION, &v));
3682264Sjacobs }
3692264Sjacobs 
3702264Sjacobs papi_status_t
3712264Sjacobs papiAttributeListAddMetadata(papi_attribute_t ***list, int flags,
3722264Sjacobs 			char *name, papi_metadata_t metadata)
3732264Sjacobs {
3742264Sjacobs 	papi_attribute_value_t v;
3752264Sjacobs 
3762264Sjacobs 	v.metadata = metadata;
3772264Sjacobs 	return (papiAttributeListAddValue(list, flags, name,
3782264Sjacobs 				PAPI_METADATA, &v));
3792264Sjacobs }
3802264Sjacobs 
3812264Sjacobs papi_status_t
3822264Sjacobs papiAttributeListDelete(papi_attribute_t ***list, char *name)
3832264Sjacobs {
3842264Sjacobs 	papi_attribute_t *attribute;
3852264Sjacobs 
3862264Sjacobs 	if ((list == NULL) || (name == NULL))
3872264Sjacobs 		return (PAPI_BAD_ARGUMENT);
3882264Sjacobs 
3892264Sjacobs 	if ((attribute = papiAttributeListFind(*list, name)) == NULL)
3902264Sjacobs 		return (PAPI_NOT_FOUND);
3912264Sjacobs 
3923125Sjacobs 	list_remove(list, attribute);
3932264Sjacobs 	papiAttributeFree(attribute);
3942264Sjacobs 
3952264Sjacobs 	return (PAPI_OK);
3962264Sjacobs }
3972264Sjacobs 
3982264Sjacobs papi_attribute_t *
3992264Sjacobs papiAttributeListFind(papi_attribute_t **list, char *name)
4002264Sjacobs {
4012264Sjacobs 	int i;
4022264Sjacobs 	if ((list == NULL) || (name == NULL))
4032264Sjacobs 		return (NULL);
4042264Sjacobs 
4052264Sjacobs 	for (i = 0; list[i] != NULL; i++)
4062264Sjacobs 		if (strcasecmp(list[i]->name, name) == 0)
4072264Sjacobs 			return ((papi_attribute_t *)list[i]);
4082264Sjacobs 
4092264Sjacobs 	return (NULL);
4102264Sjacobs }
4112264Sjacobs 
4122264Sjacobs papi_attribute_t *
4132264Sjacobs papiAttributeListGetNext(papi_attribute_t **list, void **iter)
4142264Sjacobs {
4152264Sjacobs 	papi_attribute_t **tmp, *result;
4162264Sjacobs 
4172264Sjacobs 	if ((list == NULL) && (iter == NULL))
4182264Sjacobs 		return (NULL);
4192264Sjacobs 
4202264Sjacobs 	if (*iter == NULL)
4212264Sjacobs 		*iter = list;
4222264Sjacobs 
4232264Sjacobs 	tmp = *iter;
4242264Sjacobs 	result = *tmp;
4252264Sjacobs 	*iter = ++tmp;
4262264Sjacobs 
4272264Sjacobs 	return (result);
4282264Sjacobs }
4292264Sjacobs 
4302264Sjacobs papi_status_t
4312264Sjacobs papiAttributeListGetValue(papi_attribute_t **list, void **iter,
4322264Sjacobs 			char *name, papi_attribute_value_type_t type,
4332264Sjacobs 			papi_attribute_value_t **value)
4342264Sjacobs {
4352264Sjacobs 	papi_attribute_value_t **tmp;
4362264Sjacobs 	void *fodder = NULL;
4372264Sjacobs 
4382264Sjacobs 	if ((list == NULL) || ((name == NULL) && (iter == NULL)) ||
4392264Sjacobs 	    (value == NULL))
4402264Sjacobs 		return (PAPI_BAD_ARGUMENT);
4412264Sjacobs 
4422264Sjacobs 	if (iter == NULL)
4432264Sjacobs 		iter = &fodder;
4442264Sjacobs 
4452264Sjacobs 	if ((iter == NULL) || (*iter == NULL)) {
4462264Sjacobs 		papi_attribute_t *attr = papiAttributeListFind(list, name);
4472264Sjacobs 
4482264Sjacobs 		if (attr == NULL)
4492264Sjacobs 			return (PAPI_NOT_FOUND);
4502264Sjacobs 
4512264Sjacobs 		if (attr->type != type)
4522264Sjacobs 			return (PAPI_NOT_POSSIBLE);
4532264Sjacobs 
4542264Sjacobs 		tmp = attr->values;
4552264Sjacobs 	} else
4562264Sjacobs 		tmp = *iter;
4572264Sjacobs 
4582264Sjacobs 	if (tmp == NULL)
4592264Sjacobs 		return (PAPI_NOT_FOUND);
4602264Sjacobs 
4612264Sjacobs 	*value = *tmp;
4622264Sjacobs 	*iter =  ++tmp;
4632264Sjacobs 
4642264Sjacobs 	if (*value == NULL)
4652264Sjacobs 		return (PAPI_GONE);
4662264Sjacobs 
4672264Sjacobs 	return (PAPI_OK);
4682264Sjacobs }
4692264Sjacobs 
4702264Sjacobs papi_status_t
4712264Sjacobs papiAttributeListGetString(papi_attribute_t **list, void **iter,
4722264Sjacobs 			char *name, char **vptr)
4732264Sjacobs {
4742264Sjacobs 	papi_status_t status;
4752264Sjacobs 	papi_attribute_value_t *value = NULL;
4762264Sjacobs 
4772264Sjacobs 	if (vptr == NULL)
4782264Sjacobs 		return (PAPI_BAD_ARGUMENT);
4792264Sjacobs 
4802264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
4812264Sjacobs 				PAPI_STRING, &value);
4822264Sjacobs 	if (status == PAPI_OK)
4832264Sjacobs 		*vptr = value->string;
4842264Sjacobs 
4852264Sjacobs 	return (status);
4862264Sjacobs }
4872264Sjacobs 
4882264Sjacobs papi_status_t
4892264Sjacobs papiAttributeListGetInteger(papi_attribute_t **list, void **iter,
4902264Sjacobs 			char *name, int *vptr)
4912264Sjacobs {
4922264Sjacobs 	papi_status_t status;
4932264Sjacobs 	papi_attribute_value_t *value = NULL;
4942264Sjacobs 
4952264Sjacobs 	if (vptr == NULL)
4962264Sjacobs 		return (PAPI_BAD_ARGUMENT);
4972264Sjacobs 
4982264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
4992264Sjacobs 				PAPI_INTEGER, &value);
5002264Sjacobs 	if (status == PAPI_OK)
5012264Sjacobs 		*vptr = value->integer;
5022264Sjacobs 
5032264Sjacobs 	return (status);
5042264Sjacobs }
5052264Sjacobs 
5062264Sjacobs papi_status_t
5072264Sjacobs papiAttributeListGetBoolean(papi_attribute_t **list, void **iter,
5082264Sjacobs 			char *name, char *vptr)
5092264Sjacobs {
5102264Sjacobs 	papi_status_t status;
5112264Sjacobs 	papi_attribute_value_t *value = NULL;
5122264Sjacobs 
5132264Sjacobs 	if (vptr == NULL)
5142264Sjacobs 		return (PAPI_BAD_ARGUMENT);
5152264Sjacobs 
5162264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
5172264Sjacobs 				PAPI_BOOLEAN, &value);
5182264Sjacobs 	if (status == PAPI_OK)
5192264Sjacobs 		*vptr = value->boolean;
5202264Sjacobs 
5212264Sjacobs 	return (status);
5222264Sjacobs }
5232264Sjacobs 
5242264Sjacobs papi_status_t
5252264Sjacobs papiAttributeListGetRange(papi_attribute_t **list, void **iter,
5262264Sjacobs 			char *name, int *min, int *max)
5272264Sjacobs {
5282264Sjacobs 	papi_status_t status;
5292264Sjacobs 	papi_attribute_value_t *value = NULL;
5302264Sjacobs 
5312264Sjacobs 	if ((min == NULL) || (max == NULL))
5322264Sjacobs 		return (PAPI_BAD_ARGUMENT);
5332264Sjacobs 
5342264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
5352264Sjacobs 				PAPI_RANGE, &value);
5362264Sjacobs 	if (status == PAPI_OK) {
5372264Sjacobs 		*min = value->range.lower;
5382264Sjacobs 		*max = value->range.upper;
5392264Sjacobs 	}
5402264Sjacobs 
5412264Sjacobs 	return (status);
5422264Sjacobs }
5432264Sjacobs 
5442264Sjacobs papi_status_t
5452264Sjacobs papiAttributeListGetResolution(papi_attribute_t **list, void **iter,
5462264Sjacobs 			char *name, int *x, int *y,
5472264Sjacobs 			papi_resolution_unit_t *units)
5482264Sjacobs {
5492264Sjacobs 	papi_status_t status;
5502264Sjacobs 	papi_attribute_value_t *value = NULL;
5512264Sjacobs 
5522264Sjacobs 	if ((x == NULL) || (y == NULL) || (units == NULL))
5532264Sjacobs 		return (PAPI_BAD_ARGUMENT);
5542264Sjacobs 
5552264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
5562264Sjacobs 				PAPI_RESOLUTION, &value);
5572264Sjacobs 	if (status == PAPI_OK) {
5582264Sjacobs 		*x = value->resolution.xres;
5592264Sjacobs 		*y = value->resolution.yres;
5602264Sjacobs 		*units = value->resolution.units;
5612264Sjacobs 	}
5622264Sjacobs 
5632264Sjacobs 	return (status);
5642264Sjacobs }
5652264Sjacobs 
5662264Sjacobs papi_status_t
5672264Sjacobs papiAttributeListGetDatetime(papi_attribute_t **list, void **iter,
5682264Sjacobs 			char *name, time_t *dt)
5692264Sjacobs {
5702264Sjacobs 	papi_status_t status;
5712264Sjacobs 	papi_attribute_value_t *value = NULL;
5722264Sjacobs 
5732264Sjacobs 	if (dt == NULL)
5742264Sjacobs 		return (PAPI_BAD_ARGUMENT);
5752264Sjacobs 
5762264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
5772264Sjacobs 				PAPI_DATETIME, &value);
5782264Sjacobs 	if (status == PAPI_OK) {
5792264Sjacobs 		*dt = value->datetime;
5802264Sjacobs 	}
5812264Sjacobs 
5822264Sjacobs 	return (status);
5832264Sjacobs }
5842264Sjacobs 
5852264Sjacobs papi_status_t
5862264Sjacobs papiAttributeListGetCollection(papi_attribute_t **list, void **iter,
5872264Sjacobs 			char *name, papi_attribute_t ***collection)
5882264Sjacobs {
5892264Sjacobs 	papi_status_t status;
5902264Sjacobs 	papi_attribute_value_t *value = NULL;
5912264Sjacobs 
5922264Sjacobs 	if (collection == NULL)
5932264Sjacobs 		return (PAPI_BAD_ARGUMENT);
5942264Sjacobs 
5952264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
5962264Sjacobs 				PAPI_COLLECTION, &value);
5972264Sjacobs 	if (status == PAPI_OK) {
5982264Sjacobs 		*collection = value->collection;
5992264Sjacobs 	}
6002264Sjacobs 
6012264Sjacobs 	return (status);
6022264Sjacobs }
6032264Sjacobs 
6042264Sjacobs papi_status_t
6052264Sjacobs papiAttributeListGetMetadata(papi_attribute_t **list, void **iter,
6062264Sjacobs 			char *name, papi_metadata_t *vptr)
6072264Sjacobs {
6082264Sjacobs 	papi_status_t status;
6092264Sjacobs 	papi_attribute_value_t *value = NULL;
6102264Sjacobs 
6112264Sjacobs 	if (vptr == NULL)
6122264Sjacobs 		return (PAPI_BAD_ARGUMENT);
6132264Sjacobs 
6142264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
6152264Sjacobs 				PAPI_METADATA, &value);
6162264Sjacobs 	if (status == PAPI_OK)
6172264Sjacobs 		*vptr = value->metadata;
6182264Sjacobs 
6192264Sjacobs 	return (status);
6202264Sjacobs }
6212264Sjacobs 
6222264Sjacobs 
623*6725Sjacobs /* The string is modified by this call */
6242264Sjacobs static char *
625*6725Sjacobs regvalue(regmatch_t match, char *string)
6262264Sjacobs {
6272264Sjacobs 	char *result = NULL;
628*6725Sjacobs 	if (match.rm_so != match.rm_eo) {
629*6725Sjacobs 		result = string + match.rm_so;
630*6725Sjacobs 		*(result + (match.rm_eo - match.rm_so)) = '\0';
631*6725Sjacobs 	}
632*6725Sjacobs 	return (result);
633*6725Sjacobs }
6342264Sjacobs 
635*6725Sjacobs static papi_attribute_value_type_t
636*6725Sjacobs _process_value(char *string, char ***parts)
637*6725Sjacobs {
638*6725Sjacobs 	int i;
639*6725Sjacobs 	static struct {
640*6725Sjacobs 		papi_attribute_value_type_t	type;
641*6725Sjacobs 		size_t vals;
642*6725Sjacobs 		char *expression;
643*6725Sjacobs 		int	compiled;
644*6725Sjacobs 		regex_t re;
645*6725Sjacobs 	} types[] = {
646*6725Sjacobs 		{ PAPI_BOOLEAN,	   1, "^(true|false|yes|no)$", 0 },
647*6725Sjacobs 		{ PAPI_COLLECTION, 1, "^\\{(.+)\\}$", 0 },
648*6725Sjacobs 		/* PAPI_DATETIME is unsupported, too much like an integer */
649*6725Sjacobs 		{ PAPI_INTEGER,	   1, "^([+-]{0,1}[[:digit:]]+)$", 0 },
650*6725Sjacobs 		{ PAPI_RANGE,	   3, "^([[:digit:]]+)-([[:digit:]]+)$", 0 },
651*6725Sjacobs 		{ PAPI_RESOLUTION, 4, "^([[:digit:]]+)x([[:digit:]]+)dp(i|c)$",
652*6725Sjacobs 			0 },
653*6725Sjacobs 		NULL
654*6725Sjacobs 	};
655*6725Sjacobs 	regmatch_t matches[4];
656*6725Sjacobs 
657*6725Sjacobs 	for (i = 0; i < 5; i++) {
658*6725Sjacobs 		int j;
659*6725Sjacobs 
660*6725Sjacobs 		if (types[i].compiled == 0) {
661*6725Sjacobs 			(void) regcomp(&(types[i].re), types[i].expression,
662*6725Sjacobs 						REG_EXTENDED|REG_ICASE);
663*6725Sjacobs 			types[i].compiled = 1;
6642264Sjacobs 		}
665*6725Sjacobs 		if (regexec(&(types[i].re), string, (size_t)types[i].vals,
666*6725Sjacobs 				matches, 0) == REG_NOMATCH)
667*6725Sjacobs 			continue;
668*6725Sjacobs 
669*6725Sjacobs 		for (j = 0 ; j < types[i].vals; j++)
670*6725Sjacobs 			list_append(parts, regvalue(matches[j], string));
671*6725Sjacobs 		return (types[i].type);
672*6725Sjacobs 	}
6732264Sjacobs 
674*6725Sjacobs 	list_append(parts, string);
675*6725Sjacobs 	return (PAPI_STRING);
676*6725Sjacobs }
677*6725Sjacobs 
678*6725Sjacobs static void
679*6725Sjacobs _add_attribute_value(papi_attribute_value_t ***list,
680*6725Sjacobs 			papi_attribute_value_type_t type,
681*6725Sjacobs 			papi_attribute_value_type_t dtype, char **parts)
682*6725Sjacobs {
683*6725Sjacobs 	papi_attribute_value_t *value = calloc(1, sizeof (*value));
6842264Sjacobs 
685*6725Sjacobs 	switch(type) {
686*6725Sjacobs 	case PAPI_STRING:
687*6725Sjacobs 		value->string = strdup(parts[0]);
688*6725Sjacobs 		list_append(list, value);
689*6725Sjacobs 		break;
690*6725Sjacobs 	case PAPI_BOOLEAN:
691*6725Sjacobs 		value->boolean = PAPI_TRUE;
692*6725Sjacobs 		if ((strcasecmp(parts[0], "false") == 0) ||
693*6725Sjacobs 		    (strcasecmp(parts[0], "no") == 0))
694*6725Sjacobs 			value->boolean = PAPI_FALSE;
695*6725Sjacobs 		list_append(list, value);
696*6725Sjacobs 		break;
697*6725Sjacobs 	case PAPI_INTEGER:
698*6725Sjacobs 		value->integer = atoi(parts[0]);
699*6725Sjacobs 		list_append(list, value);
700*6725Sjacobs 		break;
701*6725Sjacobs 	case PAPI_RANGE:
702*6725Sjacobs 		if (dtype == PAPI_INTEGER)
703*6725Sjacobs 			value->range.lower = value->range.upper
704*6725Sjacobs 					 = atoi(parts[0]);
705*6725Sjacobs 		else if (dtype == PAPI_RANGE)  {
706*6725Sjacobs 			value->range.lower = atoi(parts[1]);
707*6725Sjacobs 			value->range.upper = atoi(parts[2]);
7082264Sjacobs 		}
709*6725Sjacobs 		list_append(list, value);
710*6725Sjacobs 		break;
711*6725Sjacobs 	case PAPI_RESOLUTION:
712*6725Sjacobs 		value->resolution.xres = atoi(parts[1]);
713*6725Sjacobs 		value->resolution.yres = atoi(parts[2]);
714*6725Sjacobs 		if (parts[3][0] == 'i')
715*6725Sjacobs 			value->resolution.units = PAPI_RES_PER_INCH;
716*6725Sjacobs 		else
717*6725Sjacobs 			value->resolution.units = PAPI_RES_PER_CM;
718*6725Sjacobs 		list_append(list, value);
719*6725Sjacobs 		break;
720*6725Sjacobs 	case PAPI_COLLECTION:
721*6725Sjacobs 		papiAttributeListFromString(&(value->collection), 0, parts[0]);
722*6725Sjacobs 		list_append(list, value);
723*6725Sjacobs 		break;
724*6725Sjacobs 	}
725*6725Sjacobs }
7262264Sjacobs 
727*6725Sjacobs static papi_status_t
728*6725Sjacobs _papiAttributeFromStrings(papi_attribute_t ***list, int flags,
729*6725Sjacobs 			char *key, char **values)
730*6725Sjacobs {
731*6725Sjacobs 	int i;
732*6725Sjacobs 	papi_status_t result = PAPI_OK;
733*6725Sjacobs 	papi_attribute_t *attr = calloc(1, sizeof (*attr));
734*6725Sjacobs 
735*6725Sjacobs 	/* these are specified in the papi spec as ranges */
736*6725Sjacobs 	char *ranges[] = { "copies-supported", "job-impressions-supported",
737*6725Sjacobs 				"job-k-octets-supported",
738*6725Sjacobs 				"job-media-sheets-supported", "page-ranges",
739*6725Sjacobs 				NULL };
740*6725Sjacobs 
741*6725Sjacobs 	if ((attr == NULL) || ((attr->name = strdup(key)) == NULL))
742*6725Sjacobs 		return (PAPI_TEMPORARY_ERROR);
743*6725Sjacobs 
744*6725Sjacobs 	attr->type = PAPI_METADATA;
745*6725Sjacobs 	/* these are known ranges */
746*6725Sjacobs 	for (i = 0; ranges[i] != NULL; i++)
747*6725Sjacobs 		if (strcasecmp(attr->name, ranges[i]) == 0) {
748*6725Sjacobs 			attr->type = PAPI_RANGE;
749*6725Sjacobs 			break;
750*6725Sjacobs 	}
751*6725Sjacobs 
752*6725Sjacobs 	if (values != NULL) {
753*6725Sjacobs 		papi_attribute_value_t **vals = NULL;
754*6725Sjacobs 
755*6725Sjacobs 		for (i = 0; values[i] != NULL; i++) {
756*6725Sjacobs 			papi_attribute_value_type_t dtype;
757*6725Sjacobs 			char **parts = NULL;
758*6725Sjacobs 
759*6725Sjacobs 			dtype = _process_value(values[i], &parts);
760*6725Sjacobs 			if (attr->type == PAPI_METADATA)
761*6725Sjacobs 				attr->type = dtype;
762*6725Sjacobs 			_add_attribute_value(&vals, attr->type, dtype, parts);
763*6725Sjacobs 			free(parts);
7642264Sjacobs 		}
765*6725Sjacobs 		attr->values = vals;
766*6725Sjacobs 	}
767*6725Sjacobs 
768*6725Sjacobs 	list_append(list, attr);
769*6725Sjacobs 
770*6725Sjacobs 	return (result);
771*6725Sjacobs }
7722264Sjacobs 
773*6725Sjacobs static papi_status_t
774*6725Sjacobs _parse_attribute_list(papi_attribute_t ***list, int flags, char *string)
775*6725Sjacobs {
776*6725Sjacobs 	papi_status_t result = PAPI_OK;
777*6725Sjacobs 	char *ptr;
778*6725Sjacobs 
779*6725Sjacobs 	if ((list == NULL) || (string == NULL))
780*6725Sjacobs 		return (PAPI_BAD_ARGUMENT);
781*6725Sjacobs 
782*6725Sjacobs 	if ((ptr = strdup(string)) == NULL)
783*6725Sjacobs 		return (PAPI_TEMPORARY_ERROR);
784*6725Sjacobs 
785*6725Sjacobs 	while ((*ptr != '\0') && (result == PAPI_OK)) {
786*6725Sjacobs 		char *key, **values = NULL;
787*6725Sjacobs 
788*6725Sjacobs 		/* strip any leading whitespace */
789*6725Sjacobs 		while (isspace(*ptr) != 0)
790*6725Sjacobs 			ptr++;
791*6725Sjacobs 
792*6725Sjacobs 		/* Get the name: name[=value] */
793*6725Sjacobs 		key = ptr;
794*6725Sjacobs 		while ((*ptr != '\0') && (*ptr != '=') && (isspace(*ptr) == 0))
795*6725Sjacobs 			ptr++;
796*6725Sjacobs 
797*6725Sjacobs 		if (*ptr == '=') {
798*6725Sjacobs 			*ptr++ = '\0';
799*6725Sjacobs 
800*6725Sjacobs 			while ((*ptr != '\0') && (isspace(*ptr) == 0)) {
801*6725Sjacobs 				char *value = ptr;
802*6725Sjacobs 
803*6725Sjacobs 				if ((*ptr == '\'') || (*ptr == '"')) {
804*6725Sjacobs 					char q = *ptr++;
8052264Sjacobs 
806*6725Sjacobs 					/* quoted string value */
807*6725Sjacobs 					while ((*ptr != '\0') && (*ptr != q))
808*6725Sjacobs 						ptr++;
809*6725Sjacobs 					if (*ptr == q)
810*6725Sjacobs 						ptr++;
811*6725Sjacobs 				} else if (*ptr == '{') {
812*6725Sjacobs 					/* collection */
813*6725Sjacobs 					while ((*ptr != '\0') && (*ptr != '}'))
814*6725Sjacobs 						ptr++;
815*6725Sjacobs 					if (*ptr == '}')
816*6725Sjacobs 						ptr++;
817*6725Sjacobs 				} else {
818*6725Sjacobs 					/* value */
819*6725Sjacobs 					while ((*ptr != '\0') &&
820*6725Sjacobs 					       (*ptr != ',') &&
821*6725Sjacobs 					       (isspace(*ptr) == 0))
822*6725Sjacobs 						ptr++;
823*6725Sjacobs 				}
824*6725Sjacobs 				if (*ptr == ',')
825*6725Sjacobs 					*ptr++ = '\0';
826*6725Sjacobs 				list_append(&values, value);
8272264Sjacobs 			}
828*6725Sjacobs 		} else { /* boolean "[no]key" */
829*6725Sjacobs 			char *value = "true";
830*6725Sjacobs 
831*6725Sjacobs 			if (strncasecmp(key, "no", 2) == 0) {
832*6725Sjacobs 				key += 2;
833*6725Sjacobs 				value = "false";
834*6725Sjacobs 			}
835*6725Sjacobs 			list_append(&values, value);
8362264Sjacobs 		}
837*6725Sjacobs 		if (*ptr != '\0')
838*6725Sjacobs 			*ptr++ = '\0';
839*6725Sjacobs 
840*6725Sjacobs 		result = _papiAttributeFromStrings(list, flags, key, values);
841*6725Sjacobs 		free(values);
8422264Sjacobs 	}
8432264Sjacobs 
8442264Sjacobs 	return (result);
845*6725Sjacobs }
8462264Sjacobs 
8472264Sjacobs papi_status_t
8482264Sjacobs papiAttributeListFromString(papi_attribute_t ***attrs,
8492264Sjacobs 		int flags, char *string)
8502264Sjacobs {
8512264Sjacobs 	papi_status_t result = PAPI_OK;
8522264Sjacobs 
8532264Sjacobs 	if ((attrs != NULL) && (string != NULL) &&
8542264Sjacobs 	    ((flags & ~(PAPI_ATTR_APPEND+PAPI_ATTR_REPLACE+PAPI_ATTR_EXCL))
8552264Sjacobs 			== 0)) {
856*6725Sjacobs 		result = _parse_attribute_list(attrs, flags, string);
857*6725Sjacobs 	} else {
8582264Sjacobs 		result = PAPI_BAD_ARGUMENT;
8592264Sjacobs 	}
8602264Sjacobs 
8612264Sjacobs 	return (result);
8622264Sjacobs }
8632264Sjacobs 
8642264Sjacobs static papi_status_t
8652264Sjacobs papiAttributeToString(papi_attribute_t *attribute, char *delim,
8662264Sjacobs 		char *buffer, size_t buflen)
8672264Sjacobs {
8682264Sjacobs 	papi_attribute_value_t **values = attribute->values;
8692264Sjacobs 	int rc, i;
8702264Sjacobs 
871*6725Sjacobs 	if ((attribute->type == PAPI_BOOLEAN) && (values[1] == NULL)) {
872*6725Sjacobs 		if (values[0]->boolean == PAPI_FALSE) {
873*6725Sjacobs 			if (isupper(attribute->name[0]) == 0)
874*6725Sjacobs 				strlcat(buffer, "no", buflen);
875*6725Sjacobs 			else
876*6725Sjacobs 				strlcat(buffer, "No", buflen);
877*6725Sjacobs 		}
878*6725Sjacobs 		rc = strlcat(buffer, attribute->name, buflen);
879*6725Sjacobs 	} else {
880*6725Sjacobs 		strlcat(buffer, attribute->name, buflen);
881*6725Sjacobs 		rc = strlcat(buffer, "=", buflen);
882*6725Sjacobs 	}
8832264Sjacobs 
8842264Sjacobs 	if (values == NULL)
8852264Sjacobs 		return (PAPI_OK);
8862264Sjacobs 
8872264Sjacobs 	for (i = 0; values[i] != NULL; i++) {
8882264Sjacobs 		switch (attribute->type) {
8892264Sjacobs 		case PAPI_STRING:
8902264Sjacobs 			rc = strlcat(buffer, values[i]->string, buflen);
8912264Sjacobs 			break;
8922264Sjacobs 		case PAPI_INTEGER: {
8932264Sjacobs 			char string[24];
8942264Sjacobs 
8952264Sjacobs 			snprintf(string, sizeof (string), "%d",
8962264Sjacobs 				values[i]->integer);
8972264Sjacobs 			rc = strlcat(buffer, string, buflen);
8982264Sjacobs 			}
8992264Sjacobs 			break;
9002264Sjacobs 		case PAPI_BOOLEAN:
901*6725Sjacobs 			if (values[1] != NULL)
902*6725Sjacobs 				rc = strlcat(buffer, (values[i]->boolean ?
903*6725Sjacobs 						"true" : "false"), buflen);
9042264Sjacobs 			break;
9052264Sjacobs 		case PAPI_RANGE: {
9062264Sjacobs 			char string[24];
9072264Sjacobs 
908*6725Sjacobs 			if (values[i]->range.lower == values[i]->range.upper)
909*6725Sjacobs 				snprintf(string, sizeof (string), "%d",
910*6725Sjacobs 						values[i]->range.lower);
911*6725Sjacobs 			else
912*6725Sjacobs 				snprintf(string, sizeof (string), "%d-%d",
913*6725Sjacobs 						values[i]->range.lower,
914*6725Sjacobs 						values[i]->range.upper);
9152264Sjacobs 			rc = strlcat(buffer, string, buflen);
9162264Sjacobs 			}
9172264Sjacobs 			break;
9182264Sjacobs 		case PAPI_RESOLUTION: {
9192264Sjacobs 			char string[24];
9202264Sjacobs 
9212264Sjacobs 			snprintf(string, sizeof (string), "%dx%ddp%c",
9222264Sjacobs 				values[i]->resolution.xres,
9232264Sjacobs 				values[i]->resolution.yres,
9242264Sjacobs 				(values[i]->resolution.units == PAPI_RES_PER_CM
9252264Sjacobs 							? 'c' : 'i'));
9262264Sjacobs 			rc = strlcat(buffer, string, buflen);
9272264Sjacobs 			}
9282264Sjacobs 			break;
9292264Sjacobs 		case PAPI_DATETIME: {
9302264Sjacobs 			struct tm *tm = localtime(&values[i]->datetime);
9312264Sjacobs 
9322264Sjacobs 			if (tm != NULL) {
9332264Sjacobs 				char string[64];
9342264Sjacobs 
9352264Sjacobs 				strftime(string, sizeof (string), "%C", tm);
9362264Sjacobs 				rc = strlcat(buffer, string, buflen);
9372264Sjacobs 			}}
9382264Sjacobs 			break;
9392264Sjacobs 		case PAPI_COLLECTION: {
9402264Sjacobs 			char *string = alloca(buflen);
9412264Sjacobs 
9422264Sjacobs 			papiAttributeListToString(values[i]->collection,
9432264Sjacobs 					delim, string, buflen);
9442264Sjacobs 			rc = strlcat(buffer, string, buflen);
9452264Sjacobs 			}
9462264Sjacobs 			break;
9472264Sjacobs 		default: {
9482264Sjacobs 			char string[32];
9492264Sjacobs 
9502264Sjacobs 			snprintf(string, sizeof (string), "unknown-type-0x%x",
9512264Sjacobs 				attribute->type);
9522264Sjacobs 			rc = strlcat(buffer, string, buflen);
9532264Sjacobs 			}
9542264Sjacobs 		}
9552264Sjacobs 		if (values[i+1] != NULL)
9562264Sjacobs 			rc = strlcat(buffer, ",", buflen);
9572264Sjacobs 
9582264Sjacobs 		if (rc >= buflen)
9592264Sjacobs 			return (PAPI_NOT_POSSIBLE);
9602264Sjacobs 
9612264Sjacobs 	}
9622264Sjacobs 
9632264Sjacobs 	return (PAPI_OK);
9642264Sjacobs }
9652264Sjacobs 
9662264Sjacobs papi_status_t
9672264Sjacobs papiAttributeListToString(papi_attribute_t **attrs,
9682264Sjacobs 		char *delim, char *buffer, size_t buflen)
9692264Sjacobs {
9702264Sjacobs 	papi_status_t status = PAPI_OK;
9712264Sjacobs 	int i;
9722264Sjacobs 
9732264Sjacobs 	if ((attrs == NULL) || (buffer == NULL))
9742264Sjacobs 		return (PAPI_BAD_ARGUMENT);
9752264Sjacobs 
9762264Sjacobs 	buffer[0] = '\0';
9772264Sjacobs 	if (!delim)
9782264Sjacobs 		delim = " ";
9792264Sjacobs 
9802264Sjacobs 	for (i = 0; ((attrs[i] != NULL) && (status == PAPI_OK)); i++) {
9812264Sjacobs 		status = papiAttributeToString(attrs[i], delim, buffer, buflen);
9822264Sjacobs 		if (attrs[i+1] != NULL)
9832264Sjacobs 			strlcat(buffer, delim, buflen);
9842264Sjacobs 	}
9852264Sjacobs 
9862264Sjacobs 	return (status);
9872264Sjacobs }
9882264Sjacobs 
9892264Sjacobs static int
9902264Sjacobs is_in_list(char *value, char **list)
9912264Sjacobs {
9922264Sjacobs 	if ((list != NULL) && (value != NULL)) {
9932264Sjacobs 		int i;
9942264Sjacobs 
9952264Sjacobs 		for (i = 0; list[i] != NULL; i++)
9962264Sjacobs 			if (strcasecmp(value, list[i]) == 0)
9972264Sjacobs 				return (0);
9982264Sjacobs 	}
9992264Sjacobs 
10002264Sjacobs 	return (1);
10012264Sjacobs }
10022264Sjacobs 
10032264Sjacobs static papi_status_t
10042264Sjacobs copy_attribute(papi_attribute_t ***list, papi_attribute_t *attribute)
10052264Sjacobs {
10062264Sjacobs 	papi_status_t status;
10072264Sjacobs 	int i = 0;
10082264Sjacobs 
10092264Sjacobs 	if ((list == NULL) || (attribute == NULL) ||
10102264Sjacobs 	    (attribute->values == NULL))
10112264Sjacobs 		return (PAPI_BAD_ARGUMENT);
10122264Sjacobs 
10132264Sjacobs 	for (status = papiAttributeListAddValue(list, PAPI_ATTR_EXCL,
10142264Sjacobs 					attribute->name, attribute->type,
10152264Sjacobs 					attribute->values[i]);
10162264Sjacobs 	     ((status == PAPI_OK) && (attribute->values[i] != NULL));
10172264Sjacobs 	     status = papiAttributeListAddValue(list, PAPI_ATTR_APPEND,
10182264Sjacobs 					attribute->name, attribute->type,
10192264Sjacobs 					attribute->values[i]))
10202264Sjacobs 		i++;
10212264Sjacobs 
10222264Sjacobs 	return (status);
10232264Sjacobs }
10242264Sjacobs 
10252264Sjacobs void
10262264Sjacobs copy_attributes(papi_attribute_t ***result, papi_attribute_t **attributes)
10272264Sjacobs {
10282264Sjacobs 	int i;
10292264Sjacobs 
10302264Sjacobs 	if ((result == NULL) || (attributes == NULL))
10312264Sjacobs 		return;
10322264Sjacobs 
10332264Sjacobs 	for (i = 0; attributes[i] != NULL; i++)
10342264Sjacobs 		copy_attribute(result, attributes[i]);
10352264Sjacobs }
10362264Sjacobs 
10372264Sjacobs void
10382264Sjacobs split_and_copy_attributes(char **list, papi_attribute_t **attributes,
10392264Sjacobs 		papi_attribute_t ***in, papi_attribute_t ***out)
10402264Sjacobs {
10412264Sjacobs 	int i;
10422264Sjacobs 
10432264Sjacobs 	if ((list == NULL) || (attributes == NULL))
10442264Sjacobs 		return;
10452264Sjacobs 
10462264Sjacobs 	for (i = 0; attributes[i] != NULL; i++)
10472264Sjacobs 		if (is_in_list(attributes[i]->name, list) == 0)
10482264Sjacobs 			copy_attribute(in, attributes[i]);
10492264Sjacobs 		else
10502264Sjacobs 			copy_attribute(out, attributes[i]);
10512264Sjacobs }
10522264Sjacobs 
10532264Sjacobs void
10542264Sjacobs papiAttributeListPrint(FILE *fp, papi_attribute_t **attributes,
10552264Sjacobs 		char *prefix_fmt, ...)
10562264Sjacobs {
10572264Sjacobs 	char *prefix = NULL;
10582264Sjacobs 	char *buffer = NULL;
10592264Sjacobs 	char *newfmt = NULL;
10602264Sjacobs 	void *mem;
10612264Sjacobs 	ssize_t size = 0;
10622264Sjacobs 	va_list ap;
10632264Sjacobs 
10642264Sjacobs 	newfmt = malloc(strlen(prefix_fmt) + 2);
10652264Sjacobs 	sprintf(newfmt, "\n%s", prefix_fmt);
10662264Sjacobs 
10672264Sjacobs 	va_start(ap, prefix_fmt);
10682264Sjacobs 	while (vsnprintf(prefix, size, newfmt, ap) > size) {
10692264Sjacobs 		size += 1024;
10702264Sjacobs 		mem = realloc(prefix, size);
10712264Sjacobs 		if (!mem) goto error;
10722264Sjacobs 		prefix = mem;
10732264Sjacobs 	}
10742264Sjacobs 	va_end(ap);
10752264Sjacobs 
10762264Sjacobs 	if (attributes) {
10772264Sjacobs 		size = 0;
10782264Sjacobs 		while (papiAttributeListToString(attributes, prefix, buffer,
10792264Sjacobs 						size) != PAPI_OK) {
10802264Sjacobs 			size += 1024;
10812264Sjacobs 			mem = realloc(buffer, size);
10822264Sjacobs 			if (!mem) goto error;
10832264Sjacobs 			buffer = mem;
10842264Sjacobs 		}
10852264Sjacobs 	}
10862264Sjacobs 
10872264Sjacobs 	fprintf(fp, "%s%s\n", prefix, buffer ? buffer : "");
10882264Sjacobs 	fflush(fp);
10892264Sjacobs 
10902264Sjacobs  error:
10912264Sjacobs 	free(newfmt);
10922264Sjacobs 	free(prefix);
10932264Sjacobs 	free(buffer);
10942264Sjacobs }
1095