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