8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / print / libpapi-common / common / attribute.c
blob8e90d4e9e0619c686a5073e02569a1fa497f9296
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2014 Gary Mills
25 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
30 /*LINTLIBRARY*/
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <alloca.h>
38 #include <papi.h>
39 #include <regex.h>
41 #define MAX_PAGES 32767
43 * Assuming the maximum number of pages in
44 * a document to be 32767
47 static void papiAttributeFree(papi_attribute_t *attribute);
49 static void
50 papiAttributeValueFree(papi_attribute_value_type_t type,
51 papi_attribute_value_t *value)
53 if (value != NULL) {
54 switch (type) {
55 case PAPI_STRING:
56 if (value->string != NULL)
57 free(value->string);
58 break;
59 case PAPI_COLLECTION:
60 if (value->collection != NULL) {
61 int i;
63 for (i = 0; value->collection[i] != NULL; i++)
64 papiAttributeFree(value->collection[i]);
66 free(value->collection);
68 break;
69 default: /* don't need to free anything extra */
70 break;
73 free(value);
77 static void
78 papiAttributeValuesFree(papi_attribute_value_type_t type,
79 papi_attribute_value_t **values)
81 if (values != NULL) {
82 int i;
84 for (i = 0; values[i] != NULL; i++)
85 papiAttributeValueFree(type, values[i]);
87 free(values);
91 static void
92 papiAttributeFree(papi_attribute_t *attribute)
94 if (attribute != NULL) {
95 free(attribute->name);
96 if (attribute->values != NULL)
97 papiAttributeValuesFree(attribute->type,
98 attribute->values);
99 free(attribute);
103 void
104 papiAttributeListFree(papi_attribute_t **list)
106 if (list != NULL) {
107 int i;
109 for (i = 0; list[i] != NULL; i++)
110 papiAttributeFree(list[i]);
112 free(list);
116 static papi_attribute_t **
117 collection_dup(papi_attribute_t **collection)
119 papi_attribute_t **result = NULL;
121 /* allows a NULL collection that is "empty" or "no value" */
122 if (collection != NULL) {
123 papi_status_t status = PAPI_OK;
124 int i;
126 for (i = 0; ((collection[i] != NULL) && (status == PAPI_OK));
127 i++) {
128 papi_attribute_t *a = collection[i];
130 status = papiAttributeListAddValue(&result,
131 PAPI_ATTR_APPEND, a->name, a->type, NULL);
132 if ((status == PAPI_OK) && (a->values != NULL)) {
133 int j;
135 for (j = 0; ((a->values[j] != NULL) &&
136 (status == PAPI_OK)); j++)
137 status = papiAttributeListAddValue(
138 &result, PAPI_ATTR_APPEND,
139 a->name, a->type, a->values[j]);
142 if (status != PAPI_OK) {
143 papiAttributeListFree(result);
144 result = NULL;
148 return (result);
151 static papi_attribute_value_t *
152 papiAttributeValueDup(papi_attribute_value_type_t type,
153 papi_attribute_value_t *v)
155 papi_attribute_value_t *result = NULL;
157 if ((v != NULL) && ((result = calloc(1, sizeof (*result))) != NULL)) {
158 switch (type) {
159 case PAPI_STRING:
160 if (v->string == NULL) {
161 free(result);
162 result = NULL;
163 } else
164 result->string = strdup(v->string);
165 break;
166 case PAPI_INTEGER:
167 result->integer = v->integer;
168 break;
169 case PAPI_BOOLEAN:
170 result->boolean = v->boolean;
171 break;
172 case PAPI_RANGE:
173 result->range.lower = v->range.lower;
174 result->range.upper = v->range.upper;
175 break;
176 case PAPI_RESOLUTION:
177 result->resolution.xres = v->resolution.xres;
178 result->resolution.yres = v->resolution.yres;
179 result->resolution.units = v->resolution.units;
180 break;
181 case PAPI_DATETIME:
182 result->datetime = v->datetime;
183 break;
184 case PAPI_COLLECTION:
185 result->collection = collection_dup(v->collection);
186 break;
187 case PAPI_METADATA:
188 result->metadata = v->metadata;
189 break;
190 default: /* unknown type, fail to duplicate */
191 free(result);
192 result = NULL;
196 return (result);
199 static papi_attribute_t *
200 papiAttributeAlloc(char *name, papi_attribute_value_type_t type)
202 papi_attribute_t *result = NULL;
204 if ((result = calloc(1, sizeof (*result))) != NULL) {
205 result->name = strdup(name);
206 result->type = type;
209 return (result);
212 static papi_status_t
213 papiAttributeListAppendValue(papi_attribute_value_t ***values,
214 papi_attribute_value_type_t type,
215 papi_attribute_value_t *value)
218 if (values == NULL)
219 return (PAPI_BAD_ARGUMENT);
221 if (value != NULL) { /* this allows "empty" attributes */
222 papi_attribute_value_t *tmp = NULL;
224 if ((tmp = papiAttributeValueDup(type, value)) == NULL)
225 return (PAPI_TEMPORARY_ERROR);
227 list_append(values, tmp);
230 return (PAPI_OK);
233 papi_status_t
234 papiAttributeListAddValue(papi_attribute_t ***list, int flgs,
235 char *name, papi_attribute_value_type_t type,
236 papi_attribute_value_t *value)
238 papi_status_t result;
239 int flags = flgs;
240 papi_attribute_t *attribute = NULL;
241 papi_attribute_value_t **values = NULL;
243 if ((list == NULL) || (name == NULL))
244 return (PAPI_BAD_ARGUMENT);
246 if ((type == PAPI_RANGE) && (value != NULL) &&
247 (value->range.lower > value->range.upper))
248 return (PAPI_BAD_ARGUMENT); /* RANGE must have min <= max */
250 if (flags == 0) /* if it wasn't set, set a default behaviour */
251 flags = PAPI_ATTR_APPEND;
253 /* look for an existing one */
254 attribute = papiAttributeListFind(*list, name);
256 if (((flags & PAPI_ATTR_EXCL) != 0) && (attribute != NULL))
257 return (PAPI_CONFLICT); /* EXISTS */
259 if (((flags & PAPI_ATTR_REPLACE) == 0) && (attribute != NULL) &&
260 (attribute->type != type))
261 return (PAPI_CONFLICT); /* TYPE CONFLICT */
263 /* if we don't have one, create it and add it to the list */
264 if ((attribute == NULL) &&
265 ((attribute = papiAttributeAlloc(name, type)) != NULL))
266 list_append(list, attribute);
268 /* if we don't have one by now, it's most likely an alloc fail */
269 if (attribute == NULL)
270 return (PAPI_TEMPORARY_ERROR);
273 * if we are replacing, clear any existing values, but don't free
274 * until after we have replaced the values, in case we are replacing
275 * a collection with a relocated version of the original collection.
277 if (((flags & PAPI_ATTR_REPLACE) != 0) && (attribute->values != NULL)) {
278 values = attribute->values;
279 attribute->values = NULL;
282 attribute->type = type;
284 result = papiAttributeListAppendValue(&attribute->values, type, value);
286 /* free old values if we replaced them */
287 if (values != NULL)
288 papiAttributeValuesFree(type, values);
290 return (result);
293 papi_status_t
294 papiAttributeListAddString(papi_attribute_t ***list, int flags,
295 char *name, char *string)
297 papi_attribute_value_t v;
299 v.string = (char *)string;
300 return (papiAttributeListAddValue(list, flags, name, PAPI_STRING, &v));
303 papi_status_t
304 papiAttributeListAddInteger(papi_attribute_t ***list, int flags,
305 char *name, int integer)
307 papi_attribute_value_t v;
309 v.integer = integer;
310 return (papiAttributeListAddValue(list, flags, name, PAPI_INTEGER, &v));
313 papi_status_t
314 papiAttributeListAddBoolean(papi_attribute_t ***list, int flags,
315 char *name, char boolean)
317 papi_attribute_value_t v;
319 v.boolean = boolean;
320 return (papiAttributeListAddValue(list, flags, name, PAPI_BOOLEAN, &v));
323 papi_status_t
324 papiAttributeListAddRange(papi_attribute_t ***list, int flags,
325 char *name, int lower, int upper)
327 papi_attribute_value_t v;
329 v.range.lower = lower;
330 v.range.upper = upper;
331 return (papiAttributeListAddValue(list, flags, name, PAPI_RANGE, &v));
334 papi_status_t
335 papiAttributeListAddResolution(papi_attribute_t ***list, int flags,
336 char *name, int xres, int yres, papi_resolution_unit_t units)
338 papi_attribute_value_t v;
340 v.resolution.xres = xres;
341 v.resolution.yres = yres;
342 v.resolution.units = units;
343 return (papiAttributeListAddValue(list, flags, name,
344 PAPI_RESOLUTION, &v));
347 papi_status_t
348 papiAttributeListAddDatetime(papi_attribute_t ***list, int flags,
349 char *name, time_t datetime)
351 papi_attribute_value_t v;
353 v.datetime = datetime;
354 return (papiAttributeListAddValue(list, flags, name,
355 PAPI_DATETIME, &v));
358 papi_status_t
359 papiAttributeListAddCollection(papi_attribute_t ***list, int flags,
360 char *name, papi_attribute_t **collection)
362 papi_attribute_value_t v;
364 v.collection = (papi_attribute_t **)collection;
365 return (papiAttributeListAddValue(list, flags, name,
366 PAPI_COLLECTION, &v));
369 papi_status_t
370 papiAttributeListAddMetadata(papi_attribute_t ***list, int flags,
371 char *name, papi_metadata_t metadata)
373 papi_attribute_value_t v;
375 v.metadata = metadata;
376 return (papiAttributeListAddValue(list, flags, name,
377 PAPI_METADATA, &v));
380 papi_status_t
381 papiAttributeListDelete(papi_attribute_t ***list, char *name)
383 papi_attribute_t *attribute;
385 if ((list == NULL) || (name == NULL))
386 return (PAPI_BAD_ARGUMENT);
388 if ((attribute = papiAttributeListFind(*list, name)) == NULL)
389 return (PAPI_NOT_FOUND);
391 list_remove(list, attribute);
392 papiAttributeFree(attribute);
394 return (PAPI_OK);
397 papi_attribute_t *
398 papiAttributeListFind(papi_attribute_t **list, char *name)
400 int i;
401 if ((list == NULL) || (name == NULL))
402 return (NULL);
404 for (i = 0; list[i] != NULL; i++)
405 if (strcasecmp(list[i]->name, name) == 0)
406 return ((papi_attribute_t *)list[i]);
408 return (NULL);
411 papi_attribute_t *
412 papiAttributeListGetNext(papi_attribute_t **list, void **iter)
414 papi_attribute_t **tmp, *result;
416 if ((list == NULL) && (iter == NULL))
417 return (NULL);
419 if (*iter == NULL)
420 *iter = list;
422 tmp = *iter;
423 result = *tmp;
424 *iter = ++tmp;
426 return (result);
429 papi_status_t
430 papiAttributeListGetValue(papi_attribute_t **list, void **iter,
431 char *name, papi_attribute_value_type_t type,
432 papi_attribute_value_t **value)
434 papi_attribute_value_t **tmp;
435 void *fodder = NULL;
437 if ((list == NULL) || ((name == NULL) && (iter == NULL)) ||
438 (value == NULL))
439 return (PAPI_BAD_ARGUMENT);
441 if (iter == NULL)
442 iter = &fodder;
444 if ((iter == NULL) || (*iter == NULL)) {
445 papi_attribute_t *attr = papiAttributeListFind(list, name);
447 if (attr == NULL)
448 return (PAPI_NOT_FOUND);
450 if (attr->type != type)
451 return (PAPI_NOT_POSSIBLE);
453 tmp = attr->values;
454 } else
455 tmp = *iter;
457 if (tmp == NULL)
458 return (PAPI_NOT_FOUND);
460 *value = *tmp;
461 *iter = ++tmp;
463 if (*value == NULL)
464 return (PAPI_GONE);
466 return (PAPI_OK);
469 papi_status_t
470 papiAttributeListGetString(papi_attribute_t **list, void **iter,
471 char *name, char **vptr)
473 papi_status_t status;
474 papi_attribute_value_t *value = NULL;
476 if (vptr == NULL)
477 return (PAPI_BAD_ARGUMENT);
479 status = papiAttributeListGetValue(list, iter, name,
480 PAPI_STRING, &value);
481 if (status == PAPI_OK)
482 *vptr = value->string;
484 return (status);
487 papi_status_t
488 papiAttributeListGetInteger(papi_attribute_t **list, void **iter,
489 char *name, int *vptr)
491 papi_status_t status;
492 papi_attribute_value_t *value = NULL;
494 if (vptr == NULL)
495 return (PAPI_BAD_ARGUMENT);
497 status = papiAttributeListGetValue(list, iter, name,
498 PAPI_INTEGER, &value);
499 if (status == PAPI_OK)
500 *vptr = value->integer;
502 return (status);
505 papi_status_t
506 papiAttributeListGetBoolean(papi_attribute_t **list, void **iter,
507 char *name, char *vptr)
509 papi_status_t status;
510 papi_attribute_value_t *value = NULL;
512 if (vptr == NULL)
513 return (PAPI_BAD_ARGUMENT);
515 status = papiAttributeListGetValue(list, iter, name,
516 PAPI_BOOLEAN, &value);
517 if (status == PAPI_OK)
518 *vptr = value->boolean;
520 return (status);
523 papi_status_t
524 papiAttributeListGetRange(papi_attribute_t **list, void **iter,
525 char *name, int *min, int *max)
527 papi_status_t status;
528 papi_attribute_value_t *value = NULL;
530 if ((min == NULL) || (max == NULL))
531 return (PAPI_BAD_ARGUMENT);
533 status = papiAttributeListGetValue(list, iter, name,
534 PAPI_RANGE, &value);
535 if (status == PAPI_OK) {
536 *min = value->range.lower;
537 *max = value->range.upper;
540 return (status);
543 papi_status_t
544 papiAttributeListGetResolution(papi_attribute_t **list, void **iter,
545 char *name, int *x, int *y, papi_resolution_unit_t *units)
547 papi_status_t status;
548 papi_attribute_value_t *value = NULL;
550 if ((x == NULL) || (y == NULL) || (units == NULL))
551 return (PAPI_BAD_ARGUMENT);
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;
561 return (status);
564 papi_status_t
565 papiAttributeListGetDatetime(papi_attribute_t **list, void **iter,
566 char *name, time_t *dt)
568 papi_status_t status;
569 papi_attribute_value_t *value = NULL;
571 if (dt == NULL)
572 return (PAPI_BAD_ARGUMENT);
574 status = papiAttributeListGetValue(list, iter, name,
575 PAPI_DATETIME, &value);
576 if (status == PAPI_OK) {
577 *dt = value->datetime;
580 return (status);
583 papi_status_t
584 papiAttributeListGetCollection(papi_attribute_t **list, void **iter,
585 char *name, papi_attribute_t ***collection)
587 papi_status_t status;
588 papi_attribute_value_t *value = NULL;
590 if (collection == NULL)
591 return (PAPI_BAD_ARGUMENT);
593 status = papiAttributeListGetValue(list, iter, name,
594 PAPI_COLLECTION, &value);
595 if (status == PAPI_OK) {
596 *collection = value->collection;
599 return (status);
602 papi_status_t
603 papiAttributeListGetMetadata(papi_attribute_t **list, void **iter,
604 char *name, papi_metadata_t *vptr)
606 papi_status_t status;
607 papi_attribute_value_t *value = NULL;
609 if (vptr == NULL)
610 return (PAPI_BAD_ARGUMENT);
612 status = papiAttributeListGetValue(list, iter, name,
613 PAPI_METADATA, &value);
614 if (status == PAPI_OK)
615 *vptr = value->metadata;
617 return (status);
621 /* The string is modified by this call */
622 static char *
623 regvalue(regmatch_t match, char *string)
625 char *result = NULL;
626 if (match.rm_so != match.rm_eo) {
627 result = string + match.rm_so;
628 *(result + (match.rm_eo - match.rm_so)) = '\0';
630 return (result);
633 static papi_attribute_value_type_t
634 _process_value(char *string, char ***parts)
636 int i;
637 static struct {
638 papi_attribute_value_type_t type;
639 size_t vals;
640 char *expression;
641 int compiled;
642 regex_t re;
643 } types[] = {
644 { PAPI_BOOLEAN, 1, "^(true|false|yes|no)$", 0 },
645 { PAPI_COLLECTION, 1, "^\\{(.+)\\}$", 0 },
646 /* PAPI_DATETIME is unsupported, too much like an integer */
647 { PAPI_INTEGER, 1, "^([+-]{0,1}[[:digit:]]+)$", 0 },
648 { PAPI_RANGE, 3, "^([[:digit:]]*)-([[:digit:]]*)$", 0 },
649 { PAPI_RESOLUTION, 4, "^([[:digit:]]+)x([[:digit:]]+)dp(i|c)$",
650 0 },
651 NULL
653 regmatch_t matches[4];
655 for (i = 0; i < 5; i++) {
656 int j;
658 if (types[i].compiled == 0) {
659 (void) regcomp(&(types[i].re), types[i].expression,
660 REG_EXTENDED|REG_ICASE);
661 types[i].compiled = 1;
663 if (regexec(&(types[i].re), string, (size_t)types[i].vals,
664 matches, 0) == REG_NOMATCH)
665 continue;
667 for (j = 0; j < types[i].vals; j++)
668 list_append(parts, regvalue(matches[j], string));
669 return (types[i].type);
672 list_append(parts, string);
673 return (PAPI_STRING);
676 static void
677 _add_attribute_value(papi_attribute_value_t ***list,
678 papi_attribute_value_type_t type,
679 papi_attribute_value_type_t dtype, char **parts)
681 papi_attribute_value_t *value = calloc(1, sizeof (*value));
683 switch (type) {
684 case PAPI_STRING:
685 value->string = strdup(parts[0]);
686 list_append(list, value);
687 break;
688 case PAPI_BOOLEAN:
689 value->boolean = PAPI_TRUE;
690 if ((strcasecmp(parts[0], "false") == 0) ||
691 (strcasecmp(parts[0], "no") == 0))
692 value->boolean = PAPI_FALSE;
693 list_append(list, value);
694 break;
695 case PAPI_INTEGER:
696 value->integer = atoi(parts[0]);
697 list_append(list, value);
698 break;
699 case PAPI_RANGE:
700 if (dtype == PAPI_INTEGER) {
701 if (atoi(parts[0]) < 0) {
703 * Handles -P -x case
704 * which prints from page number 1
705 * till page number x
707 value->range.lower = 1;
708 value->range.upper = 0 - (atoi(parts[0]));
709 } else {
710 value->range.lower = value->range.upper
711 = atoi(parts[0]);
713 } else if (dtype == PAPI_RANGE) {
714 if (parts[2] == NULL) {
715 value->range.lower = atoi(parts[1]);
717 * Imposing an artificial limit on
718 * the upper bound for page range.
720 value->range.upper = MAX_PAGES;
721 } else if ((parts[1] != NULL) && (parts[2] != NULL)) {
722 value->range.lower = atoi(parts[1]);
723 value->range.upper = atoi(parts[2]);
726 list_append(list, value);
727 break;
728 case PAPI_RESOLUTION:
729 value->resolution.xres = atoi(parts[1]);
730 value->resolution.yres = atoi(parts[2]);
731 if (parts[3][0] == 'i')
732 value->resolution.units = PAPI_RES_PER_INCH;
733 else
734 value->resolution.units = PAPI_RES_PER_CM;
735 list_append(list, value);
736 break;
737 case PAPI_COLLECTION:
738 papiAttributeListFromString(&(value->collection), 0, parts[0]);
739 list_append(list, value);
740 break;
744 static papi_status_t
745 _papiAttributeFromStrings(papi_attribute_t ***list, int flags,
746 char *key, char **values)
748 int i;
749 papi_status_t result = PAPI_OK;
750 papi_attribute_t *attr = calloc(1, sizeof (*attr));
752 /* these are specified in the papi spec as ranges */
753 char *ranges[] = { "copies-supported", "job-impressions-supported",
754 "job-k-octets-supported",
755 "job-media-sheets-supported", "page-ranges",
756 NULL };
758 if ((attr == NULL) || ((attr->name = strdup(key)) == NULL))
759 return (PAPI_TEMPORARY_ERROR);
761 attr->type = PAPI_METADATA;
762 /* these are known ranges */
763 for (i = 0; ranges[i] != NULL; i++)
764 if (strcasecmp(attr->name, ranges[i]) == 0) {
765 attr->type = PAPI_RANGE;
766 break;
769 if (values != NULL) {
770 papi_attribute_value_t **vals = NULL;
772 for (i = 0; values[i] != NULL; i++) {
773 papi_attribute_value_type_t dtype;
774 char **parts = NULL;
776 dtype = _process_value(values[i], &parts);
777 if (attr->type == PAPI_METADATA)
778 attr->type = dtype;
779 _add_attribute_value(&vals, attr->type, dtype, parts);
780 free(parts);
782 attr->values = vals;
785 list_append(list, attr);
787 return (result);
790 static papi_status_t
791 _parse_attribute_list(papi_attribute_t ***list, int flags, char *string)
793 papi_status_t result = PAPI_OK;
794 char *ptr;
796 if ((list == NULL) || (string == NULL))
797 return (PAPI_BAD_ARGUMENT);
799 if ((ptr = strdup(string)) == NULL)
800 return (PAPI_TEMPORARY_ERROR);
802 while ((*ptr != '\0') && (result == PAPI_OK)) {
803 char *key, **values = NULL;
805 /* strip any leading whitespace */
806 while (isspace(*ptr) != 0)
807 ptr++;
809 /* Get the name: name[=value] */
810 key = ptr;
811 while ((*ptr != '\0') && (*ptr != '=') && (isspace(*ptr) == 0))
812 ptr++;
814 if (*ptr == '=') {
815 *ptr++ = '\0';
817 while ((*ptr != '\0') && (isspace(*ptr) == 0)) {
818 char *value = ptr;
820 if ((*ptr == '\'') || (*ptr == '"')) {
821 char q = *ptr++;
823 /* quoted string value */
824 while ((*ptr != '\0') && (*ptr != q))
825 ptr++;
826 if (*ptr == q)
827 ptr++;
828 } else if (*ptr == '{') {
829 /* collection */
830 while ((*ptr != '\0') && (*ptr != '}'))
831 ptr++;
832 if (*ptr == '}')
833 ptr++;
834 } else {
835 /* value */
836 while ((*ptr != '\0') &&
837 (*ptr != ',') &&
838 (isspace(*ptr) == 0))
839 ptr++;
841 if (*ptr == ',')
842 *ptr++ = '\0';
843 list_append(&values, value);
845 } else { /* boolean "[no]key" */
846 char *value = "true";
848 if (strncasecmp(key, "no", 2) == 0) {
849 key += 2;
850 value = "false";
852 list_append(&values, value);
854 if (*ptr != '\0')
855 *ptr++ = '\0';
857 result = _papiAttributeFromStrings(list, flags, key, values);
858 free(values);
861 return (result);
864 papi_status_t
865 papiAttributeListFromString(papi_attribute_t ***attrs, int flags, char *string)
867 papi_status_t result = PAPI_OK;
869 if ((attrs != NULL) && (string != NULL) &&
870 ((flags & ~(PAPI_ATTR_APPEND+PAPI_ATTR_REPLACE+PAPI_ATTR_EXCL))
871 == 0)) {
872 result = _parse_attribute_list(attrs, flags, string);
873 } else {
874 result = PAPI_BAD_ARGUMENT;
877 return (result);
880 static papi_status_t
881 papiAttributeToString(papi_attribute_t *attribute, char *delim,
882 char *buffer, size_t buflen)
884 papi_attribute_value_t **values = attribute->values;
885 int rc, i;
887 if ((attribute->type == PAPI_BOOLEAN) && (values[1] == NULL)) {
888 if (values[0]->boolean == PAPI_FALSE) {
889 if (isupper(attribute->name[0]) == 0)
890 strlcat(buffer, "no", buflen);
891 else
892 strlcat(buffer, "No", buflen);
894 rc = strlcat(buffer, attribute->name, buflen);
895 } else {
896 strlcat(buffer, attribute->name, buflen);
897 rc = strlcat(buffer, "=", buflen);
900 if (values == NULL)
901 return (PAPI_OK);
903 for (i = 0; values[i] != NULL; i++) {
904 switch (attribute->type) {
905 case PAPI_STRING:
906 rc = strlcat(buffer, values[i]->string, buflen);
907 break;
908 case PAPI_INTEGER: {
909 char string[24];
911 snprintf(string, sizeof (string), "%d",
912 values[i]->integer);
913 rc = strlcat(buffer, string, buflen);
915 break;
916 case PAPI_BOOLEAN:
917 if (values[1] != NULL)
918 rc = strlcat(buffer, values[i]->boolean ?
919 "true" : "false", buflen);
920 break;
921 case PAPI_RANGE: {
922 char string[24];
924 if (values[i]->range.lower == values[i]->range.upper)
925 snprintf(string, sizeof (string), "%d",
926 values[i]->range.lower);
927 else
928 snprintf(string, sizeof (string), "%d-%d",
929 values[i]->range.lower,
930 values[i]->range.upper);
931 rc = strlcat(buffer, string, buflen);
933 break;
934 case PAPI_RESOLUTION: {
935 char string[24];
937 snprintf(string, sizeof (string), "%dx%ddp%c",
938 values[i]->resolution.xres,
939 values[i]->resolution.yres,
940 values[i]->resolution.units == PAPI_RES_PER_CM ?
941 'c' : 'i');
942 rc = strlcat(buffer, string, buflen);
944 break;
945 case PAPI_DATETIME: {
946 struct tm *tm = localtime(&values[i]->datetime);
948 if (tm != NULL) {
949 char string[64];
951 strftime(string, sizeof (string), "%c", tm);
952 rc = strlcat(buffer, string, buflen);
954 break;
955 case PAPI_COLLECTION: {
956 char *string = alloca(buflen);
958 papiAttributeListToString(values[i]->collection,
959 delim, string, buflen);
960 rc = strlcat(buffer, string, buflen);
962 break;
963 default: {
964 char string[32];
966 snprintf(string, sizeof (string), "unknown-type-0x%x",
967 attribute->type);
968 rc = strlcat(buffer, string, buflen);
971 if (values[i+1] != NULL)
972 rc = strlcat(buffer, ",", buflen);
974 if (rc >= buflen)
975 return (PAPI_NOT_POSSIBLE);
979 return (PAPI_OK);
982 papi_status_t
983 papiAttributeListToString(papi_attribute_t **attrs,
984 char *delim, char *buffer, size_t buflen)
986 papi_status_t status = PAPI_OK;
987 int i;
989 if ((attrs == NULL) || (buffer == NULL))
990 return (PAPI_BAD_ARGUMENT);
992 buffer[0] = '\0';
993 if (!delim)
994 delim = " ";
996 for (i = 0; ((attrs[i] != NULL) && (status == PAPI_OK)); i++) {
997 status = papiAttributeToString(attrs[i], delim, buffer, buflen);
998 if (attrs[i+1] != NULL)
999 strlcat(buffer, delim, buflen);
1002 return (status);
1005 static int
1006 is_in_list(char *value, char **list)
1008 if ((list != NULL) && (value != NULL)) {
1009 int i;
1011 for (i = 0; list[i] != NULL; i++)
1012 if (strcasecmp(value, list[i]) == 0)
1013 return (0);
1016 return (1);
1019 static papi_status_t
1020 copy_attribute(papi_attribute_t ***list, papi_attribute_t *attribute)
1022 papi_status_t status;
1023 int i = 0;
1025 if ((list == NULL) || (attribute == NULL) ||
1026 (attribute->values == NULL))
1027 return (PAPI_BAD_ARGUMENT);
1029 for (status = papiAttributeListAddValue(list, PAPI_ATTR_EXCL,
1030 attribute->name, attribute->type, attribute->values[i]);
1031 ((status == PAPI_OK) && (attribute->values[i] != NULL));
1032 status = papiAttributeListAddValue(list, PAPI_ATTR_APPEND,
1033 attribute->name, attribute->type, attribute->values[i]))
1034 i++;
1036 return (status);
1039 void
1040 copy_attributes(papi_attribute_t ***result, papi_attribute_t **attributes)
1042 int i;
1044 if ((result == NULL) || (attributes == NULL))
1045 return;
1047 for (i = 0; attributes[i] != NULL; i++)
1048 copy_attribute(result, attributes[i]);
1051 void
1052 split_and_copy_attributes(char **list, papi_attribute_t **attributes,
1053 papi_attribute_t ***in, papi_attribute_t ***out)
1055 int i;
1057 if ((list == NULL) || (attributes == NULL))
1058 return;
1060 for (i = 0; attributes[i] != NULL; i++)
1061 if (is_in_list(attributes[i]->name, list) == 0)
1062 copy_attribute(in, attributes[i]);
1063 else
1064 copy_attribute(out, attributes[i]);
1067 void
1068 papiAttributeListPrint(FILE *fp, papi_attribute_t **attributes,
1069 char *prefix_fmt, ...)
1071 char *prefix = NULL;
1072 char *buffer = NULL;
1073 char *newfmt = NULL;
1074 void *mem;
1075 ssize_t size = 0;
1076 va_list ap;
1078 newfmt = malloc(strlen(prefix_fmt) + 2);
1079 sprintf(newfmt, "\n%s", prefix_fmt);
1081 va_start(ap, prefix_fmt);
1082 while (vsnprintf(prefix, size, newfmt, ap) > size) {
1083 size += 1024;
1084 mem = realloc(prefix, size);
1085 if (!mem) goto error;
1086 prefix = mem;
1088 va_end(ap);
1090 if (attributes) {
1091 size = 0;
1092 while (papiAttributeListToString(attributes, prefix, buffer,
1093 size) != PAPI_OK) {
1094 size += 1024;
1095 mem = realloc(buffer, size);
1096 if (!mem) goto error;
1097 buffer = mem;
1101 fprintf(fp, "%s%s\n", prefix, buffer ? buffer : "");
1102 fflush(fp);
1104 error:
1105 free(newfmt);
1106 free(prefix);
1107 free(buffer);