]> git.pld-linux.org Git - packages/poldek.git/blob - poldek-ls-queryfmt.patch
- rel .41
[packages/poldek.git] / poldek-ls-queryfmt.patch
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              
This page took 0.215982 seconds and 3 git commands to generate.