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