]> git.pld-linux.org Git - packages/poldek.git/blame - poldek-ls-queryfmt.patch
- zlib fixes but still some issues not solved
[packages/poldek.git] / poldek-ls-queryfmt.patch
CommitLineData
f7ff424b
MB
1commit 4b027294335c0672311f021f2dc76edaab049b11
2Author: Marcin Banasiak <marcin.banasiak@gmail.com>
3Date: 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
13diff --git a/cli/Makefile.am b/cli/Makefile.am
14index 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 \
25diff --git a/cli/ls_queryfmt.c b/cli/ls_queryfmt.c
26new file mode 100644
27index 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+}
1127diff --git a/cli/ls_queryfmt.h b/cli/ls_queryfmt.h
1128new file mode 100644
1129index 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 */
1180diff --git a/cli/ls.c b/cli/ls.c
1181index 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
This page took 0.214207 seconds and 4 git commands to generate.