Imported Upstream version 4.14.1
[platform/upstream/rpm.git] / lib / tagname.c
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  */
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  */
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 */
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
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
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
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
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
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
188 rpmTagType rpmTagGetTagType(rpmTagVal tag)
189 {
190     return (rpmTagGetType(tag) & RPM_MASK_TYPE);
191 }
192
193 rpmTagReturnType rpmTagGetReturnType(rpmTagVal tag)
194 {
195     return (rpmTagGetType(tag) & RPM_MASK_RETURN_TYPE);
196 }
197
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
225 rpmTagClass rpmTagGetClass(rpmTagVal tag)
226 {
227     return rpmTagTypeGetClass(rpmTagGetTagType(tag));
228 }
229
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 || tagsByName == 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 }