vt100.c 10.0 KB

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