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