Modify how to make symbolic link in 'find-debuginfo.sh' script
[platform/upstream/rpm.git] / lib / tagname.c
1 /**
2  * \file lib/tagname.c
3  */
4
5 #include "system.h"
6
7 #include <rpm/header.h>
8 #include <rpm/rpmstring.h>
9 #include "debug.h"
10
11 /** \ingroup header
12  * Associate tag names with numeric values.
13  */
14 typedef const struct headerTagTableEntry_s * headerTagTableEntry;
15 struct headerTagTableEntry_s {
16     const char * name;          /*!< Tag name. */
17     const char * shortname;     /*!< "Human readable" short name. */
18     rpmTagVal val;              /*!< Tag numeric value. */
19     rpmTagType type;            /*!< Tag type. */
20     rpmTagReturnType retype;    /*!< Tag return type. */
21     int extension;              /*!< Extension or "real" tag */
22 };
23
24 #include "lib/tagtbl.C"
25
26 static const int rpmTagTableSize = sizeof(rpmTagTable) / sizeof(rpmTagTable[0]) - 1;
27
28 /**
29  */
30 typedef struct headerTagIndices_s * headerTagIndices;
31
32 struct headerTagIndices_s {
33     int (*loadIndex) (headerTagTableEntry ** ipp, int * np,
34                 int (*cmp) (const void * avp, const void * bvp));
35                                         /*!< load sorted tag index. */
36     headerTagTableEntry * byName;       /*!< header tags sorted by name. */
37     int byNameSize;                     /*!< no. of entries. */
38     int (*byNameCmp) (const void * avp, const void * bvp);                              /*!< compare entries by name. */
39     rpmTagVal (*tagValue) (const char * name);  /* return value from name. */
40     headerTagTableEntry * byValue;      /*!< header tags sorted by value. */
41     int byValueSize;                    /*!< no. of entries. */
42     int (*byValueCmp) (const void * avp, const void * bvp);                             /*!< compare entries by value. */
43     const char * (*tagName) (rpmTagVal value);  /* Return name from value. */
44     rpmTagType (*tagType) (rpmTagVal value);    /* Return type from value. */
45 };
46
47 /**
48  * Compare tag table entries by name.
49  * @param *avp          tag table entry a
50  * @param *bvp          tag table entry b
51  * @return              comparison
52  */
53 static int tagCmpName(const void * avp, const void * bvp)
54 {
55     headerTagTableEntry a = *(const headerTagTableEntry *) avp;
56     headerTagTableEntry b = *(const headerTagTableEntry *) bvp;
57     return strcmp(a->name, b->name);
58 }
59
60 /**
61  * Compare tag table entries by value.
62  * @param *avp          tag table entry a
63  * @param *bvp          tag table entry b
64  * @return              comparison
65  */
66 static int tagCmpValue(const void * avp, const void * bvp)
67 {
68     headerTagTableEntry a = *(const headerTagTableEntry *) avp;
69     headerTagTableEntry b = *(const headerTagTableEntry *) bvp;
70     int ret = (a->val - b->val);
71     /* Make sure that sort is stable, longest name first. */
72     if (ret == 0)
73         ret = (strlen(b->name) - strlen(a->name));
74     return ret;
75 }
76
77 /**
78  * Load/sort a tag index.
79  * @retval *ipp         tag index
80  * @retval *np          no. of tags
81  * @param cmp           sort compare routine
82  * @return              0 always
83  */
84 static int tagLoadIndex(headerTagTableEntry ** ipp, int * np,
85                 int (*cmp) (const void * avp, const void * bvp))
86 {
87     headerTagTableEntry tte, *ip;
88     int n = 0;
89
90     ip = xcalloc(rpmTagTableSize, sizeof(*ip));
91     n = 0;
92     for (tte = (headerTagTableEntry)rpmTagTable; tte->name != NULL; tte++) {
93         ip[n] = tte;
94         n++;
95     }
96 assert(n == rpmTagTableSize);
97
98     if (n > 1)
99         qsort(ip, n, sizeof(*ip), cmp);
100     *ipp = ip;
101     *np = n;
102     return 0;
103 }
104
105
106 /* forward refs */
107 static const char * _tagName(rpmTagVal tag);
108 static rpmTagType _tagType(rpmTagVal tag);
109 static rpmTagVal _tagValue(const char * tagstr);
110
111 static struct headerTagIndices_s _rpmTags = {
112     tagLoadIndex,
113     NULL, 0, tagCmpName, _tagValue,
114     NULL, 0, tagCmpValue, _tagName, _tagType,
115 };
116
117 static headerTagIndices const rpmTags = &_rpmTags;
118
119 static const char * _tagName(rpmTagVal tag)
120 {
121     const char *name = "(unknown)";
122     const struct headerTagTableEntry_s *t;
123     int comparison, i, l, u;
124
125     if (_rpmTags.byValue == NULL)
126         tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize, tagCmpValue);
127
128     switch (tag) {
129     case RPMDBI_PACKAGES:
130         name = "Packages";
131         break;
132     /* XXX make sure rpmdb indices are identically named. */
133     case RPMTAG_CONFLICTS:
134         name = "Conflictname";
135         break;
136     case RPMTAG_HDRID:
137         name = "Sha1header";
138         break;
139
140     default:
141         if (_rpmTags.byValue == NULL)
142             break;
143         l = 0;
144         u = _rpmTags.byValueSize;
145         while (l < u) {
146             i = (l + u) / 2;
147             t = _rpmTags.byValue[i];
148         
149             comparison = (tag - t->val);
150
151             if (comparison < 0)
152                 u = i;
153             else if (comparison > 0)
154                 l = i + 1;
155             else {
156                 /* Make sure that the bsearch retrieve is stable. */
157                 while (i > 0 && tag == _rpmTags.byValue[i-1]->val) {
158                     i--;
159                 }
160                 t = _rpmTags.byValue[i];
161                 if (t->shortname != NULL)
162                     name = t->shortname;
163                 break;
164             }
165         }
166         break;
167     }
168     return name;
169 }
170
171 static rpmTagType _tagType(rpmTagVal tag)
172 {
173     const struct headerTagTableEntry_s *t;
174     int comparison, i, l, u;
175
176     if (_rpmTags.byValue == NULL)
177         tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize, tagCmpValue);
178     if (_rpmTags.byValue) {
179         l = 0;
180         u = _rpmTags.byValueSize;
181         while (l < u) {
182             i = (l + u) / 2;
183             t = _rpmTags.byValue[i];
184         
185             comparison = (tag - t->val);
186
187             if (comparison < 0)
188                 u = i;
189             else if (comparison > 0)
190                 l = i + 1;
191             else {
192                 /* Make sure that the bsearch retrieve is stable. */
193                 while (i > 0 && t->val == _rpmTags.byValue[i-1]->val) {
194                     i--;
195                 }
196                 t = _rpmTags.byValue[i];
197                 /* XXX this is dumb */
198                 return (rpmTagType)(t->type | t->retype);
199             }
200         }
201     }
202     return RPM_NULL_TYPE;
203 }
204
205 static rpmTagVal _tagValue(const char * tagstr)
206 {
207     const struct headerTagTableEntry_s *t;
208     int comparison, i, l, u;
209
210     if (!rstrcasecmp(tagstr, "Packages"))
211         return RPMDBI_PACKAGES;
212
213     if (_rpmTags.byName == NULL)
214         tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize, tagCmpName);
215     if (_rpmTags.byName == NULL)
216         return RPMTAG_NOT_FOUND;
217
218     l = 0;
219     u = _rpmTags.byNameSize;
220     while (l < u) {
221         i = (l + u) / 2;
222         t = _rpmTags.byName[i];
223         
224         comparison = rstrcasecmp(tagstr, t->shortname);
225
226         if (comparison < 0)
227             u = i;
228         else if (comparison > 0)
229             l = i + 1;
230         else
231             return t->val;
232     }
233     return RPMTAG_NOT_FOUND;
234 }
235
236 const char * rpmTagGetName(rpmTagVal tag)
237 {
238     return ((*rpmTags->tagName)(tag));
239 }
240
241 rpmTagType rpmTagGetType(rpmTagVal tag)
242 {
243     return ((*rpmTags->tagType)(tag));
244 }
245
246 rpmTagType rpmTagGetTagType(rpmTagVal tag)
247 {
248     return (rpmTagType)((*rpmTags->tagType)(tag) & RPM_MASK_TYPE);
249 }
250
251 rpmTagReturnType rpmTagGetReturnType(rpmTagVal tag)
252 {
253     return ((*rpmTags->tagType)(tag) & RPM_MASK_RETURN_TYPE);
254 }
255
256 rpmTagClass rpmTagTypeGetClass(rpmTagType type)
257 {
258     rpmTagClass tclass;
259     switch (type & RPM_MASK_TYPE) {
260     case RPM_CHAR_TYPE:
261     case RPM_INT8_TYPE:
262     case RPM_INT16_TYPE:
263     case RPM_INT32_TYPE:
264     case RPM_INT64_TYPE:
265         tclass = RPM_NUMERIC_CLASS;
266         break;
267     case RPM_STRING_TYPE:
268     case RPM_STRING_ARRAY_TYPE:
269     case RPM_I18NSTRING_TYPE:
270         tclass = RPM_STRING_CLASS;
271         break;
272     case RPM_BIN_TYPE:
273         tclass = RPM_BINARY_CLASS;
274         break;
275     case RPM_NULL_TYPE:
276     default:
277         tclass = RPM_NULL_CLASS;
278         break;
279     }
280     return tclass;
281 }
282
283 rpmTagClass rpmTagGetClass(rpmTagVal tag)
284 {
285     return rpmTagTypeGetClass(rpmTagGetTagType(tag));
286 }
287
288 rpmTagVal rpmTagGetValue(const char * tagstr)
289 {
290     return ((*rpmTags->tagValue)(tagstr));
291 }
292
293 int rpmTagGetNames(rpmtd tagnames, int fullname)
294 {
295     const char **names;
296     const char *name;
297
298     if (_rpmTags.byName == NULL)
299         tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize, tagCmpName);
300     if (tagnames == NULL ||_rpmTags.byName == NULL)
301         return 0;
302
303     rpmtdReset(tagnames);
304     tagnames->count = _rpmTags.byNameSize;
305     tagnames->data = names = xmalloc(tagnames->count * sizeof(*names));
306     tagnames->type = RPM_STRING_ARRAY_TYPE;
307     tagnames->flags = RPMTD_ALLOCED | RPMTD_IMMUTABLE;
308
309     for (int i = 0; i < tagnames->count; i++) {
310         name = fullname ? _rpmTags.byName[i]->name : 
311                           _rpmTags.byName[i]->shortname;
312         names[i] = name;
313     }
314     return tagnames->count;
315 }