vt100.c 9.9 KB

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