export.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. #include <stdarg.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include "vt.h"
  6. #include "misc.h"
  7. #include "export.h"
  8. extern struct export_module export_txt;
  9. extern struct export_module export_ansi;
  10. extern struct export_module export_html;
  11. extern struct export_module export_png;
  12. extern struct export_module export_ppm;
  13. struct export_module *modules[] =
  14. {
  15. &export_txt,
  16. &export_ansi,
  17. &export_html,
  18. &export_ppm,
  19. #ifdef WITH_PNG
  20. &export_png,
  21. #endif
  22. 0
  23. };
  24. static char *glbl_opts[] =
  25. {
  26. "reveal", // show hidden text
  27. "hide", // don't show hidden text (default)
  28. 0
  29. };
  30. static char errbuf[64];
  31. void export_error(char *str, ...)
  32. {
  33. va_list args;
  34. va_start(args, str);
  35. vsnprintf(errbuf, sizeof(errbuf)-1, str, args);
  36. }
  37. char * export_errstr(void)
  38. {
  39. return errbuf;
  40. }
  41. static int find_opt(char **opts, char *opt, char *arg)
  42. {
  43. int err = 0;
  44. char buf[256];
  45. char **oo, *o, *a;
  46. if (oo = opts)
  47. while (o = *oo++)
  48. {
  49. if (a = strchr(o, '='))
  50. {
  51. a = buf + (a - o);
  52. o = strcpy(buf, o);
  53. *a++ = 0;
  54. }
  55. if (strcasecmp(o, opt) == 0)
  56. {
  57. if ((a != 0) == (arg != 0))
  58. return oo - opts;
  59. err = -1;
  60. }
  61. }
  62. return err;
  63. }
  64. struct export * export_open(char *fmt)
  65. {
  66. struct export_module **eem, *em;
  67. struct export *e;
  68. char *opt, *optend, *optarg;
  69. int opti;
  70. if (fmt = strdup(fmt))
  71. {
  72. if (opt = strchr(fmt, ','))
  73. *opt++ = 0;
  74. for (eem = modules; em = *eem; eem++)
  75. if (strcasecmp(em->fmt_name, fmt) == 0)
  76. break;
  77. if (em)
  78. {
  79. if (e = malloc(sizeof(*e) + em->local_size))
  80. {
  81. e->mod = em;
  82. e->fmt_str = fmt;
  83. e->reveal = 0;
  84. memset(e + 1, 0, em->local_size);
  85. if (not em->open || em->open(e) == 0)
  86. {
  87. for (; opt; opt = optend)
  88. {
  89. if (optend = strchr(opt, ','))
  90. *optend++ = 0;
  91. if (not *opt)
  92. continue;
  93. if (optarg = strchr(opt, '='))
  94. *optarg++ = 0;
  95. if ((opti = find_opt(glbl_opts, opt, optarg)) > 0)
  96. {
  97. if (opti == 1) // reveal
  98. e->reveal = 1;
  99. else if (opti == 2) // hide
  100. e->reveal = 0;
  101. }
  102. else if (opti == 0 &&
  103. (opti = find_opt(em->options, opt, optarg)) > 0)
  104. {
  105. if (em->option(e, opti, optarg))
  106. break;
  107. }
  108. else
  109. {
  110. if (opti == 0)
  111. export_error("%s: unknown option", opt);
  112. else if (optarg)
  113. export_error("%s: takes no arg", opt);
  114. else
  115. export_error("%s: missing arg", opt);
  116. break;
  117. }
  118. }
  119. if (opt == 0)
  120. return e;
  121. if (em->close)
  122. em->close(e);
  123. }
  124. free(e);
  125. }
  126. else
  127. export_error("out of memory");
  128. }
  129. else
  130. export_error("unknown format: %s", fmt);
  131. free(fmt);
  132. }
  133. else
  134. export_error("out of memory");
  135. return 0;
  136. }
  137. void export_close(struct export *e)
  138. {
  139. if (e->mod->close)
  140. e->mod->close(e);
  141. free(e->fmt_str);
  142. free(e);
  143. }
  144. static char * hexnum(char *buf, unsigned int num)
  145. {
  146. char *p = buf + 5;
  147. num &= 0xffff;
  148. *--p = 0;
  149. do
  150. {
  151. *--p = "0123456789abcdef"[num % 16];
  152. num /= 16;
  153. } while (num);
  154. return p;
  155. }
  156. static char * adjust(char *p, char *str, char fill, int width)
  157. {
  158. int l = width - strlen(str);
  159. while (l-- > 0)
  160. *p++ = fill;
  161. while (*p = *str++)
  162. p++;
  163. return p;
  164. }
  165. char * export_mkname(struct export *e, char *fmt, struct vt_page *vtp, char *usr)
  166. {
  167. char bbuf[1024];
  168. char *p = bbuf;
  169. while (*p = *fmt++)
  170. if (*p++ == '%')
  171. {
  172. char buf[32], buf2[32];
  173. int width = 0;
  174. p--;
  175. while (*fmt >= '0' && *fmt <= '9')
  176. width = width*10 + *fmt++ - '0';
  177. switch (*fmt++)
  178. {
  179. case '%':
  180. p = adjust(p, "%", '%', width);
  181. break;
  182. case 'e': // extension
  183. p = adjust(p, e->mod->extension, '.', width);
  184. break;
  185. case 'p': // pageno[.subno]
  186. if (vtp->subno)
  187. p = adjust(p,strcat(strcat(hexnum(buf, vtp->pgno),
  188. "."), hexnum(buf2, vtp->subno)), ' ', width);
  189. else
  190. p = adjust(p, hexnum(buf, vtp->pgno), ' ', width);
  191. break;
  192. case 'S': // subno
  193. p = adjust(p, hexnum(buf, vtp->subno), '0', width);
  194. break;
  195. case 'P': // pgno
  196. p = adjust(p, hexnum(buf, vtp->pgno), '0', width);
  197. break;
  198. case 's': // user strin
  199. p = adjust(p, usr, ' ', width);
  200. break;
  201. //TODO: add date, channel name, ...
  202. }
  203. }
  204. p = strdup(bbuf);
  205. if (not p)
  206. export_error("out of memory");
  207. return p;
  208. }
  209. static void fmt_page(struct export *e, struct fmt_page *pg, struct vt_page *vtp)
  210. {
  211. char buf[16];
  212. int x, y;
  213. u8 *p = vtp->data[0];
  214. pg->dbl = 0;
  215. sprintf(buf, "\2%x.%02x\7", vtp->pgno, vtp->subno & 0xff);
  216. for (y = 0; y < H; y++)
  217. {
  218. struct fmt_char c;
  219. int last_ch = ' ';
  220. int dbl = 0, hold = 0;
  221. c.fg = 7;
  222. c.bg = 0;
  223. c.attr = 0;
  224. for (x = 0; x < W; ++x)
  225. {
  226. c.ch = *p++;
  227. if (y == 0 && x < 8)
  228. c.ch = buf[x];
  229. switch (c.ch)
  230. {
  231. case 0x00 ... 0x07: /* alpha + fg color */
  232. c.fg = c.ch & 7;
  233. c.attr &= ~(EA_GRAPHIC | EA_CONCEALED);
  234. goto ctrl;
  235. case 0x08: /* flash */
  236. c.attr |= EA_BLINK;
  237. goto ctrl;
  238. case 0x09: /* steady */
  239. c.attr &= ~EA_BLINK;
  240. goto ctrl;
  241. case 0x0a: /* end box */
  242. case 0x0b: /* start box */
  243. goto ctrl;
  244. case 0x0c: /* normal height */
  245. c.attr &= EA_DOUBLE;
  246. goto ctrl;
  247. case 0x0d: /* double height */
  248. if (y < H-2) /* ignored on last 2 lines */
  249. {
  250. c.attr |= EA_DOUBLE;
  251. dbl = 1;
  252. }
  253. goto ctrl;
  254. case 0x10 ... 0x17: /* gfx + fg color */
  255. c.fg = c.ch & 7;
  256. c.attr |= EA_GRAPHIC;
  257. c.attr &= ~EA_CONCEALED;
  258. goto ctrl;
  259. case 0x18: /* conceal */
  260. c.attr |= EA_CONCEALED;
  261. goto ctrl;
  262. case 0x19: /* contiguous gfx */
  263. c.attr &= ~EA_SEPARATED;
  264. goto ctrl;
  265. case 0x1a: /* separate gfx */
  266. c.attr |= EA_SEPARATED;
  267. goto ctrl;
  268. case 0x1c: /* black bg */
  269. c.bg = 0;
  270. goto ctrl;
  271. case 0x1d: /* new bg */
  272. c.bg = c.fg;
  273. goto ctrl;
  274. case 0x1e: /* hold gfx */
  275. hold = 1;
  276. goto ctrl;
  277. case 0x1f: /* release gfx */
  278. hold = 0;
  279. goto ctrl;
  280. case 0x0e: /* SO */
  281. case 0x0f: /* SI */
  282. case 0x1b: /* ESC */
  283. c.ch = ' ';
  284. break;
  285. ctrl:
  286. c.ch = ' ';
  287. if (hold && (c.attr & EA_GRAPHIC))
  288. c.ch = last_ch;
  289. break;
  290. }
  291. if (c.attr & EA_GRAPHIC)
  292. if ((c.ch & 0xa0) == 0x20)
  293. {
  294. last_ch = c.ch;
  295. c.ch += (c.ch & 0x40) ? 32 : -32;
  296. }
  297. if (c.attr & EA_CONCEALED)
  298. if (not e->reveal)
  299. c.ch = ' ';
  300. pg->data[y][x] = c;
  301. }
  302. if (dbl)
  303. {
  304. pg->dbl |= 1 << y;
  305. for (x = 0; x < W; ++x)
  306. {
  307. if (~pg->data[y][x].attr & EA_DOUBLE)
  308. pg->data[y][x].attr |= EA_HDOUBLE;
  309. pg->data[y+1][x] = pg->data[y][x];
  310. pg->data[y+1][x].ch = ' ';
  311. }
  312. y++;
  313. p += W;
  314. }
  315. }
  316. pg->hid = pg->dbl << 1;
  317. }
  318. int export(struct export *e, struct vt_page *vtp, char *name)
  319. {
  320. struct fmt_page pg[1];
  321. fmt_page(e, pg, vtp);
  322. return e->mod->output(e, name, pg);
  323. }