/*
* 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 (c) 2014 Gary Mills
*
* 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 $ */
/*LINTLIBRARY*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <alloca.h>
#include <papi.h>
#include <regex.h>
#define MAX_PAGES 32767
/*
* Assuming the maximum number of pages in
* a document to be 32767
*/
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) {
if (atoi(parts[0]) < 0) {
/*
* Handles -P -x case
* which prints from page number 1
* till page number x
*/
value->range.lower = 1;
value->range.upper = 0 - (atoi(parts[0]));
} else {
value->range.lower = value->range.upper
= atoi(parts[0]);
}
} else if (dtype == PAPI_RANGE) {
if (parts[2] == NULL) {
value->range.lower = atoi(parts[1]);
/*
* Imposing an artificial limit on
* the upper bound for page range.
*/
value->range.upper = MAX_PAGES;
} else if ((parts[1] != NULL) && (parts[2] != NULL)) {
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);
}