/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * */ /* $Id: attribute.c 157 2006-04-26 15:07:55Z ktou $ */ #pragma ident "%Z%%M% %I% %E% SMI" /*LINTLIBRARY*/ #include #include #include #include #include #include #include #include static void papiAttributeFree(papi_attribute_t *attribute); static void papiAttributeValueFree(papi_attribute_value_type_t type, papi_attribute_value_t *value) { if (value != NULL) { switch (type) { case PAPI_STRING: if (value->string != NULL) free(value->string); break; case PAPI_COLLECTION: if (value->collection != NULL) { int i; for (i = 0; value->collection[i] != NULL; i++) papiAttributeFree(value->collection[i]); free(value->collection); } break; default: /* don't need to free anything extra */ break; } free(value); } } static void papiAttributeValuesFree(papi_attribute_value_type_t type, papi_attribute_value_t **values) { if (values != NULL) { int i; for (i = 0; values[i] != NULL; i++) papiAttributeValueFree(type, values[i]); free(values); } } static void papiAttributeFree(papi_attribute_t *attribute) { if (attribute != NULL) { if (attribute->name != NULL) free(attribute->name); if (attribute->values != NULL) papiAttributeValuesFree(attribute->type, attribute->values); free(attribute); } } void papiAttributeListFree(papi_attribute_t **list) { if (list != NULL) { int i; for (i = 0; list[i] != NULL; i++) papiAttributeFree(list[i]); free(list); } } static papi_attribute_t ** collection_dup(papi_attribute_t **collection) { papi_attribute_t **result = NULL; /* allows a NULL collection that is "empty" or "no value" */ if (collection != NULL) { papi_status_t status = PAPI_OK; int i; for (i = 0; ((collection[i] != NULL) && (status == PAPI_OK)); i++) { papi_attribute_t *a = collection[i]; status = papiAttributeListAddValue(&result, PAPI_ATTR_APPEND, a->name, a->type, NULL); if ((status == PAPI_OK) && (a->values != NULL)) { int j; for (j = 0; ((a->values[j] != NULL) && (status == PAPI_OK)); j++) status = papiAttributeListAddValue( &result, PAPI_ATTR_APPEND, a->name, a->type, a->values[j]); } } if (status != PAPI_OK) { papiAttributeListFree(result); result = NULL; } } return (result); } static papi_attribute_value_t * papiAttributeValueDup(papi_attribute_value_type_t type, papi_attribute_value_t *v) { papi_attribute_value_t *result = NULL; if ((v != NULL) && ((result = calloc(1, sizeof (*result))) != NULL)) { switch (type) { case PAPI_STRING: if (v->string == NULL) { free(result); result = NULL; } else result->string = strdup(v->string); break; case PAPI_INTEGER: result->integer = v->integer; break; case PAPI_BOOLEAN: result->boolean = v->boolean; break; case PAPI_RANGE: result->range.lower = v->range.lower; result->range.upper = v->range.upper; break; case PAPI_RESOLUTION: result->resolution.xres = v->resolution.xres; result->resolution.yres = v->resolution.yres; result->resolution.units = v->resolution.units; break; case PAPI_DATETIME: result->datetime = v->datetime; break; case PAPI_COLLECTION: result->collection = collection_dup(v->collection); break; case PAPI_METADATA: result->metadata = v->metadata; break; default: /* unknown type, fail to duplicate */ free(result); result = NULL; } } return (result); } static papi_attribute_t * papiAttributeAlloc(char *name, papi_attribute_value_type_t type) { papi_attribute_t *result = NULL; if ((result = calloc(1, sizeof (*result))) != NULL) { result->name = strdup(name); result->type = type; } return (result); } static papi_status_t papiAttributeListAppendValue(papi_attribute_value_t ***values, papi_attribute_value_type_t type, papi_attribute_value_t *value) { if (values == NULL) return (PAPI_BAD_ARGUMENT); if (value != NULL) { /* this allows "empty" attributes */ papi_attribute_value_t *tmp = NULL; if ((tmp = papiAttributeValueDup(type, value)) == NULL) return (PAPI_TEMPORARY_ERROR); list_append(values, tmp); } return (PAPI_OK); } papi_status_t papiAttributeListAddValue(papi_attribute_t ***list, int flgs, char *name, papi_attribute_value_type_t type, papi_attribute_value_t *value) { papi_status_t result; int flags = flgs; papi_attribute_t *attribute = NULL; papi_attribute_value_t **values = NULL; if ((list == NULL) || (name == NULL)) return (PAPI_BAD_ARGUMENT); if ((type == PAPI_RANGE) && (value != NULL) && (value->range.lower > value->range.upper)) return (PAPI_BAD_ARGUMENT); /* RANGE must have min <= max */ if (flags == 0) /* if it wasn't set, set a default behaviour */ flags = PAPI_ATTR_APPEND; /* look for an existing one */ attribute = papiAttributeListFind(*list, name); if (((flags & PAPI_ATTR_EXCL) != 0) && (attribute != NULL)) return (PAPI_CONFLICT); /* EXISTS */ if (((flags & PAPI_ATTR_REPLACE) == 0) && (attribute != NULL) && (attribute->type != type)) return (PAPI_CONFLICT); /* TYPE CONFLICT */ /* if we don't have one, create it and add it to the list */ if ((attribute == NULL) && ((attribute = papiAttributeAlloc(name, type)) != NULL)) list_append(list, attribute); /* if we don't have one by now, it's most likely an alloc fail */ if (attribute == NULL) return (PAPI_TEMPORARY_ERROR); /* * if we are replacing, clear any existing values, but don't free * until after we have replaced the values, in case we are replacing * a collection with a relocated version of the original collection. */ if (((flags & PAPI_ATTR_REPLACE) != 0) && (attribute->values != NULL)) { values = attribute->values; attribute->values = NULL; } attribute->type = type; result = papiAttributeListAppendValue(&attribute->values, type, value); /* free old values if we replaced them */ if (values != NULL) papiAttributeValuesFree(type, values); return (result); } papi_status_t papiAttributeListAddString(papi_attribute_t ***list, int flags, char *name, char *string) { papi_attribute_value_t v; v.string = (char *)string; return (papiAttributeListAddValue(list, flags, name, PAPI_STRING, &v)); } papi_status_t papiAttributeListAddInteger(papi_attribute_t ***list, int flags, char *name, int integer) { papi_attribute_value_t v; v.integer = integer; return (papiAttributeListAddValue(list, flags, name, PAPI_INTEGER, &v)); } papi_status_t papiAttributeListAddBoolean(papi_attribute_t ***list, int flags, char *name, char boolean) { papi_attribute_value_t v; v.boolean = boolean; return (papiAttributeListAddValue(list, flags, name, PAPI_BOOLEAN, &v)); } papi_status_t papiAttributeListAddRange(papi_attribute_t ***list, int flags, char *name, int lower, int upper) { papi_attribute_value_t v; v.range.lower = lower; v.range.upper = upper; return (papiAttributeListAddValue(list, flags, name, PAPI_RANGE, &v)); } papi_status_t papiAttributeListAddResolution(papi_attribute_t ***list, int flags, char *name, int xres, int yres, papi_resolution_unit_t units) { papi_attribute_value_t v; v.resolution.xres = xres; v.resolution.yres = yres; v.resolution.units = units; return (papiAttributeListAddValue(list, flags, name, PAPI_RESOLUTION, &v)); } papi_status_t papiAttributeListAddDatetime(papi_attribute_t ***list, int flags, char *name, time_t datetime) { papi_attribute_value_t v; v.datetime = datetime; return (papiAttributeListAddValue(list, flags, name, PAPI_DATETIME, &v)); } papi_status_t papiAttributeListAddCollection(papi_attribute_t ***list, int flags, char *name, papi_attribute_t **collection) { papi_attribute_value_t v; v.collection = (papi_attribute_t **)collection; return (papiAttributeListAddValue(list, flags, name, PAPI_COLLECTION, &v)); } papi_status_t papiAttributeListAddMetadata(papi_attribute_t ***list, int flags, char *name, papi_metadata_t metadata) { papi_attribute_value_t v; v.metadata = metadata; return (papiAttributeListAddValue(list, flags, name, PAPI_METADATA, &v)); } papi_status_t papiAttributeListDelete(papi_attribute_t ***list, char *name) { papi_attribute_t *attribute; if ((list == NULL) || (name == NULL)) return (PAPI_BAD_ARGUMENT); if ((attribute = papiAttributeListFind(*list, name)) == NULL) return (PAPI_NOT_FOUND); list_remove(list, attribute); papiAttributeFree(attribute); return (PAPI_OK); } papi_attribute_t * papiAttributeListFind(papi_attribute_t **list, char *name) { int i; if ((list == NULL) || (name == NULL)) return (NULL); for (i = 0; list[i] != NULL; i++) if (strcasecmp(list[i]->name, name) == 0) return ((papi_attribute_t *)list[i]); return (NULL); } papi_attribute_t * papiAttributeListGetNext(papi_attribute_t **list, void **iter) { papi_attribute_t **tmp, *result; if ((list == NULL) && (iter == NULL)) return (NULL); if (*iter == NULL) *iter = list; tmp = *iter; result = *tmp; *iter = ++tmp; return (result); } papi_status_t papiAttributeListGetValue(papi_attribute_t **list, void **iter, char *name, papi_attribute_value_type_t type, papi_attribute_value_t **value) { papi_attribute_value_t **tmp; void *fodder = NULL; if ((list == NULL) || ((name == NULL) && (iter == NULL)) || (value == NULL)) return (PAPI_BAD_ARGUMENT); if (iter == NULL) iter = &fodder; if ((iter == NULL) || (*iter == NULL)) { papi_attribute_t *attr = papiAttributeListFind(list, name); if (attr == NULL) return (PAPI_NOT_FOUND); if (attr->type != type) return (PAPI_NOT_POSSIBLE); tmp = attr->values; } else tmp = *iter; if (tmp == NULL) return (PAPI_NOT_FOUND); *value = *tmp; *iter = ++tmp; if (*value == NULL) return (PAPI_GONE); return (PAPI_OK); } papi_status_t papiAttributeListGetString(papi_attribute_t **list, void **iter, char *name, char **vptr) { papi_status_t status; papi_attribute_value_t *value = NULL; if (vptr == NULL) return (PAPI_BAD_ARGUMENT); status = papiAttributeListGetValue(list, iter, name, PAPI_STRING, &value); if (status == PAPI_OK) *vptr = value->string; return (status); } papi_status_t papiAttributeListGetInteger(papi_attribute_t **list, void **iter, char *name, int *vptr) { papi_status_t status; papi_attribute_value_t *value = NULL; if (vptr == NULL) return (PAPI_BAD_ARGUMENT); status = papiAttributeListGetValue(list, iter, name, PAPI_INTEGER, &value); if (status == PAPI_OK) *vptr = value->integer; return (status); } papi_status_t papiAttributeListGetBoolean(papi_attribute_t **list, void **iter, char *name, char *vptr) { papi_status_t status; papi_attribute_value_t *value = NULL; if (vptr == NULL) return (PAPI_BAD_ARGUMENT); status = papiAttributeListGetValue(list, iter, name, PAPI_BOOLEAN, &value); if (status == PAPI_OK) *vptr = value->boolean; return (status); } papi_status_t papiAttributeListGetRange(papi_attribute_t **list, void **iter, char *name, int *min, int *max) { papi_status_t status; papi_attribute_value_t *value = NULL; if ((min == NULL) || (max == NULL)) return (PAPI_BAD_ARGUMENT); status = papiAttributeListGetValue(list, iter, name, PAPI_RANGE, &value); if (status == PAPI_OK) { *min = value->range.lower; *max = value->range.upper; } return (status); } papi_status_t papiAttributeListGetResolution(papi_attribute_t **list, void **iter, char *name, int *x, int *y, papi_resolution_unit_t *units) { papi_status_t status; papi_attribute_value_t *value = NULL; if ((x == NULL) || (y == NULL) || (units == NULL)) return (PAPI_BAD_ARGUMENT); status = papiAttributeListGetValue(list, iter, name, PAPI_RESOLUTION, &value); if (status == PAPI_OK) { *x = value->resolution.xres; *y = value->resolution.yres; *units = value->resolution.units; } return (status); } papi_status_t papiAttributeListGetDatetime(papi_attribute_t **list, void **iter, char *name, time_t *dt) { papi_status_t status; papi_attribute_value_t *value = NULL; if (dt == NULL) return (PAPI_BAD_ARGUMENT); status = papiAttributeListGetValue(list, iter, name, PAPI_DATETIME, &value); if (status == PAPI_OK) { *dt = value->datetime; } return (status); } papi_status_t papiAttributeListGetCollection(papi_attribute_t **list, void **iter, char *name, papi_attribute_t ***collection) { papi_status_t status; papi_attribute_value_t *value = NULL; if (collection == NULL) return (PAPI_BAD_ARGUMENT); status = papiAttributeListGetValue(list, iter, name, PAPI_COLLECTION, &value); if (status == PAPI_OK) { *collection = value->collection; } return (status); } papi_status_t papiAttributeListGetMetadata(papi_attribute_t **list, void **iter, char *name, papi_metadata_t *vptr) { papi_status_t status; papi_attribute_value_t *value = NULL; if (vptr == NULL) return (PAPI_BAD_ARGUMENT); status = papiAttributeListGetValue(list, iter, name, PAPI_METADATA, &value); if (status == PAPI_OK) *vptr = value->metadata; return (status); } /* The string is modified by this call */ static char * regvalue(regmatch_t match, char *string) { char *result = NULL; if (match.rm_so != match.rm_eo) { result = string + match.rm_so; *(result + (match.rm_eo - match.rm_so)) = '\0'; } return (result); } static papi_attribute_value_type_t _process_value(char *string, char ***parts) { int i; static struct { papi_attribute_value_type_t type; size_t vals; char *expression; int compiled; regex_t re; } types[] = { { PAPI_BOOLEAN, 1, "^(true|false|yes|no)$", 0 }, { PAPI_COLLECTION, 1, "^\\{(.+)\\}$", 0 }, /* PAPI_DATETIME is unsupported, too much like an integer */ { PAPI_INTEGER, 1, "^([+-]{0,1}[[:digit:]]+)$", 0 }, { PAPI_RANGE, 3, "^([[:digit:]]+)-([[:digit:]]+)$", 0 }, { PAPI_RESOLUTION, 4, "^([[:digit:]]+)x([[:digit:]]+)dp(i|c)$", 0 }, NULL }; regmatch_t matches[4]; for (i = 0; i < 5; i++) { int j; if (types[i].compiled == 0) { (void) regcomp(&(types[i].re), types[i].expression, REG_EXTENDED|REG_ICASE); types[i].compiled = 1; } if (regexec(&(types[i].re), string, (size_t)types[i].vals, matches, 0) == REG_NOMATCH) continue; for (j = 0 ; j < types[i].vals; j++) list_append(parts, regvalue(matches[j], string)); return (types[i].type); } list_append(parts, string); return (PAPI_STRING); } static void _add_attribute_value(papi_attribute_value_t ***list, papi_attribute_value_type_t type, papi_attribute_value_type_t dtype, char **parts) { papi_attribute_value_t *value = calloc(1, sizeof (*value)); switch(type) { case PAPI_STRING: value->string = strdup(parts[0]); list_append(list, value); break; case PAPI_BOOLEAN: value->boolean = PAPI_TRUE; if ((strcasecmp(parts[0], "false") == 0) || (strcasecmp(parts[0], "no") == 0)) value->boolean = PAPI_FALSE; list_append(list, value); break; case PAPI_INTEGER: value->integer = atoi(parts[0]); list_append(list, value); break; case PAPI_RANGE: if (dtype == PAPI_INTEGER) value->range.lower = value->range.upper = atoi(parts[0]); else if (dtype == PAPI_RANGE) { value->range.lower = atoi(parts[1]); value->range.upper = atoi(parts[2]); } list_append(list, value); break; case PAPI_RESOLUTION: value->resolution.xres = atoi(parts[1]); value->resolution.yres = atoi(parts[2]); if (parts[3][0] == 'i') value->resolution.units = PAPI_RES_PER_INCH; else value->resolution.units = PAPI_RES_PER_CM; list_append(list, value); break; case PAPI_COLLECTION: papiAttributeListFromString(&(value->collection), 0, parts[0]); list_append(list, value); break; } } static papi_status_t _papiAttributeFromStrings(papi_attribute_t ***list, int flags, char *key, char **values) { int i; papi_status_t result = PAPI_OK; papi_attribute_t *attr = calloc(1, sizeof (*attr)); /* these are specified in the papi spec as ranges */ char *ranges[] = { "copies-supported", "job-impressions-supported", "job-k-octets-supported", "job-media-sheets-supported", "page-ranges", NULL }; if ((attr == NULL) || ((attr->name = strdup(key)) == NULL)) return (PAPI_TEMPORARY_ERROR); attr->type = PAPI_METADATA; /* these are known ranges */ for (i = 0; ranges[i] != NULL; i++) if (strcasecmp(attr->name, ranges[i]) == 0) { attr->type = PAPI_RANGE; break; } if (values != NULL) { papi_attribute_value_t **vals = NULL; for (i = 0; values[i] != NULL; i++) { papi_attribute_value_type_t dtype; char **parts = NULL; dtype = _process_value(values[i], &parts); if (attr->type == PAPI_METADATA) attr->type = dtype; _add_attribute_value(&vals, attr->type, dtype, parts); free(parts); } attr->values = vals; } list_append(list, attr); return (result); } static papi_status_t _parse_attribute_list(papi_attribute_t ***list, int flags, char *string) { papi_status_t result = PAPI_OK; char *ptr; if ((list == NULL) || (string == NULL)) return (PAPI_BAD_ARGUMENT); if ((ptr = strdup(string)) == NULL) return (PAPI_TEMPORARY_ERROR); while ((*ptr != '\0') && (result == PAPI_OK)) { char *key, **values = NULL; /* strip any leading whitespace */ while (isspace(*ptr) != 0) ptr++; /* Get the name: name[=value] */ key = ptr; while ((*ptr != '\0') && (*ptr != '=') && (isspace(*ptr) == 0)) ptr++; if (*ptr == '=') { *ptr++ = '\0'; while ((*ptr != '\0') && (isspace(*ptr) == 0)) { char *value = ptr; if ((*ptr == '\'') || (*ptr == '"')) { char q = *ptr++; /* quoted string value */ while ((*ptr != '\0') && (*ptr != q)) ptr++; if (*ptr == q) ptr++; } else if (*ptr == '{') { /* collection */ while ((*ptr != '\0') && (*ptr != '}')) ptr++; if (*ptr == '}') ptr++; } else { /* value */ while ((*ptr != '\0') && (*ptr != ',') && (isspace(*ptr) == 0)) ptr++; } if (*ptr == ',') *ptr++ = '\0'; list_append(&values, value); } } else { /* boolean "[no]key" */ char *value = "true"; if (strncasecmp(key, "no", 2) == 0) { key += 2; value = "false"; } list_append(&values, value); } if (*ptr != '\0') *ptr++ = '\0'; result = _papiAttributeFromStrings(list, flags, key, values); free(values); } return (result); } papi_status_t papiAttributeListFromString(papi_attribute_t ***attrs, int flags, char *string) { papi_status_t result = PAPI_OK; if ((attrs != NULL) && (string != NULL) && ((flags & ~(PAPI_ATTR_APPEND+PAPI_ATTR_REPLACE+PAPI_ATTR_EXCL)) == 0)) { result = _parse_attribute_list(attrs, flags, string); } else { result = PAPI_BAD_ARGUMENT; } return (result); } static papi_status_t papiAttributeToString(papi_attribute_t *attribute, char *delim, char *buffer, size_t buflen) { papi_attribute_value_t **values = attribute->values; int rc, i; if ((attribute->type == PAPI_BOOLEAN) && (values[1] == NULL)) { if (values[0]->boolean == PAPI_FALSE) { if (isupper(attribute->name[0]) == 0) strlcat(buffer, "no", buflen); else strlcat(buffer, "No", buflen); } rc = strlcat(buffer, attribute->name, buflen); } else { strlcat(buffer, attribute->name, buflen); rc = strlcat(buffer, "=", buflen); } if (values == NULL) return (PAPI_OK); for (i = 0; values[i] != NULL; i++) { switch (attribute->type) { case PAPI_STRING: rc = strlcat(buffer, values[i]->string, buflen); break; case PAPI_INTEGER: { char string[24]; snprintf(string, sizeof (string), "%d", values[i]->integer); rc = strlcat(buffer, string, buflen); } break; case PAPI_BOOLEAN: if (values[1] != NULL) rc = strlcat(buffer, (values[i]->boolean ? "true" : "false"), buflen); break; case PAPI_RANGE: { char string[24]; if (values[i]->range.lower == values[i]->range.upper) snprintf(string, sizeof (string), "%d", values[i]->range.lower); else snprintf(string, sizeof (string), "%d-%d", values[i]->range.lower, values[i]->range.upper); rc = strlcat(buffer, string, buflen); } break; case PAPI_RESOLUTION: { char string[24]; snprintf(string, sizeof (string), "%dx%ddp%c", values[i]->resolution.xres, values[i]->resolution.yres, (values[i]->resolution.units == PAPI_RES_PER_CM ? 'c' : 'i')); rc = strlcat(buffer, string, buflen); } break; case PAPI_DATETIME: { struct tm *tm = localtime(&values[i]->datetime); if (tm != NULL) { char string[64]; strftime(string, sizeof (string), "%C", tm); rc = strlcat(buffer, string, buflen); }} break; case PAPI_COLLECTION: { char *string = alloca(buflen); papiAttributeListToString(values[i]->collection, delim, string, buflen); rc = strlcat(buffer, string, buflen); } break; default: { char string[32]; snprintf(string, sizeof (string), "unknown-type-0x%x", attribute->type); rc = strlcat(buffer, string, buflen); } } if (values[i+1] != NULL) rc = strlcat(buffer, ",", buflen); if (rc >= buflen) return (PAPI_NOT_POSSIBLE); } return (PAPI_OK); } papi_status_t papiAttributeListToString(papi_attribute_t **attrs, char *delim, char *buffer, size_t buflen) { papi_status_t status = PAPI_OK; int i; if ((attrs == NULL) || (buffer == NULL)) return (PAPI_BAD_ARGUMENT); buffer[0] = '\0'; if (!delim) delim = " "; for (i = 0; ((attrs[i] != NULL) && (status == PAPI_OK)); i++) { status = papiAttributeToString(attrs[i], delim, buffer, buflen); if (attrs[i+1] != NULL) strlcat(buffer, delim, buflen); } return (status); } static int is_in_list(char *value, char **list) { if ((list != NULL) && (value != NULL)) { int i; for (i = 0; list[i] != NULL; i++) if (strcasecmp(value, list[i]) == 0) return (0); } return (1); } static papi_status_t copy_attribute(papi_attribute_t ***list, papi_attribute_t *attribute) { papi_status_t status; int i = 0; if ((list == NULL) || (attribute == NULL) || (attribute->values == NULL)) return (PAPI_BAD_ARGUMENT); for (status = papiAttributeListAddValue(list, PAPI_ATTR_EXCL, attribute->name, attribute->type, attribute->values[i]); ((status == PAPI_OK) && (attribute->values[i] != NULL)); status = papiAttributeListAddValue(list, PAPI_ATTR_APPEND, attribute->name, attribute->type, attribute->values[i])) i++; return (status); } void copy_attributes(papi_attribute_t ***result, papi_attribute_t **attributes) { int i; if ((result == NULL) || (attributes == NULL)) return; for (i = 0; attributes[i] != NULL; i++) copy_attribute(result, attributes[i]); } void split_and_copy_attributes(char **list, papi_attribute_t **attributes, papi_attribute_t ***in, papi_attribute_t ***out) { int i; if ((list == NULL) || (attributes == NULL)) return; for (i = 0; attributes[i] != NULL; i++) if (is_in_list(attributes[i]->name, list) == 0) copy_attribute(in, attributes[i]); else copy_attribute(out, attributes[i]); } void papiAttributeListPrint(FILE *fp, papi_attribute_t **attributes, char *prefix_fmt, ...) { char *prefix = NULL; char *buffer = NULL; char *newfmt = NULL; void *mem; ssize_t size = 0; va_list ap; newfmt = malloc(strlen(prefix_fmt) + 2); sprintf(newfmt, "\n%s", prefix_fmt); va_start(ap, prefix_fmt); while (vsnprintf(prefix, size, newfmt, ap) > size) { size += 1024; mem = realloc(prefix, size); if (!mem) goto error; prefix = mem; } va_end(ap); if (attributes) { size = 0; while (papiAttributeListToString(attributes, prefix, buffer, size) != PAPI_OK) { size += 1024; mem = realloc(buffer, size); if (!mem) goto error; buffer = mem; } } fprintf(fp, "%s%s\n", prefix, buffer ? buffer : ""); fflush(fp); error: free(newfmt); free(prefix); free(buffer); }