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