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