]>
Commit | Line | Data |
---|---|---|
517e249f | 1 | commit 4b027294335c0672311f021f2dc76edaab049b11 |
2 | Author: Marcin Banasiak <marcin.banasiak@gmail.com> | |
3 | Date: Sun Dec 13 20:50:11 2009 +0100 | |
4 | ||
5 | Support for query format in ls command. | |
6 | ||
7 | Syntax of the queryfmt is almost the same as in rpm except query | |
8 | expressions which are not (yet) supported. | |
9 | ||
10 | To see supported tags type: | |
11 | ls --querytags | |
12 | ||
13 | diff --git a/cli/Makefile.am b/cli/Makefile.am | |
14 | index 53fcdfd..4a32e01 100644 | |
15 | --- a/cli/Makefile.am | |
16 | +++ b/cli/Makefile.am | |
17 | @@ -28,6 +28,7 @@ libpoclidek_la_SOURCES = \ | |
18 | op_split.c \ | |
19 | op_verify.c \ | |
20 | ls.c \ | |
21 | + ls_queryfmt.c ls_queryfmt.h \ | |
22 | install.c \ | |
23 | uninstall.c \ | |
24 | desc.c \ | |
25 | diff --git a/cli/ls_queryfmt.c b/cli/ls_queryfmt.c | |
26 | new file mode 100644 | |
27 | index 0000000..1a0c02f | |
28 | --- /dev/null | |
29 | +++ b/cli/ls_queryfmt.c | |
30 | @@ -0,0 +1,1096 @@ | |
31 | +/* | |
32 | + Copyright (C) 2009 Marcin Banasiak <megabajt@pld-linux.org> | |
33 | + | |
34 | + This program is free software; you can redistribute it and/or modify | |
35 | + it under the terms of the GNU General Public License, version 2 as | |
36 | + published by the Free Software Foundation (see file COPYING for details). | |
37 | + | |
38 | + You should have received a copy of the GNU General Public License | |
39 | + along with this program; if not, write to the Free Software | |
40 | + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
41 | +*/ | |
42 | + | |
43 | +#ifdef HAVE_CONFIG_H | |
44 | +# include "config.h" | |
45 | +#endif | |
46 | + | |
47 | +/* for asprintf() from stdio.h */ | |
48 | +#define _GNU_SOURCE | |
49 | + | |
50 | +/* FIXME: nbuf.h should include stdint.h */ | |
51 | +#include <stdint.h> | |
52 | + | |
53 | +#include <sys/stat.h> | |
54 | +#include <stdio.h> | |
55 | +#include <stdlib.h> | |
56 | +#include <string.h> | |
57 | +#include <time.h> | |
58 | + | |
59 | +#include <trurl/trurl.h> | |
60 | + | |
61 | +#include "capreq.h" | |
62 | +#include "i18n.h" | |
63 | +#include "log.h" | |
64 | +#include "ls_queryfmt.h" | |
65 | +#include "pkgu.h" | |
66 | +#include "pkgfl.h" | |
67 | + | |
68 | +#define n_strcase_eq(s, p) (strcasecmp(s, p) == 0) | |
69 | + | |
70 | +static const char *invalid_format = N_("invalid format:"); | |
71 | + | |
72 | +enum LsqfParseMode { | |
73 | + LSQF_PARSE_NORMAL = 0, | |
74 | + LSQF_PARSE_ARRAY | |
75 | +}; | |
76 | + | |
77 | +/* Tags have to be in alphabetical order. */ | |
78 | +enum { | |
79 | + LSQF_TAG_UNKNOWN = -1, | |
80 | + | |
81 | + LSQF_TAG_ARCH = 0, | |
82 | + LSQF_TAG_BASENAMES, | |
83 | + LSQF_TAG_BUILDHOST, | |
84 | + LSQF_TAG_BUILDTIME, | |
85 | + LSQF_TAG_CONFLICTFLAGS, | |
86 | + LSQF_TAG_CONFLICTS, | |
87 | + LSQF_TAG_CONFLICTVERSION, | |
88 | + LSQF_TAG_DESCRIPTION, | |
89 | + LSQF_TAG_DIRNAMES, | |
90 | + LSQF_TAG_EPOCH, | |
91 | + LSQF_TAG_FILELINKTOS, | |
92 | + LSQF_TAG_FILEMODES, | |
93 | + LSQF_TAG_FILENAMES, | |
94 | + LSQF_TAG_FILESIZES, | |
95 | + LSQF_TAG_GROUP, | |
96 | + LSQF_TAG_LICENSE, | |
97 | + LSQF_TAG_NAME, | |
98 | + LSQF_TAG_NVRA, | |
99 | + LSQF_TAG_OBSOLETEFLAGS, | |
100 | + LSQF_TAG_OBSOLETES, | |
101 | + LSQF_TAG_OBSOLETEVERSION, | |
102 | + LSQF_TAG_PACKAGECOLOR, | |
103 | + LSQF_TAG_PROVIDEFLAGS, | |
104 | + LSQF_TAG_PROVIDES, | |
105 | + LSQF_TAG_PROVIDEVERSION, | |
106 | + LSQF_TAG_RELEASE, | |
107 | + LSQF_TAG_REQUIREFLAGS, | |
108 | + LSQF_TAG_REQUIRES, | |
109 | + LSQF_TAG_REQUIREVERSION, | |
110 | + LSQF_TAG_SIZE, | |
111 | + LSQF_TAG_SOURCERPM, | |
112 | + LSQF_TAG_SUGGESTSFLAGS, | |
113 | + LSQF_TAG_SUGGESTS, | |
114 | + LSQF_TAG_SUGGESTSVERSION, | |
115 | + LSQF_TAG_SUMMARY, | |
116 | + LSQF_TAG_URL, | |
117 | + LSQF_TAG_VENDOR, | |
118 | + LSQF_TAG_VERSION, | |
119 | + | |
120 | + LSQF_N_TAGS | |
121 | +}; | |
122 | + | |
123 | +enum { | |
124 | + LSQF_TAG_OUTFMTFN_NONE = 0, | |
125 | + | |
126 | + LSQF_TAG_OUTFMTFN_DATE, | |
127 | + LSQF_TAG_OUTFMTFN_DAY, | |
128 | + LSQF_TAG_OUTFMTFN_DEPFLAGS | |
129 | +}; | |
130 | + | |
131 | +struct lsqf_tags { | |
132 | + int tagid; | |
133 | + int is_array : 1; | |
134 | + int need_uinf : 1; | |
135 | + int need_flist : 1; | |
136 | + const char *tagname[4]; | |
137 | +}; | |
138 | + | |
139 | +/* | |
140 | + * LSQF_TAG_* have to be added in the same sequence as in enumeration | |
141 | + * (LSQF_TAG_ value is an index in lsqf_tags[] array). | |
142 | + */ | |
143 | +static const struct lsqf_tags lsqf_tags[] = { | |
144 | + { LSQF_TAG_ARCH, 0, 0, 0, { "ARCH", NULL } }, | |
145 | + { LSQF_TAG_BASENAMES, 1, 0, 1, { "BASENAMES", NULL } }, | |
146 | + { LSQF_TAG_BUILDHOST, 0, 1, 0, { "BUILDHOST", NULL } }, | |
147 | + { LSQF_TAG_BUILDTIME, 0, 0, 0, { "BUILDTIME", NULL } }, | |
148 | + { LSQF_TAG_CONFLICTFLAGS, 1, 0, 0, { "CONFLICTFLAGS", NULL } }, | |
149 | + { LSQF_TAG_CONFLICTS, 1, 0, 0, { "C", "CONFLICTNAME", "CONFLICTS", NULL } }, | |
150 | + { LSQF_TAG_CONFLICTVERSION, 1, 0, 0, { "CONFLICTVERSION", NULL } }, | |
151 | + { LSQF_TAG_DESCRIPTION, 0, 1, 0, { "DESCRIPTION", NULL } }, | |
152 | + { LSQF_TAG_DIRNAMES, 1, 0, 1, { "DIRNAMES", NULL } }, | |
153 | + { LSQF_TAG_EPOCH, 0, 0, 0, { "E", "EPOCH", NULL } }, | |
154 | + { LSQF_TAG_FILELINKTOS, 1, 0, 1, { "FILELINKTOS", NULL } }, | |
155 | + { LSQF_TAG_FILEMODES, 1, 0, 1, { "FILEMODES", NULL } }, | |
156 | + { LSQF_TAG_FILENAMES, 1, 0, 1, { "FILENAMES", NULL } }, | |
157 | + { LSQF_TAG_FILESIZES, 1, 0, 1, { "FILESIZES", NULL } }, | |
158 | + { LSQF_TAG_GROUP, 0, 0, 0, { "GROUP", NULL } }, | |
159 | + { LSQF_TAG_LICENSE, 0, 1, 0, { "LICENSE", NULL } }, | |
160 | + { LSQF_TAG_NAME, 0, 0, 0, { "N", "NAME", NULL } }, | |
161 | + { LSQF_TAG_NVRA, 0, 0, 0, { "NVRA", NULL } }, | |
162 | + { LSQF_TAG_OBSOLETEFLAGS, 1, 0, 0, { "OBSOLETEFLAGS", NULL } }, | |
163 | + { LSQF_TAG_OBSOLETES, 1, 0, 0, { "O", "OBSOLETENAME", "OBSOLETES", NULL } }, | |
164 | + { LSQF_TAG_OBSOLETEVERSION, 1, 0, 0, { "OBSOLETEVERSION", NULL } }, | |
165 | + { LSQF_TAG_PACKAGECOLOR, 0, 0, 0, { "PACKAGECOLOR", NULL } }, | |
166 | + { LSQF_TAG_PROVIDEFLAGS, 1, 0, 0, { "PROVIDEFLAGS", NULL } }, | |
167 | + { LSQF_TAG_PROVIDES, 1, 0, 0, { "P", "PROVIDENAME", "PROVIDES", NULL } }, | |
168 | + { LSQF_TAG_PROVIDEVERSION, 1, 0, 0, { "PROVIDEVERSION", NULL } }, | |
169 | + { LSQF_TAG_RELEASE, 0, 0, 0, { "R", "RELEASE", NULL } }, | |
170 | + { LSQF_TAG_REQUIREFLAGS, 1, 0, 0, { "REQUIREFLAGS", NULL } }, | |
171 | + { LSQF_TAG_REQUIRES, 1, 0, 0, { "REQUIRENAME", "REQUIRES", NULL } }, | |
172 | + { LSQF_TAG_REQUIREVERSION, 1, 0, 0, { "REQUIREVERSION", NULL } }, | |
173 | + { LSQF_TAG_SIZE, 0, 0, 0, { "SIZE", NULL } }, | |
174 | + { LSQF_TAG_SOURCERPM, 0, 0, 0, { "SOURCERPM", NULL } }, | |
175 | + { LSQF_TAG_SUGGESTSFLAGS, 1, 0, 0, { "SUGGESTSFLAGS", NULL } }, | |
176 | + { LSQF_TAG_SUGGESTS, 1, 0, 0, { "SUGGESTS", "SUGGESTSNAME", NULL } }, | |
177 | + { LSQF_TAG_SUGGESTSVERSION, 1, 0, 0, { "SUGGESTSVERSION", NULL } }, | |
178 | + { LSQF_TAG_SUMMARY, 0, 1, 0, { "SUMMARY", NULL } }, | |
179 | + { LSQF_TAG_URL, 0, 1, 0, { "URL", NULL } }, | |
180 | + { LSQF_TAG_VENDOR, 0, 1, 0, { "VENDOR", NULL } }, | |
181 | + { LSQF_TAG_VERSION, 0, 0, 0, { "V", "VERSION", NULL } }, | |
182 | + { LSQF_N_TAGS, 0, 0, 0, { NULL } } | |
183 | +}; | |
184 | + | |
185 | +struct lsqf_pkgdata { | |
186 | + const struct pkg *pkg; | |
187 | + struct pkgflist *flist; | |
188 | + struct pkguinf *uinf; | |
189 | +}; | |
190 | + | |
191 | +static struct lsqf_pkgdata *lsqf_pkgdata_new(const struct pkg *pkg) | |
192 | +{ | |
193 | + struct lsqf_pkgdata *pkgdata = NULL; | |
194 | + | |
195 | + pkgdata = n_malloc(sizeof(struct lsqf_pkgdata)); | |
196 | + | |
197 | + if (pkgdata) { | |
198 | + pkgdata->pkg = pkg; | |
199 | + pkgdata->flist = NULL; | |
200 | + pkgdata->uinf = NULL; | |
201 | + } | |
202 | + | |
203 | + return pkgdata; | |
204 | +} | |
205 | + | |
206 | +static struct pkgflist *lsqf_pkgdata_flist(struct lsqf_pkgdata *pkgdata) | |
207 | +{ | |
208 | + if (pkgdata->flist == NULL) | |
209 | + pkgdata->flist = pkg_get_flist(pkgdata->pkg); | |
210 | + | |
211 | + return pkgdata->flist; | |
212 | +} | |
213 | + | |
214 | +static struct pkguinf *lsqf_pkgdata_uinf(struct lsqf_pkgdata *pkgdata) | |
215 | +{ | |
216 | + if (pkgdata->uinf == NULL) | |
217 | + pkgdata->uinf = pkg_uinf(pkgdata->pkg); | |
218 | + | |
219 | + return pkgdata->uinf; | |
220 | +} | |
221 | + | |
222 | +static void lsqf_pkgdata_free(struct lsqf_pkgdata *pkgdata) | |
223 | +{ | |
224 | + if (pkgdata) { | |
225 | + if (pkgdata->flist) | |
226 | + pkgflist_free(pkgdata->flist); | |
227 | + | |
228 | + if (pkgdata->uinf) | |
229 | + pkguinf_free(pkgdata->uinf); | |
230 | + | |
231 | + n_free(pkgdata); | |
232 | + } | |
233 | +} | |
234 | + | |
235 | +static int get_tagid_by_name(char *tag) | |
236 | +{ | |
237 | + if (tag) { | |
238 | + unsigned int i, j; | |
239 | + | |
240 | + for (i = 0; i < LSQF_N_TAGS; i++) { | |
241 | + for (j = 0; lsqf_tags[i].tagname[j]; j++) { | |
242 | + if (n_strcase_eq(tag, lsqf_tags[i].tagname[j])) { | |
243 | + return lsqf_tags[i].tagid; | |
244 | + } | |
245 | + } | |
246 | + } | |
247 | + } | |
248 | + | |
249 | + return LSQF_TAG_UNKNOWN; | |
250 | +} | |
251 | + | |
252 | +static int get_outfmtfnid_by_name(char *outfmtfn) | |
253 | +{ | |
254 | + if (outfmtfn && *outfmtfn) { | |
255 | + if (n_str_eq(outfmtfn, "date")) | |
256 | + return LSQF_TAG_OUTFMTFN_DATE; | |
257 | + if (n_str_eq(outfmtfn, "day")) | |
258 | + return LSQF_TAG_OUTFMTFN_DAY; | |
259 | + if (n_str_eq(outfmtfn, "depflags")) | |
260 | + return LSQF_TAG_OUTFMTFN_DEPFLAGS; | |
261 | + } | |
262 | + | |
263 | + return LSQF_TAG_OUTFMTFN_NONE; | |
264 | +} | |
265 | + | |
266 | +/* TODO: move to capreq.c */ | |
267 | +static int capreq_snprintf_evr(char *str, size_t size, const struct capreq *cr) | |
268 | +{ | |
269 | + int n = 0; | |
270 | + | |
271 | + n_assert(size > 0); | |
272 | + | |
273 | + if (capreq_has_epoch(cr)) | |
274 | + n += n_snprintf(&str[n], size - n, "%d:", capreq_epoch(cr)); | |
275 | + | |
276 | + if (capreq_has_ver(cr)) | |
277 | + n += n_snprintf(&str[n], size - n, "%s", capreq_ver(cr)); | |
278 | + | |
279 | + if (capreq_has_rel(cr)) { | |
280 | + n_assert(capreq_has_ver(cr)); | |
281 | + | |
282 | + n += n_snprintf(&str[n], size - n, "-%s", capreq_rel(cr)); | |
283 | + } | |
284 | + | |
285 | + return n; | |
286 | +} | |
287 | + | |
288 | +static char *format_date(int outfmtfnid, uint32_t time) | |
289 | +{ | |
290 | + char *buf = NULL, datestr[32];; | |
291 | + | |
292 | + if (outfmtfnid == LSQF_TAG_OUTFMTFN_DATE) { | |
293 | + strftime(datestr, sizeof(datestr), "%c", gmtime((time_t *)&time)); | |
294 | + asprintf(&buf, "%s", datestr); | |
295 | + } else if (outfmtfnid == LSQF_TAG_OUTFMTFN_DAY) { | |
296 | + strftime(datestr, sizeof(datestr), "%a %b %d %Y", gmtime((time_t *)&time)); | |
297 | + asprintf(&buf, "%s", datestr); | |
298 | + } else { | |
299 | + asprintf(&buf, "%u", time); | |
300 | + } | |
301 | + | |
302 | + return buf; | |
303 | +} | |
304 | + | |
305 | +static char *format_flags(int outfmtfnid, struct capreq *cr) | |
306 | +{ | |
307 | + char *buf = NULL; | |
308 | + | |
309 | + if (outfmtfnid == LSQF_TAG_OUTFMTFN_DEPFLAGS) { | |
310 | + char relstr[3], *p; | |
311 | + | |
312 | + p = relstr; | |
313 | + *p = '\0'; | |
314 | + | |
315 | + if (cr->cr_relflags & REL_LT) | |
316 | + *p++ = '<'; | |
317 | + else if (cr->cr_relflags & REL_GT) | |
318 | + *p++ = '>'; | |
319 | + | |
320 | + if (cr->cr_relflags & REL_EQ) | |
321 | + *p++ = '='; | |
322 | + | |
323 | + *p = '\0'; | |
324 | + | |
325 | + asprintf(&buf, " %s ", relstr); | |
326 | + } else { | |
327 | + asprintf(&buf, "%u", cr->cr_relflags); | |
328 | + } | |
329 | + | |
330 | + return buf; | |
331 | +} | |
332 | + | |
333 | +static char *get_str_by_tagid(const struct lsqf_ent *ent, struct lsqf_pkgdata *pkgdata, unsigned int num) | |
334 | +{ | |
335 | + const struct pkg *pkg = pkgdata->pkg; | |
336 | + struct capreq *c = NULL; | |
337 | + char *buf = NULL, evr[32]; | |
338 | + unsigned int i; | |
339 | + | |
340 | + if (lsqf_tags[ent->tag.id].need_uinf) { | |
341 | + struct pkguinf *pkgu = lsqf_pkgdata_uinf(pkgdata); | |
342 | + const char *str = NULL; | |
343 | + | |
344 | + switch (ent->tag.id) { | |
345 | + case LSQF_TAG_BUILDHOST: | |
346 | + str = pkguinf_get(pkgu, PKGUINF_BUILDHOST); | |
347 | + break; | |
348 | + | |
349 | + case LSQF_TAG_DESCRIPTION: | |
350 | + str = pkguinf_get(pkgu, PKGUINF_DESCRIPTION); | |
351 | + break; | |
352 | + | |
353 | + case LSQF_TAG_LICENSE: | |
354 | + str = pkguinf_get(pkgu, PKGUINF_LICENSE); | |
355 | + break; | |
356 | + | |
357 | + case LSQF_TAG_SUMMARY: | |
358 | + str = pkguinf_get(pkgu, PKGUINF_SUMMARY); | |
359 | + break; | |
360 | + | |
361 | + case LSQF_TAG_URL: | |
362 | + str = pkguinf_get(pkgu, PKGUINF_URL); | |
363 | + break; | |
364 | + | |
365 | + case LSQF_TAG_VENDOR: | |
366 | + str = pkguinf_get(pkgu, PKGUINF_VENDOR); | |
367 | + break; | |
368 | + | |
369 | + default: | |
370 | + n_assert(0); | |
371 | + } | |
372 | + | |
373 | + if (str) | |
374 | + buf = n_strdup(str); | |
375 | + else | |
376 | + buf = n_strdup("(none)"); | |
377 | + | |
378 | + } else if (lsqf_tags[ent->tag.id].need_flist) { | |
379 | + struct pkgflist *flist = lsqf_pkgdata_flist(pkgdata); | |
380 | + struct pkgfl_ent *flent; | |
381 | + | |
382 | + if (flist) { | |
383 | + switch (ent->tag.id) { | |
384 | + case LSQF_TAG_BASENAMES: | |
385 | + case LSQF_TAG_FILELINKTOS: | |
386 | + case LSQF_TAG_FILEMODES: | |
387 | + case LSQF_TAG_FILENAMES: | |
388 | + case LSQF_TAG_FILESIZES: | |
389 | + for (i = 0; i < n_tuple_size(flist->fl); i++) { | |
390 | + flent = n_tuple_nth(flist->fl, i); | |
391 | + | |
392 | + if (flent->items <= num) | |
393 | + num -= flent->items; | |
394 | + else | |
395 | + break; | |
396 | + } | |
397 | + | |
398 | + if (ent->tag.id == LSQF_TAG_BASENAMES) | |
399 | + buf = n_strdup(flent->files[num]->basename); | |
400 | + else if (ent->tag.id == LSQF_TAG_FILEMODES) | |
401 | + asprintf(&buf, "%u", flent->files[num]->mode); | |
402 | + else if (ent->tag.id == LSQF_TAG_FILENAMES) { | |
403 | + if (*flent->dirname == '/') | |
404 | + asprintf(&buf, "%s%s", flent->dirname, flent->files[num]->basename); | |
405 | + else | |
406 | + asprintf(&buf, "/%s%s%s", flent->dirname, | |
407 | + *flent->files[num]->basename ? "/" : "", | |
408 | + flent->files[num]->basename); | |
409 | + } else if (ent->tag.id == LSQF_TAG_FILESIZES) | |
410 | + asprintf(&buf, "%u", flent->files[num]->size); | |
411 | + else | |
412 | + if (S_ISLNK(flent->files[num]->mode)) | |
413 | + buf = n_strdup(flent->files[num]->basename + strlen(flent->files[num]->basename) + 1); | |
414 | + | |
415 | + break; | |
416 | + | |
417 | + case LSQF_TAG_DIRNAMES: | |
418 | + flent = n_tuple_nth(flist->fl, num); | |
419 | + | |
420 | + asprintf(&buf, "%s%s", *flent->dirname == '/' ? "" : "/", | |
421 | + flent->dirname); | |
422 | + break; | |
423 | + | |
424 | + default: | |
425 | + n_assert(0); | |
426 | + } | |
427 | + } | |
428 | + } else { | |
429 | + switch (ent->tag.id) { | |
430 | + case LSQF_TAG_ARCH: | |
431 | + buf = n_strdup(pkg_arch(pkg)); | |
432 | + break; | |
433 | + | |
434 | + case LSQF_TAG_BUILDTIME: | |
435 | + buf = format_date(ent->tag.outfmtfnid, pkg->btime); | |
436 | + break; | |
437 | + | |
438 | + case LSQF_TAG_CONFLICTFLAGS: | |
439 | + case LSQF_TAG_CONFLICTS: | |
440 | + case LSQF_TAG_CONFLICTVERSION: | |
441 | + case LSQF_TAG_OBSOLETEFLAGS: | |
442 | + case LSQF_TAG_OBSOLETES: | |
443 | + case LSQF_TAG_OBSOLETEVERSION: | |
444 | + { | |
445 | + unsigned int n = 0; | |
446 | + | |
447 | + for (i = 0; i < n_array_size(pkg->cnfls); i++) { | |
448 | + struct capreq *cr = n_array_nth(pkg->cnfls, i); | |
449 | + | |
450 | + if (ent->tag.id == LSQF_TAG_CONFLICTS || ent->tag.id == LSQF_TAG_CONFLICTFLAGS) { | |
451 | + if (!capreq_is_obsl(cr)) { | |
452 | + if (n == num) { | |
453 | + c = cr; | |
454 | + break; | |
455 | + } | |
456 | + | |
457 | + n++; | |
458 | + } | |
459 | + } else { | |
460 | + if (capreq_is_obsl(cr)) { | |
461 | + if (n == num) { | |
462 | + c = cr; | |
463 | + break; | |
464 | + } | |
465 | + | |
466 | + n++; | |
467 | + } | |
468 | + } | |
469 | + } | |
470 | + | |
471 | + if (c) { | |
472 | + if (ent->tag.id == LSQF_TAG_CONFLICTS || ent->tag.id == LSQF_TAG_OBSOLETES) | |
473 | + buf = n_strdup(capreq_name(c)); | |
474 | + else if (ent->tag.id == LSQF_TAG_CONFLICTFLAGS || ent->tag.id == LSQF_TAG_OBSOLETEFLAGS) | |
475 | + buf = format_flags(ent->tag.outfmtfnid, c); | |
476 | + else if (ent->tag.id == LSQF_TAG_CONFLICTVERSION || ent->tag.id == LSQF_TAG_OBSOLETEVERSION) | |
477 | + if (capreq_snprintf_evr(evr, sizeof(evr), c) > 0) | |
478 | + buf = n_strdup(evr); | |
479 | + | |
480 | + } | |
481 | + break; | |
482 | + } | |
483 | + | |
484 | + case LSQF_TAG_EPOCH: | |
485 | + asprintf(&buf, "%d", pkg->epoch); | |
486 | + break; | |
487 | + | |
488 | + case LSQF_TAG_GROUP: | |
489 | + buf = n_strdup(pkg_group(pkg)); | |
490 | + break; | |
491 | + | |
492 | + case LSQF_TAG_NAME: | |
493 | + buf = n_strdup(pkg->name); | |
494 | + break; | |
495 | + | |
496 | + case LSQF_TAG_NVRA: | |
497 | + buf = n_strdup(pkg_id(pkg)); | |
498 | + break; | |
499 | + | |
500 | + case LSQF_TAG_PACKAGECOLOR: | |
501 | + asprintf(&buf, "%d", pkg->color); | |
502 | + break; | |
503 | + | |
504 | + case LSQF_TAG_PROVIDEFLAGS: | |
505 | + buf = format_flags(ent->tag.outfmtfnid, n_array_nth(pkg->caps, num)); | |
506 | + break; | |
507 | + | |
508 | + case LSQF_TAG_PROVIDES: | |
509 | + c = n_array_nth(pkg->caps, num); | |
510 | + buf = n_strdup(capreq_name(c)); | |
511 | + break; | |
512 | + | |
513 | + case LSQF_TAG_PROVIDEVERSION: | |
514 | + c = n_array_nth(pkg->caps, num); | |
515 | + | |
516 | + if (capreq_snprintf_evr(evr, sizeof(evr), c) > 0) | |
517 | + buf = n_strdup(evr); | |
518 | + | |
519 | + break; | |
520 | + | |
521 | + case LSQF_TAG_RELEASE: | |
522 | + buf = n_strdup(pkg->rel); | |
523 | + break; | |
524 | + | |
525 | + case LSQF_TAG_REQUIREFLAGS: | |
526 | + buf = format_flags(ent->tag.outfmtfnid, n_array_nth(pkg->reqs, num)); | |
527 | + break; | |
528 | + | |
529 | + case LSQF_TAG_REQUIRES: | |
530 | + c = n_array_nth(pkg->reqs, num); | |
531 | + | |
532 | + if (capreq_is_rpmlib(c)) | |
533 | + asprintf(&buf, "rpmlib(%s)", capreq_name(c)); | |
534 | + else | |
535 | + buf = n_strdup(capreq_name(c)); | |
536 | + | |
537 | + break; | |
538 | + | |
539 | + case LSQF_TAG_REQUIREVERSION: | |
540 | + c = n_array_nth(pkg->reqs, num); | |
541 | + | |
542 | + if (capreq_snprintf_evr(evr, sizeof(evr), c) > 0) | |
543 | + buf = n_strdup(evr); | |
544 | + | |
545 | + break; | |
546 | + | |
547 | + case LSQF_TAG_VERSION: | |
548 | + buf = n_strdup(pkg->ver); | |
549 | + break; | |
550 | + | |
551 | + case LSQF_TAG_SIZE: | |
552 | + asprintf(&buf, "%u", pkg->size); | |
553 | + break; | |
554 | + | |
555 | + case LSQF_TAG_SOURCERPM: | |
556 | + buf = n_strdup(pkg_srcfilename_s(pkg)); | |
557 | + break; | |
558 | + | |
559 | + case LSQF_TAG_SUGGESTSFLAGS: | |
560 | + buf = format_flags(ent->tag.outfmtfnid, n_array_nth(pkg->sugs, num)); | |
561 | + break; | |
562 | + | |
563 | + case LSQF_TAG_SUGGESTS: | |
564 | + c = n_array_nth(pkg->sugs, num); | |
565 | + buf = n_strdup(capreq_name(c)); | |
566 | + break; | |
567 | + | |
568 | + case LSQF_TAG_SUGGESTSVERSION: | |
569 | + c = n_array_nth(pkg->sugs, num); | |
570 | + | |
571 | + if (capreq_snprintf_evr(evr, sizeof(evr), c) > 0) | |
572 | + buf = n_strdup(evr); | |
573 | + | |
574 | + break; | |
575 | + | |
576 | + default: | |
577 | + n_assert(0); | |
578 | + } | |
579 | + } | |
580 | + | |
581 | + return buf; | |
582 | +} | |
583 | + | |
584 | +static char get_escaped_char(char zn) | |
585 | +{ | |
586 | + switch (zn) { | |
587 | + case 'a': return '\a'; | |
588 | + case 'b': return '\b'; | |
589 | + case 'f': return '\f'; | |
590 | + case 'n': return '\n'; | |
591 | + case 'r': return '\r'; | |
592 | + case 't': return '\t'; | |
593 | + case 'v': return '\v'; | |
594 | + default: return zn; | |
595 | + } | |
596 | +} | |
597 | + | |
598 | +static struct lsqf_ent *lsqf_ent_new(int type) | |
599 | +{ | |
600 | + struct lsqf_ent *ent = NULL; | |
601 | + | |
602 | + ent = n_malloc(sizeof(struct lsqf_ent)); | |
603 | + | |
604 | + if (ent) { | |
605 | + ent->type = type; | |
606 | + | |
607 | + switch (type) { | |
608 | + case LSQF_ENT_TYPE_TAG: | |
609 | + ent->tag.id = 0; | |
610 | + ent->tag.iterate = 0; | |
611 | + ent->tag.countArray = 0; | |
612 | + ent->tag.pad = 0; | |
613 | + break; | |
614 | + | |
615 | + case LSQF_ENT_TYPE_STRING: | |
616 | + ent->string = NULL; | |
617 | + break; | |
618 | + | |
619 | + case LSQF_ENT_TYPE_ARRAY: | |
620 | + ent->array = lsqf_ent_array_new(); | |
621 | + break; | |
622 | + | |
623 | + default: | |
624 | + n_assert(0); | |
625 | + } | |
626 | + } | |
627 | + | |
628 | + return ent; | |
629 | +} | |
630 | + | |
631 | +static void lsqf_ent_free(struct lsqf_ent *ent) | |
632 | +{ | |
633 | + if (ent) { | |
634 | + switch (ent->type) { | |
635 | + case LSQF_ENT_TYPE_TAG: | |
636 | + break; | |
637 | + | |
638 | + case LSQF_ENT_TYPE_STRING: | |
639 | + if (ent->string) | |
640 | + n_free(ent->string); | |
641 | + | |
642 | + break; | |
643 | + | |
644 | + case LSQF_ENT_TYPE_ARRAY: | |
645 | + lsqf_ent_array_free(ent->array); | |
646 | + break; | |
647 | + } | |
648 | + | |
649 | + n_free(ent); | |
650 | + } | |
651 | +} | |
652 | + | |
653 | +struct lsqf_ent_array *lsqf_ent_array_new(void) | |
654 | +{ | |
655 | + struct lsqf_ent_array *array = NULL; | |
656 | + | |
657 | + array = n_malloc(sizeof(struct lsqf_ent_array)); | |
658 | + | |
659 | + if (array) { | |
660 | + array->ents = NULL; | |
661 | + array->items = 0; | |
662 | + } | |
663 | + | |
664 | + return array; | |
665 | +} | |
666 | + | |
667 | +void lsqf_ent_array_free(struct lsqf_ent_array *array) | |
668 | +{ | |
669 | + unsigned int i; | |
670 | + | |
671 | + if (array) { | |
672 | + for (i = 0; i < array->items; i++) { | |
673 | + struct lsqf_ent *ent = array->ents[i]; | |
674 | + | |
675 | + lsqf_ent_free(ent); | |
676 | + } | |
677 | + | |
678 | + if (array->ents) | |
679 | + n_free(array->ents); | |
680 | + | |
681 | + n_free(array); | |
682 | + } | |
683 | +} | |
684 | + | |
685 | +static void lsqf_ent_array_add_ent(struct lsqf_ent_array *array, struct lsqf_ent *ent) | |
686 | +{ | |
687 | + array->ents = n_realloc(array->ents, (array->items + 1) * sizeof(struct lsqf_ent *)); | |
688 | + | |
689 | + if (array->ents) { | |
690 | + array->ents[array->items] = ent; | |
691 | + | |
692 | + array->items++; | |
693 | + } | |
694 | +} | |
695 | + | |
696 | +static void lsqf_ent_array_add_ent_string(struct lsqf_ent_array *array, tn_buf *nbuf) | |
697 | +{ | |
698 | + struct lsqf_ent *ent = NULL; | |
699 | + | |
700 | + if (n_buf_size(nbuf) > 0) { | |
701 | + n_buf_putc(nbuf, '\0'); | |
702 | + | |
703 | + if ((ent = lsqf_ent_new(LSQF_ENT_TYPE_STRING))) { | |
704 | + ent->string = n_strdup(n_buf_ptr(nbuf)); | |
705 | + | |
706 | + lsqf_ent_array_add_ent(array, ent); | |
707 | + | |
708 | + n_buf_clean(nbuf); | |
709 | + } | |
710 | + } | |
711 | +} | |
712 | + | |
713 | +/** | |
714 | + * do_parse: | |
715 | + * | |
716 | + * Returns: 1 on error. | |
717 | + **/ | |
718 | +static int do_parse(struct lsqf_ent_array *array, char *fmt, char **endfmt, enum LsqfParseMode mode) | |
719 | +{ | |
720 | + struct lsqf_ent *ent; | |
721 | + tn_buf *nbuf = NULL; | |
722 | + int done = 0, error = 0; | |
723 | + char *end; | |
724 | + | |
725 | + if (fmt == NULL) | |
726 | + return 1; | |
727 | + | |
728 | + nbuf = n_buf_new(8); | |
729 | + | |
730 | + while (*fmt && !done && !error) { | |
731 | + switch (*fmt) { | |
732 | + case '%': | |
733 | + { | |
734 | + char *p, *outfmtfn; | |
735 | + int tagid, pad, countArray = 0, iterate = 0; | |
736 | + | |
737 | + fmt++; | |
738 | + | |
739 | + /* catch %% */ | |
740 | + if (*fmt == '%') { | |
741 | + n_buf_putc(nbuf, '%'); | |
742 | + break; | |
743 | + } | |
744 | + | |
745 | + pad = strtoul(fmt, &p, 10); | |
746 | + | |
747 | + fmt = p; | |
748 | + | |
749 | + if (*fmt != '{') { | |
750 | + logn(LOGERR, _("%s missing { after %%"), invalid_format); | |
751 | + error = 1; | |
752 | + break; | |
753 | + } | |
754 | + | |
755 | + fmt++; | |
756 | + | |
757 | + if (*fmt == '#') { | |
758 | + countArray = 1; | |
759 | + fmt++; | |
760 | + } else if (*fmt == '=') { | |
761 | + iterate = 1; | |
762 | + fmt++; | |
763 | + } | |
764 | + | |
765 | + if ((p = strchr(fmt, '}')) == NULL) { | |
766 | + logn(LOGERR, _("%s missing } after %%{"), invalid_format); | |
767 | + error = 1; | |
768 | + break; | |
769 | + } | |
770 | + | |
771 | + *p = '\0'; | |
772 | + | |
773 | + if (*fmt == '\0') { | |
774 | + logn(LOGERR, _("%s empty tag name"), invalid_format); | |
775 | + error = 1; | |
776 | + break; | |
777 | + } | |
778 | + | |
779 | + /* check if another output format is requested */ | |
780 | + if ((outfmtfn = strchr(fmt, ':')) != NULL) { | |
781 | + *outfmtfn = '\0'; | |
782 | + outfmtfn++; | |
783 | + } | |
784 | + | |
785 | + if ((tagid = get_tagid_by_name(fmt)) == LSQF_TAG_UNKNOWN) { | |
786 | + logn(LOGERR, _("%s unknown tag: \'%s\'"), invalid_format, fmt); | |
787 | + error = 1; | |
788 | + break; | |
789 | + } | |
790 | + | |
791 | + /* create new ent with a string that is currently stored in nbuf */ | |
792 | + lsqf_ent_array_add_ent_string(array, nbuf); | |
793 | + | |
794 | + ent = lsqf_ent_new(LSQF_ENT_TYPE_TAG); | |
795 | + ent->tag.id = tagid; | |
796 | + ent->tag.pad = pad; | |
797 | + ent->tag.countArray = countArray; | |
798 | + ent->tag.iterate = iterate; | |
799 | + ent->tag.outfmtfnid = get_outfmtfnid_by_name(outfmtfn); | |
800 | + | |
801 | + lsqf_ent_array_add_ent(array, ent); | |
802 | + | |
803 | + fmt = p; | |
804 | + | |
805 | + break; | |
806 | + } | |
807 | + case '[': | |
808 | + fmt++; | |
809 | + | |
810 | + lsqf_ent_array_add_ent_string(array, nbuf); | |
811 | + | |
812 | + ent = lsqf_ent_new(LSQF_ENT_TYPE_ARRAY); | |
813 | + lsqf_ent_array_add_ent(array, ent); | |
814 | + | |
815 | + if (do_parse(ent->array, fmt, &end, LSQF_PARSE_ARRAY)) { | |
816 | + error = 1; | |
817 | + break; | |
818 | + } | |
819 | + | |
820 | + if (*end == '\0') { | |
821 | + logn(LOGERR, _("%s missing ] at end of array"), invalid_format); | |
822 | + error = 1; | |
823 | + break; | |
824 | + } | |
825 | + | |
826 | + fmt = end; | |
827 | + | |
828 | + break; | |
829 | + | |
830 | + case ']': | |
831 | + if (mode != LSQF_PARSE_ARRAY) { | |
832 | + logn(LOGERR, _("%s unexpected ]"), invalid_format); | |
833 | + error = 1; | |
834 | + break; | |
835 | + } | |
836 | + | |
837 | + /* found end of array -> stop parsing */ | |
838 | + done = 1; | |
839 | + | |
840 | + /* save address of the last character we parsed */ | |
841 | + *endfmt = fmt; | |
842 | + | |
843 | + break; | |
844 | + | |
845 | + case '}': | |
846 | + logn(LOGERR, _("%s unexpected }"), invalid_format); | |
847 | + error = 1; | |
848 | + break; | |
849 | + | |
850 | + default: | |
851 | + if (fmt[0] == '\\' && fmt[1] != '\0') { | |
852 | + fmt++; | |
853 | + | |
854 | + n_buf_putc(nbuf, get_escaped_char(*fmt)); | |
855 | + | |
856 | + } else { | |
857 | + n_buf_putc(nbuf, *fmt); | |
858 | + } | |
859 | + } | |
860 | + | |
861 | + fmt++; | |
862 | + } | |
863 | + | |
864 | + if (error) { | |
865 | + n_buf_free(nbuf); | |
866 | + return 1; | |
867 | + } | |
868 | + | |
869 | + lsqf_ent_array_add_ent_string(array, nbuf); | |
870 | + | |
871 | + if (!done && endfmt) | |
872 | + *endfmt = fmt; | |
873 | + | |
874 | + n_buf_free(nbuf); | |
875 | + | |
876 | + return 0; | |
877 | +} | |
878 | + | |
879 | +/** | |
880 | + * lsqf_parse: | |
881 | + * | |
882 | + * Returns: On success, pointer to structure which is a base to display requested information or NULL when parsing failed. | |
883 | + **/ | |
884 | +struct lsqf_ent_array *lsqf_parse(char *fmt) | |
885 | +{ | |
886 | + struct lsqf_ent_array *array = NULL; | |
887 | + | |
888 | + if ((array = lsqf_ent_array_new())) { | |
889 | + if (do_parse(array, fmt, NULL, LSQF_PARSE_NORMAL)) { | |
890 | + lsqf_ent_array_free(array); | |
891 | + array = NULL; | |
892 | + } | |
893 | + } | |
894 | + | |
895 | + return array; | |
896 | +} | |
897 | + | |
898 | +static int get_tag_array_size(const struct lsqf_ent *ent, struct lsqf_pkgdata *pkgdata) | |
899 | +{ | |
900 | + const struct pkg *pkg = pkgdata->pkg; | |
901 | + unsigned int i; | |
902 | + int size = 1; | |
903 | + | |
904 | + n_assert(ent->type == LSQF_ENT_TYPE_TAG); | |
905 | + | |
906 | + if (lsqf_tags[ent->tag.id].is_array) { | |
907 | + size = 0; | |
908 | + | |
909 | + if (lsqf_tags[ent->tag.id].need_flist) { | |
910 | + struct pkgflist *flist = lsqf_pkgdata_flist(pkgdata); | |
911 | + | |
912 | + if (flist) { | |
913 | + switch (ent->tag.id) { | |
914 | + case LSQF_TAG_BASENAMES: | |
915 | + case LSQF_TAG_FILELINKTOS: | |
916 | + case LSQF_TAG_FILEMODES: | |
917 | + case LSQF_TAG_FILENAMES: | |
918 | + case LSQF_TAG_FILESIZES: | |
919 | + for (i = 0; i < n_tuple_size(flist->fl); i++) { | |
920 | + struct pkgfl_ent *flent = n_tuple_nth(flist->fl, i); | |
921 | + | |
922 | + size += flent->items; | |
923 | + } | |
924 | + | |
925 | + break; | |
926 | + | |
927 | + case LSQF_TAG_DIRNAMES: | |
928 | + size = n_tuple_size(flist->fl); | |
929 | + break; | |
930 | + | |
931 | + default: | |
932 | + n_assert(0); | |
933 | + } | |
934 | + } | |
935 | + } else { | |
936 | + switch (ent->tag.id) { | |
937 | + case LSQF_TAG_CONFLICTFLAGS: | |
938 | + case LSQF_TAG_CONFLICTS: | |
939 | + case LSQF_TAG_CONFLICTVERSION: | |
940 | + case LSQF_TAG_OBSOLETEFLAGS: | |
941 | + case LSQF_TAG_OBSOLETES: | |
942 | + case LSQF_TAG_OBSOLETEVERSION: | |
943 | + if (pkg->cnfls) { | |
944 | + int nobsl = 0, ncnfls = 0; | |
945 | + | |
946 | + for (i = 0; i < n_array_size(pkg->cnfls); i++) { | |
947 | + struct capreq *cr = n_array_nth(pkg->cnfls, i); | |
948 | + | |
949 | + if (capreq_is_obsl(cr)) | |
950 | + nobsl++; | |
951 | + else | |
952 | + ncnfls++; | |
953 | + } | |
954 | + | |
955 | + if (ent->tag.id == LSQF_TAG_CONFLICTFLAGS || ent->tag.id == LSQF_TAG_CONFLICTS | |
956 | + || ent->tag.id == LSQF_TAG_CONFLICTVERSION) | |
957 | + size = ncnfls; | |
958 | + else | |
959 | + size = nobsl; | |
960 | + } | |
961 | + | |
962 | + break; | |
963 | + | |
964 | + case LSQF_TAG_PROVIDEFLAGS: | |
965 | + case LSQF_TAG_PROVIDES: | |
966 | + case LSQF_TAG_PROVIDEVERSION: | |
967 | + if (pkg->caps) | |
968 | + size = n_array_size(pkg->caps); | |
969 | + break; | |
970 | + | |
971 | + case LSQF_TAG_REQUIREFLAGS: | |
972 | + case LSQF_TAG_REQUIRES: | |
973 | + case LSQF_TAG_REQUIREVERSION: | |
974 | + if (pkg->reqs) | |
975 | + size = n_array_size(pkg->reqs); | |
976 | + break; | |
977 | + | |
978 | + case LSQF_TAG_SUGGESTSFLAGS: | |
979 | + case LSQF_TAG_SUGGESTS: | |
980 | + case LSQF_TAG_SUGGESTSVERSION: | |
981 | + if (pkg->sugs) | |
982 | + size = n_array_size(pkg->sugs); | |
983 | + break; | |
984 | + | |
985 | + default: | |
986 | + n_assert(0); | |
987 | + } | |
988 | + } | |
989 | + } | |
990 | + | |
991 | + return size; | |
992 | +} | |
993 | + | |
994 | +/** | |
995 | + * Returns 1 when arrays size differ. | |
996 | + **/ | |
997 | +static int check_size(const struct lsqf_ent_array *array, struct lsqf_pkgdata *pkgdata, unsigned int *s) | |
998 | +{ | |
999 | + unsigned int i; | |
1000 | + int size = 1, prev_size = -1; | |
1001 | + | |
1002 | + for (i = 0; i < array->items; i++) { | |
1003 | + struct lsqf_ent *ent = array->ents[i]; | |
1004 | + | |
1005 | + if (ent->type == LSQF_ENT_TYPE_TAG) { | |
1006 | + if (lsqf_tags[ent->tag.id].is_array) { | |
1007 | + size = get_tag_array_size(ent, pkgdata); | |
1008 | + } else { | |
1009 | + /* check whether we want to print this tag with every iteration */ | |
1010 | + if (ent->tag.iterate) | |
1011 | + continue; | |
1012 | + | |
1013 | + size = 1; | |
1014 | + } | |
1015 | + | |
1016 | + if (prev_size < 0) | |
1017 | + prev_size = size; | |
1018 | + | |
1019 | + if (prev_size != size) | |
1020 | + return 1; | |
1021 | + } | |
1022 | + } | |
1023 | + | |
1024 | + *s = size; | |
1025 | + | |
1026 | + return 0; | |
1027 | +} | |
1028 | + | |
1029 | +static void add_tagstr_to_nbuf(tn_buf *nbuf, const struct lsqf_ent *ent, struct lsqf_pkgdata *pkgdata, unsigned int num) | |
1030 | +{ | |
1031 | + char *str = NULL, fmt[16]; | |
1032 | + | |
1033 | + if (ent->tag.countArray) { | |
1034 | + n_snprintf(fmt, sizeof(fmt), "%%%dd", ent->tag.pad); | |
1035 | + n_buf_printf(nbuf, fmt, get_tag_array_size(ent, pkgdata)); | |
1036 | + | |
1037 | + } else if ((str = get_str_by_tagid(ent, pkgdata, num))) { | |
1038 | + n_snprintf(fmt, sizeof(fmt), "%%%ds", ent->tag.pad); | |
1039 | + n_buf_printf(nbuf, fmt, str); | |
1040 | + | |
1041 | + n_free(str); | |
1042 | + } | |
1043 | +} | |
1044 | + | |
1045 | +/** | |
1046 | + * tags_size - number of items in tags. It's mostly used by tag-arrays (for example REQUIRES) | |
1047 | + */ | |
1048 | +static int ent_array_to_string(const struct lsqf_ent_array *array, | |
1049 | + struct lsqf_pkgdata *pkgdata, | |
1050 | + tn_buf *nbuf, int tags_size) | |
1051 | +{ | |
1052 | + unsigned int i, j, size = 0; | |
1053 | + | |
1054 | + for (j = 0; j < tags_size; j++) { | |
1055 | + for (i = 0; i < array->items; i++) { | |
1056 | + struct lsqf_ent *ent = array->ents[i]; | |
1057 | + int ret = 1; | |
1058 | + | |
1059 | + switch (ent->type) { | |
1060 | + case LSQF_ENT_TYPE_TAG: | |
1061 | + add_tagstr_to_nbuf(nbuf, ent, pkgdata, j); | |
1062 | + break; | |
1063 | + | |
1064 | + case LSQF_ENT_TYPE_STRING: | |
1065 | + n_buf_puts_z(nbuf, ent->string); | |
1066 | + break; | |
1067 | + | |
1068 | + case LSQF_ENT_TYPE_ARRAY: | |
1069 | + if (check_size(ent->array, pkgdata, &size)) { | |
1070 | + logn(LOGERR, _("%s array iterator used with different sized arrays"), invalid_format); | |
1071 | + ret = 0; | |
1072 | + } else { | |
1073 | + ret = ent_array_to_string(ent->array, pkgdata, nbuf, size); | |
1074 | + } | |
1075 | + | |
1076 | + break; | |
1077 | + | |
1078 | + default: | |
1079 | + n_assert(0); | |
1080 | + } | |
1081 | + | |
1082 | + /* break on error */ | |
1083 | + if (ret == 0) | |
1084 | + return 0; | |
1085 | + } | |
1086 | + } | |
1087 | + | |
1088 | + return 1; | |
1089 | +} | |
1090 | + | |
1091 | +char *lsqf_to_string(const struct lsqf_ent_array *array, const struct pkg *pkg) | |
1092 | +{ | |
1093 | + struct lsqf_pkgdata *pkgdata = NULL; | |
1094 | + tn_buf *nbuf = NULL; | |
1095 | + char *buf = NULL; | |
1096 | + | |
1097 | + pkgdata = lsqf_pkgdata_new(pkg); | |
1098 | + nbuf = n_buf_new(64); | |
1099 | + | |
1100 | + /* In the first array there can't be more than one item per tag, | |
1101 | + * so force tags_size = 1 */ | |
1102 | + if (ent_array_to_string(array, pkgdata, nbuf, 1)) { | |
1103 | + buf = n_strdup(n_buf_ptr(nbuf)); | |
1104 | + } | |
1105 | + | |
1106 | + n_buf_free(nbuf); | |
1107 | + lsqf_pkgdata_free(pkgdata); | |
1108 | + | |
1109 | + return buf; | |
1110 | +} | |
1111 | + | |
1112 | +/** | |
1113 | + * lsqf_show_querytags: | |
1114 | + * | |
1115 | + * Print all supported tags. | |
1116 | + */ | |
1117 | +void lsqf_show_querytags(struct cmdctx *cmdctx) | |
1118 | +{ | |
1119 | + int i, j; | |
1120 | + | |
1121 | + for (i = 0; i < LSQF_N_TAGS; i++) { | |
1122 | + for (j = 0; lsqf_tags[i].tagname[j]; j++) { | |
1123 | + cmdctx_printf(cmdctx, "%s\n", lsqf_tags[i].tagname[j]); | |
1124 | + } | |
1125 | + } | |
1126 | +} | |
1127 | diff --git a/cli/ls_queryfmt.h b/cli/ls_queryfmt.h | |
1128 | new file mode 100644 | |
1129 | index 0000000..43d3858 | |
1130 | --- /dev/null | |
1131 | +++ b/cli/ls_queryfmt.h | |
1132 | @@ -0,0 +1,47 @@ | |
1133 | +#ifndef POCLIDEK_LS_QUERYFMT_H | |
1134 | +#define POCLIDEK_LS_QUERYFMT_H | |
1135 | + | |
1136 | +#include "cmd.h" | |
1137 | +#include "pkg.h" | |
1138 | + | |
1139 | +struct lsqf_ent; | |
1140 | + | |
1141 | +struct lsqf_ent_array { | |
1142 | + struct lsqf_ent **ents; | |
1143 | + unsigned int items; | |
1144 | +}; | |
1145 | + | |
1146 | +struct lsqf_ent { | |
1147 | + enum { | |
1148 | + LSQF_ENT_TYPE_TAG = 1, | |
1149 | + LSQF_ENT_TYPE_STRING, | |
1150 | + LSQF_ENT_TYPE_ARRAY | |
1151 | + } type; | |
1152 | + | |
1153 | + union { | |
1154 | + struct { | |
1155 | + int id; | |
1156 | + | |
1157 | + int iterate; | |
1158 | + int countArray; | |
1159 | + int pad; | |
1160 | + int outfmtfnid; | |
1161 | + } tag; | |
1162 | + | |
1163 | + char *string; | |
1164 | + | |
1165 | + struct lsqf_ent_array *array; | |
1166 | + }; | |
1167 | +}; | |
1168 | + | |
1169 | + | |
1170 | + | |
1171 | +struct lsqf_ent_array *lsqf_parse(char *fmt); | |
1172 | +char *lsqf_to_string(const struct lsqf_ent_array *array, const struct pkg *pkg); | |
1173 | + | |
1174 | +struct lsqf_ent_array *lsqf_ent_array_new(void); | |
1175 | +void lsqf_ent_array_free(struct lsqf_ent_array *array); | |
1176 | + | |
1177 | +void lsqf_show_querytags(struct cmdctx *cmdctx); | |
1178 | + | |
1179 | +#endif /* POCLIDEK_LS_QUERYFMT_H */ | |
1180 | diff --git a/cli/ls.c b/cli/ls.c | |
1181 | index 0fe548c..e956e40 100644 | |
1182 | --- a/cli/ls.c | |
1183 | +++ b/cli/ls.c | |
1184 | @@ -24,6 +24,7 @@ | |
1185 | #include "pkgu.h" | |
1186 | #include "cli.h" | |
1187 | #include "log.h" | |
1188 | +#include "ls_queryfmt.h" | |
1189 | ||
1190 | static int ls(struct cmdctx *cmdctx); | |
1191 | static | |
1192 | @@ -51,6 +52,8 @@ | |
1193 | #define OPT_LS_NAMES_ONLY (1 << 11) | |
1194 | #define OPT_LS_SOURCERPM (1 << 12) | |
1195 | ||
1196 | +#define OPT_LS_QUERYFMT (1 << 13) | |
1197 | +#define OPT_LS_QUERYTAGS (1 << 14) | |
1198 | ||
1199 | #define OPT_LS_ERR (1 << 16); | |
1200 | ||
1201 | @@ -69,7 +72,9 @@ | |
1202 | { NULL, 'G', 0, 0, N_("Print package groups"), 1}, | |
1203 | { NULL, 'O', 0, 0, N_("Print package summaries"), 1}, | |
1204 | { "source-rpm", 's', 0, 0,N_("Print package source rpm"), 1}, | |
1205 | -// { NULL, 'i', 0, OPTION_ALIAS, 0, 1 }, | |
1206 | + { 0, 0, 0, 0, N_("Query format options:"), 2}, | |
1207 | + { "qf", OPT_LS_QUERYFMT, "QUERYFMT", 0, N_("Use the following query format"), 2}, | |
1208 | + { "querytags", OPT_LS_QUERYTAGS, 0, 0, N_("Show supported tags"), 2}, | |
1209 | { 0, 0, 0, 0, 0, 0 }, | |
1210 | }; | |
1211 | ||
1212 | @@ -152,7 +157,25 @@ | |
1213 | case 'n': | |
1214 | cmdctx->_flags |= OPT_LS_NAMES_ONLY; | |
1215 | break; | |
1216 | - | |
1217 | + | |
1218 | + case OPT_LS_QUERYFMT: | |
1219 | + cmdctx->_flags |= OPT_LS_QUERYFMT; | |
1220 | + | |
1221 | + if (arg) { | |
1222 | + struct lsqf_ent_array *array = NULL; | |
1223 | + | |
1224 | + if ((array = lsqf_parse(arg)) == NULL) | |
1225 | + return EINVAL; | |
1226 | + | |
1227 | + cmdctx->_data = array; | |
1228 | + } | |
1229 | + | |
1230 | + break; | |
1231 | + | |
1232 | + case OPT_LS_QUERYTAGS: | |
1233 | + lsqf_show_querytags(cmdctx); | |
1234 | + return EINVAL; | |
1235 | + | |
1236 | default: | |
1237 | return ARGP_ERR_UNKNOWN; | |
1238 | } | |
1239 | @@ -368,6 +391,10 @@ | |
1240 | ||
1241 | ||
1242 | l_end: | |
1243 | + if (cmdctx->_flags & OPT_LS_QUERYFMT) { | |
1244 | + lsqf_ent_array_free(cmdctx->_data); | |
1245 | + cmdctx->_data = NULL; | |
1246 | + } | |
1247 | ||
1248 | if (ls_ents) | |
1249 | n_array_free(ls_ents); | |
1250 | @@ -524,6 +524,16 @@ | |
1251 | else if (flags & OPT_LS_SOURCERPM) { | |
1252 | const char *srcrpm = pkg_srcfilename_s(pkg); | |
1253 | cmdctx_printf(cmdctx, fmt_pkg, pkg_name, srcrpm ? srcrpm : "(unset)"); | |
1254 | + | |
1255 | + } else if (flags & OPT_LS_QUERYFMT) { | |
1256 | + char *queryfmt = NULL; | |
1257 | + | |
1258 | + if ((queryfmt = lsqf_to_string(cmdctx->_data, pkg))) { | |
1259 | + cmdctx_printf(cmdctx, "%s", queryfmt); | |
1260 | + | |
1261 | + n_free(queryfmt); | |
1262 | + } | |
1263 | + | |
1264 | } else if ((flags & OPT_LS_LONG) == 0) { | |
1265 | cmdctx_printf(cmdctx, "%s\n", pkg_name); | |
1266 |