/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /*LINTLIBRARY*/ #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) { int i; for (i = 0; collection[i] != NULL; i++) { papi_attribute_t *a = collection[i]; papiAttributeListAdd(&result, PAPI_ATTR_APPEND, a->name, a->type, NULL); if (a->values != NULL) { int j; for (j = 0; a->values[j] != NULL; j++) papiAttributeListAdd(&result, PAPI_ATTR_APPEND, a->name, a->type, a->values[j]); } } } return (result); } static papi_attribute_value_t * papiAttributeValueDup(const papi_attribute_value_type_t type, const 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; default: /* unknown type, fail to duplicate */ free(result); result = NULL; } } return (result); } static papi_attribute_t * papiAttributeAlloc(const 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 papiAttributeListAddValue(papi_attribute_value_t ***values, const papi_attribute_value_type_t type, const 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 papiAttributeListAdd(papi_attribute_t ***list, const int flgs, const char *name, const papi_attribute_value_type_t type, const 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 = papiAttributeListAddValue(&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, const int flags, const char *name, const char *string) { papi_attribute_value_t v; v.string = (char *)string; return (papiAttributeListAdd(list, flags, name, PAPI_STRING, &v)); } papi_status_t papiAttributeListAddInteger(papi_attribute_t ***list, const int flags, const char *name, const int integer) { papi_attribute_value_t v; v.integer = integer; return (papiAttributeListAdd(list, flags, name, PAPI_INTEGER, &v)); } papi_status_t papiAttributeListAddBoolean(papi_attribute_t ***list, const int flags, const char *name, const char boolean) { papi_attribute_value_t v; v.boolean = boolean; return (papiAttributeListAdd(list, flags, name, PAPI_BOOLEAN, &v)); } papi_status_t papiAttributeListAddRange(papi_attribute_t ***list, const int flags, const char *name, const int lower, const int upper) { papi_attribute_value_t v; v.range.lower = lower; v.range.upper = upper; return (papiAttributeListAdd(list, flags, name, PAPI_RANGE, &v)); } papi_status_t papiAttributeListAddResolution(papi_attribute_t ***list, const int flags, const char *name, const int xres, const int yres, const papi_resolution_unit_t units) { papi_attribute_value_t v; v.resolution.xres = xres; v.resolution.yres = yres; v.resolution.units = units; return (papiAttributeListAdd(list, flags, name, PAPI_RESOLUTION, &v)); } papi_status_t papiAttributeListAddDatetime(papi_attribute_t ***list, const int flags, const char *name, const time_t datetime) { papi_attribute_value_t v; v.datetime = datetime; return (papiAttributeListAdd(list, flags, name, PAPI_DATETIME, &v)); } papi_status_t papiAttributeListAddCollection(papi_attribute_t ***list, const int flags, const char *name, const papi_attribute_t **collection) { papi_attribute_value_t v; v.collection = (papi_attribute_t **)collection; return (papiAttributeListAdd(list, flags, name, PAPI_COLLECTION, &v)); } papi_status_t papiAttributeListDelete(papi_attribute_t ***list, const 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, const char *name) { if (list != NULL) { int i; 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, const 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, const 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, const 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, const 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, const 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, const 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, const 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, const 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); } /* * ***************************************************************************** * * Description: The given string contains one or more attributes, in the * following form: * "aaaa=true bbbbb=1 ccccc=abcd" * extract the next attribute from that string; the 'next' * parameter should be set to zero to extract the first attribute * in the string. * * ***************************************************************************** */ static char * _getNextAttr(const char *string, int *next) { char *result = NULL; char *start = (char *)string + *next; char *nl = NULL; char *sp = NULL; char *tab = NULL; char *val = NULL; int len = 0; if ((string != NULL) && (*start != '\0')) { while ((*start == ' ') || (*start == '\t') || (*start == '\n')) { start++; } nl = strchr(start, '\n'); sp = strchr(start, ' '); tab = strchr(start, '\t'); val = strchr(start, '='); if ((val != NULL) && ((val[1] == '"') || (val[1] == '\''))) { val = strchr(&val[2], val[1]); if (val != NULL) { nl = strchr(&val[1], '\n'); sp = strchr(&val[1], ' '); tab = strchr(&val[1], '\t'); } } if ((nl != NULL) && ((sp == NULL) || ((sp != NULL) && (nl < sp))) && ((tab == NULL) || ((tab != NULL) && (nl < tab)))) { len = nl-start; } else if ((sp != NULL) && (tab != NULL) && (sp > tab)) { len = tab-start; } else if ((sp != NULL) && (sp != NULL)) { len = sp-start; } else if ((tab != NULL) && (tab != NULL)) { len = tab-start; } if (len == 0) { len = strlen(start); } if (len > 0) { result = (char *)malloc(len+1); if (result != NULL) { strncpy(result, start, len); result[len] = '\0'; *next = (start-string)+len; } } } return (result); } /* _getNextAttr() */ /* * ***************************************************************************** * * Description: Parse the given attribute string value and transform it into * the papi_attribute_value_t in the papi_attribute_t structure. * * ***************************************************************************** */ static papi_status_t _parseAttrValue(char *value, papi_attribute_t *attr) { papi_status_t result = PAPI_OK; int len = 0; int i = 0; char *papiString = NULL; char *tmp1 = NULL; char *tmp2 = NULL; char *tmp3 = NULL; papi_attribute_value_t **avalues = NULL; avalues = malloc(sizeof (papi_attribute_value_t *) * 2); if (avalues == NULL) { result = PAPI_TEMPORARY_ERROR; return (result); } avalues[0] = malloc(sizeof (papi_attribute_value_t)); avalues[1] = NULL; if (avalues[0] == NULL) { free(avalues); result = PAPI_TEMPORARY_ERROR; return (result); } /* * TODO - need to sort out 'resolution', 'dateandtime' & 'collection' values */ if ((value != NULL) && (strlen(value) > 0) && (attr != NULL)) { len = strlen(value); if ((len >= 2) && (((value[0] == '"') && (value[len-1] == '"')) || ((value[0] == '\'') && (value[len-1] == '\'')))) { /* string value */ attr->type = PAPI_STRING; papiString = strdup(value+1); if (papiString != NULL) { papiString[strlen(papiString)-1] = '\0'; avalues[0]->string = papiString; } else { result = PAPI_TEMPORARY_ERROR; } } else if ((strcasecmp(value, "true") == 0) || (strcasecmp(value, "YES") == 0)) { /* boolean = true */ attr->type = PAPI_BOOLEAN; avalues[0]->boolean = PAPI_TRUE; } else if ((strcasecmp(value, "false") == 0) || (strcasecmp(value, "NO") == 0)) { /* boolean = false */ attr->type = PAPI_BOOLEAN; avalues[0]->boolean = PAPI_FALSE; } else { /* is value an integer or a range? */ i = 0; attr->type = PAPI_INTEGER; tmp1 = strdup(value); while (((value[i] >= '0') && (value[i] <= '9')) || (value[i] == '-')) { if (value[i] == '-') { tmp1[i] = '\0'; tmp2 = &tmp1[i+1]; attr->type = PAPI_RANGE; } i++; } if (strlen(value) == i) { if (attr->type == PAPI_RANGE) { avalues[0]->range.lower = atoi(tmp1); avalues[0]->range.upper = atoi(tmp2); } else { avalues[0]->integer = atoi(value); } } else { /* is value a resolution? */ i = 0; attr->type = PAPI_INTEGER; tmp1 = strdup(value); while (((value[i] >= '0') && (value[i] <= '9')) || (value[i] == 'x')) { if (value[i] == 'x') { tmp1[i] = '\0'; if (attr->type == PAPI_INTEGER) { tmp2 = &tmp1[i+1]; attr->type = PAPI_RESOLUTION; } else { tmp3 = &tmp1[i+1]; } } i++; } if (strlen(value) == i) { if (attr->type == PAPI_RESOLUTION) { avalues[0]->resolution.xres = atoi(tmp1); avalues[0]->resolution.yres = atoi(tmp2); if (tmp3 != NULL) { avalues[0]-> resolution.units = atoi(tmp3); } else { avalues[0]-> resolution.units = 0; } } } if (attr->type != PAPI_RESOLUTION) { attr->type = PAPI_STRING; avalues[0]->string = strdup(value); if (avalues[0]->string == NULL) { result = PAPI_TEMPORARY_ERROR; } } } free(tmp1); } } else { result = PAPI_BAD_ARGUMENT; } if (result != PAPI_OK) { i = 0; while (avalues[i] != NULL) { free(avalues[i]); i++; } free(avalues); } else { attr->values = avalues; } return (result); } /* _parseAttrValue() */ /* * ***************************************************************************** * * Description: Parse the given attribute string and transform it into the * papi_attribute_t structure. * * ***************************************************************************** */ static papi_status_t _parseAttributeString(char *attrString, papi_attribute_t *attr) { papi_status_t result = PAPI_OK; char *string = NULL; char *p = NULL; papi_attribute_value_t **avalues = NULL; if ((attrString != NULL) && (strlen(attrString) >= 3) && (attr != NULL)) { attr->name = NULL; string = strdup(attrString); if (string != NULL) { p = strchr(string, '='); if (p != NULL) { *p = '\0'; attr->name = string; p++; /* pointer to value */ result = _parseAttrValue(p, attr); } else { /* boolean - no value so assume 'true' */ attr->name = string; attr->type = PAPI_BOOLEAN; avalues = malloc( sizeof (papi_attribute_value_t *) * 2); if (avalues == NULL) { result = PAPI_TEMPORARY_ERROR; } else { avalues[0] = malloc( sizeof (papi_attribute_value_t)); avalues[1] = NULL; if (avalues[0] == NULL) { free(avalues); result = PAPI_TEMPORARY_ERROR; } else { avalues[0]->boolean = PAPI_TRUE; attr->values = avalues; } } } } } else { result = PAPI_BAD_ARGUMENT; } return (result); } /* _parseAttributeString() */ papi_status_t papiAttributeListFromString(papi_attribute_t ***attrs, const int flags, const char *string) { papi_status_t result = PAPI_OK; int next = 0; char *attrString = NULL; papi_attribute_t attr; if ((attrs != NULL) && (string != NULL) && ((flags & ~(PAPI_ATTR_APPEND+PAPI_ATTR_REPLACE+PAPI_ATTR_EXCL)) == 0)) { attrString = _getNextAttr(string, &next); while ((result == PAPI_OK) && (attrString != NULL)) { printf("papiAttributeListFromString() attr='%s'\n", attrString); result = _parseAttributeString(attrString, &attr); if ((result == PAPI_OK) && (attr.name != NULL)) { /* add this attribute to the list */ if ((attr.values != NULL) && (attr.values[0] != NULL)) { result = papiAttributeListAdd( attrs, PAPI_ATTR_APPEND, attr.name, attr.type, attr.values[0]); free(attr.values[0]); free(attr.values); } else { result = PAPI_TEMPORARY_ERROR; } } free(attrString); attrString = _getNextAttr(string, &next); } } else { result = PAPI_BAD_ARGUMENT; } return (result); } papi_status_t papiAttributeListToString(const papi_attribute_t **attrs, const char *delim, char *buffer, const size_t buflen) { return (PAPI_OPERATION_NOT_SUPPORTED); } /* for debugging, not part of the public API */ static char * typeString(papi_attribute_value_type_t type) { switch (type) { case PAPI_STRING: return ("string"); case PAPI_INTEGER: return ("integer"); case PAPI_BOOLEAN: return ("boolean"); case PAPI_RANGE: return ("range"); case PAPI_RESOLUTION: return ("resolution"); case PAPI_DATETIME: return ("datetime"); case PAPI_COLLECTION: return ("collection"); } return ("unknown"); } void papiAttributeListPrint(FILE *fp, char *prefix, papi_attribute_t **list); void papiAttributePrint(FILE *fp, char *prefix, papi_attribute_t *attribute) { if (attribute != NULL) { char *name = attribute->name; if (prefix == NULL) prefix = ""; /* * fprintf(fp, "%s'%s' (%s) =\n", prefix, (name ? name : "(NULL)"), * typeString(attribute->type)); */ if (attribute->values != NULL) { papi_attribute_value_t **values = attribute->values; int i; for (i = 0; values[i] != NULL; i++) { fprintf(fp, "%s=", (name ? name : "(NULL)")); /* * if (attribute->type != PAPI_COLLECTION) * fprintf(fp, "%s\t", prefix); */ switch (attribute->type) { case PAPI_STRING: if ((strchr(values[i]->string, ' ') != NULL) || (strchr(values[i]->string, '\t') != NULL)) { /* quote the string */ fprintf(fp, "\"%s\"", values[i]->string); } else { fprintf(fp, "%s", values[i]->string); } break; case PAPI_INTEGER: fprintf(fp, "%d", values[i]->integer); break; case PAPI_BOOLEAN: fprintf(fp, "%s", (values[i]->boolean ? "true" : "false")); break; case PAPI_RANGE: fprintf(fp, "%d-%d", values[i]->range.lower, values[i]->range.upper); break; case PAPI_RESOLUTION: fprintf(fp, "%dx%d", values[i]->resolution.xres, values[i]->resolution.yres); break; case PAPI_DATETIME: { struct tm *tm; tm = localtime(&values[i]->datetime); if (tm != NULL) { char buf[64]; strftime(buf, sizeof (buf), "%C", tm); fprintf(fp, "%s", buf); }} break; case PAPI_COLLECTION: { char s[64]; snprintf(s, sizeof (s), "%s\t", prefix); papiAttributeListPrint(fp, s, values[i]->collection); } break; default: fprintf(fp, "unknown"); } if (attribute->type != PAPI_COLLECTION) fprintf(fp, "\n"); } } } } void papiAttributeListPrint(FILE *fp, char *prefix, papi_attribute_t **list) { if (list != NULL) { int i; for (i = 0; list[i] != NULL; i++) papiAttributePrint(fp, prefix, list[i]); } }