lineedit.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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. for (BufChar *bc = le->head; bc; bc = bc->next)
  136. lineedit_send_data(le, make_ptrlen(bc->wire, bc->nwire));
  137. lineedit_free_buffer(le);
  138. le->quote_next_char = false;
  139. }
  140. static void lineedit_complete_line(TermLineEditor *le)
  141. {
  142. lineedit_term_newline(le);
  143. lineedit_send_line(le);
  144. lineedit_send_newline(le);
  145. }
  146. /*
  147. * Send data to the terminal to display a BufChar. As a side effect,
  148. * update bc->width to indicate how many character cells we think were
  149. * taken up by what we just wrote. No other change to bc is made.
  150. */
  151. static void lineedit_display_bufchar(TermLineEditor *le, BufChar *bc,
  152. unsigned chr)
  153. {
  154. char buf[6];
  155. buffer_sink bs[1];
  156. buffer_sink_init(bs, buf, lenof(buf));
  157. /* Handle single-byte character set translation. */
  158. if (!in_utf(le->term) && DIRECT_CHAR(chr)) {
  159. /*
  160. * If we're not in UTF-8, i.e. we're in a single-byte
  161. * character set, then first we must feed the input byte
  162. * through term_translate, which will tell us whether it's a
  163. * control character or not. (That varies with the charset:
  164. * e.g. ISO 8859-1 and Win1252 disagree on a lot of
  165. * 0x80-0x9F).
  166. *
  167. * In principle, we could pass NULL as our term_utf8_decode
  168. * pointer, on the grounds that since the terminal isn't in
  169. * UTF-8 mode term_translate shouldn't access it. But that
  170. * seems needlessly reckless; we'll make up an empty one.
  171. */
  172. term_utf8_decode dummy_utf8 = { .state = 0, .chr = 0, .size = 0 };
  173. chr = term_translate(
  174. le->term, &dummy_utf8, (unsigned char)chr);
  175. /*
  176. * After that, chr will be either a control-character value
  177. * (00-1F, 7F, 80-9F), or a byte value ORed with one of the
  178. * CSET_FOO character set indicators. The latter indicates
  179. * that it's a printing character in this charset, in which
  180. * case it takes up one character cell.
  181. */
  182. if (chr & CSET_MASK) {
  183. put_byte(bs, chr);
  184. bc->width = 1;
  185. goto got_char;
  186. }
  187. }
  188. /*
  189. * If we got here without taking the 'goto' above, then we're now
  190. * holding an actual Unicode character.
  191. */
  192. assert(!IS_SURROGATE(chr)); /* and it should be an _actual_ one */
  193. /*
  194. * Deal with symbolic representations of control characters.
  195. */
  196. if (chr < 0x20 || chr == 0x7F) {
  197. /*
  198. * Represent C0 controls as '^C' or similar, and 7F as ^?.
  199. */
  200. put_byte(bs, '^');
  201. put_byte(bs, chr ^ 0x40);
  202. bc->width = 2;
  203. goto got_char;
  204. }
  205. if (chr >= 0x80 && chr < 0xA0) {
  206. /*
  207. * Represent C1 controls as <9B> or similar.
  208. */
  209. put_fmt(bs, "<%02X>", chr);
  210. bc->width = 4;
  211. goto got_char;
  212. }
  213. /*
  214. * And if we get _here_, we're holding a printing (or at least not
  215. * _control_, even if zero-width) Unicode character, which _must_
  216. * mean that the terminal is currently in UTF-8 mode (since if it
  217. * were not then printing characters would have gone through the
  218. * term_translate case above). So we can just write the UTF-8 for
  219. * the character - but we must also pay attention to its width in
  220. * character cells, which might be 0, 1 or 2.
  221. */
  222. assert(in_utf(le->term));
  223. put_utf8_char(bs, chr);
  224. bc->width = term_char_width(le->term, chr);
  225. got_char:
  226. lineedit_term_write(le, make_ptrlen(buf, bs->out - buf));
  227. }
  228. /* Called when we've just added a byte to a UTF-8 character and want
  229. * to see if it's complete */
  230. static void lineedit_check_utf8_complete(TermLineEditor *le, BufChar *bc)
  231. {
  232. BinarySource src[1];
  233. BinarySource_BARE_INIT(src, bc->wire, bc->nwire);
  234. DecodeUTF8Failure err;
  235. unsigned chr = decode_utf8(src, &err);
  236. if (err == DUTF8_E_OUT_OF_DATA)
  237. return; /* not complete yet */
  238. /* Any other error code is regarded as complete, and we just
  239. * display the character as the U+FFFD that decode_utf8 will have
  240. * returned anyway */
  241. bc->complete = true;
  242. bc->space = (chr == ' ');
  243. lineedit_display_bufchar(le, bc, chr);
  244. }
  245. static void lineedit_input_printing_char(TermLineEditor *le, char ch);
  246. static void lineedit_redraw_line(TermLineEditor *le)
  247. {
  248. /* FIXME: I'm not 100% sure this is the behaviour I really want in
  249. * this situation, but it's at least very simple to implement */
  250. BufChar *prevhead = le->head;
  251. le->head = le->tail = NULL;
  252. while (prevhead) {
  253. BufChar *bc = prevhead;
  254. prevhead = prevhead->next;
  255. for (unsigned i = 0; i < bc->nwire; i++)
  256. lineedit_input_printing_char(le, bc->wire[i]);
  257. bufchar_free(bc);
  258. }
  259. }
  260. #define CTRL(c) ((char) (0x40 ^ (unsigned char)c))
  261. void lineedit_input(TermLineEditor *le, char ch, bool dedicated)
  262. {
  263. if (le->quote_next_char) {
  264. /*
  265. * If the previous keypress was ^V, 'quoting' the next
  266. * character to be treated literally, then skip all the
  267. * editing-control processing, and clear that flag.
  268. */
  269. le->quote_next_char = false;
  270. } else {
  271. /*
  272. * Input events that are only valid with the 'dedicated' flag.
  273. * These are limited to the control codes that _have_
  274. * dedicated keys.
  275. *
  276. * Any case we actually handle here ends with a 'return'
  277. * statement, so that if we fall out of the end of this switch
  278. * at all, it's because the byte hasn't been handled here and
  279. * will fall into the next switch dealing with ordinary input.
  280. */
  281. if (dedicated) {
  282. switch (ch) {
  283. /*
  284. * The Backspace key.
  285. *
  286. * Since our terminal can be configured to send either
  287. * ^H or 7F (aka ^?) via the backspace key, we accept
  288. * both.
  289. *
  290. * (We could query the Terminal's configuration here
  291. * and accept only the one of those codes that the
  292. * terminal is currently set to. But it's pointless,
  293. * because whichever one the terminal isn't set to,
  294. * the front end won't be sending it with
  295. * dedicated=true anyway.)
  296. */
  297. case CTRL('H'):
  298. case 0x7F:
  299. lineedit_delete_char(le);
  300. return;
  301. /*
  302. * The Return key.
  303. */
  304. case CTRL('M'):
  305. lineedit_complete_line(le);
  306. return;
  307. }
  308. }
  309. /*
  310. * Editing and special functions in response to ordinary keys
  311. * or Ctrl+key combinations. Many editing functions have to be
  312. * supported in this mode, like ^W and ^U, because there are
  313. * no dedicated keys that generate the same control codes
  314. * anyway.
  315. *
  316. * Again, we return if the key was handled. The final
  317. * processing of ordinary data to go into the input buffer
  318. * happens if we break from this switch.
  319. */
  320. switch (ch) {
  321. case CTRL('W'):
  322. lineedit_delete_word(le);
  323. return;
  324. case CTRL('U'):
  325. lineedit_delete_line(le);
  326. return;
  327. case CTRL('['):
  328. if (!(le->flags & LE_ESC_ERASES))
  329. break; /* treat as normal input */
  330. lineedit_delete_line(le);
  331. return;
  332. case CTRL('R'):
  333. lineedit_term_write(le, PTRLEN_LITERAL("^R"));
  334. lineedit_term_newline(le);
  335. lineedit_redraw_line(le);
  336. return;
  337. case CTRL('V'):
  338. le->quote_next_char = true;
  339. return;
  340. case CTRL('C'):
  341. lineedit_delete_line(le);
  342. if (!(le->flags & LE_INTERRUPT))
  343. break; /* treat as normal input */
  344. lineedit_special(le, SS_IP, 0);
  345. return;
  346. case CTRL('Z'):
  347. lineedit_delete_line(le);
  348. if (!(le->flags & LE_SUSPEND))
  349. break; /* treat as normal input */
  350. lineedit_special(le, SS_SUSP, 0);
  351. return;
  352. case CTRL('\\'):
  353. lineedit_delete_line(le);
  354. if (!(le->flags & LE_ABORT))
  355. break; /* treat as normal input */
  356. lineedit_special(le, SS_ABORT, 0);
  357. return;
  358. case CTRL('D'):
  359. if (le->flags & LE_EOF_ALWAYS) {
  360. /* Our client wants to treat ^D / EOF as a special
  361. * character in their own way. Just send an EOF
  362. * special. */
  363. lineedit_special(le, SS_EOF, 0);
  364. return;
  365. }
  366. /*
  367. * Otherwise, ^D has the same behaviour as in Unix tty
  368. * line editing: if the edit buffer is non-empty then it's
  369. * sent immediately without a newline, and if it is empty
  370. * then an EOF is sent.
  371. */
  372. if (le->head) {
  373. lineedit_send_line(le);
  374. return;
  375. }
  376. lineedit_special(le, SS_EOF, 0);
  377. return;
  378. case CTRL('J'):
  379. if (le->flags & LE_CRLF_NEWLINE) {
  380. /*
  381. * If the previous character in the buffer is a
  382. * literal Ctrl-M, and now the user sends Ctrl-J, then
  383. * we amalgamate both into a newline event.
  384. */
  385. if (le->tail && le->tail->nwire == 1 &&
  386. le->tail->wire[0] == CTRL('M')) {
  387. lineedit_delete_char(le); /* erase ^J from buffer */
  388. lineedit_complete_line(le);
  389. return;
  390. }
  391. }
  392. }
  393. }
  394. /*
  395. * If we get to here, we've exhausted the options for treating our
  396. * character as an editing or special function of any kind. Treat
  397. * it as a printing character, or part of one.
  398. */
  399. lineedit_input_printing_char(le, ch);
  400. }
  401. static void lineedit_input_printing_char(TermLineEditor *le, char ch)
  402. {
  403. /*
  404. * Append ch to the line buffer, either as a new BufChar or by
  405. * adding it to a previous one containing an as yet incomplete
  406. * UTF-8 encoding.
  407. */
  408. if (le->tail && !le->tail->complete) {
  409. BufChar *bc = le->tail;
  410. /*
  411. * If we're in UTF-8 mode, and ch is a UTF-8 continuation
  412. * byte, then we can append it to bc, which we've just checked
  413. * is missing at least one of those.
  414. */
  415. if (in_utf(le->term) && (unsigned char)ch - 0x80U < 0x40) {
  416. assert(bc->nwire < lenof(bc->wire));
  417. bc->wire[bc->nwire++] = ch;
  418. lineedit_check_utf8_complete(le, bc);
  419. return;
  420. }
  421. /*
  422. * Otherwise, the previous incomplete character can't be
  423. * extended. Mark it as complete, and if possible, display it
  424. * as a replacement character indicating that something weird
  425. * happened.
  426. */
  427. bc->complete = true;
  428. if (in_utf(le->term))
  429. lineedit_display_bufchar(le, bc, 0xFFFD);
  430. /*
  431. * But we still haven't processed the byte we're holding. Fall
  432. * through to the next step, where we make a fresh BufChar for
  433. * it.
  434. */
  435. }
  436. /*
  437. * Make a fresh BufChar.
  438. */
  439. BufChar *bc = snew(BufChar);
  440. bc->prev = le->tail;
  441. le->tail = bc;
  442. if (bc->prev)
  443. bc->prev->next = bc;
  444. else
  445. le->head = bc;
  446. bc->next = NULL;
  447. bc->complete = false;
  448. bc->space = false;
  449. bc->nwire = 1;
  450. bc->wire[0] = ch;
  451. if (in_utf(le->term)) {
  452. lineedit_check_utf8_complete(le, bc);
  453. } else {
  454. bc->complete = true; /* always, in a single-byte charset */
  455. bc->space = (bc->wire[0] == ' ');
  456. lineedit_display_bufchar(le, bc, CSET_ASCII | (unsigned char)ch);
  457. }
  458. }