pkg-format.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * libdpkg - Debian packaging suite library routines
  3. * pkg-format.c - customizable package formatting
  4. *
  5. * Copyright © 2001 Wichert Akkerman <wakkerma@debian.org>
  6. * Copyright © 2008-2015 Guillem Jover <guillem@debian.org>
  7. *
  8. * This is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. */
  21. #include <config.h>
  22. #include <compat.h>
  23. #include <errno.h>
  24. #include <limits.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <dpkg/i18n.h>
  29. #include <dpkg/error.h>
  30. #include <dpkg/dpkg.h>
  31. #include <dpkg/dpkg-db.h>
  32. #include <dpkg/parsedump.h>
  33. #include <dpkg/pkg-show.h>
  34. #include <dpkg/pkg-format.h>
  35. enum pkg_format_type {
  36. PKG_FORMAT_INVALID,
  37. PKG_FORMAT_STRING,
  38. PKG_FORMAT_FIELD,
  39. };
  40. struct pkg_format_node {
  41. struct pkg_format_node *next;
  42. enum pkg_format_type type;
  43. size_t width;
  44. int pad;
  45. char *data;
  46. };
  47. static struct pkg_format_node *
  48. pkg_format_node_new(void)
  49. {
  50. struct pkg_format_node *buf;
  51. buf = m_malloc(sizeof(*buf));
  52. buf->type = PKG_FORMAT_INVALID;
  53. buf->next = NULL;
  54. buf->data = NULL;
  55. buf->width = 0;
  56. buf->pad = 0;
  57. return buf;
  58. }
  59. static bool
  60. parsefield(struct pkg_format_node *node, const char *fmt, const char *fmtend,
  61. struct dpkg_error *err)
  62. {
  63. int len;
  64. const char *ws;
  65. len = fmtend - fmt + 1;
  66. ws = memchr(fmt, ';', len);
  67. if (ws) {
  68. char *endptr;
  69. long w;
  70. errno = 0;
  71. w = strtol(ws + 1, &endptr, 0);
  72. if (endptr[0] != '}') {
  73. dpkg_put_error(err,
  74. _("invalid character '%c' in field width"),
  75. *endptr);
  76. return false;
  77. }
  78. if (w < INT_MIN || w > INT_MAX || errno == ERANGE) {
  79. dpkg_put_error(err, _("field width is out of range"));
  80. return false;
  81. }
  82. if (w < 0) {
  83. node->pad = 1;
  84. node->width = (size_t)-w;
  85. } else
  86. node->width = (size_t)w;
  87. len = ws - fmt;
  88. }
  89. node->type = PKG_FORMAT_FIELD;
  90. node->data = m_malloc(len + 1);
  91. memcpy(node->data, fmt, len);
  92. node->data[len] = '\0';
  93. return true;
  94. }
  95. static bool
  96. parsestring(struct pkg_format_node *node, const char *fmt, const char *fmtend,
  97. struct dpkg_error *err)
  98. {
  99. int len;
  100. char *write;
  101. len = fmtend - fmt + 1;
  102. node->type = PKG_FORMAT_STRING;
  103. node->data = write = m_malloc(len + 1);
  104. while (fmt <= fmtend) {
  105. if (*fmt == '\\') {
  106. fmt++;
  107. switch (*fmt) {
  108. case 'n':
  109. *write = '\n';
  110. break;
  111. case 't':
  112. *write = '\t';
  113. break;
  114. case 'r':
  115. *write = '\r';
  116. break;
  117. case '\\':
  118. default:
  119. *write = *fmt;
  120. break;
  121. }
  122. } else
  123. *write = *fmt;
  124. write++;
  125. fmt++;
  126. }
  127. *write = '\0';
  128. return true;
  129. }
  130. void
  131. pkg_format_free(struct pkg_format_node *head)
  132. {
  133. struct pkg_format_node *node;
  134. while (head) {
  135. node = head;
  136. head = node->next;
  137. free(node->data);
  138. free(node);
  139. }
  140. }
  141. struct pkg_format_node *
  142. pkg_format_parse(const char *fmt, struct dpkg_error *err)
  143. {
  144. struct pkg_format_node *head, *node;
  145. const char *fmtend;
  146. head = node = NULL;
  147. while (*fmt) {
  148. if (node)
  149. node = node->next = pkg_format_node_new();
  150. else
  151. head = node = pkg_format_node_new();
  152. if (fmt[0] == '$' && fmt[1] == '{') {
  153. fmtend = strchr(fmt, '}');
  154. if (!fmtend) {
  155. dpkg_put_error(err, _("missing closing brace"));
  156. pkg_format_free(head);
  157. return NULL;
  158. }
  159. if (!parsefield(node, fmt + 2, fmtend - 1, err)) {
  160. pkg_format_free(head);
  161. return NULL;
  162. }
  163. fmt = fmtend + 1;
  164. } else {
  165. fmtend = fmt;
  166. do {
  167. fmtend += 1;
  168. fmtend = strchr(fmtend, '$');
  169. } while (fmtend && fmtend[1] != '{');
  170. if (!fmtend)
  171. fmtend = fmt + strlen(fmt);
  172. if (!parsestring(node, fmt, fmtend - 1, err)) {
  173. pkg_format_free(head);
  174. return NULL;
  175. }
  176. fmt = fmtend;
  177. }
  178. }
  179. if (!head)
  180. dpkg_put_error(err, _("may not be empty string"));
  181. return head;
  182. }
  183. static void
  184. virt_package(struct varbuf *vb,
  185. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  186. enum fwriteflags flags, const struct fieldinfo *fip)
  187. {
  188. varbuf_add_pkgbin_name(vb, pkg, pkgbin, pnaw_nonambig);
  189. }
  190. static void
  191. virt_status_abbrev(struct varbuf *vb,
  192. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  193. enum fwriteflags flags, const struct fieldinfo *fip)
  194. {
  195. if (pkgbin != &pkg->installed)
  196. return;
  197. varbuf_add_char(vb, pkg_abbrev_want(pkg));
  198. varbuf_add_char(vb, pkg_abbrev_status(pkg));
  199. varbuf_add_char(vb, pkg_abbrev_eflag(pkg));
  200. }
  201. static void
  202. virt_status_want(struct varbuf *vb,
  203. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  204. enum fwriteflags flags, const struct fieldinfo *fip)
  205. {
  206. if (pkgbin != &pkg->installed)
  207. return;
  208. varbuf_add_str(vb, pkg_want_name(pkg));
  209. }
  210. static void
  211. virt_status_status(struct varbuf *vb,
  212. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  213. enum fwriteflags flags, const struct fieldinfo *fip)
  214. {
  215. if (pkgbin != &pkg->installed)
  216. return;
  217. varbuf_add_str(vb, pkg_status_name(pkg));
  218. }
  219. static void
  220. virt_status_eflag(struct varbuf *vb,
  221. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  222. enum fwriteflags flags, const struct fieldinfo *fip)
  223. {
  224. if (pkgbin != &pkg->installed)
  225. return;
  226. varbuf_add_str(vb, pkg_eflag_name(pkg));
  227. }
  228. static void
  229. virt_summary(struct varbuf *vb,
  230. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  231. enum fwriteflags flags, const struct fieldinfo *fip)
  232. {
  233. const char *desc;
  234. int len;
  235. desc = pkg_summary(pkg, pkgbin, &len);
  236. varbuf_add_buf(vb, desc, len);
  237. }
  238. static void
  239. virt_source_package(struct varbuf *vb,
  240. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  241. enum fwriteflags flags, const struct fieldinfo *fip)
  242. {
  243. const char *name;
  244. size_t len;
  245. name = pkgbin->source;
  246. if (name == NULL)
  247. name = pkg->set->name;
  248. len = strcspn(name, " ");
  249. if (len == 0)
  250. len = strlen(name);
  251. varbuf_add_buf(vb, name, len);
  252. }
  253. static void
  254. virt_source_version(struct varbuf *vb,
  255. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  256. enum fwriteflags flags, const struct fieldinfo *fip)
  257. {
  258. const char *version;
  259. size_t len;
  260. if (pkgbin->source)
  261. version = strchr(pkgbin->source, '(');
  262. else
  263. version = NULL;
  264. if (version == NULL) {
  265. varbufversion(vb, &pkgbin->version, vdew_nonambig);
  266. } else {
  267. version++;
  268. len = strcspn(version, ")");
  269. if (len == 0)
  270. len = strlen(version);
  271. varbuf_add_buf(vb, version, len);
  272. }
  273. }
  274. static const struct fieldinfo virtinfos[] = {
  275. { FIELD("binary:Package"), NULL, virt_package },
  276. { FIELD("binary:Summary"), NULL, virt_summary },
  277. { FIELD("db:Status-Abbrev"), NULL, virt_status_abbrev },
  278. { FIELD("db:Status-Want"), NULL, virt_status_want },
  279. { FIELD("db:Status-Status"), NULL, virt_status_status },
  280. { FIELD("db:Status-Eflag"), NULL, virt_status_eflag },
  281. { FIELD("source:Package"), NULL, virt_source_package },
  282. { FIELD("source:Version"), NULL, virt_source_version },
  283. { NULL },
  284. };
  285. void
  286. pkg_format_show(const struct pkg_format_node *head,
  287. struct pkginfo *pkg, struct pkgbin *pkgbin)
  288. {
  289. const struct pkg_format_node *node;
  290. struct varbuf vb = VARBUF_INIT, fb = VARBUF_INIT, wb = VARBUF_INIT;
  291. for (node = head; node; node = node->next) {
  292. bool ok;
  293. char fmt[16];
  294. ok = false;
  295. if (node->width > 0)
  296. snprintf(fmt, 16, "%%%s%zus",
  297. ((node->pad) ? "-" : ""), node->width);
  298. else
  299. strcpy(fmt, "%s");
  300. if (node->type == PKG_FORMAT_STRING) {
  301. varbuf_printf(&fb, fmt, node->data);
  302. ok = true;
  303. } else if (node->type == PKG_FORMAT_FIELD) {
  304. const struct fieldinfo *fip;
  305. fip = find_field_info(fieldinfos, node->data);
  306. if (fip == NULL)
  307. fip = find_field_info(virtinfos, node->data);
  308. if (fip) {
  309. fip->wcall(&wb, pkg, pkgbin, 0, fip);
  310. varbuf_end_str(&wb);
  311. varbuf_printf(&fb, fmt, wb.buf);
  312. varbuf_reset(&wb);
  313. ok = true;
  314. } else {
  315. const struct arbitraryfield *afp;
  316. afp = find_arbfield_info(pkgbin->arbs, node->data);
  317. if (afp) {
  318. varbuf_printf(&fb, fmt, afp->value);
  319. ok = true;
  320. }
  321. }
  322. }
  323. if (ok) {
  324. size_t len = fb.used;
  325. if ((node->width > 0) && (len > node->width))
  326. len = node->width;
  327. varbuf_add_buf(&vb, fb.buf, len);
  328. }
  329. varbuf_reset(&fb);
  330. }
  331. if (vb.buf) {
  332. varbuf_end_str(&vb);
  333. fputs(vb.buf, stdout);
  334. }
  335. varbuf_destroy(&wb);
  336. varbuf_destroy(&fb);
  337. varbuf_destroy(&vb);
  338. }