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 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 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 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 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 ** 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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