
--print-format currently uses printf-style format strings, which have limited namespace (a-zA-Z), low flexibility (depends-with-version and depends-without-version have to be different sequences), and are difficult to remember (is %d depends or description?). Python/Rust format strings allow full word substitutions. In addition, the mfmt.c library being used makes it possible to extend the standard formatting for much greater control. For example, we can allow nested templates so that instead of having "{depends}" and "{depends-without-version}" variants, we can allow something like "{depends<{name}={version}: {description}>}". For example: pacman -Sp --pformat="{name}: {description} ({packager})" pacman
226 lines
5.9 KiB
C
226 lines
5.9 KiB
C
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include "alpm.h"
|
|
#include "util.h"
|
|
|
|
#include "mfmt.h"
|
|
|
|
typedef enum field_t {
|
|
FILENAME,
|
|
NAME,
|
|
BASE,
|
|
DESCRIPTION,
|
|
VERSION,
|
|
ORIGIN,
|
|
REASON,
|
|
LICENSE,
|
|
GROUP,
|
|
|
|
DEPENDS,
|
|
OPTDEPENDS,
|
|
CONFLICTS,
|
|
PROVIDES,
|
|
REPLACES,
|
|
REQUIREDBY,
|
|
|
|
DELTAS,
|
|
FILES,
|
|
BACKUP,
|
|
DB,
|
|
VALIDATION,
|
|
URL,
|
|
BUILDDATE,
|
|
INSTALLDATE,
|
|
PACKAGER,
|
|
MD5SUM,
|
|
SHA256SUM,
|
|
ARCH,
|
|
SIZE,
|
|
ISIZE,
|
|
BASE64SIG,
|
|
|
|
UNKNOWN,
|
|
} field_t;
|
|
|
|
static struct field_map_t {
|
|
const char *input;
|
|
field_t field;
|
|
} field_map[] = {
|
|
{"filename", FILENAME},
|
|
{"name", NAME},
|
|
{"base", BASE},
|
|
{"description", DESCRIPTION},
|
|
{"version", VERSION},
|
|
|
|
{"license", LICENSE},
|
|
{"group", GROUP},
|
|
{"groups", GROUP},
|
|
|
|
{"depends", DEPENDS},
|
|
{"optdepends", OPTDEPENDS},
|
|
{"conflicts", CONFLICTS},
|
|
{"provides", PROVIDES},
|
|
{"replaces", REPLACES},
|
|
{"requiredby", REQUIREDBY},
|
|
|
|
{"url", URL},
|
|
{"builddate", BUILDDATE},
|
|
{"installdate", INSTALLDATE},
|
|
{"packager", PACKAGER},
|
|
{"md5sum", MD5SUM},
|
|
{"sha256sum", SHA256SUM},
|
|
{"arch", ARCH},
|
|
{"size", SIZE},
|
|
{"isize", ISIZE},
|
|
{"base64sig", BASE64SIG},
|
|
|
|
{NULL, 0}
|
|
};
|
|
|
|
static char *_alpm_hr_size(off_t bytes, char *dest)
|
|
{
|
|
static const char *suff[] = {"B", "K", "M", "G", "T", "P", "E", NULL};
|
|
float hrsize;
|
|
int s = 0;
|
|
while((bytes >= 1000000 || bytes <= -1000000) && suff[s + 1]) {
|
|
bytes /= 1024;
|
|
++s;
|
|
}
|
|
hrsize = bytes;
|
|
if((hrsize >= 1000 || hrsize <= -1000) && suff[s + 1]) {
|
|
hrsize /= 1024;
|
|
++s;
|
|
}
|
|
sprintf(dest, "%.2f %s", hrsize, suff[s]);
|
|
return dest;
|
|
}
|
|
|
|
static field_t _alpm_info_lookup_field(const char *name) {
|
|
struct field_map_t *m;
|
|
for(m = field_map; m->input; m++) {
|
|
if(strcmp(name, m->input) == 0) { return m->field; }
|
|
}
|
|
return UNKNOWN;
|
|
}
|
|
|
|
static size_t _alpm_info_print_str(mfmt_token_callback_t *t, const char *str, FILE *f) {
|
|
return mfmt_render_str(t, str ? str : "NULL", f);
|
|
}
|
|
|
|
static size_t _alpm_info_print_size(mfmt_token_callback_t *t, const off_t s, FILE *f) {
|
|
if(s) {
|
|
char hrsize[50];
|
|
if(t->conversion == 'd') {
|
|
snprintf(hrsize, 50, "%lld", (long long)s);
|
|
} else {
|
|
_alpm_hr_size(s, hrsize);
|
|
}
|
|
return mfmt_render_str(t, hrsize, f);
|
|
} else {
|
|
return mfmt_render_str(t, "NULL", f);
|
|
}
|
|
}
|
|
|
|
static size_t _alpm_info_print_strlist(mfmt_token_callback_t *t, alpm_list_t *l, FILE *f) {
|
|
if(l) {
|
|
size_t len = 0;
|
|
while(l) {
|
|
len += mfmt_render_str(t, l->data, f) + 1;
|
|
fputc('\n', f);
|
|
l = l->next;
|
|
}
|
|
return len;
|
|
} else {
|
|
return mfmt_render_str(t, "NULL", f);
|
|
}
|
|
}
|
|
|
|
static size_t _alpm_info_print_deplist(mfmt_token_callback_t *t, alpm_list_t *l, FILE *f) {
|
|
if(l) {
|
|
size_t len = 0;
|
|
while(l) {
|
|
char *s = alpm_dep_compute_string(l->data);
|
|
len += mfmt_render_str(t, s, f) + 1;
|
|
fputc('\n', f);
|
|
l = l->next;
|
|
free(s);
|
|
}
|
|
return len;
|
|
} else {
|
|
return mfmt_render_str(t, "NULL", f);
|
|
}
|
|
}
|
|
|
|
static size_t _alpm_info_print_timestamp(mfmt_token_callback_t *t, const alpm_time_t s, FILE *f) {
|
|
if(s) {
|
|
char datestr[50] = "";
|
|
if(strftime(datestr, 50, " %c", localtime(&s)) == 0) { return 0; }
|
|
return mfmt_render_str(t, datestr + 1, f);
|
|
} else {
|
|
return mfmt_render_str(t, "NULL", f);
|
|
}
|
|
}
|
|
|
|
static size_t _alpm_info_process_token(FILE *f, mfmt_token_callback_t *t, void *ctx, void *arg) {
|
|
alpm_pkg_t *p = arg;
|
|
(void)ctx;
|
|
switch(_alpm_info_lookup_field(t->name)) {
|
|
case NAME: return _alpm_info_print_str(t, alpm_pkg_get_name(p), f);
|
|
case DESCRIPTION: return _alpm_info_print_str(t, alpm_pkg_get_desc(p), f);
|
|
case PACKAGER: return _alpm_info_print_str(t, alpm_pkg_get_packager(p), f);
|
|
case MD5SUM: return _alpm_info_print_str(t, alpm_pkg_get_md5sum(p), f);
|
|
case FILENAME: return _alpm_info_print_str(t, alpm_pkg_get_filename(p), f);
|
|
case BASE: return _alpm_info_print_str(t, alpm_pkg_get_base(p), f);
|
|
case VERSION: return _alpm_info_print_str(t, alpm_pkg_get_version(p), f);
|
|
case URL: return _alpm_info_print_str(t, alpm_pkg_get_url(p), f);
|
|
case SHA256SUM: return _alpm_info_print_str(t, alpm_pkg_get_sha256sum(p), f);
|
|
case ARCH: return _alpm_info_print_str(t, alpm_pkg_get_arch(p), f);
|
|
case BASE64SIG: return _alpm_info_print_str(t, alpm_pkg_get_base64_sig(p), f);
|
|
|
|
case SIZE: return _alpm_info_print_size(t, alpm_pkg_get_size(p), f);
|
|
case ISIZE: return _alpm_info_print_size(t, alpm_pkg_get_isize(p), f);
|
|
|
|
case BUILDDATE: return _alpm_info_print_timestamp(t, alpm_pkg_get_builddate(p), f);
|
|
case INSTALLDATE: return _alpm_info_print_timestamp(t, alpm_pkg_get_installdate(p), f);
|
|
|
|
case DEPENDS: return _alpm_info_print_deplist(t, alpm_pkg_get_depends(p), f);
|
|
case OPTDEPENDS: return _alpm_info_print_deplist(t, alpm_pkg_get_optdepends(p), f);
|
|
case CONFLICTS: return _alpm_info_print_deplist(t, alpm_pkg_get_conflicts(p), f);
|
|
case PROVIDES: return _alpm_info_print_deplist(t, alpm_pkg_get_provides(p), f);
|
|
case REPLACES: return _alpm_info_print_deplist(t, alpm_pkg_get_replaces(p), f);
|
|
case REQUIREDBY: {
|
|
alpm_list_t *rb = alpm_pkg_compute_requiredby(p);
|
|
size_t len = _alpm_info_print_strlist(t, rb, f);
|
|
FREELIST(rb);
|
|
return len;
|
|
}
|
|
|
|
default: errno = EINVAL; return 0;
|
|
}
|
|
}
|
|
|
|
size_t SYMEXPORT alpm_info_print_pkg(const char *format, alpm_pkg_t *pkg) {
|
|
alpm_list_t l = {
|
|
.data = pkg,
|
|
.next = NULL,
|
|
};
|
|
l.prev = &l;
|
|
return alpm_info_print_pkgs(format, &l);
|
|
}
|
|
|
|
size_t SYMEXPORT alpm_info_print_pkgs(const char *format, alpm_list_t *pkgs) {
|
|
mfmt_t *mfmt = mfmt_parse(format, _alpm_info_process_token, NULL);
|
|
size_t len = 0;
|
|
if(mfmt == NULL) {
|
|
return 0;
|
|
}
|
|
for(alpm_list_t *i = pkgs; i; i = i->next) {
|
|
size_t plen = mfmt_printf(mfmt, i->data, stdout);
|
|
if(plen == 0) { return 0; }
|
|
len += plen;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/* vim: set ts=2 sw=2 et: */
|