1*2264Sjacobs /*
2*2264Sjacobs  * CDDL HEADER START
3*2264Sjacobs  *
4*2264Sjacobs  * The contents of this file are subject to the terms of the
5*2264Sjacobs  * Common Development and Distribution License (the "License").
6*2264Sjacobs  * You may not use this file except in compliance with the License.
7*2264Sjacobs  *
8*2264Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2264Sjacobs  * or http://www.opensolaris.org/os/licensing.
10*2264Sjacobs  * See the License for the specific language governing permissions
11*2264Sjacobs  * and limitations under the License.
12*2264Sjacobs  *
13*2264Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
14*2264Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2264Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
16*2264Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
17*2264Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2264Sjacobs  *
19*2264Sjacobs  * CDDL HEADER END
20*2264Sjacobs  */
21*2264Sjacobs 
22*2264Sjacobs /*
23*2264Sjacobs  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*2264Sjacobs  * Use is subject to license terms.
25*2264Sjacobs  *
26*2264Sjacobs  */
27*2264Sjacobs 
28*2264Sjacobs /* $Id: attribute.c 157 2006-04-26 15:07:55Z ktou $ */
29*2264Sjacobs 
30*2264Sjacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*2264Sjacobs 
32*2264Sjacobs /*LINTLIBRARY*/
33*2264Sjacobs 
34*2264Sjacobs #include <stdio.h>
35*2264Sjacobs #include <stdlib.h>
36*2264Sjacobs #include <stdarg.h>
37*2264Sjacobs #include <string.h>
38*2264Sjacobs #include <alloca.h>
39*2264Sjacobs #include <papi.h>
40*2264Sjacobs 
41*2264Sjacobs static void papiAttributeFree(papi_attribute_t *attribute);
42*2264Sjacobs 
43*2264Sjacobs static void
44*2264Sjacobs papiAttributeValueFree(papi_attribute_value_type_t type,
45*2264Sjacobs 		    papi_attribute_value_t *value)
46*2264Sjacobs {
47*2264Sjacobs 	if (value != NULL) {
48*2264Sjacobs 		switch (type) {
49*2264Sjacobs 		case PAPI_STRING:
50*2264Sjacobs 			if (value->string != NULL)
51*2264Sjacobs 				free(value->string);
52*2264Sjacobs 			break;
53*2264Sjacobs 		case PAPI_COLLECTION:
54*2264Sjacobs 			if (value->collection != NULL) {
55*2264Sjacobs 				int i;
56*2264Sjacobs 
57*2264Sjacobs 				for (i = 0; value->collection[i] != NULL; i++)
58*2264Sjacobs 					papiAttributeFree(value->collection[i]);
59*2264Sjacobs 
60*2264Sjacobs 				free(value->collection);
61*2264Sjacobs 			}
62*2264Sjacobs 			break;
63*2264Sjacobs 		default: /* don't need to free anything extra */
64*2264Sjacobs 			break;
65*2264Sjacobs 		}
66*2264Sjacobs 
67*2264Sjacobs 		free(value);
68*2264Sjacobs 	}
69*2264Sjacobs }
70*2264Sjacobs 
71*2264Sjacobs static void
72*2264Sjacobs papiAttributeValuesFree(papi_attribute_value_type_t type,
73*2264Sjacobs 		    papi_attribute_value_t **values)
74*2264Sjacobs {
75*2264Sjacobs 	if (values != NULL) {
76*2264Sjacobs 		int i;
77*2264Sjacobs 
78*2264Sjacobs 		for (i = 0; values[i] != NULL; i++)
79*2264Sjacobs 			papiAttributeValueFree(type, values[i]);
80*2264Sjacobs 
81*2264Sjacobs 		free(values);
82*2264Sjacobs 	}
83*2264Sjacobs }
84*2264Sjacobs 
85*2264Sjacobs static void
86*2264Sjacobs papiAttributeFree(papi_attribute_t *attribute)
87*2264Sjacobs {
88*2264Sjacobs 	if (attribute != NULL) {
89*2264Sjacobs 		if (attribute->name != NULL)
90*2264Sjacobs 			free(attribute->name);
91*2264Sjacobs 		if (attribute->values != NULL)
92*2264Sjacobs 			papiAttributeValuesFree(attribute->type,
93*2264Sjacobs 						attribute->values);
94*2264Sjacobs 			free(attribute);
95*2264Sjacobs 	}
96*2264Sjacobs }
97*2264Sjacobs 
98*2264Sjacobs void
99*2264Sjacobs papiAttributeListFree(papi_attribute_t **list)
100*2264Sjacobs {
101*2264Sjacobs 	if (list != NULL) {
102*2264Sjacobs 		int i;
103*2264Sjacobs 
104*2264Sjacobs 		for (i = 0; list[i] != NULL; i++)
105*2264Sjacobs 			papiAttributeFree(list[i]);
106*2264Sjacobs 
107*2264Sjacobs 		free(list);
108*2264Sjacobs 	}
109*2264Sjacobs }
110*2264Sjacobs 
111*2264Sjacobs static papi_attribute_t **
112*2264Sjacobs collection_dup(papi_attribute_t **collection)
113*2264Sjacobs {
114*2264Sjacobs 	papi_attribute_t **result = NULL;
115*2264Sjacobs 
116*2264Sjacobs 	/* allows a NULL collection that is "empty" or "no value" */
117*2264Sjacobs 	if (collection != NULL) {
118*2264Sjacobs 		papi_status_t status = PAPI_OK;
119*2264Sjacobs 		int i;
120*2264Sjacobs 
121*2264Sjacobs 		for (i = 0; ((collection[i] != NULL) && (status == PAPI_OK));
122*2264Sjacobs 		     i++) {
123*2264Sjacobs 			papi_attribute_t *a = collection[i];
124*2264Sjacobs 
125*2264Sjacobs 			status = papiAttributeListAddValue(&result,
126*2264Sjacobs 					PAPI_ATTR_APPEND, a->name, a->type,
127*2264Sjacobs 					NULL);
128*2264Sjacobs 			if ((status == PAPI_OK) && (a->values != NULL)) {
129*2264Sjacobs 				int j;
130*2264Sjacobs 
131*2264Sjacobs 				for (j = 0; ((a->values[j] != NULL) &&
132*2264Sjacobs 					     (status == PAPI_OK)); j++)
133*2264Sjacobs 					status = papiAttributeListAddValue(
134*2264Sjacobs 							&result,
135*2264Sjacobs 							PAPI_ATTR_APPEND,
136*2264Sjacobs 							a->name, a->type,
137*2264Sjacobs 							a->values[j]);
138*2264Sjacobs 			}
139*2264Sjacobs 		}
140*2264Sjacobs 		if (status != PAPI_OK) {
141*2264Sjacobs 			papiAttributeListFree(result);
142*2264Sjacobs 			result = NULL;
143*2264Sjacobs 		}
144*2264Sjacobs 	}
145*2264Sjacobs 
146*2264Sjacobs 	return (result);
147*2264Sjacobs }
148*2264Sjacobs 
149*2264Sjacobs static papi_attribute_value_t *
150*2264Sjacobs papiAttributeValueDup(papi_attribute_value_type_t type,
151*2264Sjacobs 		papi_attribute_value_t *v)
152*2264Sjacobs {
153*2264Sjacobs 	papi_attribute_value_t *result = NULL;
154*2264Sjacobs 
155*2264Sjacobs 	if ((v != NULL) && ((result = calloc(1, sizeof (*result))) != NULL)) {
156*2264Sjacobs 		switch (type) {
157*2264Sjacobs 		case PAPI_STRING:
158*2264Sjacobs 			if (v->string == NULL) {
159*2264Sjacobs 				free(result);
160*2264Sjacobs 				result = NULL;
161*2264Sjacobs 			} else
162*2264Sjacobs 				result->string = strdup(v->string);
163*2264Sjacobs 			break;
164*2264Sjacobs 		case PAPI_INTEGER:
165*2264Sjacobs 			result->integer = v->integer;
166*2264Sjacobs 			break;
167*2264Sjacobs 		case PAPI_BOOLEAN:
168*2264Sjacobs 			result->boolean = v->boolean;
169*2264Sjacobs 			break;
170*2264Sjacobs 		case PAPI_RANGE:
171*2264Sjacobs 			result->range.lower = v->range.lower;
172*2264Sjacobs 			result->range.upper = v->range.upper;
173*2264Sjacobs 			break;
174*2264Sjacobs 		case PAPI_RESOLUTION:
175*2264Sjacobs 			result->resolution.xres = v->resolution.xres;
176*2264Sjacobs 			result->resolution.yres = v->resolution.yres;
177*2264Sjacobs 			result->resolution.units = v->resolution.units;
178*2264Sjacobs 			break;
179*2264Sjacobs 		case PAPI_DATETIME:
180*2264Sjacobs 			result->datetime = v->datetime;
181*2264Sjacobs 			break;
182*2264Sjacobs 		case PAPI_COLLECTION:
183*2264Sjacobs 			result->collection = collection_dup(v->collection);
184*2264Sjacobs 			break;
185*2264Sjacobs 		case PAPI_METADATA:
186*2264Sjacobs 			result->metadata = v->metadata;
187*2264Sjacobs 			break;
188*2264Sjacobs 		default:	/* unknown type, fail to duplicate */
189*2264Sjacobs 			free(result);
190*2264Sjacobs 			result = NULL;
191*2264Sjacobs 		}
192*2264Sjacobs 	}
193*2264Sjacobs 
194*2264Sjacobs 	return (result);
195*2264Sjacobs }
196*2264Sjacobs 
197*2264Sjacobs static papi_attribute_t *
198*2264Sjacobs papiAttributeAlloc(char *name, papi_attribute_value_type_t type)
199*2264Sjacobs {
200*2264Sjacobs 	papi_attribute_t *result = NULL;
201*2264Sjacobs 
202*2264Sjacobs 	if ((result = calloc(1, sizeof (*result))) != NULL) {
203*2264Sjacobs 		result->name = strdup(name);
204*2264Sjacobs 		result->type = type;
205*2264Sjacobs 	}
206*2264Sjacobs 
207*2264Sjacobs 	return (result);
208*2264Sjacobs }
209*2264Sjacobs 
210*2264Sjacobs static papi_status_t
211*2264Sjacobs papiAttributeListAppendValue(papi_attribute_value_t ***values,
212*2264Sjacobs 		papi_attribute_value_type_t type,
213*2264Sjacobs 		papi_attribute_value_t *value)
214*2264Sjacobs {
215*2264Sjacobs 
216*2264Sjacobs 	if (values == NULL)
217*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
218*2264Sjacobs 
219*2264Sjacobs 	if (value != NULL) {	/* this allows "empty" attributes */
220*2264Sjacobs 		papi_attribute_value_t *tmp = NULL;
221*2264Sjacobs 
222*2264Sjacobs 		if ((tmp = papiAttributeValueDup(type, value)) == NULL)
223*2264Sjacobs 			return (PAPI_TEMPORARY_ERROR);
224*2264Sjacobs 
225*2264Sjacobs 		list_append(values, tmp);
226*2264Sjacobs 	}
227*2264Sjacobs 
228*2264Sjacobs 	return (PAPI_OK);
229*2264Sjacobs }
230*2264Sjacobs 
231*2264Sjacobs papi_status_t
232*2264Sjacobs papiAttributeListAddValue(papi_attribute_t ***list, int flgs,
233*2264Sjacobs 		char *name, papi_attribute_value_type_t type,
234*2264Sjacobs 		papi_attribute_value_t *value)
235*2264Sjacobs {
236*2264Sjacobs 	papi_status_t result;
237*2264Sjacobs 	int flags = flgs;
238*2264Sjacobs 	papi_attribute_t *attribute = NULL;
239*2264Sjacobs 	papi_attribute_value_t **values = NULL;
240*2264Sjacobs 
241*2264Sjacobs 	if ((list == NULL) || (name == NULL))
242*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
243*2264Sjacobs 
244*2264Sjacobs 	if ((type == PAPI_RANGE) && (value != NULL) &&
245*2264Sjacobs 	    (value->range.lower > value->range.upper))
246*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);	/* RANGE must have min <= max */
247*2264Sjacobs 
248*2264Sjacobs 	if (flags == 0) /* if it wasn't set, set a default behaviour */
249*2264Sjacobs 		flags = PAPI_ATTR_APPEND;
250*2264Sjacobs 
251*2264Sjacobs 	/* look for an existing one */
252*2264Sjacobs 	attribute = papiAttributeListFind(*list, name);
253*2264Sjacobs 
254*2264Sjacobs 	if (((flags & PAPI_ATTR_EXCL) != 0) && (attribute != NULL))
255*2264Sjacobs 		return (PAPI_CONFLICT); /* EXISTS */
256*2264Sjacobs 
257*2264Sjacobs 	if (((flags & PAPI_ATTR_REPLACE) == 0) && (attribute != NULL) &&
258*2264Sjacobs 	    (attribute->type != type))
259*2264Sjacobs 		return (PAPI_CONFLICT); /* TYPE CONFLICT */
260*2264Sjacobs 
261*2264Sjacobs 	/* if we don't have one, create it and add it to the list */
262*2264Sjacobs 	if ((attribute == NULL) &&
263*2264Sjacobs 	    ((attribute = papiAttributeAlloc(name, type)) != NULL))
264*2264Sjacobs 		list_append(list, attribute);
265*2264Sjacobs 
266*2264Sjacobs 	/* if we don't have one by now, it's most likely an alloc fail */
267*2264Sjacobs 	if (attribute == NULL)
268*2264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
269*2264Sjacobs 
270*2264Sjacobs 	/*
271*2264Sjacobs 	 * if we are replacing, clear any existing values, but don't free
272*2264Sjacobs 	 * until after we have replaced the values, in case we are replacing
273*2264Sjacobs 	 * a collection with a relocated version of the original collection.
274*2264Sjacobs 	 */
275*2264Sjacobs 	if (((flags & PAPI_ATTR_REPLACE) != 0) && (attribute->values != NULL)) {
276*2264Sjacobs 		values = attribute->values;
277*2264Sjacobs 		attribute->values = NULL;
278*2264Sjacobs 	}
279*2264Sjacobs 
280*2264Sjacobs 	attribute->type = type;
281*2264Sjacobs 
282*2264Sjacobs 	result = papiAttributeListAppendValue(&attribute->values, type, value);
283*2264Sjacobs 
284*2264Sjacobs 	/* free old values if we replaced them */
285*2264Sjacobs 	if (values != NULL)
286*2264Sjacobs 		papiAttributeValuesFree(type, values);
287*2264Sjacobs 
288*2264Sjacobs 	return (result);
289*2264Sjacobs }
290*2264Sjacobs 
291*2264Sjacobs papi_status_t
292*2264Sjacobs papiAttributeListAddString(papi_attribute_t ***list, int flags,
293*2264Sjacobs 			char *name, char *string)
294*2264Sjacobs {
295*2264Sjacobs 	papi_attribute_value_t v;
296*2264Sjacobs 
297*2264Sjacobs 	v.string = (char *)string;
298*2264Sjacobs 	return (papiAttributeListAddValue(list, flags, name, PAPI_STRING, &v));
299*2264Sjacobs }
300*2264Sjacobs 
301*2264Sjacobs papi_status_t
302*2264Sjacobs papiAttributeListAddInteger(papi_attribute_t ***list, int flags,
303*2264Sjacobs 			char *name, int integer)
304*2264Sjacobs {
305*2264Sjacobs 	papi_attribute_value_t v;
306*2264Sjacobs 
307*2264Sjacobs 	v.integer = integer;
308*2264Sjacobs 	return (papiAttributeListAddValue(list, flags, name, PAPI_INTEGER, &v));
309*2264Sjacobs }
310*2264Sjacobs 
311*2264Sjacobs papi_status_t
312*2264Sjacobs papiAttributeListAddBoolean(papi_attribute_t ***list, int flags,
313*2264Sjacobs 			char *name, char boolean)
314*2264Sjacobs {
315*2264Sjacobs 	papi_attribute_value_t v;
316*2264Sjacobs 
317*2264Sjacobs 	v.boolean = boolean;
318*2264Sjacobs 	return (papiAttributeListAddValue(list, flags, name, PAPI_BOOLEAN, &v));
319*2264Sjacobs }
320*2264Sjacobs 
321*2264Sjacobs papi_status_t
322*2264Sjacobs papiAttributeListAddRange(papi_attribute_t ***list, int flags,
323*2264Sjacobs 			char *name, int lower, int upper)
324*2264Sjacobs {
325*2264Sjacobs 	papi_attribute_value_t v;
326*2264Sjacobs 
327*2264Sjacobs 	v.range.lower = lower;
328*2264Sjacobs 	v.range.upper = upper;
329*2264Sjacobs 	return (papiAttributeListAddValue(list, flags, name, PAPI_RANGE, &v));
330*2264Sjacobs }
331*2264Sjacobs 
332*2264Sjacobs papi_status_t
333*2264Sjacobs papiAttributeListAddResolution(papi_attribute_t ***list, int flags,
334*2264Sjacobs 			char *name, int xres, int yres,
335*2264Sjacobs 			papi_resolution_unit_t units)
336*2264Sjacobs {
337*2264Sjacobs 	papi_attribute_value_t v;
338*2264Sjacobs 
339*2264Sjacobs 	v.resolution.xres = xres;
340*2264Sjacobs 	v.resolution.yres = yres;
341*2264Sjacobs 	v.resolution.units = units;
342*2264Sjacobs 	return (papiAttributeListAddValue(list, flags, name,
343*2264Sjacobs 				PAPI_RESOLUTION, &v));
344*2264Sjacobs }
345*2264Sjacobs 
346*2264Sjacobs papi_status_t
347*2264Sjacobs papiAttributeListAddDatetime(papi_attribute_t ***list, int flags,
348*2264Sjacobs 			char *name, time_t datetime)
349*2264Sjacobs {
350*2264Sjacobs 	papi_attribute_value_t v;
351*2264Sjacobs 
352*2264Sjacobs 	v.datetime = datetime;
353*2264Sjacobs 	return (papiAttributeListAddValue(list, flags, name,
354*2264Sjacobs 				PAPI_DATETIME, &v));
355*2264Sjacobs }
356*2264Sjacobs 
357*2264Sjacobs papi_status_t
358*2264Sjacobs papiAttributeListAddCollection(papi_attribute_t ***list, int flags,
359*2264Sjacobs 			char *name, papi_attribute_t **collection)
360*2264Sjacobs {
361*2264Sjacobs 	papi_attribute_value_t v;
362*2264Sjacobs 
363*2264Sjacobs 	v.collection = (papi_attribute_t **)collection;
364*2264Sjacobs 	return (papiAttributeListAddValue(list, flags, name,
365*2264Sjacobs 				PAPI_COLLECTION, &v));
366*2264Sjacobs }
367*2264Sjacobs 
368*2264Sjacobs papi_status_t
369*2264Sjacobs papiAttributeListAddMetadata(papi_attribute_t ***list, int flags,
370*2264Sjacobs 			char *name, papi_metadata_t metadata)
371*2264Sjacobs {
372*2264Sjacobs 	papi_attribute_value_t v;
373*2264Sjacobs 
374*2264Sjacobs 	v.metadata = metadata;
375*2264Sjacobs 	return (papiAttributeListAddValue(list, flags, name,
376*2264Sjacobs 				PAPI_METADATA, &v));
377*2264Sjacobs }
378*2264Sjacobs 
379*2264Sjacobs papi_status_t
380*2264Sjacobs papiAttributeListDelete(papi_attribute_t ***list, char *name)
381*2264Sjacobs {
382*2264Sjacobs 	papi_attribute_t *attribute;
383*2264Sjacobs 
384*2264Sjacobs 	if ((list == NULL) || (name == NULL))
385*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
386*2264Sjacobs 
387*2264Sjacobs 	if ((attribute = papiAttributeListFind(*list, name)) == NULL)
388*2264Sjacobs 		return (PAPI_NOT_FOUND);
389*2264Sjacobs 
390*2264Sjacobs 	list_remove(*list, attribute);
391*2264Sjacobs 	papiAttributeFree(attribute);
392*2264Sjacobs 
393*2264Sjacobs 	return (PAPI_OK);
394*2264Sjacobs }
395*2264Sjacobs 
396*2264Sjacobs papi_attribute_t *
397*2264Sjacobs papiAttributeListFind(papi_attribute_t **list, char *name)
398*2264Sjacobs {
399*2264Sjacobs 	int i;
400*2264Sjacobs 	if ((list == NULL) || (name == NULL))
401*2264Sjacobs 		return (NULL);
402*2264Sjacobs 
403*2264Sjacobs 	for (i = 0; list[i] != NULL; i++)
404*2264Sjacobs 		if (strcasecmp(list[i]->name, name) == 0)
405*2264Sjacobs 			return ((papi_attribute_t *)list[i]);
406*2264Sjacobs 
407*2264Sjacobs 	return (NULL);
408*2264Sjacobs }
409*2264Sjacobs 
410*2264Sjacobs papi_attribute_t *
411*2264Sjacobs papiAttributeListGetNext(papi_attribute_t **list, void **iter)
412*2264Sjacobs {
413*2264Sjacobs 	papi_attribute_t **tmp, *result;
414*2264Sjacobs 
415*2264Sjacobs 	if ((list == NULL) && (iter == NULL))
416*2264Sjacobs 		return (NULL);
417*2264Sjacobs 
418*2264Sjacobs 	if (*iter == NULL)
419*2264Sjacobs 		*iter = list;
420*2264Sjacobs 
421*2264Sjacobs 	tmp = *iter;
422*2264Sjacobs 	result = *tmp;
423*2264Sjacobs 	*iter = ++tmp;
424*2264Sjacobs 
425*2264Sjacobs 	return (result);
426*2264Sjacobs }
427*2264Sjacobs 
428*2264Sjacobs papi_status_t
429*2264Sjacobs papiAttributeListGetValue(papi_attribute_t **list, void **iter,
430*2264Sjacobs 			char *name, papi_attribute_value_type_t type,
431*2264Sjacobs 			papi_attribute_value_t **value)
432*2264Sjacobs {
433*2264Sjacobs 	papi_attribute_value_t **tmp;
434*2264Sjacobs 	void *fodder = NULL;
435*2264Sjacobs 
436*2264Sjacobs 	if ((list == NULL) || ((name == NULL) && (iter == NULL)) ||
437*2264Sjacobs 	    (value == NULL))
438*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
439*2264Sjacobs 
440*2264Sjacobs 	if (iter == NULL)
441*2264Sjacobs 		iter = &fodder;
442*2264Sjacobs 
443*2264Sjacobs 	if ((iter == NULL) || (*iter == NULL)) {
444*2264Sjacobs 		papi_attribute_t *attr = papiAttributeListFind(list, name);
445*2264Sjacobs 
446*2264Sjacobs 		if (attr == NULL)
447*2264Sjacobs 			return (PAPI_NOT_FOUND);
448*2264Sjacobs 
449*2264Sjacobs 		if (attr->type != type)
450*2264Sjacobs 			return (PAPI_NOT_POSSIBLE);
451*2264Sjacobs 
452*2264Sjacobs 		tmp = attr->values;
453*2264Sjacobs 	} else
454*2264Sjacobs 		tmp = *iter;
455*2264Sjacobs 
456*2264Sjacobs 	if (tmp == NULL)
457*2264Sjacobs 		return (PAPI_NOT_FOUND);
458*2264Sjacobs 
459*2264Sjacobs 	*value = *tmp;
460*2264Sjacobs 	*iter =  ++tmp;
461*2264Sjacobs 
462*2264Sjacobs 	if (*value == NULL)
463*2264Sjacobs 		return (PAPI_GONE);
464*2264Sjacobs 
465*2264Sjacobs 	return (PAPI_OK);
466*2264Sjacobs }
467*2264Sjacobs 
468*2264Sjacobs papi_status_t
469*2264Sjacobs papiAttributeListGetString(papi_attribute_t **list, void **iter,
470*2264Sjacobs 			char *name, char **vptr)
471*2264Sjacobs {
472*2264Sjacobs 	papi_status_t status;
473*2264Sjacobs 	papi_attribute_value_t *value = NULL;
474*2264Sjacobs 
475*2264Sjacobs 	if (vptr == NULL)
476*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
477*2264Sjacobs 
478*2264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
479*2264Sjacobs 				PAPI_STRING, &value);
480*2264Sjacobs 	if (status == PAPI_OK)
481*2264Sjacobs 		*vptr = value->string;
482*2264Sjacobs 
483*2264Sjacobs 	return (status);
484*2264Sjacobs }
485*2264Sjacobs 
486*2264Sjacobs papi_status_t
487*2264Sjacobs papiAttributeListGetInteger(papi_attribute_t **list, void **iter,
488*2264Sjacobs 			char *name, int *vptr)
489*2264Sjacobs {
490*2264Sjacobs 	papi_status_t status;
491*2264Sjacobs 	papi_attribute_value_t *value = NULL;
492*2264Sjacobs 
493*2264Sjacobs 	if (vptr == NULL)
494*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
495*2264Sjacobs 
496*2264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
497*2264Sjacobs 				PAPI_INTEGER, &value);
498*2264Sjacobs 	if (status == PAPI_OK)
499*2264Sjacobs 		*vptr = value->integer;
500*2264Sjacobs 
501*2264Sjacobs 	return (status);
502*2264Sjacobs }
503*2264Sjacobs 
504*2264Sjacobs papi_status_t
505*2264Sjacobs papiAttributeListGetBoolean(papi_attribute_t **list, void **iter,
506*2264Sjacobs 			char *name, char *vptr)
507*2264Sjacobs {
508*2264Sjacobs 	papi_status_t status;
509*2264Sjacobs 	papi_attribute_value_t *value = NULL;
510*2264Sjacobs 
511*2264Sjacobs 	if (vptr == NULL)
512*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
513*2264Sjacobs 
514*2264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
515*2264Sjacobs 				PAPI_BOOLEAN, &value);
516*2264Sjacobs 	if (status == PAPI_OK)
517*2264Sjacobs 		*vptr = value->boolean;
518*2264Sjacobs 
519*2264Sjacobs 	return (status);
520*2264Sjacobs }
521*2264Sjacobs 
522*2264Sjacobs papi_status_t
523*2264Sjacobs papiAttributeListGetRange(papi_attribute_t **list, void **iter,
524*2264Sjacobs 			char *name, int *min, int *max)
525*2264Sjacobs {
526*2264Sjacobs 	papi_status_t status;
527*2264Sjacobs 	papi_attribute_value_t *value = NULL;
528*2264Sjacobs 
529*2264Sjacobs 	if ((min == NULL) || (max == NULL))
530*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
531*2264Sjacobs 
532*2264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
533*2264Sjacobs 				PAPI_RANGE, &value);
534*2264Sjacobs 	if (status == PAPI_OK) {
535*2264Sjacobs 		*min = value->range.lower;
536*2264Sjacobs 		*max = value->range.upper;
537*2264Sjacobs 	}
538*2264Sjacobs 
539*2264Sjacobs 	return (status);
540*2264Sjacobs }
541*2264Sjacobs 
542*2264Sjacobs papi_status_t
543*2264Sjacobs papiAttributeListGetResolution(papi_attribute_t **list, void **iter,
544*2264Sjacobs 			char *name, int *x, int *y,
545*2264Sjacobs 			papi_resolution_unit_t *units)
546*2264Sjacobs {
547*2264Sjacobs 	papi_status_t status;
548*2264Sjacobs 	papi_attribute_value_t *value = NULL;
549*2264Sjacobs 
550*2264Sjacobs 	if ((x == NULL) || (y == NULL) || (units == NULL))
551*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
552*2264Sjacobs 
553*2264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
554*2264Sjacobs 				PAPI_RESOLUTION, &value);
555*2264Sjacobs 	if (status == PAPI_OK) {
556*2264Sjacobs 		*x = value->resolution.xres;
557*2264Sjacobs 		*y = value->resolution.yres;
558*2264Sjacobs 		*units = value->resolution.units;
559*2264Sjacobs 	}
560*2264Sjacobs 
561*2264Sjacobs 	return (status);
562*2264Sjacobs }
563*2264Sjacobs 
564*2264Sjacobs papi_status_t
565*2264Sjacobs papiAttributeListGetDatetime(papi_attribute_t **list, void **iter,
566*2264Sjacobs 			char *name, time_t *dt)
567*2264Sjacobs {
568*2264Sjacobs 	papi_status_t status;
569*2264Sjacobs 	papi_attribute_value_t *value = NULL;
570*2264Sjacobs 
571*2264Sjacobs 	if (dt == NULL)
572*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
573*2264Sjacobs 
574*2264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
575*2264Sjacobs 				PAPI_DATETIME, &value);
576*2264Sjacobs 	if (status == PAPI_OK) {
577*2264Sjacobs 		*dt = value->datetime;
578*2264Sjacobs 	}
579*2264Sjacobs 
580*2264Sjacobs 	return (status);
581*2264Sjacobs }
582*2264Sjacobs 
583*2264Sjacobs papi_status_t
584*2264Sjacobs papiAttributeListGetCollection(papi_attribute_t **list, void **iter,
585*2264Sjacobs 			char *name, papi_attribute_t ***collection)
586*2264Sjacobs {
587*2264Sjacobs 	papi_status_t status;
588*2264Sjacobs 	papi_attribute_value_t *value = NULL;
589*2264Sjacobs 
590*2264Sjacobs 	if (collection == NULL)
591*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
592*2264Sjacobs 
593*2264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
594*2264Sjacobs 				PAPI_COLLECTION, &value);
595*2264Sjacobs 	if (status == PAPI_OK) {
596*2264Sjacobs 		*collection = value->collection;
597*2264Sjacobs 	}
598*2264Sjacobs 
599*2264Sjacobs 	return (status);
600*2264Sjacobs }
601*2264Sjacobs 
602*2264Sjacobs papi_status_t
603*2264Sjacobs papiAttributeListGetMetadata(papi_attribute_t **list, void **iter,
604*2264Sjacobs 			char *name, papi_metadata_t *vptr)
605*2264Sjacobs {
606*2264Sjacobs 	papi_status_t status;
607*2264Sjacobs 	papi_attribute_value_t *value = NULL;
608*2264Sjacobs 
609*2264Sjacobs 	if (vptr == NULL)
610*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
611*2264Sjacobs 
612*2264Sjacobs 	status = papiAttributeListGetValue(list, iter, name,
613*2264Sjacobs 				PAPI_METADATA, &value);
614*2264Sjacobs 	if (status == PAPI_OK)
615*2264Sjacobs 		*vptr = value->metadata;
616*2264Sjacobs 
617*2264Sjacobs 	return (status);
618*2264Sjacobs }
619*2264Sjacobs 
620*2264Sjacobs /*
621*2264Sjacobs  * Description: The given string contains one or more attributes, in the
622*2264Sjacobs  *	      following form:
623*2264Sjacobs  *		  "aaaa=true bbbbb=1 ccccc=abcd"
624*2264Sjacobs  *	      extract the next attribute from that string; the 'next'
625*2264Sjacobs  *	      parameter should be set to zero to extract the first attribute
626*2264Sjacobs  *	      in the string.
627*2264Sjacobs  *
628*2264Sjacobs  */
629*2264Sjacobs 
630*2264Sjacobs static char *
631*2264Sjacobs _getNextAttr(char *string, int *next)
632*2264Sjacobs 
633*2264Sjacobs {
634*2264Sjacobs 	char *result = NULL;
635*2264Sjacobs 	char *start = (char *)string + *next;
636*2264Sjacobs 	char *nl = NULL;
637*2264Sjacobs 	char *sp = NULL;
638*2264Sjacobs 	char *tab = NULL;
639*2264Sjacobs 	char *val = NULL;
640*2264Sjacobs 	int len = 0;
641*2264Sjacobs 
642*2264Sjacobs 	if ((string != NULL) && (*start != '\0')) {
643*2264Sjacobs 		while ((*start == ' ') || (*start == '\t') || (*start == '\n'))
644*2264Sjacobs 		{
645*2264Sjacobs 			start++;
646*2264Sjacobs 		}
647*2264Sjacobs 		nl = strchr(start, '\n');
648*2264Sjacobs 		sp = strchr(start, ' ');
649*2264Sjacobs 		tab = strchr(start, '\t');
650*2264Sjacobs 
651*2264Sjacobs 		val = strchr(start, '=');
652*2264Sjacobs 
653*2264Sjacobs 		if ((val != NULL) && ((val[1] == '"') || (val[1] == '\''))) {
654*2264Sjacobs 			val = strchr(&val[2], val[1]);
655*2264Sjacobs 			if (val != NULL) {
656*2264Sjacobs 				nl = strchr(&val[1], '\n');
657*2264Sjacobs 				sp = strchr(&val[1], ' ');
658*2264Sjacobs 				tab = strchr(&val[1], '\t');
659*2264Sjacobs 			}
660*2264Sjacobs 		}
661*2264Sjacobs 
662*2264Sjacobs 		if ((nl != NULL) &&
663*2264Sjacobs 		    ((sp == NULL) || ((sp != NULL) && (nl < sp))) &&
664*2264Sjacobs 		    ((tab == NULL) || ((tab != NULL) && (nl < tab)))) {
665*2264Sjacobs 			len = nl-start;
666*2264Sjacobs 		} else if ((sp != NULL) && (tab != NULL) && (sp > tab)) {
667*2264Sjacobs 			len = tab-start;
668*2264Sjacobs 		} else if ((sp != NULL) && (sp != NULL)) {
669*2264Sjacobs 			len = sp-start;
670*2264Sjacobs 		} else if ((tab != NULL) && (tab != NULL)) {
671*2264Sjacobs 			len = tab-start;
672*2264Sjacobs 		}
673*2264Sjacobs 
674*2264Sjacobs 		if (len == 0) {
675*2264Sjacobs 			len = strlen(start);
676*2264Sjacobs 		}
677*2264Sjacobs 
678*2264Sjacobs 		if (len > 0) {
679*2264Sjacobs 			result = (char *)malloc(len+1);
680*2264Sjacobs 			if (result != NULL) {
681*2264Sjacobs 				strncpy(result, start, len);
682*2264Sjacobs 				result[len] = '\0';
683*2264Sjacobs 				*next = (start-string)+len;
684*2264Sjacobs 			}
685*2264Sjacobs 		}
686*2264Sjacobs 	}
687*2264Sjacobs 
688*2264Sjacobs 	return (result);
689*2264Sjacobs } /* _getNextAttr() */
690*2264Sjacobs 
691*2264Sjacobs 
692*2264Sjacobs /*
693*2264Sjacobs  * Description: Parse the given attribute string value and transform it into
694*2264Sjacobs  *	      the papi_attribute_value_t in the papi_attribute_t structure.
695*2264Sjacobs  *
696*2264Sjacobs  */
697*2264Sjacobs 
698*2264Sjacobs static papi_status_t
699*2264Sjacobs _parseAttrValue(char *value, papi_attribute_t *attr)
700*2264Sjacobs 
701*2264Sjacobs {
702*2264Sjacobs 	papi_status_t result = PAPI_OK;
703*2264Sjacobs 	int len = 0;
704*2264Sjacobs 	int i = 0;
705*2264Sjacobs 	char *papiString = NULL;
706*2264Sjacobs 	char *tmp1 = NULL;
707*2264Sjacobs 	char *tmp2 = NULL;
708*2264Sjacobs 	char *tmp3 = NULL;
709*2264Sjacobs 	papi_attribute_value_t **avalues = NULL;
710*2264Sjacobs 
711*2264Sjacobs 	avalues = malloc(sizeof (papi_attribute_value_t *) * 2);
712*2264Sjacobs 	if (avalues == NULL) {
713*2264Sjacobs 		result = PAPI_TEMPORARY_ERROR;
714*2264Sjacobs 		return (result);
715*2264Sjacobs 	}
716*2264Sjacobs 	avalues[0] = malloc(sizeof (papi_attribute_value_t));
717*2264Sjacobs 	avalues[1] = NULL;
718*2264Sjacobs 	if (avalues[0] == NULL) {
719*2264Sjacobs 		free(avalues);
720*2264Sjacobs 		result = PAPI_TEMPORARY_ERROR;
721*2264Sjacobs 		return (result);
722*2264Sjacobs 	}
723*2264Sjacobs 
724*2264Sjacobs 
725*2264Sjacobs /*
726*2264Sjacobs  * TODO - need to sort out 'resolution', 'dateandtime' & 'collection' values
727*2264Sjacobs  */
728*2264Sjacobs 	if ((value != NULL) && (strlen(value) > 0) && (attr != NULL)) {
729*2264Sjacobs 
730*2264Sjacobs 		len = strlen(value);
731*2264Sjacobs 		if ((len >= 2) && (((value[0] == '"') &&
732*2264Sjacobs 				(value[len-1] == '"')) || ((value[0] == '\'') &&
733*2264Sjacobs 				(value[len-1] == '\'')))) {
734*2264Sjacobs 			/* string value */
735*2264Sjacobs 			attr->type = PAPI_STRING;
736*2264Sjacobs 
737*2264Sjacobs 			papiString = strdup(value+1);
738*2264Sjacobs 			if (papiString != NULL) {
739*2264Sjacobs 				papiString[strlen(papiString)-1] = '\0';
740*2264Sjacobs 				avalues[0]->string = papiString;
741*2264Sjacobs 			} else {
742*2264Sjacobs 				result = PAPI_TEMPORARY_ERROR;
743*2264Sjacobs 			}
744*2264Sjacobs 		} else if ((strcasecmp(value, "true") == 0) ||
745*2264Sjacobs 		    (strcasecmp(value, "YES") == 0)) {
746*2264Sjacobs 			/* boolean = true */
747*2264Sjacobs 			attr->type = PAPI_BOOLEAN;
748*2264Sjacobs 			avalues[0]->boolean = PAPI_TRUE;
749*2264Sjacobs 		} else if ((strcasecmp(value, "false") == 0) ||
750*2264Sjacobs 		    (strcasecmp(value, "NO") == 0)) {
751*2264Sjacobs 			/* boolean = false */
752*2264Sjacobs 			attr->type = PAPI_BOOLEAN;
753*2264Sjacobs 			avalues[0]->boolean = PAPI_FALSE;
754*2264Sjacobs 		} else {
755*2264Sjacobs 			/* is value an integer or a range ? */
756*2264Sjacobs 
757*2264Sjacobs 			i = 0;
758*2264Sjacobs 			attr->type = PAPI_INTEGER;
759*2264Sjacobs 			tmp1 = strdup(value);
760*2264Sjacobs 			while (((value[i] >= '0') && (value[i] <= '9')) ||
761*2264Sjacobs 					(value[i] == '-')) {
762*2264Sjacobs 				if (value[i] == '-') {
763*2264Sjacobs 					tmp1[i] = '\0';
764*2264Sjacobs 					tmp2 = &tmp1[i+1];
765*2264Sjacobs 					attr->type = PAPI_RANGE;
766*2264Sjacobs 				}
767*2264Sjacobs 
768*2264Sjacobs 				i++;
769*2264Sjacobs 			}
770*2264Sjacobs 
771*2264Sjacobs 			if (strlen(value) == i) {
772*2264Sjacobs 				if (attr->type == PAPI_RANGE) {
773*2264Sjacobs 					avalues[0]->range.lower = atoi(tmp1);
774*2264Sjacobs 					avalues[0]->range.upper = atoi(tmp2);
775*2264Sjacobs 				} else {
776*2264Sjacobs 					avalues[0]->integer = atoi(value);
777*2264Sjacobs 				}
778*2264Sjacobs 			} else {
779*2264Sjacobs 				/* is value a resolution ? */
780*2264Sjacobs 				i = 0;
781*2264Sjacobs 				attr->type = PAPI_INTEGER;
782*2264Sjacobs 				tmp1 = strdup(value);
783*2264Sjacobs 				while (((value[i] >= '0') &&
784*2264Sjacobs 					(value[i] <= '9')) ||
785*2264Sjacobs 					(value[i] == 'x')) {
786*2264Sjacobs 					if (value[i] == 'x') {
787*2264Sjacobs 						tmp1[i] = '\0';
788*2264Sjacobs 						if (attr->type == PAPI_INTEGER)
789*2264Sjacobs 						{
790*2264Sjacobs 							tmp2 = &tmp1[i+1];
791*2264Sjacobs 							attr->type =
792*2264Sjacobs 								PAPI_RESOLUTION;
793*2264Sjacobs 						} else {
794*2264Sjacobs 							tmp3 = &tmp1[i+1];
795*2264Sjacobs 						}
796*2264Sjacobs 					}
797*2264Sjacobs 
798*2264Sjacobs 					i++;
799*2264Sjacobs 				}
800*2264Sjacobs 
801*2264Sjacobs 				if (strlen(value) == i) {
802*2264Sjacobs 					if (attr->type == PAPI_RESOLUTION) {
803*2264Sjacobs 						avalues[0]->resolution.xres =
804*2264Sjacobs 								atoi(tmp1);
805*2264Sjacobs 						avalues[0]->resolution.yres =
806*2264Sjacobs 								atoi(tmp2);
807*2264Sjacobs 						if (tmp3 != NULL) {
808*2264Sjacobs 							avalues[0]->
809*2264Sjacobs 							resolution.units =
810*2264Sjacobs 								atoi(tmp3);
811*2264Sjacobs 						} else {
812*2264Sjacobs 							avalues[0]->
813*2264Sjacobs 							resolution.units = 0;
814*2264Sjacobs 						}
815*2264Sjacobs 					}
816*2264Sjacobs 				}
817*2264Sjacobs 
818*2264Sjacobs 				if (attr->type != PAPI_RESOLUTION) {
819*2264Sjacobs 					attr->type = PAPI_STRING;
820*2264Sjacobs 					avalues[0]->string = strdup(value);
821*2264Sjacobs 					if (avalues[0]->string == NULL) {
822*2264Sjacobs 						result = PAPI_TEMPORARY_ERROR;
823*2264Sjacobs 					}
824*2264Sjacobs 				}
825*2264Sjacobs 			}
826*2264Sjacobs 			free(tmp1);
827*2264Sjacobs 		}
828*2264Sjacobs 
829*2264Sjacobs 	} else {
830*2264Sjacobs 		result = PAPI_BAD_ARGUMENT;
831*2264Sjacobs 	}
832*2264Sjacobs 
833*2264Sjacobs 	if (result != PAPI_OK) {
834*2264Sjacobs 		i = 0;
835*2264Sjacobs 		while (avalues[i] != NULL) {
836*2264Sjacobs 			free(avalues[i]);
837*2264Sjacobs 			i++;
838*2264Sjacobs 		}
839*2264Sjacobs 		free(avalues);
840*2264Sjacobs 	} else {
841*2264Sjacobs 		attr->values = avalues;
842*2264Sjacobs 	}
843*2264Sjacobs 
844*2264Sjacobs 	return (result);
845*2264Sjacobs } /* _parseAttrValue() */
846*2264Sjacobs 
847*2264Sjacobs 
848*2264Sjacobs /*
849*2264Sjacobs  * Description: Parse the given attribute string and transform it into the
850*2264Sjacobs  *	      papi_attribute_t structure.
851*2264Sjacobs  *
852*2264Sjacobs  */
853*2264Sjacobs 
854*2264Sjacobs static papi_status_t
855*2264Sjacobs _parseAttributeString(char *attrString, papi_attribute_t *attr)
856*2264Sjacobs 
857*2264Sjacobs {
858*2264Sjacobs 	papi_status_t result = PAPI_OK;
859*2264Sjacobs 	char *string = NULL;
860*2264Sjacobs 	char *p = NULL;
861*2264Sjacobs 	papi_attribute_value_t **avalues = NULL;
862*2264Sjacobs 
863*2264Sjacobs 	if ((attrString != NULL) && (strlen(attrString) >= 3) &&
864*2264Sjacobs 	    (attr != NULL)) {
865*2264Sjacobs 		attr->name = NULL;
866*2264Sjacobs 		string = strdup(attrString);
867*2264Sjacobs 		if (string != NULL) {
868*2264Sjacobs 			p = strchr(string, '=');
869*2264Sjacobs 			if (p != NULL) {
870*2264Sjacobs 				*p = '\0';
871*2264Sjacobs 				attr->name = string;
872*2264Sjacobs 				p++;  /* pointer to value */
873*2264Sjacobs 
874*2264Sjacobs 				result = _parseAttrValue(p, attr);
875*2264Sjacobs 			} else {
876*2264Sjacobs 				char value;
877*2264Sjacobs 				/* boolean - no value so assume 'true' */
878*2264Sjacobs 				if (strncasecmp(string, "no", 2) == 0) {
879*2264Sjacobs 					string += 2;
880*2264Sjacobs 					value = PAPI_FALSE;
881*2264Sjacobs 				} else
882*2264Sjacobs 					value = PAPI_TRUE;
883*2264Sjacobs 
884*2264Sjacobs 				attr->name = string;
885*2264Sjacobs 				attr->type = PAPI_BOOLEAN;
886*2264Sjacobs 
887*2264Sjacobs 				avalues = malloc(
888*2264Sjacobs 					sizeof (papi_attribute_value_t *) * 2);
889*2264Sjacobs 				if (avalues == NULL) {
890*2264Sjacobs 					result = PAPI_TEMPORARY_ERROR;
891*2264Sjacobs 				} else {
892*2264Sjacobs 					avalues[0] = malloc(
893*2264Sjacobs 					sizeof (papi_attribute_value_t));
894*2264Sjacobs 					avalues[1] = NULL;
895*2264Sjacobs 					if (avalues[0] == NULL) {
896*2264Sjacobs 						free(avalues);
897*2264Sjacobs 						result = PAPI_TEMPORARY_ERROR;
898*2264Sjacobs 					} else {
899*2264Sjacobs 						avalues[0]->boolean = value;
900*2264Sjacobs 						attr->values = avalues;
901*2264Sjacobs 					}
902*2264Sjacobs 				}
903*2264Sjacobs 			}
904*2264Sjacobs 		}
905*2264Sjacobs 	} else {
906*2264Sjacobs 		result = PAPI_BAD_ARGUMENT;
907*2264Sjacobs 	}
908*2264Sjacobs 
909*2264Sjacobs 	return (result);
910*2264Sjacobs } /* _parseAttributeString() */
911*2264Sjacobs 
912*2264Sjacobs 
913*2264Sjacobs papi_status_t
914*2264Sjacobs papiAttributeListFromString(papi_attribute_t ***attrs,
915*2264Sjacobs 		int flags, char *string)
916*2264Sjacobs {
917*2264Sjacobs 	papi_status_t result = PAPI_OK;
918*2264Sjacobs 	int	   next = 0;
919*2264Sjacobs 	char	 *attrString = NULL;
920*2264Sjacobs 	papi_attribute_t attr;
921*2264Sjacobs 
922*2264Sjacobs 	if ((attrs != NULL) && (string != NULL) &&
923*2264Sjacobs 	    ((flags & ~(PAPI_ATTR_APPEND+PAPI_ATTR_REPLACE+PAPI_ATTR_EXCL))
924*2264Sjacobs 			== 0)) {
925*2264Sjacobs 		attrString = _getNextAttr(string, &next);
926*2264Sjacobs 		while ((result == PAPI_OK) && (attrString != NULL)) {
927*2264Sjacobs 			result = _parseAttributeString(attrString, &attr);
928*2264Sjacobs 			if ((result == PAPI_OK) && (attr.name != NULL)) {
929*2264Sjacobs 				/* add this attribute to the list */
930*2264Sjacobs 				if ((attr.values != NULL) &&
931*2264Sjacobs 				    (attr.values[0] != NULL)) {
932*2264Sjacobs 					result = papiAttributeListAddValue(
933*2264Sjacobs 							attrs, PAPI_ATTR_APPEND,
934*2264Sjacobs 							attr.name, attr.type,
935*2264Sjacobs 							attr.values[0]);
936*2264Sjacobs 					free(attr.values[0]);
937*2264Sjacobs 					free(attr.values);
938*2264Sjacobs 				} else {
939*2264Sjacobs 					result = PAPI_TEMPORARY_ERROR;
940*2264Sjacobs 				}
941*2264Sjacobs 			}
942*2264Sjacobs 			free(attrString);
943*2264Sjacobs 
944*2264Sjacobs 			attrString = _getNextAttr(string, &next);
945*2264Sjacobs 		}
946*2264Sjacobs 	}
947*2264Sjacobs 	else
948*2264Sjacobs 	{
949*2264Sjacobs 		result = PAPI_BAD_ARGUMENT;
950*2264Sjacobs 	}
951*2264Sjacobs 
952*2264Sjacobs 	return (result);
953*2264Sjacobs }
954*2264Sjacobs 
955*2264Sjacobs static papi_status_t
956*2264Sjacobs papiAttributeToString(papi_attribute_t *attribute, char *delim,
957*2264Sjacobs 		char *buffer, size_t buflen)
958*2264Sjacobs {
959*2264Sjacobs 	papi_attribute_value_t **values = attribute->values;
960*2264Sjacobs 	int rc, i;
961*2264Sjacobs 
962*2264Sjacobs 	strlcat(buffer, attribute->name, buflen);
963*2264Sjacobs 	strlcat(buffer, "=", buflen);
964*2264Sjacobs 
965*2264Sjacobs 	if (values == NULL)
966*2264Sjacobs 		return (PAPI_OK);
967*2264Sjacobs 
968*2264Sjacobs 	for (i = 0; values[i] != NULL; i++) {
969*2264Sjacobs 		switch (attribute->type) {
970*2264Sjacobs 		case PAPI_STRING:
971*2264Sjacobs 			rc = strlcat(buffer, values[i]->string, buflen);
972*2264Sjacobs 			break;
973*2264Sjacobs 		case PAPI_INTEGER: {
974*2264Sjacobs 			char string[24];
975*2264Sjacobs 
976*2264Sjacobs 			snprintf(string, sizeof (string), "%d",
977*2264Sjacobs 				values[i]->integer);
978*2264Sjacobs 			rc = strlcat(buffer, string, buflen);
979*2264Sjacobs 			}
980*2264Sjacobs 			break;
981*2264Sjacobs 		case PAPI_BOOLEAN:
982*2264Sjacobs 			rc = strlcat(buffer, (values[i]->boolean ? "true" :
983*2264Sjacobs 							"false"), buflen);
984*2264Sjacobs 			break;
985*2264Sjacobs 		case PAPI_RANGE: {
986*2264Sjacobs 			char string[24];
987*2264Sjacobs 
988*2264Sjacobs 			snprintf(string, sizeof (string), "%d-%d",
989*2264Sjacobs 				values[i]->range.lower, values[i]->range.upper);
990*2264Sjacobs 			rc = strlcat(buffer, string, buflen);
991*2264Sjacobs 			}
992*2264Sjacobs 			break;
993*2264Sjacobs 		case PAPI_RESOLUTION: {
994*2264Sjacobs 			char string[24];
995*2264Sjacobs 
996*2264Sjacobs 			snprintf(string, sizeof (string), "%dx%ddp%c",
997*2264Sjacobs 				values[i]->resolution.xres,
998*2264Sjacobs 				values[i]->resolution.yres,
999*2264Sjacobs 				(values[i]->resolution.units == PAPI_RES_PER_CM
1000*2264Sjacobs 							? 'c' : 'i'));
1001*2264Sjacobs 			rc = strlcat(buffer, string, buflen);
1002*2264Sjacobs 			}
1003*2264Sjacobs 			break;
1004*2264Sjacobs 		case PAPI_DATETIME: {
1005*2264Sjacobs 			struct tm *tm = localtime(&values[i]->datetime);
1006*2264Sjacobs 
1007*2264Sjacobs 			if (tm != NULL) {
1008*2264Sjacobs 				char string[64];
1009*2264Sjacobs 
1010*2264Sjacobs 				strftime(string, sizeof (string), "%C", tm);
1011*2264Sjacobs 				rc = strlcat(buffer, string, buflen);
1012*2264Sjacobs 			}}
1013*2264Sjacobs 			break;
1014*2264Sjacobs 		case PAPI_COLLECTION: {
1015*2264Sjacobs 			char *string = alloca(buflen);
1016*2264Sjacobs #ifdef DEBUG
1017*2264Sjacobs 			char prefix[256];
1018*2264Sjacobs 
1019*2264Sjacobs 			snprintf(prefix, sizeof (prefix), "%s  %s(%d)  ", delim,
1020*2264Sjacobs 					attribute->name, i);
1021*2264Sjacobs 
1022*2264Sjacobs 			papiAttributeListToString(values[i]->collection,
1023*2264Sjacobs 					prefix, string, buflen);
1024*2264Sjacobs #else
1025*2264Sjacobs 			papiAttributeListToString(values[i]->collection,
1026*2264Sjacobs 					delim, string, buflen);
1027*2264Sjacobs #endif
1028*2264Sjacobs 			rc = strlcat(buffer, string, buflen);
1029*2264Sjacobs 			}
1030*2264Sjacobs 			break;
1031*2264Sjacobs 		default: {
1032*2264Sjacobs 			char string[32];
1033*2264Sjacobs 
1034*2264Sjacobs 			snprintf(string, sizeof (string), "unknown-type-0x%x",
1035*2264Sjacobs 				attribute->type);
1036*2264Sjacobs 			rc = strlcat(buffer, string, buflen);
1037*2264Sjacobs 			}
1038*2264Sjacobs 		}
1039*2264Sjacobs 		if (values[i+1] != NULL)
1040*2264Sjacobs 			rc = strlcat(buffer, ",", buflen);
1041*2264Sjacobs 
1042*2264Sjacobs 		if (rc >= buflen)
1043*2264Sjacobs 			return (PAPI_NOT_POSSIBLE);
1044*2264Sjacobs 
1045*2264Sjacobs 	}
1046*2264Sjacobs 
1047*2264Sjacobs 	return (PAPI_OK);
1048*2264Sjacobs }
1049*2264Sjacobs 
1050*2264Sjacobs papi_status_t
1051*2264Sjacobs papiAttributeListToString(papi_attribute_t **attrs,
1052*2264Sjacobs 		char *delim, char *buffer, size_t buflen)
1053*2264Sjacobs {
1054*2264Sjacobs 	papi_status_t status = PAPI_OK;
1055*2264Sjacobs 	int i;
1056*2264Sjacobs 
1057*2264Sjacobs 	if ((attrs == NULL) || (buffer == NULL))
1058*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
1059*2264Sjacobs 
1060*2264Sjacobs 	buffer[0] = '\0';
1061*2264Sjacobs 	if (!delim)
1062*2264Sjacobs 		delim = " ";
1063*2264Sjacobs 
1064*2264Sjacobs #ifdef DEBUG
1065*2264Sjacobs 	strlcat(buffer, delim, buflen);
1066*2264Sjacobs #endif
1067*2264Sjacobs 	for (i = 0; ((attrs[i] != NULL) && (status == PAPI_OK)); i++) {
1068*2264Sjacobs 		status = papiAttributeToString(attrs[i], delim, buffer, buflen);
1069*2264Sjacobs 		if (attrs[i+1] != NULL)
1070*2264Sjacobs 			strlcat(buffer, delim, buflen);
1071*2264Sjacobs 	}
1072*2264Sjacobs 
1073*2264Sjacobs 	return (status);
1074*2264Sjacobs }
1075*2264Sjacobs 
1076*2264Sjacobs static int
1077*2264Sjacobs is_in_list(char *value, char **list)
1078*2264Sjacobs {
1079*2264Sjacobs 	if ((list != NULL) && (value != NULL)) {
1080*2264Sjacobs 		int i;
1081*2264Sjacobs 
1082*2264Sjacobs 		for (i = 0; list[i] != NULL; i++)
1083*2264Sjacobs 			if (strcasecmp(value, list[i]) == 0)
1084*2264Sjacobs 				return (0);
1085*2264Sjacobs 	}
1086*2264Sjacobs 
1087*2264Sjacobs 	return (1);
1088*2264Sjacobs }
1089*2264Sjacobs 
1090*2264Sjacobs static papi_status_t
1091*2264Sjacobs copy_attribute(papi_attribute_t ***list, papi_attribute_t *attribute)
1092*2264Sjacobs {
1093*2264Sjacobs 	papi_status_t status;
1094*2264Sjacobs 	int i = 0;
1095*2264Sjacobs 
1096*2264Sjacobs 	if ((list == NULL) || (attribute == NULL) ||
1097*2264Sjacobs 	    (attribute->values == NULL))
1098*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
1099*2264Sjacobs 
1100*2264Sjacobs 	for (status = papiAttributeListAddValue(list, PAPI_ATTR_EXCL,
1101*2264Sjacobs 					attribute->name, attribute->type,
1102*2264Sjacobs 					attribute->values[i]);
1103*2264Sjacobs 	     ((status == PAPI_OK) && (attribute->values[i] != NULL));
1104*2264Sjacobs 	     status = papiAttributeListAddValue(list, PAPI_ATTR_APPEND,
1105*2264Sjacobs 					attribute->name, attribute->type,
1106*2264Sjacobs 					attribute->values[i]))
1107*2264Sjacobs 		i++;
1108*2264Sjacobs 
1109*2264Sjacobs 	return (status);
1110*2264Sjacobs }
1111*2264Sjacobs 
1112*2264Sjacobs void
1113*2264Sjacobs copy_attributes(papi_attribute_t ***result, papi_attribute_t **attributes)
1114*2264Sjacobs {
1115*2264Sjacobs 	int i;
1116*2264Sjacobs 
1117*2264Sjacobs 	if ((result == NULL) || (attributes == NULL))
1118*2264Sjacobs 		return;
1119*2264Sjacobs 
1120*2264Sjacobs 	for (i = 0; attributes[i] != NULL; i++)
1121*2264Sjacobs 		copy_attribute(result, attributes[i]);
1122*2264Sjacobs }
1123*2264Sjacobs 
1124*2264Sjacobs void
1125*2264Sjacobs split_and_copy_attributes(char **list, papi_attribute_t **attributes,
1126*2264Sjacobs 		papi_attribute_t ***in, papi_attribute_t ***out)
1127*2264Sjacobs {
1128*2264Sjacobs 	int i;
1129*2264Sjacobs 
1130*2264Sjacobs 	if ((list == NULL) || (attributes == NULL))
1131*2264Sjacobs 		return;
1132*2264Sjacobs 
1133*2264Sjacobs 	for (i = 0; attributes[i] != NULL; i++)
1134*2264Sjacobs 		if (is_in_list(attributes[i]->name, list) == 0)
1135*2264Sjacobs 			copy_attribute(in, attributes[i]);
1136*2264Sjacobs 		else
1137*2264Sjacobs 			copy_attribute(out, attributes[i]);
1138*2264Sjacobs }
1139*2264Sjacobs 
1140*2264Sjacobs void
1141*2264Sjacobs papiAttributeListPrint(FILE *fp, papi_attribute_t **attributes,
1142*2264Sjacobs 		char *prefix_fmt, ...)
1143*2264Sjacobs {
1144*2264Sjacobs 	char *prefix = NULL;
1145*2264Sjacobs 	char *buffer = NULL;
1146*2264Sjacobs 	char *newfmt = NULL;
1147*2264Sjacobs 	void *mem;
1148*2264Sjacobs 	ssize_t size = 0;
1149*2264Sjacobs 	va_list ap;
1150*2264Sjacobs 
1151*2264Sjacobs 	newfmt = malloc(strlen(prefix_fmt) + 2);
1152*2264Sjacobs 	sprintf(newfmt, "\n%s", prefix_fmt);
1153*2264Sjacobs 
1154*2264Sjacobs 	va_start(ap, prefix_fmt);
1155*2264Sjacobs 	while (vsnprintf(prefix, size, newfmt, ap) > size) {
1156*2264Sjacobs 		size += 1024;
1157*2264Sjacobs 		mem = realloc(prefix, size);
1158*2264Sjacobs 		if (!mem) goto error;
1159*2264Sjacobs 		prefix = mem;
1160*2264Sjacobs 	}
1161*2264Sjacobs 	va_end(ap);
1162*2264Sjacobs 
1163*2264Sjacobs 	if (attributes) {
1164*2264Sjacobs 		size = 0;
1165*2264Sjacobs 		while (papiAttributeListToString(attributes, prefix, buffer,
1166*2264Sjacobs 						size) != PAPI_OK) {
1167*2264Sjacobs 			size += 1024;
1168*2264Sjacobs 			mem = realloc(buffer, size);
1169*2264Sjacobs 			if (!mem) goto error;
1170*2264Sjacobs 			buffer = mem;
1171*2264Sjacobs 		}
1172*2264Sjacobs 	}
1173*2264Sjacobs 
1174*2264Sjacobs 	fprintf(fp, "%s%s\n", prefix, buffer ? buffer : "");
1175*2264Sjacobs 	fflush(fp);
1176*2264Sjacobs 
1177*2264Sjacobs  error:
1178*2264Sjacobs 	free(newfmt);
1179*2264Sjacobs 	free(prefix);
1180*2264Sjacobs 	free(buffer);
1181*2264Sjacobs }
1182