Blame lib/tagname.c

2ff057
/**
2ff057
 * \file lib/tagname.c
2ff057
 */
2ff057
2ff057
#include "system.h"
2ff057
2ff057
#include <pthread.h>
2ff057
2ff057
#include <rpm/header.h>
2ff057
#include <rpm/rpmstring.h>
2ff057
#include "debug.h"
2ff057
2ff057
/** \ingroup header
2ff057
 * Associate tag names with numeric values.
2ff057
 */
2ff057
typedef const struct headerTagTableEntry_s * headerTagTableEntry;
2ff057
struct headerTagTableEntry_s {
2ff057
    const char * name;		/*!< Tag name. */
2ff057
    const char * shortname;	/*!< "Human readable" short name. */
2ff057
    rpmTagVal val;		/*!< Tag numeric value. */
2ff057
    rpmTagType type;		/*!< Tag type. */
2ff057
    rpmTagReturnType retype;	/*!< Tag return type. */
2ff057
    int extension;		/*!< Extension or "real" tag */
2ff057
};
2ff057
2ff057
#include "lib/tagtbl.C"
2ff057
2ff057
#define TABLESIZE (sizeof(rpmTagTable) / sizeof(rpmTagTable[0]) - 1)
2ff057
static const int rpmTagTableSize = TABLESIZE;
2ff057
2ff057
static headerTagTableEntry tagsByName[TABLESIZE]; /*!< tags sorted by name. */
2ff057
static headerTagTableEntry tagsByValue[TABLESIZE]; /*!< tags sorted by value. */
2ff057
2ff057
/**
2ff057
 * Compare tag table entries by name.
2ff057
 * @param *avp		tag table entry a
2ff057
 * @param *bvp		tag table entry b
2ff057
 * @return		comparison
2ff057
 */
2ff057
static int tagCmpName(const void * avp, const void * bvp)
2ff057
{
2ff057
    headerTagTableEntry a = *(const headerTagTableEntry *) avp;
2ff057
    headerTagTableEntry b = *(const headerTagTableEntry *) bvp;
2ff057
    return strcmp(a->name, b->name);
2ff057
}
2ff057
2ff057
/**
2ff057
 * Compare tag table entries by value.
2ff057
 * @param *avp		tag table entry a
2ff057
 * @param *bvp		tag table entry b
2ff057
 * @return		comparison
2ff057
 */
