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