kawa.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. /* A front-end using readline to "cook" input lines for Kawa.
  2. *
  3. * Copyright (C) 1999, 2004, 2007 Per Bothner
  4. *
  5. * This front-end program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as published
  7. * by the Free Software Foundation; either version 2, or (at your option)
  8. * any later version.
  9. *
  10. * Some code from Johnson & Troan: "Linux Application Development"
  11. * (Addison-Wesley, 1998) was used directly or for inspiration.
  12. *
  13. * Three different implementations are actually provided, see below.
  14. */
  15. /* If use_telnet==PREFER_PTY, run the inferior using a pty. */
  16. #define PREFER_PTY 0
  17. /* If use_telnet==PREFER_TELNET_CLIENT, connect to the inferior using
  18. Telnet protocol. This front-end is a telnet client. */
  19. #define PREFER_TELNET_CLIENT 1
  20. /* If use_telnet==PREFER_TELNET_CONNECT, connect to the inferior using
  21. Telnet protocol. However, note the unusual set-up: This front-end
  22. program starts up first as a server, starts up the inferior process,
  23. and then listens from connections from the inferior process.
  24. But once a connection has been made, the inferior acts like a
  25. telnet server, while this front-end acts like telnet client.
  26. This is the default and preferred implementation. */
  27. #define PREFER_TELNET_CONNECT 2
  28. #ifndef SUPPORT_PTY
  29. #define SUPPORT_PTY 0
  30. #endif
  31. #ifndef SUPPORT_TELNET
  32. #define SUPPORT_TELNET 1
  33. #endif
  34. #ifndef SUPPORT_TELNET_CLIENT
  35. #define SUPPORT_TELNET_CLIENT 0
  36. #endif
  37. #include <stdio.h>
  38. #include <fcntl.h>
  39. #include <sys/types.h>
  40. #include <sys/wait.h>
  41. #include <sys/socket.h>
  42. #include <netinet/in.h>
  43. #include <arpa/inet.h>
  44. #if SUPPORT_TELNET
  45. #include <arpa/telnet.h>
  46. #endif
  47. #include <signal.h>
  48. #include <netdb.h>
  49. #include <stdlib.h>
  50. #include <errno.h>
  51. #include <grp.h>
  52. #include <string.h>
  53. #include <sys/stat.h>
  54. #include <unistd.h>
  55. #include <sys/ioctl.h>
  56. #include <termios.h>
  57. #include <readline/readline.h>
  58. #include <readline/history.h>
  59. #ifndef PREFERRED_PROTOCOL
  60. #if SUPPORT_TELNET
  61. #define PREFERRED_PROTOCOL PREFER_TELNET_CONNECT
  62. #else
  63. #define PREFERRED_PROTOCOL PREFER_PTY
  64. #endif
  65. #endif
  66. extern char * get_classpath(const char *);
  67. #ifndef JAVA
  68. #define JAVA "java"
  69. #endif
  70. #ifndef COMMAND
  71. #ifdef GCJ_COMPILED
  72. #define COMMAND "kawa-bin"
  73. #else
  74. #define COMMAND JAVA
  75. #endif
  76. #endif
  77. #ifdef GCJ_COMPILED
  78. /* Make COMMAND relative to PROGNAME, which is main's argv[0]. */
  79. char*
  80. get_command (char *progname)
  81. {
  82. char *command = COMMAND;
  83. char* rp = strrchr(progname, '/');
  84. if (rp != NULL)
  85. {
  86. int dirlen = rp - progname;
  87. char *tmp = malloc (dirlen + strlen(command) + 2);
  88. sprintf(tmp, "%.*s/%s", dirlen, progname, command);
  89. command = tmp;
  90. }
  91. return command;
  92. }
  93. #endif
  94. #if defined(SUPPORT_PTY) && !defined(SUPPORT_TELNET)
  95. static int use_telnet = 0;
  96. #elif !defined(SUPPORT_PTY) && defined(SUPPORT_TELNET)
  97. static int use_telnet = 2;
  98. #else
  99. static int use_telnet = PREFERRED_PROTOCOL;
  100. #endif
  101. #define APPLICATION_NAME "kawa"
  102. static int in_from_inferior_fd;
  103. static int out_to_inferior_fd;
  104. static void set_edit_mode ();
  105. #ifdef DEBUG
  106. FILE *logfile = NULL;
  107. #define DPRINT0(FMT) (fprintf(logfile, FMT), fflush(logfile))
  108. #define DPRINT1(FMT, V1) (fprintf(logfile, FMT, V1), fflush(logfile))
  109. #define DPRINT2(FMT, V1, V2) (fprintf(logfile, FMT, V1, V2), fflush(logfile))
  110. #else
  111. #define DPRINT0(FMT) ((void) 0) /* Do nothing */
  112. #define DPRINT1(FMT, V1) ((void) 0) /* Do nothing */
  113. #define DPRINT2(FMT, V1, V2) ((void) 0) /* Do nothing */
  114. #endif
  115. struct termios orig_term;
  116. static pid_t child = -1;
  117. /* This could also be used as a SIGCHLD handler.
  118. However, in that case for some reason we're not getting the
  119. correct exit code. */
  120. static void
  121. sig_child (int signo)
  122. {
  123. int status;
  124. waitpid (child, &status, 0);
  125. DPRINT2("(Child process died. status:%d, exited:%d.)\n", status, WIFEXITED (status));
  126. fflush(stderr);
  127. if (use_telnet)
  128. rl_deprep_terminal ();
  129. else
  130. tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
  131. exit (WIFEXITED (status) ? WEXITSTATUS (status) : 0);
  132. }
  133. #if SUPPORT_PTY
  134. volatile int propagate_sigwinch = 0;
  135. /* sigwinch_handler
  136. * propagate window size changes from input file descriptor to
  137. * master side of pty.
  138. */
  139. void sigwinch_handler(int signal) {
  140. propagate_sigwinch = 1;
  141. }
  142. /* get_slave_pty() returns an integer file descriptor.
  143. * If it returns < 0, an error has occurred.
  144. * Otherwise, it has returned the slave file descriptor.
  145. */
  146. int get_slave_pty(char *name) {
  147. struct group *gptr;
  148. gid_t gid;
  149. int slave = -1;
  150. /* chown/chmod the corresponding pty, if possible.
  151. * This will only work if the process has root permissions.
  152. * Alternatively, write and exec a small setuid program that
  153. * does just this.
  154. */
  155. if ((gptr = getgrnam("tty")) != 0) {
  156. gid = gptr->gr_gid;
  157. } else {
  158. /* if the tty group does not exist, don't change the
  159. * group on the slave pty, only the owner
  160. */
  161. gid = -1;
  162. }
  163. /* Note that we do not check for errors here. If this is code
  164. * where these actions are critical, check for errors!
  165. */
  166. chown(name, getuid(), gid);
  167. /* This code only makes the slave read/writeable for the user.
  168. * If this is for an interactive shell that will want to
  169. * receive "write" and "wall" messages, OR S_IWGRP into the
  170. * second argument below.
  171. */
  172. chmod(name, S_IRUSR|S_IWUSR);
  173. /* open the corresponding slave pty */
  174. slave = open(name, O_RDWR);
  175. return (slave);
  176. }
  177. #endif
  178. #if SUPPORT_TELNET
  179. static int telnet_input_state = 0;
  180. void
  181. write_telnet_command2 (int code, int option)
  182. {
  183. char buf[3];
  184. buf[0] = IAC;
  185. buf[1] = code;
  186. buf[2] = option;
  187. write (out_to_inferior_fd, buf, 3);
  188. }
  189. /* Used to store the the current state of negotiation of telnet options.
  190. For example, for option LINEMODE (34), (telnet_options_state[34] & 7)
  191. is the state of the option on this side, and
  192. ((telnet_options_state[34] >> 3) & 7) is the state on the other side.
  193. The 3 bits for each side can be any of OPTION_NO though OPTION_YES.
  194. The option is only enabled if the value is OPTION_YES.
  195. See RFC 1143. */
  196. static char telnet_options_state[256];
  197. /* The option is disabled, and no negotiating is in progress. */
  198. #define OPTION_NO 0
  199. /* We sent out DONT/WONT and are waiting for confirming WONT/DONT. */
  200. #define OPTION_WANTNO 1
  201. /* Like WANTNO, but we changed our mind. */
  202. #define OPTION_WANTNO_OPPOSITE 2
  203. /* We sent out DO/WILL and are waiting for confirming WILL/DO. */
  204. #define OPTION_WANTYES 3
  205. /* Like WANTYES, but we changed our mind. */
  206. #define OPTION_WANTYES_OPPOSITE 4
  207. /* The option is enabled, and no negotiating is in progress. */
  208. #define OPTION_YES 5
  209. /* Actually (try to) change the state for an option.
  210. Return false is we don't know how or don't want to.
  211. command is DO if we're enabling on this side;
  212. DONT if we're disabling on this side;
  213. WILL if we're enabling for the other side;
  214. WONT if we're disabling for the other side.
  215. You should not call this function directly.
  216. Instead, call request to send a request to the other side
  217. (but with DO/WILL and DONT/WONT switched). Then, when
  218. confirmation comes back, it is handled by the handle method, which
  219. calls change.
  220. The telnet_options_state array may not have been updated yet.
  221. */
  222. int
  223. change (int command, int option)
  224. {
  225. return 0;
  226. }
  227. /* Handle a request from the other side.
  228. Command is one of DO, DONT, WILL, WONT. */
  229. static void
  230. handle_telnet_option_request (int command, int option)
  231. {
  232. /* True if the other side wants to change itself I.e. we got WILL/WONT);
  233. false if it wants us to change (i.e. we got DO/DONT). */
  234. int other_side = command < DO;
  235. /* True if DO or WILL; false if DONT or WONT. */
  236. int want_on = (command & 1) != 0;
  237. char state;
  238. DPRINT2 ("saw request (%d, %d)\n", command, option);
  239. option = option & 0xFF;
  240. state = telnet_options_state[option];
  241. if (other_side)
  242. state >>= 3;
  243. switch ((state >> 3) & 7)
  244. {
  245. case OPTION_YES:
  246. if (want_on)
  247. return; /* Nothing to do. */
  248. /* Got a DONT or WONT. Disable without arguing. */
  249. state = OPTION_NO;
  250. change(command, option);
  251. write_telnet_command2 (other_side ? DONT : WONT, option);
  252. break;
  253. case OPTION_NO:
  254. if (! want_on)
  255. return; /* Nothing to do. */
  256. if (change (command, option))
  257. {
  258. state = OPTION_YES;
  259. write_telnet_command2 (other_side ? DO : WILL, option);
  260. }
  261. else
  262. {
  263. write_telnet_command2 (other_side ? DONT : WONT, option);
  264. }
  265. break;
  266. case OPTION_WANTNO:
  267. state = OPTION_NO;
  268. break;
  269. case OPTION_WANTNO_OPPOSITE:
  270. /* if (goalState) Error: DONT/WONT answered by WILL/DO.
  271. Maybe some packets crossed in the mail.
  272. Presumably the other side will take our original
  273. request as de-conformation. In any case: */
  274. state = OPTION_WANTYES;
  275. write_telnet_command2 (other_side ? DO : WILL, option);
  276. break;
  277. case OPTION_WANTYES:
  278. if (want_on)
  279. {
  280. state = OPTION_YES;
  281. change (command, option);
  282. }
  283. else
  284. state = OPTION_NO; /* Declined. */
  285. break;
  286. case OPTION_WANTYES_OPPOSITE:
  287. if (want_on)
  288. {
  289. state = OPTION_WANTNO;
  290. write_telnet_command2 (other_side ? DONT : WONT, option);
  291. }
  292. else
  293. {
  294. state = OPTION_NO;
  295. }
  296. break;
  297. }
  298. if (other_side)
  299. state = (telnet_options_state[option] & 0xC7) | (state << 3);
  300. else
  301. state = (telnet_options_state[option] & 0xF8) | state;
  302. telnet_options_state[option] = state;
  303. }
  304. static int
  305. process_telnet_input (char *buffer, int length)
  306. {
  307. char *in_ptr = buffer;
  308. char *out_ptr = buffer;
  309. while (in_ptr < buffer + length)
  310. {
  311. unsigned char ch = (unsigned char) *in_ptr++;
  312. switch (telnet_input_state)
  313. {
  314. case 0:
  315. if (ch == IAC)
  316. telnet_input_state = IAC;
  317. else
  318. *out_ptr++ = ch;
  319. break;
  320. case IAC:
  321. if (ch == IAC)
  322. {
  323. telnet_input_state = 0;
  324. *out_ptr++ = ch;
  325. }
  326. else if (ch == WILL || ch == WONT || ch == DO || ch == DONT
  327. || ch == SB)
  328. {
  329. telnet_input_state = ch;
  330. }
  331. else
  332. {
  333. telnet_input_state = 0;
  334. }
  335. break;
  336. case DO:
  337. case DONT:
  338. case WILL:
  339. case WONT:
  340. handle_telnet_option_request (telnet_input_state, ch);
  341. telnet_input_state = 0;
  342. break;
  343. #if 0
  344. case SB:
  345. case SB_IAC:
  346. #endif
  347. }
  348. }
  349. return out_ptr - buffer;
  350. }
  351. #endif
  352. static char buf[1024];
  353. /* buf[0 .. buf_count-1] is the what has been emitted on the current line.
  354. It is used as the readline prompt. */
  355. static int buf_count = 0;
  356. int num_keys = 0;
  357. /* True if readine input should be boldface.
  358. Default off because it isn't quite robust - sometimes
  359. the prompt becomes bold when it shouldn't. */
  360. int bold_input = 0;
  361. static void
  362. null_prep_terminal (int meta)
  363. {
  364. }
  365. static void
  366. null_deprep_terminal ()
  367. {
  368. if (bold_input)
  369. {
  370. fprintf (rl_outstream, "\033[0m");
  371. fflush (rl_outstream);
  372. }
  373. }
  374. static int
  375. pre_input_change_mode ()
  376. {
  377. if (bold_input)
  378. {
  379. fprintf (rl_outstream, "\033[1m");
  380. fflush (rl_outstream);
  381. }
  382. return 0;
  383. }
  384. static void
  385. line_handler (char *line)
  386. {
  387. if (line == NULL)
  388. {
  389. if (use_telnet)
  390. {
  391. #if SUPPORT_TELNET
  392. static char buf[2];
  393. buf[0] = IAC;
  394. buf[1] = xEOF;
  395. write (out_to_inferior_fd, buf, 2);
  396. DPRINT0("Sent EOF.\n");
  397. #endif
  398. }
  399. else
  400. {
  401. char buf[1];
  402. DPRINT0("saw eof!\n");
  403. buf[0] = '\004'; /* ctrl/d */
  404. write (out_to_inferior_fd, buf, 1);
  405. }
  406. }
  407. else
  408. {
  409. static char newline[] = "\r\n";
  410. /* Send line to Kawa inferior: */
  411. write (out_to_inferior_fd, line, strlen (line));
  412. write (out_to_inferior_fd, newline, sizeof(newline)-1);
  413. if (*line)
  414. add_history (line);
  415. free (line);
  416. }
  417. rl_callback_handler_remove ();
  418. buf_count = 0;
  419. num_keys = 0;
  420. }
  421. int
  422. main(int argc, char** argv)
  423. {
  424. int in_from_tty_fd;
  425. #if SUPPORT_TELNET
  426. char *hostname = "127.0.0.1"; /* localhost */
  427. int port = 5555;
  428. struct in_addr inaddr;
  429. struct hostent *host;
  430. int sock;
  431. struct sockaddr_in address;
  432. #endif
  433. int child, i;
  434. #if SUPPORT_PTY
  435. int master;
  436. char *name;
  437. struct sigaction act;
  438. struct winsize ws;
  439. #endif
  440. struct termios t;
  441. int maxfd;
  442. fd_set in_set;
  443. static char empty_string[1] = "";
  444. char *prompt = empty_string;
  445. int out_argc = 0;
  446. int in_argc = 1;
  447. #ifdef COMMAND_ARGS
  448. static char* command_args[] = { COMMAND_ARGS };
  449. char** out_argv = (char **)
  450. malloc (sizeof(command_args) + (5 + argc) * sizeof(char*));
  451. for (i = 0; i < sizeof(command_args)/sizeof(char*); i++)
  452. out_argv[out_argc++] = command_args[i];
  453. #else
  454. char** out_argv = (char **) malloc ((7 + argc) * sizeof(char*));
  455. #if defined(GCJ_COMPILED)
  456. out_argv[out_argc++] = get_command (argv[0]);
  457. #else
  458. putenv (get_classpath(argv[0]));
  459. out_argv[out_argc++] = "java";
  460. #endif
  461. /* Calculate and set the kawa.command.line property. */
  462. char command_prop[] = { "-Dkawa.command.line=" };
  463. int command_prop_len = sizeof(command_prop)-1;
  464. int sum_length = command_prop_len;
  465. for (i = 0; i < argc; i++)
  466. sum_length += strlen(argv[i])+1;
  467. char* command_line = malloc(sum_length);
  468. strcpy(command_line, command_prop);
  469. sum_length = command_prop_len;
  470. for (i = 0; ;)
  471. {
  472. char* arg = argv[i];
  473. int arglen = strlen(arg);
  474. strcpy(command_line+sum_length, arg);
  475. sum_length += arglen;
  476. if (++i == argc)
  477. break;
  478. command_line[sum_length++] = ' ';
  479. }
  480. out_argv[out_argc++] = command_line;
  481. /* Pass initial -D and -J flags to java. */
  482. for (; in_argc < argc; in_argc++)
  483. {
  484. char* arg = argv[in_argc];
  485. if (arg[0] != '-' || (arg[1] != 'D' && arg[1] != 'J'))
  486. break;
  487. if (arg[1] == 'J')
  488. arg = arg+2;
  489. out_argv[out_argc++] = arg;
  490. }
  491. out_argv[out_argc++] = "kawa.repl";
  492. #endif
  493. if (! isatty(0) || ! isatty(1))
  494. {
  495. #if 0
  496. /* No longer needed, asssuming Java 6 or higher,
  497. which has java.lang.Console. */
  498. out_argv[out_argc++] = "--no-console";
  499. #endif
  500. for (; in_argc < argc; in_argc++)
  501. out_argv[out_argc++] = argv[in_argc];
  502. out_argv[out_argc] = NULL;
  503. execvp(out_argv[0], out_argv);
  504. perror ("failed to exec " COMMAND);
  505. exit (-1);
  506. }
  507. #ifdef DEBUG
  508. logfile = fopen("kawa-frontend.log", "w");
  509. #endif
  510. set_edit_mode ();
  511. rl_readline_name = APPLICATION_NAME;
  512. if (! use_telnet)
  513. {
  514. #if SUPPORT_PTY
  515. if ((master = OpenPTY(&name)) < 0)
  516. {
  517. perror("kawa-frontend: could not open master pty");
  518. exit(1);
  519. }
  520. DPRINT1("pty name: '%s'\n", name);
  521. /* set up SIGWINCH handler */
  522. act.sa_handler = sigwinch_handler;
  523. sigemptyset(&(act.sa_mask));
  524. act.sa_flags = 0;
  525. if (sigaction(SIGWINCH, &act, NULL) < 0)
  526. {
  527. perror("kawa-frontend: could not handle SIGWINCH ");
  528. exit(1);
  529. }
  530. if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
  531. {
  532. perror("kawa-frontend: could not get window size");
  533. }
  534. if ((child = fork()) < 0)
  535. {
  536. perror("cannot fork");
  537. exit(1);
  538. }
  539. if (child == 0)
  540. {
  541. int slave; /* file descriptor for slave pty */
  542. /* We are in the child process */
  543. close(master);
  544. #ifdef TIOCSCTTY
  545. if ((slave = get_slave_pty(name)) < 0)
  546. {
  547. perror("kawa-frontend: could not open slave pty");
  548. exit(1);
  549. }
  550. #endif
  551. /* We need to make this process a session group leader, because
  552. * it is on a new PTY, and things like job control simply will
  553. * not work correctly unless there is a session group leader
  554. * and process group leader (which a session group leader
  555. * automatically is). This also disassociates us from our old
  556. * controlling tty.
  557. */
  558. if (setsid() < 0)
  559. {
  560. perror("could not set session leader");
  561. }
  562. /* Tie us to our new controlling tty. */
  563. #ifdef TIOCSCTTY
  564. if (ioctl(slave, TIOCSCTTY, NULL))
  565. {
  566. perror("could not set new controlling tty");
  567. }
  568. #else
  569. if ((slave = get_slave_pty(name)) < 0)
  570. {
  571. perror("kawa-frontend: could not open slave pty");
  572. exit(1);
  573. }
  574. #endif
  575. /* make slave pty be standard in, out, and error */
  576. dup2(slave, STDIN_FILENO);
  577. dup2(slave, STDOUT_FILENO);
  578. dup2(slave, STDERR_FILENO);
  579. /* at this point the slave pty should be standard input */
  580. if (slave > 2)
  581. {
  582. close(slave);
  583. }
  584. /* Try to restore window size; failure isn't critical */
  585. if (ioctl(STDOUT_FILENO, TIOCSWINSZ, &ws) < 0)
  586. {
  587. perror("could not restore window size");
  588. }
  589. /* now start the shell */
  590. {
  591. #if defined(GCJ_COMPILED) && ! defined(COMMAND_ARGS)
  592. char *command_args[2];
  593. char *progname
  594. char *command = get_command (argv[0]);
  595. command_args[0] = command;
  596. command_args[1] = NULL;
  597. execvp(command, command_args);
  598. #else
  599. static char* command_args[] = { COMMAND_ARGS, NULL };
  600. execvp(COMMAND, command_args);
  601. #endif
  602. }
  603. /* should never be reached */
  604. exit(1);
  605. }
  606. /* Note that we only set termios settings for standard input;
  607. * the master side of a pty is NOT a tty.
  608. */
  609. tcgetattr(STDIN_FILENO, &orig_term);
  610. t = orig_term;
  611. t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \
  612. ECHOK | ECHOKE | ECHONL | ECHOPRT );
  613. t.c_iflag &= ~ICRNL;
  614. t.c_iflag |= IGNBRK;
  615. t.c_cc[VMIN] = 1;
  616. t.c_cc[VTIME] = 0;
  617. tcsetattr(STDIN_FILENO, TCSANOW, &t);
  618. in_from_inferior_fd = master;
  619. out_to_inferior_fd = master;
  620. #else
  621. fprintf (stderr, "no pty support!\n");
  622. exit (1);
  623. #endif
  624. }
  625. else /* use_telnet */
  626. {
  627. #if SUPPORT_TELNET
  628. address.sin_family = AF_INET;
  629. if (use_telnet == 2)
  630. {
  631. char port_buf[12];
  632. socklen_t namelen;
  633. int conn;
  634. sock = socket (PF_INET, SOCK_STREAM, 0);
  635. if (sock < 0)
  636. {
  637. perror ("cannot create socket");
  638. exit (-1);
  639. }
  640. namelen = 1;
  641. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
  642. (void*) &namelen, sizeof(int));
  643. port = 0;
  644. address.sin_port = htons(port);
  645. memset (&address.sin_addr, 0, sizeof (address.sin_addr));
  646. if (bind (sock, (struct sockaddr*) &address, sizeof (address)) != 0)
  647. {
  648. perror ("cannot bind socket");
  649. }
  650. namelen = sizeof (address);
  651. if (getsockname (sock, (struct sockaddr*) &address, &namelen) != 0)
  652. {
  653. perror ("getsockname call failed");
  654. exit(-1);
  655. }
  656. port = ntohs(address.sin_port);
  657. if (listen (sock, 5) != 0)
  658. {
  659. perror ("listen on socket failed");
  660. exit(-1);
  661. }
  662. out_argv[out_argc++] = "--connect";
  663. sprintf (port_buf, "%d", port);
  664. out_argv[out_argc++] = port_buf;
  665. for (; in_argc < argc; in_argc++)
  666. out_argv[out_argc++] = argv[in_argc];
  667. out_argv[out_argc] = NULL;
  668. child = fork();
  669. if (child == 0)
  670. {
  671. execvp(out_argv[0], out_argv);
  672. perror ("failed to exec " COMMAND);
  673. exit (-1);
  674. }
  675. else if (child < 0)
  676. {
  677. perror ("failed to fork " COMMAND);
  678. exit (-1);
  679. }
  680. conn = accept (sock, (struct sockaddr*) &address, &namelen);
  681. if (conn < 0)
  682. {
  683. perror ("accept of socket failed");
  684. exit(-1);
  685. }
  686. close (sock);
  687. sock = conn;
  688. }
  689. #if SUPPORT_TELNET_CLIENT
  690. else
  691. {
  692. if (inet_aton (hostname, &inaddr))
  693. host = gethostbyaddr ((char*) &inaddr, sizeof(inaddr), AF_INET);
  694. else
  695. host = gethostbyname (hostname);
  696. if (! host)
  697. {
  698. herror ("error looking up host");
  699. exit (1);
  700. }
  701. sock = socket (PF_INET, SOCK_STREAM, 0);
  702. if (sock < 0)
  703. {
  704. perror ("can't get socket");
  705. exit (1);
  706. }
  707. address.sin_port = htons (port);
  708. memcpy (&address.sin_addr,
  709. host->h_addr_list[0], sizeof (address.sin_addr));
  710. connect (sock, (struct sockaddr *) &address, sizeof(address));
  711. }
  712. #endif
  713. in_from_inferior_fd = sock;
  714. out_to_inferior_fd = sock;
  715. #else
  716. fprintf (stderr, "No telnet support!\n");
  717. exit (1);
  718. #endif
  719. }
  720. rl_callback_handler_install (prompt, line_handler);
  721. if (use_telnet)
  722. {
  723. rl_prep_term_function = null_prep_terminal;
  724. rl_deprep_term_function = null_deprep_terminal;
  725. rl_pre_input_hook = pre_input_change_mode;
  726. }
  727. in_from_tty_fd = STDIN_FILENO;
  728. FD_ZERO (&in_set);
  729. maxfd = in_from_inferior_fd > in_from_tty_fd ? in_from_inferior_fd
  730. : in_from_tty_fd;
  731. for (;;)
  732. {
  733. int num;
  734. FD_SET (in_from_inferior_fd, &in_set);
  735. FD_SET (in_from_tty_fd, &in_set);
  736. num = select(maxfd+1, &in_set, NULL, NULL, NULL);
  737. #if SUPPORT_PTY
  738. if (propagate_sigwinch)
  739. {
  740. struct winsize ws;
  741. if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
  742. {
  743. ioctl (master, TIOCSWINSZ, &ws);
  744. }
  745. propagate_sigwinch = 0;
  746. continue;
  747. }
  748. #endif
  749. if (num <= 0)
  750. {
  751. perror ("select");
  752. exit (-1);
  753. }
  754. if (FD_ISSET (in_from_tty_fd, &in_set))
  755. {
  756. int do_canon = 1;
  757. DPRINT1("[tty avail num_keys:%d]\n", num_keys);
  758. #if SUPPORT_PTY
  759. if (! use_telnet)
  760. {
  761. struct termios term_master;
  762. tcgetattr(master, &term_master);
  763. DPRINT2 ("echo:%d, canon:%d\n",
  764. (term_master.c_lflag & ECHO) != 0,
  765. (term_master.c_lflag & ICANON) != 0);
  766. do_canon = (term_master.c_lflag & ICANON) != 0;
  767. }
  768. #endif
  769. if (do_canon == 0 && num_keys == 0)
  770. {
  771. char ch[10];
  772. int count = read (STDIN_FILENO, ch, sizeof(ch));
  773. write (out_to_inferior_fd, ch, count);
  774. }
  775. else
  776. {
  777. if (num_keys == 0)
  778. {
  779. /* Re-install callback handler for new prompt. */
  780. if (prompt != empty_string)
  781. free (prompt);
  782. int num_escapes = 0;
  783. int num_escape_delims = 0;
  784. int j;
  785. for (j = 0; j < buf_count; j++) {
  786. char c = buf[j];
  787. if (c == '\033')
  788. num_escapes++;
  789. else if (c == '\001' || c == '\002')
  790. num_escape_delims++;
  791. }
  792. int psize = buf_count + 1;
  793. int escaping = num_escapes > 0 && num_escape_delims == 0;
  794. if (escaping)
  795. psize += 2 * num_escapes;
  796. prompt = malloc (psize + 1);
  797. if (prompt == NULL)
  798. prompt = empty_string;
  799. else
  800. {
  801. if (escaping)
  802. {
  803. int in_escape = 0;
  804. char *p = prompt;
  805. for (j = 0; j < buf_count; j++) {
  806. char c = buf[j];
  807. if (c == '\033' && ! in_escape)
  808. {
  809. *p++ = '\001';
  810. *p++ = c;
  811. in_escape = 1;
  812. }
  813. else if (in_escape
  814. && c != '[' && c != ';'
  815. && ! (c >= '0' && c <= '9'))
  816. {
  817. *p++ = c;
  818. *p++ = '\002';
  819. in_escape = 0;
  820. }
  821. else
  822. *p++ = c;
  823. }
  824. if (in_escape)
  825. *p++ = '\002';
  826. *p = '\0';
  827. }
  828. else
  829. {
  830. memcpy (prompt, buf, buf_count);
  831. prompt[buf_count] = '\0';
  832. }
  833. DPRINT1("New prompt '%s'\n", prompt);
  834. if (buf_count > 0)
  835. write (1, "\r", 1);
  836. }
  837. rl_callback_handler_install (prompt, line_handler);
  838. }
  839. num_keys++;
  840. rl_callback_read_char ();
  841. }
  842. }
  843. else /* output from Kawa inferior. */
  844. {
  845. int i;
  846. int count;
  847. if (buf_count > (sizeof(buf) >> 2))
  848. buf_count = 0;
  849. count = read (in_from_inferior_fd, buf+buf_count,
  850. sizeof(buf) - buf_count);
  851. if (count <= 0)
  852. {
  853. DPRINT0 ("(Connection closed by inferior)\n");
  854. sig_child(-1);
  855. }
  856. DPRINT2("from inferior [%*.s]\n", count, buf+buf_count);
  857. #if SUPPORT_TELNET
  858. count = process_telnet_input (buf + buf_count, count);
  859. #endif
  860. write (1, buf + buf_count, count);
  861. buf_count += count;
  862. for (i = buf_count; --i >= buf_count - count; )
  863. {
  864. if (buf[i] == '\n' || buf[i] == '\r')
  865. {
  866. i++;
  867. memmove (buf, buf+i, buf_count - i);
  868. buf_count -= i;
  869. break;
  870. }
  871. }
  872. DPRINT2("-> i: %d, buf_count: %d\n", i, buf_count);
  873. }
  874. }
  875. }
  876. static void set_edit_mode ()
  877. {
  878. int vi = 0;
  879. char *shellopts;
  880. shellopts = getenv ("SHELLOPTS");
  881. while (shellopts != 0)
  882. {
  883. if (strncmp ("vi", shellopts, 2) == 0)
  884. {
  885. vi = 1;
  886. break;
  887. }
  888. shellopts = index (shellopts + 1, ':');
  889. }
  890. if (!vi)
  891. {
  892. if (getenv ("EDITOR") != 0)
  893. vi |= strcmp (getenv ("EDITOR"), "vi") == 0;
  894. }
  895. if (vi)
  896. rl_variable_bind ("editing-mode", "vi");
  897. else
  898. rl_variable_bind ("editing-mode", "emacs");
  899. }