2ff057
static int tagCmpValue(const void * avp, const void * bvp)
2ff057
{
2ff057
    headerTagTableEntry a = *(const headerTagTableEntry *) avp;
2ff057
    headerTagTableEntry b = *(const headerTagTableEntry *) bvp;
2ff057
    int ret = (a->val - b->val);
2ff057
    /* Make sure that sort is stable, longest name first. */
2ff057
    if (ret == 0)
2ff057
	ret = (strlen(b->name) - strlen(a->name));
2ff057
    return ret;
2ff057
}
2ff057
2ff057
static pthread_once_t tagsLoaded = PTHREAD_ONCE_INIT;
2ff057
2ff057
/* Initialize tag by-value and by-name lookup tables */
2ff057
static void loadTags(void)
2ff057
{
2ff057
    for (int i = 0; i < rpmTagTableSize; i++) {
2ff057
	tagsByValue[i] = &rpmTagTable[i];
2ff057
	tagsByName[i] = &rpmTagTable[i];
2ff057
    }
2ff057
2ff057
    qsort(tagsByValue, rpmTagTableSize, sizeof(*tagsByValue), tagCmpValue);
2ff057
    qsort(tagsByName, rpmTagTableSize, sizeof(*tagsByName), tagCmpName);
2ff057
}
2ff057
2ff057
static headerTagTableEntry entryByTag(rpmTagVal tag)
2ff057
{
2ff057
    headerTagTableEntry entry = NULL;
2ff057
    int i, comparison;
2ff057
    int l = 0;
2ff057
    int u = rpmTagTableSize;
2ff057
2ff057
    while (l < u) {
2ff057
	i = (l + u) / 2;
2ff057
	comparison = (tag - tagsByValue[i]->val);
2ff057
2ff057
	if (comparison < 0) {
2ff057
	    u = i;
2ff057
	} else if (comparison > 0) {
2ff057
	    l = i + 1;
2ff057
	} else {
2ff057
	    /* Make sure that the bsearch retrieve is stable. */
2ff057
	    while (i > 0 && tag == tagsByValue[i-1]->val) {
2ff057
		i--;
2ff057
	    }
2ff057
	    entry = tagsByValue[i];
2ff057
	    break;
2ff057
	}
2ff057
    }
2ff057
    return entry;
2ff057
}
2ff057
2ff057
static headerTagTableEntry entryByName(const char *tag)
2ff057
{
2ff057
    headerTagTableEntry entry = NULL;
2ff057
    int i, comparison;
2ff057
    int l = 0;
2ff057
    int u = rpmTagTableSize;
2ff057
2ff057
    while (l < u) {
2ff057
	i = (l + u) / 2;
2ff057
	comparison = rstrcasecmp(tag, tagsByName[i]->shortname);
2ff057
2ff057
	if (comparison < 0) {
2ff057
	    u = i;
2ff057
	} else if (comparison > 0) {
2ff057
	    l = i + 1;
2ff057
	} else {
2ff057
	    entry = tagsByName[i];
2ff057
	    break;
2ff057
	}
2ff057
    }
2ff057
    return entry;
2ff057
}
2ff057
2ff057
const char * rpmTagGetName(rpmTagVal tag)
2ff057
{
2ff057
    const char *name = "(unknown)";
2ff057
    const struct headerTagTableEntry_s *t;
2ff057
2ff057
    pthread_once(&tagsLoaded, loadTags);
2ff057
2ff057
    switch (tag) {
2ff057
    case RPMDBI_PACKAGES:
2ff057
	name = "Packages";
2ff057
	break;
2ff057
    /* XXX make sure rpmdb indices are identically named. */
2ff057
    case RPMTAG_CONFLICTS:
2ff057
	name = "Conflictname";
2ff057
	break;
2ff057
    case RPMTAG_HDRID:
2ff057
	name = "Sha1header";
2ff057
	break;
2ff057
2ff057
    default:
2ff057
	t = entryByTag(tag);
2ff057
	if (t && t->shortname)
2ff057
	    name = t->shortname;
2ff057
	break;
2ff057
    }
2ff057
    return name;
2ff057
}
2ff057
2ff057
rpmTagType rpmTagGetType(rpmTagVal tag)
2ff057
{
2ff057
    const struct headerTagTableEntry_s *t;
2ff057
    rpmTagType tagtype = RPM_NULL_TYPE;
2ff057
2ff057
    pthread_once(&tagsLoaded, loadTags);
2ff057
2ff057
    t = entryByTag(tag);
2ff057
    if (t) {
2ff057
	/* XXX this is dumb */
2ff057
	tagtype = (rpmTagType)(t->type | t->retype);
2ff057
    }
2ff057
    return tagtype;
2ff057
}
2ff057
2ff057
rpmTagVal rpmTagGetValue(const char * tagstr)
2ff057
{
2ff057
    const struct headerTagTableEntry_s *t;
2ff057
    rpmTagType tagval = RPMTAG_NOT_FOUND;
2ff057
2ff057
    pthread_once(&tagsLoaded, loadTags);
2ff057
2ff057
    if (!rstrcasecmp(tagstr, "Packages"))
2ff057
	return RPMDBI_PACKAGES;
2ff057
2ff057
    t = entryByName(tagstr);
2ff057
    if (t)
2ff057
	tagval = t->val;
2ff057
	
2ff057
    return tagval;
2ff057
}
2ff057
2ff057
rpmTagType rpmTagGetTagType(rpmTagVal tag)
2ff057
{
2ff057
    return (rpmTagGetType(tag) & RPM_MASK_TYPE);
2ff057
}
2ff057
2ff057
rpmTagReturnType rpmTagGetReturnType(rpmTagVal tag)
2ff057
{
2ff057
    return (rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE);
2ff057
}
2ff057
2ff057
rpmTagClass rpmTagTypeGetClass(rpmTagType type)
2ff057
{
2ff057
    rpmTagClass tclass;
2ff057
    switch (type & RPM_MASK_TYPE) {
2ff057
    case RPM_CHAR_TYPE:
2ff057
    case RPM_INT8_TYPE:
2ff057
    case RPM_INT16_TYPE:
2ff057
    case RPM_INT32_TYPE:
2ff057
    case RPM_INT64_TYPE:
2ff057
	tclass = RPM_NUMERIC_CLASS;
2ff057
	break;
2ff057
    case RPM_STRING_TYPE:
2ff057
    case RPM_STRING_ARRAY_TYPE:
2ff057
    case RPM_I18NSTRING_TYPE:
2ff057
	tclass = RPM_STRING_CLASS;
2ff057
	break;
2ff057
    case RPM_BIN_TYPE:
2ff057
	tclass = RPM_BINARY_CLASS;
2ff057
	break;
2ff057
    case RPM_NULL_TYPE:
2ff057
    default:
2ff057
	tclass = RPM_NULL_CLASS;
2ff057
	break;
2ff057
    }
2ff057
    return tclass;
2ff057
}
2ff057
2ff057
rpmTagClass rpmTagGetClass(rpmTagVal tag)
2ff057
{
2ff057
    return rpmTagTypeGetClass(rpmTagGetTagType(tag));
2ff057
}
2ff057
2ff057
int rpmTagGetNames(rpmtd tagnames, int fullname)
2ff057
{
2ff057
    const char **names;
2ff057
    const char *name;
2ff057
2ff057
    pthread_once(&tagsLoaded, loadTags);
2ff057
2ff057
    if (tagnames == NULL || tagsByName == NULL)
2ff057
	return 0;
2ff057
2ff057
    rpmtdReset(tagnames);
2ff057
    tagnames->count = rpmTagTableSize;
2ff057
    tagnames->data = names = xmalloc(tagnames->count * sizeof(*names));
2ff057
    tagnames->type = RPM_STRING_ARRAY_TYPE;
2ff057
    tagnames->flags = RPMTD_ALLOCED | RPMTD_IMMUTABLE;
2ff057
2ff057
    for (int i = 0; i < tagnames->count; i++) {
2ff057
	name = fullname ? tagsByName[i]->name :
2ff057
			  tagsByName[i]->shortname;
2ff057
	names[i] = name;
2ff057
    }
2ff057
    return tagnames->count;
2ff057
}