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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 */ 27 28 /* $Id: attribute.c 157 2006-04-26 15:07:55Z ktou $ */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 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 static void papiAttributeFree(papi_attribute_t *attribute); 44 45 static void 46 papiAttributeValueFree(papi_attribute_value_type_t type, 47 papi_attribute_value_t *value) 48 { 49 if (value != NULL) { 50 switch (type) { 51 case PAPI_STRING: 52 if (value->string != NULL) 53 free(value->string); 54 break; 55 case PAPI_COLLECTION: 56 if (value->collection != NULL) { 57 int i; 58 59 for (i = 0; value->collection[i] != NULL; i++) 60 papiAttributeFree(value->collection[i]); 61 62 free(value->collection); 63 } 64 break; 65 default: /* don't need to free anything extra */ 66 break; 67 } 68 69 free(value); 70 } 71 } 72 73 static void 74 papiAttributeValuesFree(papi_attribute_value_type_t type, 75 papi_attribute_value_t **values) 76 { 77 if (values != NULL) { 78 int i; 79 80 for (i = 0; values[i] != NULL; i++) 81 papiAttributeValueFree(type, values[i]); 82 83 free(values); 84 } 85 } 86 87 static void 88 papiAttributeFree(papi_attribute_t *attribute) 89 { 90 if (attribute != NULL) { 91 if (attribute->name != NULL) 92 free(attribute->name); 93 if (attribute->values != NULL) 94 papiAttributeValuesFree(attribute->type, 95 attribute->values); 96 free(attribute); 97 } 98 } 99 100 void 101 papiAttributeListFree(papi_attribute_t **list) 102 { 103 if (list != NULL) { 104 int i; 105 106 for (i = 0; list[i] != NULL; i++) 107 papiAttributeFree(list[i]); 108 109 free(list); 110 } 111 } 112 113 static papi_attribute_t ** 114 collection_dup(papi_attribute_t **collection) 115 { 116 papi_attribute_t **result = NULL; 117 118 /* allows a NULL collection that is "empty" or "no value" */ 119 if (collection != NULL) { 120 papi_status_t status = PAPI_OK; 121 int i; 122 123 for (i = 0; ((collection[i] != NULL) && (status == PAPI_OK)); 124 i++) { 125 papi_attribute_t *a = collection[i]; 126 127 status = papiAttributeListAddValue(&result, 128 PAPI_ATTR_APPEND, a->name, a->type, 129 NULL); 130 if ((status == PAPI_OK) && (a->values != NULL)) { 131 int j; 132 133 for (j = 0; ((a->values[j] != NULL) && 134 (status == PAPI_OK)); j++) 135 status = papiAttributeListAddValue( 136 &result, 137 PAPI_ATTR_APPEND, 138 a->name, a->type, 139 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, 337 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 if (tmp == NULL) 459 return (PAPI_NOT_FOUND); 460 461 *value = *tmp; 462 *iter = ++tmp; 463 464 if (*value == NULL) 465 return (PAPI_GONE); 466 467 return (PAPI_OK); 468 } 469 470 papi_status_t 471 papiAttributeListGetString(papi_attribute_t **list, void **iter, 472 char *name, char **vptr) 473 { 474 papi_status_t status; 475 papi_attribute_value_t *value = NULL; 476 477 if (vptr == NULL) 478 return (PAPI_BAD_ARGUMENT); 479 480 status = papiAttributeListGetValue(list, iter, name, 481 PAPI_STRING, &value); 482 if (status == PAPI_OK) 483 *vptr = value->string; 484 485 return (status); 486 } 487 488 papi_status_t 489 papiAttributeListGetInteger(papi_attribute_t **list, void **iter, 490 char *name, int *vptr) 491 { 492 papi_status_t status; 493 papi_attribute_value_t *value = NULL; 494 495 if (vptr == NULL) 496 return (PAPI_BAD_ARGUMENT); 497 498 status = papiAttributeListGetValue(list, iter, name, 499 PAPI_INTEGER, &value); 500 if (status == PAPI_OK) 501 *vptr = value->integer; 502 503 return (status); 504 } 505 506 papi_status_t 507 papiAttributeListGetBoolean(papi_attribute_t **list, void **iter, 508 char *name, char *vptr) 509 { 510 papi_status_t status; 511 papi_attribute_value_t *value = NULL; 512 513 if (vptr == NULL) 514 return (PAPI_BAD_ARGUMENT); 515 516 status = papiAttributeListGetValue(list, iter, name, 517 PAPI_BOOLEAN, &value); 518 if (status == PAPI_OK) 519 *vptr = value->boolean; 520 521 return (status); 522 } 523 524 papi_status_t 525 papiAttributeListGetRange(papi_attribute_t **list, void **iter, 526 char *name, int *min, int *max) 527 { 528 papi_status_t status; 529 papi_attribute_value_t *value = NULL; 530 531 if ((min == NULL) || (max == NULL)) 532 return (PAPI_BAD_ARGUMENT); 533 534 status = papiAttributeListGetValue(list, iter, name, 535 PAPI_RANGE, &value); 536 if (status == PAPI_OK) { 537 *min = value->range.lower; 538 *max = value->range.upper; 539 } 540 541 return (status); 542 } 543 544 papi_status_t 545 papiAttributeListGetResolution(papi_attribute_t **list, void **iter, 546 char *name, int *x, int *y, 547 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 NULL 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 value->range.lower = value->range.upper 704 = atoi(parts[0]); 705 else if (dtype == PAPI_RANGE) { 706 value->range.lower = atoi(parts[1]); 707 value->range.upper = atoi(parts[2]); 708 } 709 list_append(list, value); 710 break; 711 case PAPI_RESOLUTION: 712 value->resolution.xres = atoi(parts[1]); 713 value->resolution.yres = atoi(parts[2]); 714 if (parts[3][0] == 'i') 715 value->resolution.units = PAPI_RES_PER_INCH; 716 else 717 value->resolution.units = PAPI_RES_PER_CM; 718 list_append(list, value); 719 break; 720 case PAPI_COLLECTION: 721 papiAttributeListFromString(&(value->collection), 0, parts[0]); 722 list_append(list, value); 723 break; 724 } 725 } 726 727 static papi_status_t 728 _papiAttributeFromStrings(papi_attribute_t ***list, int flags, 729 char *key, char **values) 730 { 731 int i; 732 papi_status_t result = PAPI_OK; 733 papi_attribute_t *attr = calloc(1, sizeof (*attr)); 734 735 /* these are specified in the papi spec as ranges */ 736 char *ranges[] = { "copies-supported", "job-impressions-supported", 737 "job-k-octets-supported", 738 "job-media-sheets-supported", "page-ranges", 739 NULL }; 740 741 if ((attr == NULL) || ((attr->name = strdup(key)) == NULL)) 742 return (PAPI_TEMPORARY_ERROR); 743 744 attr->type = PAPI_METADATA; 745 /* these are known ranges */ 746 for (i = 0; ranges[i] != NULL; i++) 747 if (strcasecmp(attr->name, ranges[i]) == 0) { 748 attr->type = PAPI_RANGE; 749 break; 750 } 751 752 if (values != NULL) { 753 papi_attribute_value_t **vals = NULL; 754 755 for (i = 0; values[i] != NULL; i++) { 756 papi_attribute_value_type_t dtype; 757 char **parts = NULL; 758 759 dtype = _process_value(values[i], &parts); 760 if (attr->type == PAPI_METADATA) 761 attr->type = dtype; 762 _add_attribute_value(&vals, attr->type, dtype, parts); 763 free(parts); 764 } 765 attr->values = vals; 766 } 767 768 list_append(list, attr); 769 770 return (result); 771 } 772 773 static papi_status_t 774 _parse_attribute_list(papi_attribute_t ***list, int flags, char *string) 775 { 776 papi_status_t result = PAPI_OK; 777 char *ptr; 778 779 if ((list == NULL) || (string == NULL)) 780 return (PAPI_BAD_ARGUMENT); 781 782 if ((ptr = strdup(string)) == NULL) 783 return (PAPI_TEMPORARY_ERROR); 784 785 while ((*ptr != '\0') && (result == PAPI_OK)) { 786 char *key, **values = NULL; 787 788 /* strip any leading whitespace */ 789 while (isspace(*ptr) != 0) 790 ptr++; 791 792 /* Get the name: name[=value] */ 793 key = ptr; 794 while ((*ptr != '\0') && (*ptr != '=') && (isspace(*ptr) == 0)) 795 ptr++; 796 797 if (*ptr == '=') { 798 *ptr++ = '\0'; 799 800 while ((*ptr != '\0') && (isspace(*ptr) == 0)) { 801 char *value = ptr; 802 803 if ((*ptr == '\'') || (*ptr == '"')) { 804 char q = *ptr++; 805 806 /* quoted string value */ 807 while ((*ptr != '\0') && (*ptr != q)) 808 ptr++; 809 if (*ptr == q) 810 ptr++; 811 } else if (*ptr == '{') { 812 /* collection */ 813 while ((*ptr != '\0') && (*ptr != '}')) 814 ptr++; 815 if (*ptr == '}') 816 ptr++; 817 } else { 818 /* value */ 819 while ((*ptr != '\0') && 820 (*ptr != ',') && 821 (isspace(*ptr) == 0)) 822 ptr++; 823 } 824 if (*ptr == ',') 825 *ptr++ = '\0'; 826 list_append(&values, value); 827 } 828 } else { /* boolean "[no]key" */ 829 char *value = "true"; 830 831 if (strncasecmp(key, "no", 2) == 0) { 832 key += 2; 833 value = "false"; 834 } 835 list_append(&values, value); 836 } 837 if (*ptr != '\0') 838 *ptr++ = '\0'; 839 840 result = _papiAttributeFromStrings(list, flags, key, values); 841 free(values); 842 } 843 844 return (result); 845 } 846 847 papi_status_t 848 papiAttributeListFromString(papi_attribute_t ***attrs, 849 int flags, char *string) 850 { 851 papi_status_t result = PAPI_OK; 852 853 if ((attrs != NULL) && (string != NULL) && 854 ((flags & ~(PAPI_ATTR_APPEND+PAPI_ATTR_REPLACE+PAPI_ATTR_EXCL)) 855 == 0)) { 856 result = _parse_attribute_list(attrs, flags, string); 857 } else { 858 result = PAPI_BAD_ARGUMENT; 859 } 860 861 return (result); 862 } 863 864 static papi_status_t 865 papiAttributeToString(papi_attribute_t *attribute, char *delim, 866 char *buffer, size_t buflen) 867 { 868 papi_attribute_value_t **values = attribute->values; 869 int rc, i; 870 871 if ((attribute->type == PAPI_BOOLEAN) && (values[1] == NULL)) { 872 if (values[0]->boolean == PAPI_FALSE) { 873 if (isupper(attribute->name[0]) == 0) 874 strlcat(buffer, "no", buflen); 875 else 876 strlcat(buffer, "No", buflen); 877 } 878 rc = strlcat(buffer, attribute->name, buflen); 879 } else { 880 strlcat(buffer, attribute->name, buflen); 881 rc = strlcat(buffer, "=", buflen); 882 } 883 884 if (values == NULL) 885 return (PAPI_OK); 886 887 for (i = 0; values[i] != NULL; i++) { 888 switch (attribute->type) { 889 case PAPI_STRING: 890 rc = strlcat(buffer, values[i]->string, buflen); 891 break; 892 case PAPI_INTEGER: { 893 char string[24]; 894 895 snprintf(string, sizeof (string), "%d", 896 values[i]->integer); 897 rc = strlcat(buffer, string, buflen); 898 } 899 break; 900 case PAPI_BOOLEAN: 901 if (values[1] != NULL) 902 rc = strlcat(buffer, (values[i]->boolean ? 903 "true" : "false"), buflen); 904 break; 905 case PAPI_RANGE: { 906 char string[24]; 907 908 if (values[i]->range.lower == values[i]->range.upper) 909 snprintf(string, sizeof (string), "%d", 910 values[i]->range.lower); 911 else 912 snprintf(string, sizeof (string), "%d-%d", 913 values[i]->range.lower, 914 values[i]->range.upper); 915 rc = strlcat(buffer, string, buflen); 916 } 917 break; 918 case PAPI_RESOLUTION: { 919 char string[24]; 920 921 snprintf(string, sizeof (string), "%dx%ddp%c", 922 values[i]->resolution.xres, 923 values[i]->resolution.yres, 924 (values[i]->resolution.units == PAPI_RES_PER_CM 925 ? 'c' : 'i')); 926 rc = strlcat(buffer, string, buflen); 927 } 928 break; 929 case PAPI_DATETIME: { 930 struct tm *tm = localtime(&values[i]->datetime); 931 932 if (tm != NULL) { 933 char string[64]; 934 935 strftime(string, sizeof (string), "%C", tm); 936 rc = strlcat(buffer, string, buflen); 937 }} 938 break; 939 case PAPI_COLLECTION: { 940 char *string = alloca(buflen); 941 942 papiAttributeListToString(values[i]->collection, 943 delim, string, buflen); 944 rc = strlcat(buffer, string, buflen); 945 } 946 break; 947 default: { 948 char string[32]; 949 950 snprintf(string, sizeof (string), "unknown-type-0x%x", 951 attribute->type); 952 rc = strlcat(buffer, string, buflen); 953 } 954 } 955 if (values[i+1] != NULL) 956 rc = strlcat(buffer, ",", buflen); 957 958 if (rc >= buflen) 959 return (PAPI_NOT_POSSIBLE); 960 961 } 962 963 return (PAPI_OK); 964 } 965 966 papi_status_t 967 papiAttributeListToString(papi_attribute_t **attrs, 968 char *delim, char *buffer, size_t buflen) 969 { 970 papi_status_t status = PAPI_OK; 971 int i; 972 973 if ((attrs == NULL) || (buffer == NULL)) 974 return (PAPI_BAD_ARGUMENT); 975 976 buffer[0] = '\0'; 977 if (!delim) 978 delim = " "; 979 980 for (i = 0; ((attrs[i] != NULL) && (status == PAPI_OK)); i++) { 981 status = papiAttributeToString(attrs[i], delim, buffer, buflen); 982 if (attrs[i+1] != NULL) 983 strlcat(buffer, delim, buflen); 984 } 985 986 return (status); 987 } 988 989 static int 990 is_in_list(char *value, char **list) 991 { 992 if ((list != NULL) && (value != NULL)) { 993 int i; 994 995 for (i = 0; list[i] != NULL; i++) 996 if (strcasecmp(value, list[i]) == 0) 997 return (0); 998 } 999 1000 return (1); 1001 } 1002 1003 static papi_status_t 1004 copy_attribute(papi_attribute_t ***list, papi_attribute_t *attribute) 1005 { 1006 papi_status_t status; 1007 int i = 0; 1008 1009 if ((list == NULL) || (attribute == NULL) || 1010 (attribute->values == NULL)) 1011 return (PAPI_BAD_ARGUMENT); 1012 1013 for (status = papiAttributeListAddValue(list, PAPI_ATTR_EXCL, 1014 attribute->name, attribute->type, 1015 attribute->values[i]); 1016 ((status == PAPI_OK) && (attribute->values[i] != NULL)); 1017 status = papiAttributeListAddValue(list, PAPI_ATTR_APPEND, 1018 attribute->name, attribute->type, 1019 attribute->values[i])) 1020 i++; 1021 1022 return (status); 1023 } 1024 1025 void 1026 copy_attributes(papi_attribute_t ***result, papi_attribute_t **attributes) 1027 { 1028 int i; 1029 1030 if ((result == NULL) || (attributes == NULL)) 1031 return; 1032 1033 for (i = 0; attributes[i] != NULL; i++) 1034 copy_attribute(result, attributes[i]); 1035 } 1036 1037 void 1038 split_and_copy_attributes(char **list, papi_attribute_t **attributes, 1039 papi_attribute_t ***in, papi_attribute_t ***out) 1040 { 1041 int i; 1042 1043 if ((list == NULL) || (attributes == NULL)) 1044 return; 1045 1046 for (i = 0; attributes[i] != NULL; i++) 1047 if (is_in_list(attributes[i]->name, list) == 0) 1048 copy_attribute(in, attributes[i]); 1049 else 1050 copy_attribute(out, attributes[i]); 1051 } 1052 1053 void 1054 papiAttributeListPrint(FILE *fp, papi_attribute_t **attributes, 1055 char *prefix_fmt, ...) 1056 { 1057 char *prefix = NULL; 1058 char *buffer = NULL; 1059 char *newfmt = NULL; 1060 void *mem; 1061 ssize_t size = 0; 1062 va_list ap; 1063 1064 newfmt = malloc(strlen(prefix_fmt) + 2); 1065 sprintf(newfmt, "\n%s", prefix_fmt); 1066 1067 va_start(ap, prefix_fmt); 1068 while (vsnprintf(prefix, size, newfmt, ap) > size) { 1069 size += 1024; 1070 mem = realloc(prefix, size); 1071 if (!mem) goto error; 1072 prefix = mem; 1073 } 1074 va_end(ap); 1075 1076 if (attributes) { 1077 size = 0; 1078 while (papiAttributeListToString(attributes, prefix, buffer, 1079 size) != PAPI_OK) { 1080 size += 1024; 1081 mem = realloc(buffer, size); 1082 if (!mem) goto error; 1083 buffer = mem; 1084 } 1085 } 1086 1087 fprintf(fp, "%s%s\n", prefix, buffer ? buffer : ""); 1088 fflush(fp); 1089 1090 error: 1091 free(newfmt); 1092 free(prefix); 1093 free(buffer); 1094 } 1095