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