pkg-format.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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-2012 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 <http://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 *cur, 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. cur->pad = 1;
  84. cur->width = (size_t)-w;
  85. } else
  86. cur->width = (size_t)w;
  87. len = ws - fmt;
  88. }
  89. cur->type = PKG_FORMAT_FIELD;
  90. cur->data = m_malloc(len + 1);
  91. memcpy(cur->data, fmt, len);
  92. cur->data[len] = '\0';
  93. return true;
  94. }
  95. static bool
  96. parsestring(struct pkg_format_node *cur, const char *fmt, const char *fmtend,
  97. struct dpkg_error *err)
  98. {
  99. int len;
  100. char *write;
  101. len = fmtend - fmt + 1;
  102. cur->type = PKG_FORMAT_STRING;
  103. write = cur->data = 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 *next;
  134. while (head) {
  135. next = head->next;
  136. free(head->data);
  137. free(head);
  138. head = next;
  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;
  145. struct pkg_format_node *cur;
  146. const char *fmtend;
  147. head = cur = NULL;
  148. while (*fmt) {
  149. if (cur)
  150. cur = cur->next = pkg_format_node_new();
  151. else
  152. head = cur = pkg_format_node_new();
  153. if (fmt[0] == '$' && fmt[1] == '{') {
  154. fmtend = strchr(fmt, '}');
  155. if (!fmtend) {
  156. dpkg_put_error(err, _("missing closing brace"));
  157. pkg_format_free(head);
  158. return NULL;
  159. }
  160. if (!parsefield(cur, fmt + 2, fmtend - 1, err)) {
  161. pkg_format_free(head);
  162. return NULL;
  163. }
  164. fmt = fmtend + 1;
  165. } else {
  166. fmtend = fmt;
  167. do {
  168. fmtend += 1;
  169. fmtend = strchr(fmtend, '$');
  170. } while (fmtend && fmtend[1] != '{');
  171. if (!fmtend)
  172. fmtend = fmt + strlen(fmt);
  173. if (!parsestring(cur, fmt, fmtend - 1, err)) {
  174. pkg_format_free(head);
  175. return NULL;
  176. }
  177. fmt = fmtend;
  178. }
  179. }
  180. if (!head)
  181. dpkg_put_error(err, _("may not be empty string"));
  182. return head;
  183. }
  184. static void
  185. virt_package(struct varbuf *vb,
  186. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  187. enum fwriteflags flags, const struct fieldinfo *fip)
  188. {
  189. varbuf_add_pkgbin_name(vb, pkg, pkgbin, pnaw_nonambig);
  190. }
  191. static void
  192. virt_status_abbrev(struct varbuf *vb,
  193. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  194. enum fwriteflags flags, const struct fieldinfo *fip)
  195. {
  196. if (pkgbin != &pkg->installed)
  197. return;
  198. varbuf_add_char(vb, pkg_abbrev_want(pkg));
  199. varbuf_add_char(vb, pkg_abbrev_status(pkg));
  200. varbuf_add_char(vb, pkg_abbrev_eflag(pkg));
  201. }
  202. static void
  203. virt_summary(struct varbuf *vb,
  204. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  205. enum fwriteflags flags, const struct fieldinfo *fip)
  206. {
  207. const char *desc;
  208. int len;
  209. desc = pkg_summary(pkg, pkgbin, &len);
  210. varbuf_add_buf(vb, desc, len);
  211. }
  212. static void
  213. virt_source_package(struct varbuf *vb,
  214. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  215. enum fwriteflags flags, const struct fieldinfo *fip)
  216. {
  217. const char *name;
  218. size_t len;
  219. name = pkgbin->source;
  220. if (name == NULL)
  221. name = pkg->set->name;
  222. len = strcspn(name, " ");
  223. if (len == 0)
  224. len = strlen(name);
  225. varbuf_add_buf(vb, name, len);
  226. }
  227. static void
  228. virt_source_version(struct varbuf *vb,
  229. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  230. enum fwriteflags flags, const struct fieldinfo *fip)
  231. {
  232. const char *version;
  233. size_t len;
  234. if (pkgbin->source)
  235. version = strchr(pkgbin->source, '(');
  236. else
  237. version = NULL;
  238. if (version == NULL) {
  239. varbufversion(vb, &pkgbin->version, vdew_nonambig);
  240. } else {
  241. version++;
  242. len = strcspn(version, ")");
  243. if (len == 0)
  244. len = strlen(version);
  245. varbuf_add_buf(vb, version, len);
  246. }
  247. }
  248. const struct fieldinfo virtinfos[] = {
  249. { "binary:Package", NULL, virt_package },
  250. { "binary:Summary", NULL, virt_summary },
  251. { "db:Status-Abbrev", NULL, virt_status_abbrev },
  252. { "source:Package", NULL, virt_source_package },
  253. { "source:Version", NULL, virt_source_version },
  254. { NULL },
  255. };
  256. static const struct fieldinfo *
  257. find_field_info(const struct fieldinfo *fields_head,
  258. const struct pkg_format_node *fmt_node)
  259. {
  260. const struct fieldinfo *fip;
  261. for (fip = fields_head; fip->name; fip++)
  262. if (strcasecmp(fmt_node->data, fip->name) == 0)
  263. break;
  264. return fip;
  265. }
  266. void
  267. pkg_format_show(const struct pkg_format_node *head,
  268. struct pkginfo *pkg, struct pkgbin *pkgbin)
  269. {
  270. struct varbuf vb = VARBUF_INIT, fb = VARBUF_INIT, wb = VARBUF_INIT;
  271. while (head) {
  272. bool ok;
  273. char fmt[16];
  274. ok = false;
  275. if (head->width > 0)
  276. snprintf(fmt, 16, "%%%s%zus",
  277. ((head->pad) ? "-" : ""), head->width);
  278. else
  279. strcpy(fmt, "%s");
  280. if (head->type == PKG_FORMAT_STRING) {
  281. varbuf_printf(&fb, fmt, head->data);
  282. ok = true;
  283. } else if (head->type == PKG_FORMAT_FIELD) {
  284. const struct fieldinfo *fip;
  285. fip = find_field_info(fieldinfos, head);
  286. if (fip->name == NULL)
  287. fip = find_field_info(virtinfos, head);
  288. if (fip->name) {
  289. fip->wcall(&wb, pkg, pkgbin, 0, fip);
  290. varbuf_end_str(&wb);
  291. varbuf_printf(&fb, fmt, wb.buf);
  292. varbuf_reset(&wb);
  293. ok = true;
  294. } else {
  295. const struct arbitraryfield *afp;
  296. for (afp = pkgbin->arbs; afp; afp = afp->next)
  297. if (strcasecmp(head->data, afp->name) == 0) {
  298. varbuf_printf(&fb, fmt, afp->value);
  299. ok = true;
  300. break;
  301. }
  302. }
  303. }
  304. if (ok) {
  305. size_t len = strlen(fb.buf);
  306. if ((head->width > 0) && (len > head->width))
  307. len = head->width;
  308. varbuf_add_buf(&vb, fb.buf, len);
  309. }
  310. varbuf_reset(&fb);
  311. head = head->next;
  312. }
  313. if (vb.buf) {
  314. varbuf_end_str(&vb);
  315. fputs(vb.buf, stdout);
  316. }
  317. varbuf_destroy(&wb);
  318. varbuf_destroy(&fb);
  319. varbuf_destroy(&vb);
  320. }