rlptytest.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. *
  3. * Another test harness for the readline callback interface.
  4. *
  5. * Author: Bob Rossi <bob@brasko.net>
  6. */
  7. #if defined (HAVE_CONFIG_H)
  8. #include <config.h>
  9. #endif
  10. #include <stdio.h>
  11. #include <sys/types.h>
  12. #include <errno.h>
  13. #include <curses.h>
  14. #include <stdlib.h>
  15. #include <unistd.h>
  16. #include <signal.h>
  17. #if 0 /* LINUX */
  18. #include <pty.h>
  19. #else
  20. #include <util.h>
  21. #endif
  22. #ifdef READLINE_LIBRARY
  23. # include "readline.h"
  24. #else
  25. # include <readline/readline.h>
  26. #endif
  27. /**
  28. * Master/Slave PTY used to keep readline off of stdin/stdout.
  29. */
  30. static int masterfd = -1;
  31. static int slavefd;
  32. void
  33. sigint (s)
  34. int s;
  35. {
  36. tty_reset (STDIN_FILENO);
  37. close (masterfd);
  38. close (slavefd);
  39. printf ("\n");
  40. exit (0);
  41. }
  42. static int
  43. user_input()
  44. {
  45. int size;
  46. const int MAX = 1024;
  47. char *buf = (char *)malloc(MAX+1);
  48. size = read (STDIN_FILENO, buf, MAX);
  49. if (size == -1)
  50. return -1;
  51. size = write (masterfd, buf, size);
  52. if (size == -1)
  53. return -1;
  54. return 0;
  55. }
  56. static int
  57. readline_input()
  58. {
  59. const int MAX = 1024;
  60. char *buf = (char *)malloc(MAX+1);
  61. int size;
  62. size = read (masterfd, buf, MAX);
  63. if (size == -1)
  64. {
  65. free( buf );
  66. buf = NULL;
  67. return -1;
  68. }
  69. buf[size] = 0;
  70. /* Display output from readline */
  71. if ( size > 0 )
  72. fprintf(stderr, "%s", buf);
  73. free( buf );
  74. buf = NULL;
  75. return 0;
  76. }
  77. static void
  78. rlctx_send_user_command(char *line)
  79. {
  80. /* This happens when rl_callback_read_char gets EOF */
  81. if ( line == NULL )
  82. return;
  83. if (strcmp (line, "exit") == 0) {
  84. tty_reset (STDIN_FILENO);
  85. close (masterfd);
  86. close (slavefd);
  87. printf ("\n");
  88. exit (0);
  89. }
  90. /* Don't add the enter command */
  91. if ( line && *line != '\0' )
  92. add_history(line);
  93. }
  94. static void
  95. custom_deprep_term_function ()
  96. {
  97. }
  98. static int
  99. init_readline (int inputfd, int outputfd)
  100. {
  101. FILE *inputFILE, *outputFILE;
  102. inputFILE = fdopen (inputfd, "r");
  103. if (!inputFILE)
  104. return -1;
  105. outputFILE = fdopen (outputfd, "w");
  106. if (!outputFILE)
  107. return -1;
  108. rl_instream = inputFILE;
  109. rl_outstream = outputFILE;
  110. /* Tell readline what the prompt is if it needs to put it back */
  111. rl_callback_handler_install("(rltest): ", rlctx_send_user_command);
  112. /* Set the terminal type to dumb so the output of readline can be
  113. * understood by tgdb */
  114. if ( rl_reset_terminal("dumb") == -1 )
  115. return -1;
  116. /* For some reason, readline can not deprep the terminal.
  117. * However, it doesn't matter because no other application is working on
  118. * the terminal besides readline */
  119. rl_deprep_term_function = custom_deprep_term_function;
  120. using_history();
  121. read_history(".history");
  122. return 0;
  123. }
  124. static int
  125. main_loop(void)
  126. {
  127. fd_set rset;
  128. int max;
  129. max = (masterfd > STDIN_FILENO) ? masterfd : STDIN_FILENO;
  130. max = (max > slavefd) ? max : slavefd;
  131. for (;;)
  132. {
  133. /* Reset the fd_set, and watch for input from GDB or stdin */
  134. FD_ZERO(&rset);
  135. FD_SET(STDIN_FILENO, &rset);
  136. FD_SET(slavefd, &rset);
  137. FD_SET(masterfd, &rset);
  138. /* Wait for input */
  139. if (select(max + 1, &rset, NULL, NULL, NULL) == -1)
  140. {
  141. if (errno == EINTR)
  142. continue;
  143. else
  144. return -1;
  145. }
  146. /* Input received through the pty: Handle it
  147. * Wrote to masterfd, slave fd has that input, alert readline to read it.
  148. */
  149. if (FD_ISSET(slavefd, &rset))
  150. rl_callback_read_char();
  151. /* Input received through the pty.
  152. * Readline read from slavefd, and it wrote to the masterfd.
  153. */
  154. if (FD_ISSET(masterfd, &rset))
  155. if ( readline_input() == -1 )
  156. return -1;
  157. /* Input received: Handle it, write to masterfd (input to readline) */
  158. if (FD_ISSET(STDIN_FILENO, &rset))
  159. if ( user_input() == -1 )
  160. return -1;
  161. }
  162. return 0;
  163. }
  164. /* The terminal attributes before calling tty_cbreak */
  165. static struct termios save_termios;
  166. static struct winsize size;
  167. static enum { RESET, TCBREAK } ttystate = RESET;
  168. /* tty_cbreak: Sets terminal to cbreak mode. Also known as noncanonical mode.
  169. * 1. Signal handling is still turned on, so the user can still type those.
  170. * 2. echo is off
  171. * 3. Read in one char at a time.
  172. *
  173. * fd - The file descriptor of the terminal
  174. *
  175. * Returns: 0 on sucess, -1 on error
  176. */
  177. int tty_cbreak(int fd){
  178. struct termios buf;
  179. int ttysavefd = -1;
  180. if(tcgetattr(fd, &save_termios) < 0)
  181. return -1;
  182. buf = save_termios;
  183. buf.c_lflag &= ~(ECHO | ICANON);
  184. buf.c_iflag &= ~(ICRNL | INLCR);
  185. buf.c_cc[VMIN] = 1;
  186. buf.c_cc[VTIME] = 0;
  187. #if defined (VLNEXT) && defined (_POSIX_VDISABLE)
  188. buf.c_cc[VLNEXT] = _POSIX_VDISABLE;
  189. #endif
  190. #if defined (VDSUSP) && defined (_POSIX_VDISABLE)
  191. buf.c_cc[VDSUSP] = _POSIX_VDISABLE;
  192. #endif
  193. /* enable flow control; only stty start char can restart output */
  194. #if 0
  195. buf.c_iflag |= (IXON|IXOFF);
  196. #ifdef IXANY
  197. buf.c_iflag &= ~IXANY;
  198. #endif
  199. #endif
  200. /* disable flow control; let ^S and ^Q through to pty */
  201. buf.c_iflag &= ~(IXON|IXOFF);
  202. #ifdef IXANY
  203. buf.c_iflag &= ~IXANY;
  204. #endif
  205. if(tcsetattr(fd, TCSAFLUSH, &buf) < 0)
  206. return -1;
  207. ttystate = TCBREAK;
  208. ttysavefd = fd;
  209. /* set size */
  210. if(ioctl(fd, TIOCGWINSZ, (char *)&size) < 0)
  211. return -1;
  212. #ifdef DEBUG
  213. err_msg("%d rows and %d cols\n", size.ws_row, size.ws_col);
  214. #endif
  215. return (0);
  216. }
  217. int
  218. tty_off_xon_xoff (int fd)
  219. {
  220. struct termios buf;
  221. int ttysavefd = -1;
  222. if(tcgetattr(fd, &buf) < 0)
  223. return -1;
  224. buf.c_iflag &= ~(IXON|IXOFF);
  225. if(tcsetattr(fd, TCSAFLUSH, &buf) < 0)
  226. return -1;
  227. return 0;
  228. }
  229. /* tty_reset: Sets the terminal attributes back to their previous state.
  230. * PRE: tty_cbreak must have already been called.
  231. *
  232. * fd - The file descrioptor of the terminal to reset.
  233. *
  234. * Returns: 0 on success, -1 on error
  235. */
  236. int tty_reset(int fd)
  237. {
  238. if(ttystate != TCBREAK)
  239. return (0);
  240. if(tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
  241. return (-1);
  242. ttystate = RESET;
  243. return 0;
  244. }
  245. int
  246. main()
  247. {
  248. int val;
  249. val = openpty (&masterfd, &slavefd, NULL, NULL, NULL);
  250. if (val == -1)
  251. return -1;
  252. val = tty_off_xon_xoff (masterfd);
  253. if (val == -1)
  254. return -1;
  255. val = init_readline (slavefd, slavefd);
  256. if (val == -1)
  257. return -1;
  258. val = tty_cbreak (STDIN_FILENO);
  259. if (val == -1)
  260. return -1;
  261. signal (SIGINT, sigint);
  262. val = main_loop ();
  263. tty_reset (STDIN_FILENO);
  264. if (val == -1)
  265. return -1;
  266. return 0;
  267. }