pkg-format.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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/dpkg.h>
  30. #include <dpkg/dpkg-db.h>
  31. #include <dpkg/parsedump.h>
  32. #include <dpkg/pkg-show.h>
  33. #include <dpkg/pkg-format.h>
  34. enum pkg_format_type {
  35. PKG_FORMAT_INVALID,
  36. PKG_FORMAT_STRING,
  37. PKG_FORMAT_FIELD,
  38. };
  39. struct pkg_format_node {
  40. struct pkg_format_node *next;
  41. enum pkg_format_type type;
  42. size_t width;
  43. int pad;
  44. char *data;
  45. };
  46. static struct pkg_format_node *
  47. pkg_format_node_new(void)
  48. {
  49. struct pkg_format_node *buf;
  50. buf = m_malloc(sizeof(*buf));
  51. buf->type = PKG_FORMAT_INVALID;
  52. buf->next = NULL;
  53. buf->data = NULL;
  54. buf->width = 0;
  55. buf->pad = 0;
  56. return buf;
  57. }
  58. static bool
  59. parsefield(struct pkg_format_node *cur, const char *fmt, const char *fmtend)
  60. {
  61. int len;
  62. const char *ws;
  63. len = fmtend - fmt + 1;
  64. ws = memchr(fmt, ';', len);
  65. if (ws) {
  66. char *endptr;
  67. long w;
  68. errno = 0;
  69. w = strtol(ws + 1, &endptr, 0);
  70. if (endptr[0] != '}') {
  71. fprintf(stderr,
  72. _("invalid character `%c' in field width\n"),
  73. *endptr);
  74. return false;
  75. }
  76. if (w < INT_MAX || w > INT_MAX || errno == ERANGE) {
  77. fprintf(stderr, _("field width is out of range\n"));
  78. return false;
  79. }
  80. if (w < 0) {
  81. cur->pad = 1;
  82. cur->width = (size_t)-w;
  83. } else
  84. cur->width = (size_t)w;
  85. len = ws - fmt;
  86. }
  87. cur->type = PKG_FORMAT_FIELD;
  88. cur->data = m_malloc(len + 1);
  89. memcpy(cur->data, fmt, len);
  90. cur->data[len] = '\0';
  91. return true;
  92. }
  93. static bool
  94. parsestring(struct pkg_format_node *cur, const char *fmt, const char *fmtend)
  95. {
  96. int len;
  97. char *write;
  98. len = fmtend - fmt + 1;
  99. cur->type = PKG_FORMAT_STRING;
  100. write = cur->data = m_malloc(len + 1);
  101. while (fmt <= fmtend) {
  102. if (*fmt == '\\') {
  103. fmt++;
  104. switch (*fmt) {
  105. case 'n':
  106. *write = '\n';
  107. break;
  108. case 't':
  109. *write = '\t';
  110. break;
  111. case 'r':
  112. *write = '\r';
  113. break;
  114. case '\\':
  115. default:
  116. *write = *fmt;
  117. break;
  118. }
  119. } else
  120. *write = *fmt;
  121. write++;
  122. fmt++;
  123. }
  124. *write = '\0';
  125. return true;
  126. }
  127. void
  128. pkg_format_free(struct pkg_format_node *head)
  129. {
  130. struct pkg_format_node *next;
  131. while (head) {
  132. next = head->next;
  133. free(head->data);
  134. free(head);
  135. head = next;
  136. }
  137. }
  138. struct pkg_format_node *
  139. pkg_format_parse(const char *fmt)
  140. {
  141. struct pkg_format_node *head;
  142. struct pkg_format_node *cur;
  143. const char *fmtend;
  144. head = cur = NULL;
  145. while (*fmt) {
  146. if (cur)
  147. cur = cur->next = pkg_format_node_new();
  148. else
  149. head = cur = pkg_format_node_new();
  150. if (fmt[0] == '$' && fmt[1] == '{') {
  151. fmtend = strchr(fmt, '}');
  152. if (!fmtend) {
  153. fprintf(stderr,
  154. _("Closing brace missing in format\n"));
  155. pkg_format_free(head);
  156. return NULL;
  157. }
  158. if (!parsefield(cur, fmt + 2, fmtend - 1)) {
  159. pkg_format_free(head);
  160. return NULL;
  161. }
  162. fmt = fmtend + 1;
  163. } else {
  164. fmtend = fmt;
  165. do {
  166. fmtend += 1;
  167. fmtend = strchr(fmtend, '$');
  168. } while (fmtend && fmtend[1] != '{');
  169. if (!fmtend)
  170. fmtend = fmt + strlen(fmt);
  171. if (!parsestring(cur, fmt, fmtend - 1)) {
  172. pkg_format_free(head);
  173. return NULL;
  174. }
  175. fmt = fmtend;
  176. }
  177. }
  178. return head;
  179. }
  180. static void
  181. virt_package(struct varbuf *vb,
  182. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  183. enum fwriteflags flags, const struct fieldinfo *fip)
  184. {
  185. varbuf_add_pkgbin_name(vb, pkg, pkgbin, pnaw_nonambig);
  186. }
  187. static void
  188. virt_status_abbrev(struct varbuf *vb,
  189. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  190. enum fwriteflags flags, const struct fieldinfo *fip)
  191. {
  192. if (pkgbin != &pkg->installed)
  193. return;
  194. varbuf_add_char(vb, pkg_abbrev_want(pkg));
  195. varbuf_add_char(vb, pkg_abbrev_status(pkg));
  196. varbuf_add_char(vb, pkg_abbrev_eflag(pkg));
  197. }
  198. static void
  199. virt_summary(struct varbuf *vb,
  200. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  201. enum fwriteflags flags, const struct fieldinfo *fip)
  202. {
  203. const char *desc;
  204. int len;
  205. desc = pkg_summary(pkg, pkgbin, &len);
  206. varbuf_add_buf(vb, desc, len);
  207. }
  208. static void
  209. virt_source_package(struct varbuf *vb,
  210. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  211. enum fwriteflags flags, const struct fieldinfo *fip)
  212. {
  213. const char *name;
  214. size_t len;
  215. name = pkgbin->source;
  216. if (name == NULL)
  217. name = pkg->set->name;
  218. len = strcspn(name, " ");
  219. if (len == 0)
  220. len = strlen(name);
  221. varbuf_add_buf(vb, name, len);
  222. }
  223. static void
  224. virt_source_version(struct varbuf *vb,
  225. const struct pkginfo *pkg, const struct pkgbin *pkgbin,
  226. enum fwriteflags flags, const struct fieldinfo *fip)
  227. {
  228. const char *version;
  229. size_t len;
  230. if (pkgbin->source)
  231. version = strchr(pkgbin->source, '(');
  232. else
  233. version = NULL;
  234. if (version == NULL) {
  235. varbufversion(vb, &pkgbin->version, vdew_nonambig);
  236. } else {
  237. version++;
  238. len = strcspn(version, ")");
  239. if (len == 0)
  240. len = strlen(version);
  241. varbuf_add_buf(vb, version, len);
  242. }
  243. }
  244. const struct fieldinfo virtinfos[] = {
  245. { "binary:Package", NULL, virt_package },
  246. { "binary:Summary", NULL, virt_summary },
  247. { "db:Status-Abbrev", NULL, virt_status_abbrev },
  248. { "source:Package", NULL, virt_source_package },
  249. { "source:Version", NULL, virt_source_version },
  250. { NULL },
  251. };
  252. static const struct fieldinfo *
  253. find_field_info(const struct fieldinfo *fields_head,
  254. const struct pkg_format_node *fmt_node)
  255. {
  256. const struct fieldinfo *fip;
  257. for (fip = fields_head; fip->name; fip++)
  258. if (strcasecmp(fmt_node->data, fip->name) == 0)
  259. break;
  260. return fip;
  261. }
  262. void
  263. pkg_format_show(const struct pkg_format_node *head,
  264. struct pkginfo *pkg, struct pkgbin *pkgbin)
  265. {
  266. struct varbuf vb = VARBUF_INIT, fb = VARBUF_INIT, wb = VARBUF_INIT;
  267. while (head) {
  268. bool ok;
  269. char fmt[16];
  270. ok = false;
  271. if (head->width > 0)
  272. snprintf(fmt, 16, "%%%s%zus",
  273. ((head->pad) ? "-" : ""), head->width);
  274. else
  275. strcpy(fmt, "%s");
  276. if (head->type == PKG_FORMAT_STRING) {
  277. varbuf_printf(&fb, fmt, head->data);
  278. ok = true;
  279. } else if (head->type == PKG_FORMAT_FIELD) {
  280. const struct fieldinfo *fip;
  281. fip = find_field_info(fieldinfos, head);
  282. if (fip->name == NULL)
  283. fip = find_field_info(virtinfos, head);
  284. if (fip->name) {
  285. fip->wcall(&wb, pkg, pkgbin, 0, fip);
  286. varbuf_end_str(&wb);
  287. varbuf_printf(&fb, fmt, wb.buf);
  288. varbuf_reset(&wb);
  289. ok = true;
  290. } else {
  291. const struct arbitraryfield *afp;
  292. for (afp = pkgbin->arbs; afp; afp = afp->next)
  293. if (strcasecmp(head->data, afp->name) == 0) {
  294. varbuf_printf(&fb, fmt, afp->value);
  295. ok = true;
  296. break;
  297. }
  298. }
  299. }
  300. if (ok) {
  301. size_t len = strlen(fb.buf);
  302. if ((head->width > 0) && (len > head->width))
  303. len = head->width;
  304. varbuf_add_buf(&vb, fb.buf, len);
  305. }
  306. varbuf_reset(&fb);
  307. head = head->next;
  308. }
  309. if (vb.buf) {
  310. varbuf_end_str(&vb);
  311. fputs(vb.buf, stdout);
  312. }
  313. varbuf_destroy(&wb);
  314. varbuf_destroy(&fb);
  315. varbuf_destroy(&vb);
  316. }