lineedit.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /*
  2. * Implementation of local line editing. Used during username and
  3. * password input at login time, and also by ldisc during the main
  4. * session (if the session's virtual terminal is in that mode).
  5. *
  6. * Because we're tied into a real GUI terminal (and not a completely
  7. * standalone line-discipline module that deals purely with byte
  8. * streams), we can support a slightly richer input interface than
  9. * plain bytes.
  10. *
  11. * In particular, the 'dedicated' flag sent along with every byte is
  12. * used to distinguish control codes input via Ctrl+letter from the
  13. * same code input by a dedicated key like Return or Backspace. This
  14. * allows us to interpret the Ctrl+letter key combination as inputting
  15. * a literal control character to go into the line buffer, and the
  16. * dedicated-key version as performing an editing function.
  17. */
  18. #include "putty.h"
  19. #include "terminal.h"
  20. typedef struct BufChar BufChar;
  21. struct TermLineEditor {
  22. Terminal *term;
  23. BufChar *head, *tail;
  24. unsigned flags;
  25. bool quote_next_char;
  26. TermLineEditorCallbackReceiver *receiver;
  27. };
  28. struct BufChar {
  29. BufChar *prev, *next;
  30. /* The bytes of the character, to be sent on the wire */
  31. char wire[6];
  32. uint8_t nwire;
  33. /* Whether this character is considered complete */
  34. bool complete;
  35. /* Width of the character when it was displayed, in terminal cells */
  36. uint8_t width;
  37. /* Whether this character counts as whitespace, for ^W purposes */
  38. bool space;
  39. };
  40. TermLineEditor *lineedit_new(Terminal *term, unsigned flags,
  41. TermLineEditorCallbackReceiver *receiver)
  42. {
  43. TermLineEditor *le = snew(TermLineEditor);
  44. le->term = term;
  45. le->head = le->tail = NULL;
  46. le->flags = flags;
  47. le->quote_next_char = false;
  48. le->receiver = receiver;
  49. return le;
  50. }
  51. static void bufchar_free(BufChar *bc)
  52. {
  53. smemclr(bc, sizeof(*bc));
  54. sfree(bc);
  55. }
  56. static void lineedit_free_buffer(TermLineEditor *le)
  57. {
  58. while (le->head) {
  59. BufChar *bc = le->head;
  60. le->head = bc->next;
  61. bufchar_free(bc);
  62. }
  63. le->tail = NULL;
  64. }
  65. void lineedit_free(TermLineEditor *le)
  66. {
  67. lineedit_free_buffer(le);
  68. sfree(le);
  69. }
  70. void lineedit_modify_flags(TermLineEditor *le, unsigned clr, unsigned flip)
  71. {
  72. le->flags &= ~clr;
  73. le->flags ^= flip;
  74. }
  75. static void lineedit_term_write(TermLineEditor *le, ptrlen data)
  76. {
  77. le->receiver->vt->to_terminal(le->receiver, data);
  78. }
  79. static void lineedit_term_newline(TermLineEditor *le)
  80. {
  81. lineedit_term_write(le, PTRLEN_LITERAL("\x0D\x0A"));
  82. }
  83. static inline void lineedit_send_data(TermLineEditor *le, ptrlen data)
  84. {
  85. le->receiver->vt->to_backend(le->receiver, data);
  86. }
  87. static inline void lineedit_special(TermLineEditor *le,
  88. SessionSpecialCode code, int arg)
  89. {
  90. le->receiver->vt->special(le->receiver, code, arg);
  91. }
  92. static inline void lineedit_send_newline(TermLineEditor *le)
  93. {
  94. le->receiver->vt->newline(le->receiver);
  95. }
  96. static void lineedit_delete_char(TermLineEditor *le)
  97. {
  98. if (le->tail) {
  99. BufChar *bc = le->tail;
  100. le->tail = bc->prev;
  101. if (!le->tail)
  102. le->head = NULL;
  103. else
  104. le->tail->next = NULL;
  105. for (unsigned i = 0; i < bc->width; i++)
  106. lineedit_term_write(le, PTRLEN_LITERAL("\x08 \x08"));
  107. bufchar_free(bc);
  108. }
  109. }
  110. static void lineedit_delete_word(TermLineEditor *le)
  111. {
  112. /*
  113. * Deleting a word stops at the _start_ of a word, i.e. at any
  114. * boundary with a space on the left and a non-space on the right.
  115. */
  116. if (!le->tail)
  117. return;
  118. while (true) {
  119. bool deleted_char_is_space = le->tail->space;
  120. lineedit_delete_char(le);
  121. if (!le->tail)
  122. break; /* we've cleared the whole line */
  123. if (le->tail->space && !deleted_char_is_space)
  124. break; /* we've just reached a word boundary */
  125. }
  126. }
  127. static void lineedit_delete_line(TermLineEditor *le)
  128. {
  129. while (le->tail)
  130. lineedit_delete_char(le);
  131. lineedit_special(le, SS_EL, 0);
  132. }
  133. void lineedit_send_line(TermLineEditor *le)
  134. {
  135. bufchain output;
  136. bufchain_init(&output);
  137. for (BufChar *bc = le->head; bc; bc = bc->next)
  138. bufchain_add(&output, bc->wire, bc->nwire);
  139. while (bufchain_size(&output) > 0) {
  140. ptrlen data = bufchain_prefix(&output);
  141. lineedit_send_data(le, data);
  142. bufchain_consume(&output, data.len);
  143. }
  144. bufchain_clear(&output);
  145. lineedit_free_buffer(le);
  146. le->quote_next_char = false;
  147. }
  148. static void lineedit_complete_line(TermLineEditor *le)
  149. {
  150. lineedit_term_newline(le);
  151. lineedit_send_line(le);
  152. lineedit_send_newline(le);
  153. }
  154. /*
  155. * Send data to the terminal to display a BufChar. As a side effect,
  156. * update bc->width to indicate how many character cells we think were
  157. * taken up by what we just wrote. No other change to bc is made.
  158. */
  159. static void lineedit_display_bufchar(TermLineEditor *le, BufChar *bc,
  160. unsigned chr)
  161. {
  162. char buf[6];
  163. buffer_sink bs[1];
  164. buffer_sink_init(bs, buf, lenof(buf));
  165. /* Handle single-byte character set translation. */
  166. if (!in_utf(le->term) && DIRECT_CHAR(chr)) {
  167. /*
  168. * If we're not in UTF-8, i.e. we're in a single-byte
  169. * character set, then first we must feed the input byte
  170. * through term_translate, which will tell us whether it's a
  171. * control character or not. (That varies with the charset:
  172. * e.g. ISO 8859-1 and Win1252 disagree on a lot of
  173. * 0x80-0x9F).
  174. *
  175. * In principle, we could pass NULL as our term_utf8_decode
  176. * pointer, on the grounds that since the terminal isn't in
  177. * UTF-8 mode term_translate shouldn't access it. But that
  178. * seems needlessly reckless; we'll make up an empty one.
  179. */
  180. term_utf8_decode dummy_utf8 = { .state = 0, .chr = 0, .size = 0 };
  181. chr = term_translate(
  182. le->term, &dummy_utf8, (unsigned char)chr);
  183. /*
  184. * After that, chr will be either a control-character value
  185. * (00-1F, 7F, 80-9F), or a byte value ORed with one of the
  186. * CSET_FOO character set indicators. The latter indicates
  187. * that it's a printing character in this charset, in which
  188. * case it takes up one character cell.
  189. */
  190. if (chr & CSET_MASK) {
  191. put_byte(bs, chr);
  192. bc->width = 1;
  193. goto got_char;
  194. }
  195. }
  196. /*
  197. * If we got here without taking the 'goto' above, then we're now
  198. * holding an actual Unicode character.
  199. */
  200. assert(!IS_SURROGATE(chr)); /* and it should be an _actual_ one */
  201. /*
  202. * Deal with symbolic representations of control characters.
  203. */
  204. if (chr < 0x20 || chr == 0x7F) {
  205. /*
  206. * Represent C0 controls as '^C' or similar, and 7F as ^?.
  207. */
  208. put_byte(bs, '^');
  209. put_byte(bs, chr ^ 0x40);
  210. bc->width = 2;
  211. goto got_char;
  212. }
  213. if (chr >= 0x80 && chr < 0xA0) {
  214. /*
  215. * Represent C1 controls as <9B> or similar.
  216. */
  217. put_fmt(bs, "<%02X>", chr);
  218. bc->width = 4;
  219. goto got_char;
  220. }
  221. /*
  222. * And if we get _here_, we're holding a printing (or at least not
  223. * _control_, even if zero-width) Unicode character, which _must_
  224. * mean that the terminal is currently in UTF-8 mode (since if it
  225. * were not then printing characters would have gone through the
  226. * term_translate case above). So we can just write the UTF-8 for
  227. * the character - but we must also pay attention to its width in
  228. * character cells, which might be 0, 1 or 2.
  229. */
  230. assert(in_utf(le->term));
  231. put_utf8_char(bs, chr);
  232. bc->width = term_char_width(le->term, chr);
  233. got_char:
  234. lineedit_term_write(le, make_ptrlen(buf, bs->out - buf));
  235. }
  236. /* Called when we've just added a byte to a UTF-8 character and want
  237. * to see if it's complete */
  238. static void lineedit_check_utf8_complete(TermLineEditor *le, BufChar *bc)
  239. {
  240. BinarySource src[1];
  241. BinarySource_BARE_INIT(src, bc->wire, bc->nwire);
  242. DecodeUTF8Failure err;
  243. unsigned chr = decode_utf8(src, &err);
  244. if (err == DUTF8_E_OUT_OF_DATA)
  245. return; /* not complete yet */
  246. /* Any other error code is regarded as complete, and we just
  247. * display the character as the U+FFFD that decode_utf8 will have
  248. * returned anyway */
  249. bc->complete = true;
  250. bc->space = (chr == ' ');
  251. lineedit_display_bufchar(le, bc, chr);
  252. }
  253. static void lineedit_input_printing_char(TermLineEditor *le, char ch);
  254. static void lineedit_redraw_line(TermLineEditor *le)
  255. {
  256. /* FIXME: I'm not 100% sure this is the behaviour I really want in
  257. * this situation, but it's at least very simple to implement */
  258. BufChar *prevhead = le->head;
  259. le->head = le->tail = NULL;
  260. while (prevhead) {
  261. BufChar *bc = prevhead;
  262. prevhead = prevhead->next;
  263. for (unsigned i = 0; i < bc->nwire; i++)
  264. lineedit_input_printing_char(le, bc->wire[i]);
  265. bufchar_free(bc);
  266. }
  267. }
  268. #define CTRL(c) ((char) (0x40 ^ (unsigned char)c))
  269. void lineedit_input(TermLineEditor *le, char ch, bool dedicated)
  270. {
  271. if (le->quote_next_char) {
  272. /*
  273. * If the previous keypress was ^V, 'quoting' the next
  274. * character to be treated literally, then skip all the
  275. * editing-control processing, and clear that flag.
  276. */
  277. le->quote_next_char = false;
  278. } else {
  279. /*
  280. * Input events that are only valid with the 'dedicated' flag.
  281. * These are limited to the control codes that _have_
  282. * dedicated keys.
  283. *
  284. * Any case we actually handle here ends with a 'return'
  285. * statement, so that if we fall out of the end of this switch
  286. * at all, it's because the byte hasn't been handled here and
  287. * will fall into the next switch dealing with ordinary input.
  288. */
  289. if (dedicated) {
  290. switch (ch) {
  291. /*
  292. * The Backspace key.
  293. *
  294. * Since our terminal can be configured to send either
  295. * ^H or 7F (aka ^?) via the backspace key, we accept
  296. * both.
  297. *
  298. * (We could query the Terminal's configuration here
  299. * and accept only the one of those codes that the
  300. * terminal is currently set to. But it's pointless,
  301. * because whichever one the terminal isn't set to,
  302. * the front end won't be sending it with
  303. * dedicated=true anyway.)
  304. */
  305. case CTRL('H'):
  306. case 0x7F:
  307. lineedit_delete_char(le);
  308. return;
  309. /*
  310. * The Return key.
  311. */
  312. case CTRL('M'):
  313. lineedit_complete_line(le);
  314. return;
  315. }
  316. }
  317. /*
  318. * Editing and special functions in response to ordinary keys
  319. * or Ctrl+key combinations. Many editing functions have to be
  320. * supported in this mode, like ^W and ^U, because there are
  321. * no dedicated keys that generate the same control codes
  322. * anyway.
  323. *
  324. * Again, we return if the key was handled. The final
  325. * processing of ordinary data to go into the input buffer
  326. * happens if we break from this switch.
  327. */
  328. switch (ch) {
  329. case CTRL('W'):
  330. lineedit_delete_word(le);
  331. return;
  332. case CTRL('U'):
  333. lineedit_delete_line(le);
  334. return;
  335. case CTRL('['):
  336. if (!(le->flags & LE_ESC_ERASES))
  337. break; /* treat as normal input */
  338. lineedit_delete_line(le);
  339. return;
  340. case CTRL('R'):
  341. lineedit_term_write(le, PTRLEN_LITERAL("^R"));
  342. lineedit_term_newline(le);
  343. lineedit_redraw_line(le);
  344. return;
  345. case CTRL('V'):
  346. le->quote_next_char = true;
  347. return;
  348. case CTRL('C'):
  349. lineedit_delete_line(le);
  350. if (!(le->flags & LE_INTERRUPT))
  351. break; /* treat as normal input */
  352. lineedit_special(le, SS_IP, 0);
  353. return;
  354. case CTRL('Z'):
  355. lineedit_delete_line(le);
  356. if (!(le->flags & LE_SUSPEND))
  357. break; /* treat as normal input */
  358. lineedit_special(le, SS_SUSP, 0);
  359. return;
  360. case CTRL('\\'):
  361. lineedit_delete_line(le);
  362. if (!(le->flags & LE_ABORT))
  363. break; /* treat as normal input */
  364. lineedit_special(le, SS_ABORT, 0);
  365. return;
  366. case CTRL('D'):
  367. if (le->flags & LE_EOF_ALWAYS) {
  368. /* Our client wants to treat ^D / EOF as a special
  369. * character in their own way. Just send an EOF
  370. * special. */
  371. lineedit_special(le, SS_EOF, 0);
  372. return;
  373. }
  374. /*
  375. * Otherwise, ^D has the same behaviour as in Unix tty
  376. * line editing: if the edit buffer is non-empty then it's
  377. * sent immediately without a newline, and if it is empty
  378. * then an EOF is sent.
  379. */
  380. if (le->head) {
  381. lineedit_send_line(le);
  382. return;
  383. }
  384. lineedit_special(le, SS_EOF, 0);
  385. return;
  386. case CTRL('J'):
  387. if (le->flags & LE_CRLF_NEWLINE) {
  388. /*
  389. * If the previous character in the buffer is a
  390. * literal Ctrl-M, and now the user sends Ctrl-J, then
  391. * we amalgamate both into a newline event.
  392. */
  393. if (le->tail && le->tail->nwire == 1 &&
  394. le->tail->wire[0] == CTRL('M')) {
  395. lineedit_delete_char(le); /* erase ^J from buffer */
  396. lineedit_complete_line(le);
  397. return;
  398. }
  399. } else {
  400. /* If we're not in LE_CRLF_NEWLINE mode, then ^J by
  401. * itself acts as a full newline character */
  402. lineedit_complete_line(le);
  403. return;
  404. }
  405. case CTRL('M'):
  406. if (le->flags & LE_CRLF_NEWLINE) {
  407. /* In this mode, ^M is literal, and can combine with
  408. * ^J (see case above). So do nothing, and fall
  409. * through into the 'treat it literally' code, */
  410. } else {
  411. /* If we're not in LE_CRLF_NEWLINE mode, then ^M by
  412. * itself acts as a full newline character */
  413. lineedit_complete_line(le);
  414. return;
  415. }
  416. }
  417. }
  418. /*
  419. * If we get to here, we've exhausted the options for treating our
  420. * character as an editing or special function of any kind. Treat
  421. * it as a printing character, or part of one.
  422. */
  423. lineedit_input_printing_char(le, ch);
  424. }
  425. static void lineedit_input_printing_char(TermLineEditor *le, char ch)
  426. {
  427. /*
  428. * Append ch to the line buffer, either as a new BufChar or by
  429. * adding it to a previous one containing an as yet incomplete
  430. * UTF-8 encoding.
  431. */
  432. if (le->tail && !le->tail->complete) {
  433. BufChar *bc = le->tail;
  434. /*
  435. * If we're in UTF-8 mode, and ch is a UTF-8 continuation
  436. * byte, then we can append it to bc, which we've just checked
  437. * is missing at least one of those.
  438. */
  439. if (in_utf(le->term) && (unsigned char)ch - 0x80U < 0x40) {
  440. assert(bc->nwire < lenof(bc->wire));
  441. bc->wire[bc->nwire++] = ch;
  442. lineedit_check_utf8_complete(le, bc);
  443. return;
  444. }
  445. /*
  446. * Otherwise, the previous incomplete character can't be
  447. * extended. Mark it as complete, and if possible, display it
  448. * as a replacement character indicating that something weird
  449. * happened.
  450. */
  451. bc->complete = true;
  452. if (in_utf(le->term))
  453. lineedit_display_bufchar(le, bc, 0xFFFD);
  454. /*
  455. * But we still haven't processed the byte we're holding. Fall
  456. * through to the next step, where we make a fresh BufChar for
  457. * it.
  458. */
  459. }
  460. /*
  461. * Make a fresh BufChar.
  462. */
  463. BufChar *bc = snew(BufChar);
  464. bc->prev = le->tail;
  465. le->tail = bc;
  466. if (bc->prev)
  467. bc->prev->next = bc;
  468. else
  469. le->head = bc;
  470. bc->next = NULL;
  471. bc->complete = false;
  472. bc->space = false;
  473. bc->nwire = 1;
  474. bc->wire[0] = ch;
  475. if (in_utf(le->term)) {
  476. lineedit_check_utf8_complete(le, bc);
  477. } else {
  478. bc->complete = true; /* always, in a single-byte charset */
  479. bc->space = (bc->wire[0] == ' ');
  480. lineedit_display_bufchar(le, bc, CSET_ASCII | (unsigned char)ch);
  481. }
  482. }