1 /**
2 * \file lib/tagname.c
3 */
4
5 #include "system.h"
6
7 #include <pthread.h>
8
9 #include <rpm/header.h>
10 #include <rpm/rpmstring.h>
11 #include "debug.h"
12
13 /** \ingroup header
14 * Associate tag names with numeric values.
15 */
16 typedef const struct headerTagTableEntry_s * headerTagTableEntry;
17 struct headerTagTableEntry_s {
18 const char * name; /*!< Tag name. */
19 const char * shortname; /*!< "Human readable" short name. */
20 rpmTagVal val; /*!< Tag numeric value. */
21 rpmTagType type; /*!< Tag type. */
22 rpmTagReturnType retype; /*!< Tag return type. */
23 int extension; /*!< Extension or "real" tag */
24 };
25
26 #include "lib/tagtbl.C"
27
28 #define TABLESIZE (sizeof(rpmTagTable) / sizeof(rpmTagTable[0]) - 1)
29 static const int rpmTagTableSize = TABLESIZE;
30
31 static headerTagTableEntry tagsByName[TABLESIZE]; /*!< tags sorted by name. */
32 static headerTagTableEntry tagsByValue[TABLESIZE]; /*!< tags sorted by value. */
33
34 /**
35 * Compare tag table entries by name.
36 * @param *avp tag table entry a
37 * @param *bvp tag table entry b
38 * @return comparison
39 */
tagCmpName(const void * avp,const void * bvp)40 static int tagCmpName(const void * avp, const void * bvp)
41 {
42 headerTagTableEntry a = *(const headerTagTableEntry *) avp;
43 headerTagTableEntry b = *(const headerTagTableEntry *) bvp;
44 return strcmp(a->name, b->name);
45 }
46
47 /**
48 * Compare tag table entries by value.
49 * @param *avp tag table entry a
50 * @param *bvp tag table entry b
51 * @return comparison
52 */
tagCmpValue(const void * avp,const void * bvp)53 static int tagCmpValue(const void * avp, const void * bvp)
54 {
55 headerTagTableEntry a = *(const headerTagTableEntry *) avp;
56 headerTagTableEntry b = *(const headerTagTableEntry *) bvp;
57 int ret = (a->val - b->val);
58 /* Make sure that sort is stable, longest name first. */
59 if (ret == 0)
60 ret = (strlen(b->name) - strlen(a->name));
61 return ret;
62 }
63
64 static pthread_once_t tagsLoaded = PTHREAD_ONCE_INIT;
65
66 /* Initialize tag by-value and by-name lookup tables */
loadTags(void)67 static void loadTags(void)
68 {
69 for (int i = 0; i < rpmTagTableSize; i++) {
70 tagsByValue[i] = &rpmTagTable[i];
71 tagsByName[i] = &rpmTagTable[i];
72 }
73
74 qsort(tagsByValue, rpmTagTableSize, sizeof(*tagsByValue), tagCmpValue);
75 qsort(tagsByName, rpmTagTableSize, sizeof(*tagsByName), tagCmpName);
76 }
77
entryByTag(rpmTagVal tag)78 static headerTagTableEntry entryByTag(rpmTagVal tag)
79 {
80 headerTagTableEntry entry = NULL;
81 int i, comparison;
82 int l = 0;
83 int u = rpmTagTableSize;
84
85 while (l < u) {
86 i = (l + u) / 2;
87 comparison = (tag - tagsByValue[i]->val);
88
89 if (comparison < 0) {
90 u = i;
91 } else if (comparison > 0) {
92 l = i + 1;
93 } else {
94 /* Make sure that the bsearch retrieve is stable. */
95 while (i > 0 && tag == tagsByValue[i-1]->val) {
96 i--;
97 }
98 entry = tagsByValue[i];
99 break;
100 }
101 }
102 return entry;
103 }
104
entryByName(const char * tag)105 static headerTagTableEntry entryByName(const char *tag)
106 {
107 headerTagTableEntry entry = NULL;
108 int i, comparison;
109 int l = 0;
110 int u = rpmTagTableSize;
111
112 while (l < u) {
113 i = (l + u) / 2;
114 comparison = rstrcasecmp(tag, tagsByName[i]->shortname);
115
116 if (comparison < 0) {
117 u = i;
118 } else if (comparison > 0) {
119 l = i + 1;
120 } else {
121 entry = tagsByName[i];
122 break;
123 }
124 }
125 return entry;
126 }
127
rpmTagGetName(rpmTagVal tag)128 const char * rpmTagGetName(rpmTagVal tag)
129 {
130 const char *name = "(unknown)";
131 const struct headerTagTableEntry_s *t;
132
133 pthread_once(&tagsLoaded, loadTags);
134
135 switch (tag) {
136 case RPMDBI_PACKAGES:
137 name = "Packages";
138 break;
139 /* XXX make sure rpmdb indices are identically named. */
140 case RPMTAG_CONFLICTS:
141 name = "Conflictname";
142 break;
143 case RPMTAG_HDRID:
144 name = "Sha1header";
145 break;
146
147 default:
148 t = entryByTag(tag);
149 if (t && t->shortname)
150 name = t->shortname;
151 break;
152 }
153 return name;
154 }
155
rpmTagGetType(rpmTagVal tag)156 rpmTagType rpmTagGetType(rpmTagVal tag)
157 {
158 const struct headerTagTableEntry_s *t;
159 rpmTagType tagtype = RPM_NULL_TYPE;
160
161 pthread_once(&tagsLoaded, loadTags);
162
163 t = entryByTag(tag);
164 if (t) {
165 /* XXX this is dumb */
166 tagtype = (rpmTagType)(t->type | t->retype);
167 }
168 return tagtype;
169 }
170
rpmTagGetValue(const char * tagstr)171 rpmTagVal rpmTagGetValue(const char * tagstr)
172 {
173 const struct headerTagTableEntry_s *t;
174 rpmTagType tagval = RPMTAG_NOT_FOUND;
175
176 pthread_once(&tagsLoaded, loadTags);
177
178 if (!rstrcasecmp(tagstr, "Packages"))
179 return RPMDBI_PACKAGES;
180
181 t = entryByName(tagstr);
182 if (t)
183 tagval = t->val;
184
185 return tagval;
186 }
187
rpmTagGetTagType(rpmTagVal tag)188 rpmTagType rpmTagGetTagType(rpmTagVal tag)
189 {
190 return (rpmTagGetType(tag) & RPM_MASK_TYPE);
191 }
192
rpmTagGetReturnType(rpmTagVal tag)193 rpmTagReturnType rpmTagGetReturnType(rpmTagVal tag)
194 {
195 return (rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE);
196 }
197
rpmTagTypeGetClass(rpmTagType type)198 rpmTagClass rpmTagTypeGetClass(rpmTagType type)
199 {
200 rpmTagClass tclass;
201 switch (type & RPM_MASK_TYPE) {
202 case RPM_CHAR_TYPE:
203 case RPM_INT8_TYPE:
204 case RPM_INT16_TYPE:
205 case RPM_INT32_TYPE:
206 case RPM_INT64_TYPE:
207 tclass = RPM_NUMERIC_CLASS;
208 break;
209 case RPM_STRING_TYPE:
210 case RPM_STRING_ARRAY_TYPE:
211 case RPM_I18NSTRING_TYPE:
212 tclass = RPM_STRING_CLASS;
213 break;
214 case RPM_BIN_TYPE:
215 tclass = RPM_BINARY_CLASS;
216 break;
217 case RPM_NULL_TYPE:
218 default:
219 tclass = RPM_NULL_CLASS;
220 break;
221 }
222 return tclass;
223 }
224
rpmTagGetClass(rpmTagVal tag)225 rpmTagClass rpmTagGetClass(rpmTagVal tag)
226 {
227 return rpmTagTypeGetClass(rpmTagGetTagType(tag));
228 }
229
rpmTagGetNames(rpmtd tagnames,int fullname)230 int rpmTagGetNames(rpmtd tagnames, int fullname)
231 {
232 const char **names;
233 const char *name;
234
235 pthread_once(&tagsLoaded, loadTags);
236
237 if (tagnames == NULL)
238 return 0;
239
240 rpmtdReset(tagnames);
241 tagnames->count = rpmTagTableSize;
242 tagnames->data = names = xmalloc(tagnames->count * sizeof(*names));
243 tagnames->type = RPM_STRING_ARRAY_TYPE;
244 tagnames->flags = RPMTD_ALLOCED | RPMTD_IMMUTABLE;
245
246 for (int i = 0; i < tagnames->count; i++) {
247 name = fullname ? tagsByName[i]->name :
248 tagsByName[i]->shortname;
249 names[i] = name;
250 }
251 return tagnames->count;
252 }
253