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