vt100.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. #undef __STRICT_ANSI__ /* we need to use fileno() */
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <string.h>
  7. #include <sys/ioctl.h>
  8. #include <sys/time.h>
  9. #include <sys/types.h>
  10. #include <sys/select.h>
  11. #include <errno.h>
  12. #include "private.h"
  13. typedef struct {
  14. const char* sequence;
  15. tinyrl_vt100_escape_t code;
  16. } vt100_decode_t;
  17. /* This table maps the vt100 escape codes to an enumeration */
  18. static vt100_decode_t cmds[] = {
  19. {"[A", tinyrl_vt100_CURSOR_UP},
  20. {"[B", tinyrl_vt100_CURSOR_DOWN},
  21. {"[C", tinyrl_vt100_CURSOR_RIGHT},
  22. {"[D", tinyrl_vt100_CURSOR_LEFT},
  23. {"[H", tinyrl_vt100_HOME},
  24. {"[1~", tinyrl_vt100_HOME},
  25. {"[F", tinyrl_vt100_END},
  26. {"[4~", tinyrl_vt100_END},
  27. {"[2~", tinyrl_vt100_INSERT},
  28. {"[3~", tinyrl_vt100_DELETE},
  29. {"[5~", tinyrl_vt100_PGUP},
  30. {"[6~", tinyrl_vt100_PGDOWN},
  31. };
  32. /*--------------------------------------------------------- */
  33. tinyrl_vt100_escape_t tinyrl_vt100_escape_decode(const tinyrl_vt100_t *this,
  34. const char *esc_seq)
  35. {
  36. tinyrl_vt100_escape_t result = tinyrl_vt100_UNKNOWN;
  37. unsigned int i;
  38. /* Decode the sequence to macros */
  39. for (i = 0; i < (sizeof(cmds) / sizeof(vt100_decode_t)); i++) {
  40. if (strcmp(cmds[i].sequence, esc_seq))
  41. continue;
  42. result = cmds[i].code;
  43. break;
  44. }
  45. return result;
  46. }
  47. /*-------------------------------------------------------- */
  48. int tinyrl_vt100_printf(const tinyrl_vt100_t * this, const char *fmt, ...)
  49. {
  50. va_list args;
  51. int len;
  52. if (!this->ostream)
  53. return 0;
  54. va_start(args, fmt);
  55. len = tinyrl_vt100_vprintf(this, fmt, args);
  56. va_end(args);
  57. return len;
  58. }
  59. /*-------------------------------------------------------- */
  60. int
  61. tinyrl_vt100_vprintf(const tinyrl_vt100_t * this, const char *fmt, va_list args)
  62. {
  63. if (!this->ostream)
  64. return 0;
  65. return vfprintf(this->ostream, fmt, args);
  66. }
  67. /*-------------------------------------------------------- */
  68. int tinyrl_vt100_getchar(const tinyrl_vt100_t *this)
  69. {
  70. unsigned char c;
  71. int istream_fd;
  72. fd_set rfds;
  73. struct timeval tv;
  74. int retval;
  75. ssize_t res;
  76. if (!this->istream)
  77. return VT100_ERR;
  78. istream_fd = fileno(this->istream);
  79. /* Just wait for the input if no timeout */
  80. if (this->timeout <= 0) {
  81. while (((res = read(istream_fd, &c, 1)) < 0) &&
  82. (EAGAIN == errno));
  83. /* EOF or error */
  84. if (res < 0)
  85. return VT100_ERR;
  86. if (!res)
  87. return VT100_EOF;
  88. return c;
  89. }
  90. /* Set timeout for the select() */
  91. FD_ZERO(&rfds);
  92. FD_SET(istream_fd, &rfds);
  93. tv.tv_sec = this->timeout;
  94. tv.tv_usec = 0;
  95. while (((retval = select(istream_fd + 1, &rfds, NULL, NULL, &tv)) < 0) &&
  96. (EAGAIN == errno));
  97. /* Error or timeout */
  98. if (retval < 0)
  99. return VT100_ERR;
  100. if (!retval)
  101. return VT100_TIMEOUT;
  102. res = read(istream_fd, &c, 1);
  103. /* EOF or error */
  104. if (res < 0)
  105. return VT100_ERR;
  106. if (!res)
  107. return VT100_EOF;
  108. return c;
  109. }
  110. /*-------------------------------------------------------- */
  111. int tinyrl_vt100_oflush(const tinyrl_vt100_t * this)
  112. {
  113. if (!this->ostream)
  114. return 0;
  115. return fflush(this->ostream);
  116. }
  117. /*-------------------------------------------------------- */
  118. int tinyrl_vt100_ierror(const tinyrl_vt100_t * this)
  119. {
  120. if (!this->istream)
  121. return 0;
  122. return ferror(this->istream);
  123. }
  124. /*-------------------------------------------------------- */
  125. int tinyrl_vt100_oerror(const tinyrl_vt100_t * this)
  126. {
  127. if (!this->ostream)
  128. return 0;
  129. return ferror(this->ostream);
  130. }
  131. /*-------------------------------------------------------- */
  132. int tinyrl_vt100_ieof(const tinyrl_vt100_t * this)
  133. {
  134. if (!this->istream)
  135. return 0;
  136. return feof(this->istream);
  137. }
  138. /*-------------------------------------------------------- */
  139. int tinyrl_vt100_eof(const tinyrl_vt100_t * this)
  140. {
  141. if (!this->istream)
  142. return 0;
  143. return feof(this->istream);
  144. }
  145. /*-------------------------------------------------------- */
  146. unsigned int tinyrl_vt100__get_width(const tinyrl_vt100_t *this)
  147. {
  148. #ifdef TIOCGWINSZ
  149. struct winsize ws;
  150. int res;
  151. #endif
  152. if(!this->ostream)
  153. return 80;
  154. #ifdef TIOCGWINSZ
  155. ws.ws_col = 0;
  156. res = ioctl(fileno(this->ostream), TIOCGWINSZ, &ws);
  157. if (res || !ws.ws_col)
  158. return 80;
  159. return ws.ws_col;
  160. #else
  161. return 80;
  162. #endif
  163. }
  164. /*-------------------------------------------------------- */
  165. unsigned int tinyrl_vt100__get_height(const tinyrl_vt100_t *this)
  166. {
  167. #ifdef TIOCGWINSZ
  168. struct winsize ws;
  169. int res;
  170. #endif
  171. if(!this->ostream)
  172. return 25;
  173. #ifdef TIOCGWINSZ
  174. ws.ws_row = 0;
  175. res = ioctl(fileno(this->ostream), TIOCGWINSZ, &ws);
  176. if (res || !ws.ws_row)
  177. return 25;
  178. return ws.ws_row;
  179. #else
  180. return 25;
  181. #endif
  182. }
  183. /*-------------------------------------------------------- */
  184. static void
  185. tinyrl_vt100_init(tinyrl_vt100_t * this, FILE * istream, FILE * ostream)
  186. {
  187. this->istream = istream;
  188. this->ostream = ostream;
  189. this->timeout = -1; /* No timeout by default */
  190. }
  191. /*-------------------------------------------------------- */
  192. static void tinyrl_vt100_fini(tinyrl_vt100_t * this)
  193. {
  194. /* nothing to do yet... */
  195. this = this;
  196. }
  197. /*-------------------------------------------------------- */
  198. tinyrl_vt100_t *tinyrl_vt100_new(FILE * istream, FILE * ostream)
  199. {
  200. tinyrl_vt100_t *this = NULL;
  201. this = malloc(sizeof(tinyrl_vt100_t));
  202. if (this) {
  203. tinyrl_vt100_init(this, istream, ostream);
  204. }
  205. return this;
  206. }
  207. /*-------------------------------------------------------- */
  208. void tinyrl_vt100_delete(tinyrl_vt100_t * this)
  209. {
  210. tinyrl_vt100_fini(this);
  211. /* release the memory */
  212. free(this);
  213. }
  214. /*-------------------------------------------------------- */
  215. void tinyrl_vt100_ding(const tinyrl_vt100_t * this)
  216. {
  217. tinyrl_vt100_printf(this, "%c", KEY_BEL);
  218. (void)tinyrl_vt100_oflush(this);
  219. }
  220. /*-------------------------------------------------------- */
  221. void tinyrl_vt100_attribute_reset(const tinyrl_vt100_t * this)
  222. {
  223. tinyrl_vt100_printf(this, "%c[0m", KEY_ESC);
  224. }
  225. /*-------------------------------------------------------- */
  226. void tinyrl_vt100_attribute_bright(const tinyrl_vt100_t * this)
  227. {
  228. tinyrl_vt100_printf(this, "%c[1m", KEY_ESC);
  229. }
  230. /*-------------------------------------------------------- */
  231. void tinyrl_vt100_attribute_dim(const tinyrl_vt100_t * this)
  232. {
  233. tinyrl_vt100_printf(this, "%c[2m", KEY_ESC);
  234. }
  235. /*-------------------------------------------------------- */
  236. void tinyrl_vt100_attribute_underscore(const tinyrl_vt100_t * this)
  237. {
  238. tinyrl_vt100_printf(this, "%c[4m", KEY_ESC);
  239. }
  240. /*-------------------------------------------------------- */
  241. void tinyrl_vt100_attribute_blink(const tinyrl_vt100_t * this)
  242. {
  243. tinyrl_vt100_printf(this, "%c[5m", KEY_ESC);
  244. }
  245. /*-------------------------------------------------------- */
  246. void tinyrl_vt100_attribute_reverse(const tinyrl_vt100_t * this)
  247. {
  248. tinyrl_vt100_printf(this, "%c[7m", KEY_ESC);
  249. }
  250. /*-------------------------------------------------------- */
  251. void tinyrl_vt100_attribute_hidden(const tinyrl_vt100_t * this)
  252. {
  253. tinyrl_vt100_printf(this, "%c[8m", KEY_ESC);
  254. }
  255. /*-------------------------------------------------------- */
  256. void tinyrl_vt100_erase_line(const tinyrl_vt100_t * this)
  257. {
  258. tinyrl_vt100_printf(this, "%c[2K", KEY_ESC);
  259. }
  260. /*-------------------------------------------------------- */
  261. void tinyrl_vt100_clear_screen(const tinyrl_vt100_t * this)
  262. {
  263. tinyrl_vt100_printf(this, "%c[2J", KEY_ESC);
  264. }
  265. /*-------------------------------------------------------- */
  266. void tinyrl_vt100_cursor_save(const tinyrl_vt100_t * this)
  267. {
  268. tinyrl_vt100_printf(this, "%c7", KEY_ESC); /* VT100 */
  269. /* tinyrl_vt100_printf(this, "%c[s", KEY_ESC); */ /* ANSI */
  270. }
  271. /*-------------------------------------------------------- */
  272. void tinyrl_vt100_cursor_restore(const tinyrl_vt100_t * this)
  273. {
  274. tinyrl_vt100_printf(this, "%c8", KEY_ESC); /* VT100 */
  275. /* tinyrl_vt100_printf(this, "%c[u", KEY_ESC); */ /* ANSI */
  276. }
  277. /*-------------------------------------------------------- */
  278. void tinyrl_vt100_cursor_forward(const tinyrl_vt100_t * this, unsigned count)
  279. {
  280. tinyrl_vt100_printf(this, "%c[%dC", KEY_ESC, count);
  281. }
  282. /*-------------------------------------------------------- */
  283. void tinyrl_vt100_cursor_back(const tinyrl_vt100_t * this, unsigned count)
  284. {
  285. tinyrl_vt100_printf(this, "%c[%dD", KEY_ESC, count);
  286. }
  287. /*-------------------------------------------------------- */
  288. void tinyrl_vt100_cursor_up(const tinyrl_vt100_t * this, unsigned count)
  289. {
  290. tinyrl_vt100_printf(this, "%c[%dA", KEY_ESC, count);
  291. }
  292. /*-------------------------------------------------------- */
  293. void tinyrl_vt100_cursor_down(const tinyrl_vt100_t * this, unsigned count)
  294. {
  295. tinyrl_vt100_printf(this, "%c[%dB", KEY_ESC, count);
  296. }
  297. /*-------------------------------------------------------- */
  298. void tinyrl_vt100_scroll_up(const tinyrl_vt100_t *this)
  299. {
  300. tinyrl_vt100_printf(this, "%cD", KEY_ESC);
  301. }
  302. /*-------------------------------------------------------- */
  303. void tinyrl_vt100_scroll_down(const tinyrl_vt100_t *this)
  304. {
  305. tinyrl_vt100_printf(this, "%cM", KEY_ESC);
  306. }
  307. /*-------------------------------------------------------- */
  308. void tinyrl_vt100_next_line(const tinyrl_vt100_t *this)
  309. {
  310. tinyrl_vt100_printf(this, "%cE", KEY_ESC);
  311. }
  312. /*-------------------------------------------------------- */
  313. void tinyrl_vt100_cursor_home(const tinyrl_vt100_t * this)
  314. {
  315. tinyrl_vt100_printf(this, "%c[H", KEY_ESC);
  316. }
  317. /*-------------------------------------------------------- */
  318. void tinyrl_vt100_erase(const tinyrl_vt100_t * this, unsigned count)
  319. {
  320. tinyrl_vt100_printf(this, "%c[%dP", KEY_ESC, count);
  321. }
  322. /*-------------------------------------------------------- */
  323. void tinyrl_vt100__set_timeout(tinyrl_vt100_t *this, int timeout)
  324. {
  325. this->timeout = timeout;
  326. }
  327. /*-------------------------------------------------------- */
  328. void tinyrl_vt100_erase_down(const tinyrl_vt100_t * this)
  329. {
  330. tinyrl_vt100_printf(this, "%c[J", KEY_ESC);
  331. }
  332. /*-------------------------------------------------------- */
  333. void tinyrl_vt100__set_istream(tinyrl_vt100_t * this, FILE * istream)
  334. {
  335. this->istream = istream;
  336. }
  337. /*-------------------------------------------------------- */
  338. FILE *tinyrl_vt100__get_istream(const tinyrl_vt100_t * this)
  339. {
  340. return this->istream;
  341. }
  342. /*-------------------------------------------------------- */
  343. FILE *tinyrl_vt100__get_ostream(const tinyrl_vt100_t * this)
  344. {
  345. return this->ostream;
  346. }
  347. /*-------------------------------------------------------- */