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