alevt-cap.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <locale.h>
  5. #include <signal.h>
  6. #include <unistd.h>
  7. #include "vt.h"
  8. #include "misc.h"
  9. #include "fdset.h"
  10. #include "vbi.h"
  11. #include "lang.h"
  12. #include "dllist.h"
  13. #include "export.h"
  14. static volatile int timed_out = 0;
  15. static char *channel;
  16. char *outfile = "";
  17. u_int16_t sid;
  18. struct req
  19. {
  20. struct dl_node node[1];
  21. char *name; // file name
  22. char *pgno_str; // the pgno as given on the cmdline
  23. int pgno, subno; // decoded pgno
  24. struct export *export; // export data
  25. struct vt_page vtp[1]; // the capture page data
  26. };
  27. static void usage(FILE *fp, int exitval)
  28. {
  29. fprintf(fp, "\nUsage: %s [options] ppp.ss...\n", prgname);
  30. fprintf(fp,
  31. "\n"
  32. " Valid options:\t\tDefault:\n"
  33. " -cs -charset\t\tlatin-1\n"
  34. " <latin-1/2/koi8-r/iso8859-7>\n"
  35. " -f -format <fmt,options>\tascii\n"
  36. " -f help -format help\n"
  37. " -h -help\n"
  38. " -n -name <filename>\t\tttext-%%s.%%e\n"
  39. " -s -sid <sid>\t\t(none;dvb only)\n"
  40. " -to -timeout <secs>\t\t(none)\n"
  41. " -t -ttpid <ttpid>\t\t(none;dvb only)\n"
  42. " -v -vbi <vbidev>\t\t/dev/vbi\n"
  43. " \t\t/dev/vbi0\n"
  44. " \t\t/dev/video0\n"
  45. " \t\t/dev/dvb/adapter0/demux0\n"
  46. "\n"
  47. " ppp.ss stands for a page number and an\n"
  48. " optional subpage number (ie 123.4).\n"
  49. );
  50. exit(exitval);
  51. }
  52. static void exp_help(FILE *fp)
  53. {
  54. struct export_module **ep;
  55. char **cp, c;
  56. fprintf(fp,
  57. "\nSyntax: -format Name[,Options]\n"
  58. "\n"
  59. " Name\tExt.\tOptions\n"
  60. " --------------------------------\n"
  61. );
  62. for (ep = modules; *ep; ep++)
  63. {
  64. fprintf(fp, " %-7s\t.%-4s", (*ep)->fmt_name, (*ep)->extension);
  65. for (c = '\t', cp = (*ep)->options; cp && *cp; cp++, c = ',')
  66. fprintf(fp, "%c%s", c, *cp);
  67. fprintf(fp, "\n");
  68. }
  69. fprintf(fp,
  70. "\n"
  71. "Common options: reveal,hide\n"
  72. "Example: -format ansi,reveal,bg=none\n"
  73. "\n"
  74. );
  75. exit(0);
  76. }
  77. static int arg_pgno(char *p, int *subno)
  78. {
  79. char *end;
  80. int pgno;
  81. *subno = ANY_SUB;
  82. if (*p)
  83. {
  84. pgno = strtol(p, &end, 16);
  85. if ((*end == ':' || *end == '/' || *end == '.') && end[1])
  86. *subno = strtol(end + 1, &end, 16);
  87. if (*end == 0)
  88. if (pgno >= 0x100 && pgno <= 0x899)
  89. if (*subno == ANY_SUB || (*subno >= 0x00 && *subno <= 0x3f7f))
  90. return pgno;
  91. }
  92. fatal("%s: invalid page number", p);
  93. }
  94. static int option(int argc, char **argv, int *ind, char **arg)
  95. {
  96. static struct { char *nam, *altnam; int arg; } opts[] = {
  97. { "-charset", "-cs", 1 },
  98. { "-format", "-f", 1 },
  99. { "-help", "-h", 0 },
  100. { "-name", "-n", 1 },
  101. { "-sid", "-s", 1 },
  102. { "-timeout", "-to", 1 },
  103. { "-ttpid", "-t", 1 },
  104. { "-vbi", "-v", 1 },
  105. };
  106. int i;
  107. if (*ind >= argc)
  108. return 0;
  109. *arg = argv[(*ind)++];
  110. for (i = 0; i < NELEM(opts); ++i)
  111. if (streq(*arg, opts[i].nam) || streq(*arg, opts[i].altnam))
  112. {
  113. if (opts[i].arg)
  114. if (*ind < argc)
  115. *arg = argv[(*ind)++];
  116. else
  117. fatal("option %s requires an argument", *arg);
  118. return i+1;
  119. }
  120. if (**arg == '-')
  121. {
  122. fatal("%s: invalid option", *arg);
  123. usage(stderr, 2);
  124. }
  125. return -1;
  126. }
  127. static void event(struct dl_head *reqs, struct vt_event *ev)
  128. {
  129. struct req *req, *nxt;
  130. switch (ev->type)
  131. {
  132. case EV_PAGE: // new page
  133. {
  134. struct vt_page *vtp = ev->p1;
  135. for (req = PTR reqs->first; nxt = PTR req->node->next; req = nxt)
  136. if (req->pgno == vtp->pgno)
  137. if (req->subno == ANY_SUB || req->subno == vtp->subno)
  138. {
  139. *req->vtp = *vtp;
  140. dl_insert_last(reqs + 1, dl_remove(req->node));
  141. }
  142. }
  143. }
  144. }
  145. int main(int argc, char **argv)
  146. {
  147. char *vbi_name = NULL;
  148. int timeout = 0;
  149. char *fname = "ttext-%s.%e";
  150. char *out_fmt = "ascii";
  151. struct export *fmt = 0;
  152. int opt, ind;
  153. char *arg;
  154. struct vbi *vbi;
  155. struct req *req;
  156. struct dl_head reqs[2]; // simple linear lists of requests & captures
  157. int ttpid = -1;
  158. setlocale (LC_CTYPE, "");
  159. setprgname(argv[0]);
  160. fdset_init(fds);
  161. dl_init(reqs); // the requests
  162. dl_init(reqs+1); // the captured pages
  163. ind = 1;
  164. while (opt = option(argc, argv, &ind, &arg))
  165. switch (opt)
  166. {
  167. case 1: // charset
  168. if (streq(arg, "latin-1") || streq(arg, "1"))
  169. latin1 = 1;
  170. else if (streq(arg, "latin-2") || streq(arg, "2"))
  171. latin1 = 0;
  172. else if (streq(arg, "koi8-r") || streq(arg, "koi"))
  173. latin1 = KOI8;
  174. else if (streq(arg, "iso8859-7") || streq(arg, "el"))
  175. latin1 = GREEK;
  176. else
  177. fatal("bad charset (not latin-1/2/koi8-r/iso8859-7)");
  178. break;
  179. case 2: // format
  180. if (streq(arg, "help") || streq(arg, "?") || streq(arg, "list"))
  181. exp_help(stdout);
  182. out_fmt = arg;
  183. fmt = 0;
  184. break;
  185. case 3: // help
  186. usage(stdout, 0);
  187. break;
  188. case 4: // name
  189. fname = arg;
  190. break;
  191. case 5: // timeout
  192. timeout = strtol(arg, 0, 10);
  193. if (timeout < 1 || timeout > 999999)
  194. fatal("bad timeout value", timeout);
  195. break;
  196. case 6: // service id
  197. sid = strtoul(arg, NULL, 0);
  198. break;
  199. case 7: // teletext pid
  200. ttpid = strtoul(arg, NULL, 0);
  201. break;
  202. case 8: // vbi
  203. vbi_name = arg;
  204. break;
  205. case -1: // non-option arg
  206. if (not fmt)
  207. fmt = export_open(out_fmt);
  208. if (not fmt)
  209. fatal("%s", export_errstr());
  210. if (not(req = malloc(sizeof(*req))))
  211. out_of_mem(sizeof(*req));
  212. req->name = fname;
  213. req->pgno_str = arg;
  214. req->pgno = arg_pgno(arg, &req->subno);
  215. req->export = fmt;
  216. dl_insert_last(reqs, req->node);
  217. break;
  218. }
  219. if (dl_empty(reqs))
  220. fatal("no pages requested");
  221. // setup device
  222. if (not(vbi = vbi_open(vbi_name, 0, channel, outfile, sid, ttpid)))
  223. fatal("cannot open %s", vbi_name);
  224. vbi_add_handler(vbi, event, reqs); // register event handler
  225. if (timeout)
  226. alarm(timeout);
  227. // capture pages (moves requests from reqs[0] to reqs[1])
  228. while (not dl_empty(reqs) && not timed_out)
  229. if (fdset_select(fds, 30000) == 0) // 30sec select time out
  230. {
  231. error("no signal.");
  232. break;
  233. }
  234. alarm(0);
  235. vbi_del_handler(vbi, event, reqs);
  236. vbi_close(vbi);
  237. if (not dl_empty(reqs))
  238. error("capture aborted. Some pages are missing.");
  239. for (req = PTR reqs[1].first; req->node->next; req = PTR req->node->next)
  240. {
  241. fname = export_mkname(req->export, req->name, req->vtp, req->pgno_str);
  242. if (not fname || export(req->export, req->vtp, fname))
  243. error("error saving page %s: %s", req->pgno_str, export_errstr());
  244. if (fname)
  245. free(fname);
  246. }
  247. exit(dl_empty(reqs) ? 0 : 1);
  248. }