refresh.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. /* $NetBSD: refresh.c,v 1.18 2002/03/18 16:00:58 christos Exp $ */
  2. /*-
  3. * Copyright (c) 1992, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * This code is derived from software contributed to Berkeley by
  7. * Christos Zoulas of Cornell University.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. All advertising materials mentioning features or use of this software
  18. * must display the following acknowledgement:
  19. * This product includes software developed by the University of
  20. * California, Berkeley and its contributors.
  21. * 4. Neither the name of the University nor the names of its contributors
  22. * may be used to endorse or promote products derived from this software
  23. * without specific prior written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35. * SUCH DAMAGE.
  36. */
  37. #include "config.h"
  38. #if !defined(lint) && !defined(SCCSID)
  39. #if 0
  40. static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93";
  41. #else
  42. __RCSID("$NetBSD: refresh.c,v 1.18 2002/03/18 16:00:58 christos Exp $");
  43. #endif
  44. #endif /* not lint && not SCCSID */
  45. /*
  46. * refresh.c: Lower level screen refreshing functions
  47. */
  48. #include <stdio.h>
  49. #include <ctype.h>
  50. #include <unistd.h>
  51. #include <string.h>
  52. #include "el.h"
  53. private void re_addc(EditLine *, int);
  54. private void re_update_line(EditLine *, char *, char *, int);
  55. private void re_insert (EditLine *, char *, int, int, char *, int);
  56. private void re_delete(EditLine *, char *, int, int, int);
  57. private void re_fastputc(EditLine *, int);
  58. private void re__strncopy(char *, char *, size_t);
  59. private void re__copy_and_pad(char *, const char *, size_t);
  60. #ifdef DEBUG_REFRESH
  61. private void re_printstr(EditLine *, char *, char *, char *);
  62. #define __F el->el_errfile
  63. #define ELRE_ASSERT(a, b, c) do \
  64. if (a) { \
  65. (void) fprintf b; \
  66. c; \
  67. } \
  68. while (0)
  69. #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;)
  70. /* re_printstr():
  71. * Print a string on the debugging pty
  72. */
  73. private void
  74. re_printstr(EditLine *el, char *str, char *f, char *t)
  75. {
  76. ELRE_DEBUG(1, (__F, "%s:\"", str));
  77. while (f < t)
  78. ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
  79. ELRE_DEBUG(1, (__F, "\"\r\n"));
  80. }
  81. #else
  82. #define ELRE_ASSERT(a, b, c)
  83. #define ELRE_DEBUG(a, b)
  84. #endif
  85. /* re_addc():
  86. * Draw c, expanding tabs, control chars etc.
  87. */
  88. private void
  89. re_addc(EditLine *el, int c)
  90. {
  91. if (isprint(c)) {
  92. re_putc(el, c, 1);
  93. return;
  94. }
  95. if (c == '\n') { /* expand the newline */
  96. int oldv = el->el_refresh.r_cursor.v;
  97. re_putc(el, '\0', 0); /* assure end of line */
  98. if (oldv == el->el_refresh.r_cursor.v) { /* XXX */
  99. el->el_refresh.r_cursor.h = 0; /* reset cursor pos */
  100. el->el_refresh.r_cursor.v++;
  101. }
  102. return;
  103. }
  104. if (c == '\t') { /* expand the tab */
  105. for (;;) {
  106. re_putc(el, ' ', 1);
  107. if ((el->el_refresh.r_cursor.h & 07) == 0)
  108. break; /* go until tab stop */
  109. }
  110. } else if (iscntrl(c)) {
  111. re_putc(el, '^', 1);
  112. if (c == '\177')
  113. re_putc(el, '?', 1);
  114. else
  115. /* uncontrolify it; works only for iso8859-1 like sets */
  116. re_putc(el, (c | 0100), 1);
  117. } else {
  118. re_putc(el, '\\', 1);
  119. re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1);
  120. re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1);
  121. re_putc(el, (c & 07) + '0', 1);
  122. }
  123. }
  124. /* re_putc():
  125. * Draw the character given
  126. */
  127. protected void
  128. re_putc(EditLine *el, int c, int shift)
  129. {
  130. ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
  131. el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
  132. if (!shift)
  133. return;
  134. el->el_refresh.r_cursor.h++; /* advance to next place */
  135. if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
  136. el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] = '\0';
  137. /* assure end of line */
  138. el->el_refresh.r_cursor.h = 0; /* reset it. */
  139. /*
  140. * If we would overflow (input is longer than terminal size),
  141. * emulate scroll by dropping first line and shuffling the rest.
  142. * We do this via pointer shuffling - it's safe in this case
  143. * and we avoid memcpy().
  144. */
  145. if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) {
  146. int i, lins = el->el_term.t_size.v;
  147. char *firstline = el->el_vdisplay[0];
  148. for(i=1; i < lins; i++)
  149. el->el_vdisplay[i-1] = el->el_vdisplay[i];
  150. firstline[0] = '\0'; /* empty the string */
  151. el->el_vdisplay[i-1] = firstline;
  152. } else
  153. el->el_refresh.r_cursor.v++;
  154. ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
  155. (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
  156. el->el_refresh.r_cursor.v, el->el_term.t_size.v),
  157. abort());
  158. }
  159. }
  160. /* re_refresh():
  161. * draws the new virtual screen image from the current input
  162. * line, then goes line-by-line changing the real image to the new
  163. * virtual image. The routine to re-draw a line can be replaced
  164. * easily in hopes of a smarter one being placed there.
  165. */
  166. protected void
  167. re_refresh(EditLine *el)
  168. {
  169. int i, rhdiff;
  170. char *cp, *st;
  171. coord_t cur;
  172. #ifdef notyet
  173. size_t termsz;
  174. #endif
  175. ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
  176. el->el_line.buffer));
  177. /* reset the Drawing cursor */
  178. el->el_refresh.r_cursor.h = 0;
  179. el->el_refresh.r_cursor.v = 0;
  180. /* temporarily draw rprompt to calculate its size */
  181. prompt_print(el, EL_RPROMPT);
  182. /* reset the Drawing cursor */
  183. el->el_refresh.r_cursor.h = 0;
  184. el->el_refresh.r_cursor.v = 0;
  185. cur.h = -1; /* set flag in case I'm not set */
  186. cur.v = 0;
  187. prompt_print(el, EL_PROMPT);
  188. /* draw the current input buffer */
  189. #ifdef notyet
  190. termsz = el->el_term.t_size.h * el->el_term.t_size.v;
  191. if (el->el_line.lastchar - el->el_line.buffer > termsz) {
  192. /*
  193. * If line is longer than terminal, process only part
  194. * of line which would influence display.
  195. */
  196. size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
  197. st = el->el_line.lastchar - rem
  198. - (termsz - (((rem / el->el_term.t_size.v) - 1)
  199. * el->el_term.t_size.v));
  200. } else
  201. #endif
  202. st = el->el_line.buffer;
  203. for (cp = st; cp < el->el_line.lastchar; cp++) {
  204. if (cp == el->el_line.cursor) {
  205. /* save for later */
  206. cur.h = el->el_refresh.r_cursor.h;
  207. cur.v = el->el_refresh.r_cursor.v;
  208. }
  209. re_addc(el, (unsigned char) *cp);
  210. }
  211. if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
  212. cur.h = el->el_refresh.r_cursor.h;
  213. cur.v = el->el_refresh.r_cursor.v;
  214. }
  215. rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h -
  216. el->el_rprompt.p_pos.h;
  217. if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
  218. !el->el_refresh.r_cursor.v && rhdiff > 1) {
  219. /*
  220. * have a right-hand side prompt that will fit
  221. * on the end of the first line with at least
  222. * one character gap to the input buffer.
  223. */
  224. while (--rhdiff > 0) /* pad out with spaces */
  225. re_putc(el, ' ', 1);
  226. prompt_print(el, EL_RPROMPT);
  227. } else {
  228. el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */
  229. el->el_rprompt.p_pos.v = 0;
  230. }
  231. re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */
  232. el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
  233. ELRE_DEBUG(1, (__F,
  234. "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
  235. el->el_term.t_size.h, el->el_refresh.r_cursor.h,
  236. el->el_refresh.r_cursor.v, el->el_vdisplay[0]));
  237. ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
  238. for (i = 0; i <= el->el_refresh.r_newcv; i++) {
  239. /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
  240. re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
  241. /*
  242. * Copy the new line to be the current one, and pad out with
  243. * spaces to the full width of the terminal so that if we try
  244. * moving the cursor by writing the character that is at the
  245. * end of the screen line, it won't be a NUL or some old
  246. * leftover stuff.
  247. */
  248. re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
  249. (size_t) el->el_term.t_size.h);
  250. }
  251. ELRE_DEBUG(1, (__F,
  252. "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
  253. el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
  254. if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
  255. for (; i <= el->el_refresh.r_oldcv; i++) {
  256. term_move_to_line(el, i);
  257. term_move_to_char(el, 0);
  258. term_clear_EOL(el, (int) strlen(el->el_display[i]));
  259. #ifdef DEBUG_REFRESH
  260. term_overwrite(el, "C\b", 2);
  261. #endif /* DEBUG_REFRESH */
  262. el->el_display[i][0] = '\0';
  263. }
  264. el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
  265. ELRE_DEBUG(1, (__F,
  266. "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
  267. el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
  268. cur.h, cur.v));
  269. term_move_to_line(el, cur.v); /* go to where the cursor is */
  270. term_move_to_char(el, cur.h);
  271. }
  272. /* re_goto_bottom():
  273. * used to go to last used screen line
  274. */
  275. protected void
  276. re_goto_bottom(EditLine *el)
  277. {
  278. term_move_to_line(el, el->el_refresh.r_oldcv);
  279. term__putc('\r');
  280. term__putc('\n');
  281. re_clear_display(el);
  282. term__flush();
  283. }
  284. /* re_insert():
  285. * insert num characters of s into d (in front of the character)
  286. * at dat, maximum length of d is dlen
  287. */
  288. private void
  289. /*ARGSUSED*/
  290. re_insert(EditLine *el, char *d, int dat, int dlen, char *s, int num)
  291. {
  292. char *a, *b;
  293. if (num <= 0)
  294. return;
  295. if (num > dlen - dat)
  296. num = dlen - dat;
  297. ELRE_DEBUG(1,
  298. (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
  299. num, dat, dlen, d));
  300. ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
  301. /* open up the space for num chars */
  302. if (num > 0) {
  303. b = d + dlen - 1;
  304. a = b - num;
  305. while (a >= &d[dat])
  306. *b-- = *a--;
  307. d[dlen] = '\0'; /* just in case */
  308. }
  309. ELRE_DEBUG(1, (__F,
  310. "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
  311. num, dat, dlen, d));
  312. ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
  313. /* copy the characters */
  314. for (a = d + dat; (a < d + dlen) && (num > 0); num--)
  315. *a++ = *s++;
  316. ELRE_DEBUG(1,
  317. (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
  318. num, dat, dlen, d, s));
  319. ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
  320. }
  321. /* re_delete():
  322. * delete num characters d at dat, maximum length of d is dlen
  323. */
  324. private void
  325. /*ARGSUSED*/
  326. re_delete(EditLine *el, char *d, int dat, int dlen, int num)
  327. {
  328. char *a, *b;
  329. if (num <= 0)
  330. return;
  331. if (dat + num >= dlen) {
  332. d[dat] = '\0';
  333. return;
  334. }
  335. ELRE_DEBUG(1,
  336. (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
  337. num, dat, dlen, d));
  338. /* open up the space for num chars */
  339. if (num > 0) {
  340. b = d + dat;
  341. a = b + num;
  342. while (a < &d[dlen])
  343. *b++ = *a++;
  344. d[dlen] = '\0'; /* just in case */
  345. }
  346. ELRE_DEBUG(1,
  347. (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
  348. num, dat, dlen, d));
  349. }
  350. /* re__strncopy():
  351. * Like strncpy without padding.
  352. */
  353. private void
  354. re__strncopy(char *a, char *b, size_t n)
  355. {
  356. while (n-- && *b)
  357. *a++ = *b++;
  358. }
  359. /*****************************************************************
  360. re_update_line() is based on finding the middle difference of each line
  361. on the screen; vis:
  362. /old first difference
  363. /beginning of line | /old last same /old EOL
  364. v v v v
  365. old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
  366. new: eddie> Oh, my little buggy says to me, as lurgid as
  367. ^ ^ ^ ^
  368. \beginning of line | \new last same \new end of line
  369. \new first difference
  370. all are character pointers for the sake of speed. Special cases for
  371. no differences, as well as for end of line additions must be handled.
  372. **************************************************************** */
  373. /* Minimum at which doing an insert it "worth it". This should be about
  374. * half the "cost" of going into insert mode, inserting a character, and
  375. * going back out. This should really be calculated from the termcap
  376. * data... For the moment, a good number for ANSI terminals.
  377. */
  378. #define MIN_END_KEEP 4
  379. private void
  380. re_update_line(EditLine *el, char *old, char *new, int i)
  381. {
  382. char *o, *n, *p, c;
  383. char *ofd, *ols, *oe, *nfd, *nls, *ne;
  384. char *osb, *ose, *nsb, *nse;
  385. int fx, sx;
  386. /*
  387. * find first diff
  388. */
  389. for (o = old, n = new; *o && (*o == *n); o++, n++)
  390. continue;
  391. ofd = o;
  392. nfd = n;
  393. /*
  394. * Find the end of both old and new
  395. */
  396. while (*o)
  397. o++;
  398. /*
  399. * Remove any trailing blanks off of the end, being careful not to
  400. * back up past the beginning.
  401. */
  402. while (ofd < o) {
  403. if (o[-1] != ' ')
  404. break;
  405. o--;
  406. }
  407. oe = o;
  408. *oe = '\0';
  409. while (*n)
  410. n++;
  411. /* remove blanks from end of new */
  412. while (nfd < n) {
  413. if (n[-1] != ' ')
  414. break;
  415. n--;
  416. }
  417. ne = n;
  418. *ne = '\0';
  419. /*
  420. * if no diff, continue to next line of redraw
  421. */
  422. if (*ofd == '\0' && *nfd == '\0') {
  423. ELRE_DEBUG(1, (__F, "no difference.\r\n"));
  424. return;
  425. }
  426. /*
  427. * find last same pointer
  428. */
  429. while ((o > ofd) && (n > nfd) && (*--o == *--n))
  430. continue;
  431. ols = ++o;
  432. nls = ++n;
  433. /*
  434. * find same begining and same end
  435. */
  436. osb = ols;
  437. nsb = nls;
  438. ose = ols;
  439. nse = nls;
  440. /*
  441. * case 1: insert: scan from nfd to nls looking for *ofd
  442. */
  443. if (*ofd) {
  444. for (c = *ofd, n = nfd; n < nls; n++) {
  445. if (c == *n) {
  446. for (o = ofd, p = n;
  447. p < nls && o < ols && *o == *p;
  448. o++, p++)
  449. continue;
  450. /*
  451. * if the new match is longer and it's worth
  452. * keeping, then we take it
  453. */
  454. if (((nse - nsb) < (p - n)) &&
  455. (2 * (p - n) > n - nfd)) {
  456. nsb = n;
  457. nse = p;
  458. osb = ofd;
  459. ose = o;
  460. }
  461. }
  462. }
  463. }
  464. /*
  465. * case 2: delete: scan from ofd to ols looking for *nfd
  466. */
  467. if (*nfd) {
  468. for (c = *nfd, o = ofd; o < ols; o++) {
  469. if (c == *o) {
  470. for (n = nfd, p = o;
  471. p < ols && n < nls && *p == *n;
  472. p++, n++)
  473. continue;
  474. /*
  475. * if the new match is longer and it's worth
  476. * keeping, then we take it
  477. */
  478. if (((ose - osb) < (p - o)) &&
  479. (2 * (p - o) > o - ofd)) {
  480. nsb = nfd;
  481. nse = n;
  482. osb = o;
  483. ose = p;
  484. }
  485. }
  486. }
  487. }
  488. /*
  489. * Pragmatics I: If old trailing whitespace or not enough characters to
  490. * save to be worth it, then don't save the last same info.
  491. */
  492. if ((oe - ols) < MIN_END_KEEP) {
  493. ols = oe;
  494. nls = ne;
  495. }
  496. /*
  497. * Pragmatics II: if the terminal isn't smart enough, make the data
  498. * dumber so the smart update doesn't try anything fancy
  499. */
  500. /*
  501. * fx is the number of characters we need to insert/delete: in the
  502. * beginning to bring the two same begins together
  503. */
  504. fx = (nsb - nfd) - (osb - ofd);
  505. /*
  506. * sx is the number of characters we need to insert/delete: in the
  507. * end to bring the two same last parts together
  508. */
  509. sx = (nls - nse) - (ols - ose);
  510. if (!EL_CAN_INSERT) {
  511. if (fx > 0) {
  512. osb = ols;
  513. ose = ols;
  514. nsb = nls;
  515. nse = nls;
  516. }
  517. if (sx > 0) {
  518. ols = oe;
  519. nls = ne;
  520. }
  521. if ((ols - ofd) < (nls - nfd)) {
  522. ols = oe;
  523. nls = ne;
  524. }
  525. }
  526. if (!EL_CAN_DELETE) {
  527. if (fx < 0) {
  528. osb = ols;
  529. ose = ols;
  530. nsb = nls;
  531. nse = nls;
  532. }
  533. if (sx < 0) {
  534. ols = oe;
  535. nls = ne;
  536. }
  537. if ((ols - ofd) > (nls - nfd)) {
  538. ols = oe;
  539. nls = ne;
  540. }
  541. }
  542. /*
  543. * Pragmatics III: make sure the middle shifted pointers are correct if
  544. * they don't point to anything (we may have moved ols or nls).
  545. */
  546. /* if the change isn't worth it, don't bother */
  547. /* was: if (osb == ose) */
  548. if ((ose - osb) < MIN_END_KEEP) {
  549. osb = ols;
  550. ose = ols;
  551. nsb = nls;
  552. nse = nls;
  553. }
  554. /*
  555. * Now that we are done with pragmatics we recompute fx, sx
  556. */
  557. fx = (nsb - nfd) - (osb - ofd);
  558. sx = (nls - nse) - (ols - ose);
  559. ELRE_DEBUG(1, (__F, "\n"));
  560. ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
  561. ofd - old, osb - old, ose - old, ols - old, oe - old));
  562. ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
  563. nfd - new, nsb - new, nse - new, nls - new, ne - new));
  564. ELRE_DEBUG(1, (__F,
  565. "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
  566. ELRE_DEBUG(1, (__F,
  567. "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
  568. #ifdef DEBUG_REFRESH
  569. re_printstr(el, "old- oe", old, oe);
  570. re_printstr(el, "new- ne", new, ne);
  571. re_printstr(el, "old-ofd", old, ofd);
  572. re_printstr(el, "new-nfd", new, nfd);
  573. re_printstr(el, "ofd-osb", ofd, osb);
  574. re_printstr(el, "nfd-nsb", nfd, nsb);
  575. re_printstr(el, "osb-ose", osb, ose);
  576. re_printstr(el, "nsb-nse", nsb, nse);
  577. re_printstr(el, "ose-ols", ose, ols);
  578. re_printstr(el, "nse-nls", nse, nls);
  579. re_printstr(el, "ols- oe", ols, oe);
  580. re_printstr(el, "nls- ne", nls, ne);
  581. #endif /* DEBUG_REFRESH */
  582. /*
  583. * el_cursor.v to this line i MUST be in this routine so that if we
  584. * don't have to change the line, we don't move to it. el_cursor.h to
  585. * first diff char
  586. */
  587. term_move_to_line(el, i);
  588. /*
  589. * at this point we have something like this:
  590. *
  591. * /old /ofd /osb /ose /ols /oe
  592. * v.....................v v..................v v........v
  593. * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
  594. * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
  595. * ^.....................^ ^..................^ ^........^
  596. * \new \nfd \nsb \nse \nls \ne
  597. *
  598. * fx is the difference in length between the chars between nfd and
  599. * nsb, and the chars between ofd and osb, and is thus the number of
  600. * characters to delete if < 0 (new is shorter than old, as above),
  601. * or insert (new is longer than short).
  602. *
  603. * sx is the same for the second differences.
  604. */
  605. /*
  606. * if we have a net insert on the first difference, AND inserting the
  607. * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
  608. * character (which is ne if nls != ne, otherwise is nse) off the edge
  609. * of the screen (el->el_term.t_size.h) else we do the deletes first
  610. * so that we keep everything we need to.
  611. */
  612. /*
  613. * if the last same is the same like the end, there is no last same
  614. * part, otherwise we want to keep the last same part set p to the
  615. * last useful old character
  616. */
  617. p = (ols != oe) ? oe : ose;
  618. /*
  619. * if (There is a diffence in the beginning) && (we need to insert
  620. * characters) && (the number of characters to insert is less than
  621. * the term width)
  622. * We need to do an insert!
  623. * else if (we need to delete characters)
  624. * We need to delete characters!
  625. * else
  626. * No insert or delete
  627. */
  628. if ((nsb != nfd) && fx > 0 &&
  629. ((p - old) + fx <= el->el_term.t_size.h)) {
  630. ELRE_DEBUG(1,
  631. (__F, "first diff insert at %d...\r\n", nfd - new));
  632. /*
  633. * Move to the first char to insert, where the first diff is.
  634. */
  635. term_move_to_char(el, nfd - new);
  636. /*
  637. * Check if we have stuff to keep at end
  638. */
  639. if (nsb != ne) {
  640. ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
  641. /*
  642. * insert fx chars of new starting at nfd
  643. */
  644. if (fx > 0) {
  645. ELRE_DEBUG(!EL_CAN_INSERT, (__F,
  646. "ERROR: cannot insert in early first diff\n"));
  647. term_insertwrite(el, nfd, fx);
  648. re_insert(el, old, ofd - old,
  649. el->el_term.t_size.h, nfd, fx);
  650. }
  651. /*
  652. * write (nsb-nfd) - fx chars of new starting at
  653. * (nfd + fx)
  654. */
  655. term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
  656. re__strncopy(ofd + fx, nfd + fx,
  657. (size_t) ((nsb - nfd) - fx));
  658. } else {
  659. ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
  660. term_overwrite(el, nfd, (nsb - nfd));
  661. re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
  662. /*
  663. * Done
  664. */
  665. return;
  666. }
  667. } else if (fx < 0) {
  668. ELRE_DEBUG(1,
  669. (__F, "first diff delete at %d...\r\n", ofd - old));
  670. /*
  671. * move to the first char to delete where the first diff is
  672. */
  673. term_move_to_char(el, ofd - old);
  674. /*
  675. * Check if we have stuff to save
  676. */
  677. if (osb != oe) {
  678. ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
  679. /*
  680. * fx is less than zero *always* here but we check
  681. * for code symmetry
  682. */
  683. if (fx < 0) {
  684. ELRE_DEBUG(!EL_CAN_DELETE, (__F,
  685. "ERROR: cannot delete in first diff\n"));
  686. term_deletechars(el, -fx);
  687. re_delete(el, old, ofd - old,
  688. el->el_term.t_size.h, -fx);
  689. }
  690. /*
  691. * write (nsb-nfd) chars of new starting at nfd
  692. */
  693. term_overwrite(el, nfd, (nsb - nfd));
  694. re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
  695. } else {
  696. ELRE_DEBUG(1, (__F,
  697. "but with nothing left to save\r\n"));
  698. /*
  699. * write (nsb-nfd) chars of new starting at nfd
  700. */
  701. term_overwrite(el, nfd, (nsb - nfd));
  702. ELRE_DEBUG(1, (__F,
  703. "cleareol %d\n", (oe - old) - (ne - new)));
  704. term_clear_EOL(el, (oe - old) - (ne - new));
  705. /*
  706. * Done
  707. */
  708. return;
  709. }
  710. } else
  711. fx = 0;
  712. if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) {
  713. ELRE_DEBUG(1, (__F,
  714. "second diff delete at %d...\r\n", (ose - old) + fx));
  715. /*
  716. * Check if we have stuff to delete
  717. */
  718. /*
  719. * fx is the number of characters inserted (+) or deleted (-)
  720. */
  721. term_move_to_char(el, (ose - old) + fx);
  722. /*
  723. * Check if we have stuff to save
  724. */
  725. if (ols != oe) {
  726. ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
  727. /*
  728. * Again a duplicate test.
  729. */
  730. if (sx < 0) {
  731. ELRE_DEBUG(!EL_CAN_DELETE, (__F,
  732. "ERROR: cannot delete in second diff\n"));
  733. term_deletechars(el, -sx);
  734. }
  735. /*
  736. * write (nls-nse) chars of new starting at nse
  737. */
  738. term_overwrite(el, nse, (nls - nse));
  739. } else {
  740. ELRE_DEBUG(1, (__F,
  741. "but with nothing left to save\r\n"));
  742. term_overwrite(el, nse, (nls - nse));
  743. ELRE_DEBUG(1, (__F,
  744. "cleareol %d\n", (oe - old) - (ne - new)));
  745. if ((oe - old) - (ne - new) != 0)
  746. term_clear_EOL(el, (oe - old) - (ne - new));
  747. }
  748. }
  749. /*
  750. * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
  751. */
  752. if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
  753. ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
  754. nfd - new));
  755. term_move_to_char(el, nfd - new);
  756. /*
  757. * Check if we have stuff to keep at the end
  758. */
  759. if (nsb != ne) {
  760. ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
  761. /*
  762. * We have to recalculate fx here because we set it
  763. * to zero above as a flag saying that we hadn't done
  764. * an early first insert.
  765. */
  766. fx = (nsb - nfd) - (osb - ofd);
  767. if (fx > 0) {
  768. /*
  769. * insert fx chars of new starting at nfd
  770. */
  771. ELRE_DEBUG(!EL_CAN_INSERT, (__F,
  772. "ERROR: cannot insert in late first diff\n"));
  773. term_insertwrite(el, nfd, fx);
  774. re_insert(el, old, ofd - old,
  775. el->el_term.t_size.h, nfd, fx);
  776. }
  777. /*
  778. * write (nsb-nfd) - fx chars of new starting at
  779. * (nfd + fx)
  780. */
  781. term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
  782. re__strncopy(ofd + fx, nfd + fx,
  783. (size_t) ((nsb - nfd) - fx));
  784. } else {
  785. ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
  786. term_overwrite(el, nfd, (nsb - nfd));
  787. re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
  788. }
  789. }
  790. /*
  791. * line is now NEW up to nse
  792. */
  793. if (sx >= 0) {
  794. ELRE_DEBUG(1, (__F,
  795. "second diff insert at %d...\r\n", nse - new));
  796. term_move_to_char(el, nse - new);
  797. if (ols != oe) {
  798. ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
  799. if (sx > 0) {
  800. /* insert sx chars of new starting at nse */
  801. ELRE_DEBUG(!EL_CAN_INSERT, (__F,
  802. "ERROR: cannot insert in second diff\n"));
  803. term_insertwrite(el, nse, sx);
  804. }
  805. /*
  806. * write (nls-nse) - sx chars of new starting at
  807. * (nse + sx)
  808. */
  809. term_overwrite(el, nse + sx, (nls - nse) - sx);
  810. } else {
  811. ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
  812. term_overwrite(el, nse, (nls - nse));
  813. /*
  814. * No need to do a clear-to-end here because we were
  815. * doing a second insert, so we will have over
  816. * written all of the old string.
  817. */
  818. }
  819. }
  820. ELRE_DEBUG(1, (__F, "done.\r\n"));
  821. }
  822. /* re__copy_and_pad():
  823. * Copy string and pad with spaces
  824. */
  825. private void
  826. re__copy_and_pad(char *dst, const char *src, size_t width)
  827. {
  828. int i;
  829. for (i = 0; i < width; i++) {
  830. if (*src == '\0')
  831. break;
  832. *dst++ = *src++;
  833. }
  834. for (; i < width; i++)
  835. *dst++ = ' ';
  836. *dst = '\0';
  837. }
  838. /* re_refresh_cursor():
  839. * Move to the new cursor position
  840. */
  841. protected void
  842. re_refresh_cursor(EditLine *el)
  843. {
  844. char *cp, c;
  845. int h, v, th;
  846. /* first we must find where the cursor is... */
  847. h = el->el_prompt.p_pos.h;
  848. v = el->el_prompt.p_pos.v;
  849. th = el->el_term.t_size.h; /* optimize for speed */
  850. /* do input buffer to el->el_line.cursor */
  851. for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
  852. c = *cp;
  853. h++; /* all chars at least this long */
  854. if (c == '\n') {/* handle newline in data part too */
  855. h = 0;
  856. v++;
  857. } else {
  858. if (c == '\t') { /* if a tab, to next tab stop */
  859. while (h & 07) {
  860. h++;
  861. }
  862. } else if (iscntrl((unsigned char) c)) {
  863. /* if control char */
  864. h++;
  865. if (h > th) { /* if overflow, compensate */
  866. h = 1;
  867. v++;
  868. }
  869. } else if (!isprint((unsigned char) c)) {
  870. h += 3;
  871. if (h > th) { /* if overflow, compensate */
  872. h = h - th;
  873. v++;
  874. }
  875. }
  876. }
  877. if (h >= th) { /* check, extra long tabs picked up here also */
  878. h = 0;
  879. v++;
  880. }
  881. }
  882. /* now go there */
  883. term_move_to_line(el, v);
  884. term_move_to_char(el, h);
  885. term__flush();
  886. }
  887. /* re_fastputc():
  888. * Add a character fast.
  889. */
  890. private void
  891. re_fastputc(EditLine *el, int c)
  892. {
  893. term__putc(c);
  894. el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
  895. if (el->el_cursor.h >= el->el_term.t_size.h) {
  896. /* if we must overflow */
  897. el->el_cursor.h = 0;
  898. /*
  899. * If we would overflow (input is longer than terminal size),
  900. * emulate scroll by dropping first line and shuffling the rest.
  901. * We do this via pointer shuffling - it's safe in this case
  902. * and we avoid memcpy().
  903. */
  904. if (el->el_cursor.v + 1 >= el->el_term.t_size.v) {
  905. int i, lins = el->el_term.t_size.v;
  906. char *firstline = el->el_display[0];
  907. for(i=1; i < lins; i++)
  908. el->el_display[i-1] = el->el_display[i];
  909. re__copy_and_pad(firstline, "", 0);
  910. el->el_display[i-1] = firstline;
  911. } else {
  912. el->el_cursor.v++;
  913. el->el_refresh.r_oldcv++;
  914. }
  915. if (EL_HAS_AUTO_MARGINS) {
  916. if (EL_HAS_MAGIC_MARGINS) {
  917. term__putc(' ');
  918. term__putc('\b');
  919. }
  920. } else {
  921. term__putc('\r');
  922. term__putc('\n');
  923. }
  924. }
  925. }
  926. /* re_fastaddc():
  927. * we added just one char, handle it fast.
  928. * Assumes that screen cursor == real cursor
  929. */
  930. protected void
  931. re_fastaddc(EditLine *el)
  932. {
  933. char c;
  934. int rhdiff;
  935. c = el->el_line.cursor[-1];
  936. if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
  937. re_refresh(el); /* too hard to handle */
  938. return;
  939. }
  940. rhdiff = el->el_term.t_size.h - el->el_cursor.h -
  941. el->el_rprompt.p_pos.h;
  942. if (el->el_rprompt.p_pos.h && rhdiff < 3) {
  943. re_refresh(el); /* clear out rprompt if less than 1 char gap */
  944. return;
  945. } /* else (only do at end of line, no TAB) */
  946. if (iscntrl((unsigned char) c)) { /* if control char, do caret */
  947. char mc = (c == '\177') ? '?' : (c | 0100);
  948. re_fastputc(el, '^');
  949. re_fastputc(el, mc);
  950. } else if (isprint((unsigned char) c)) { /* normal char */
  951. re_fastputc(el, c);
  952. } else {
  953. re_fastputc(el, '\\');
  954. re_fastputc(el, (int) ((((unsigned int) c >> 6) & 7) + '0'));
  955. re_fastputc(el, (int) ((((unsigned int) c >> 3) & 7) + '0'));
  956. re_fastputc(el, (c & 7) + '0');
  957. }
  958. term__flush();
  959. }
  960. /* re_clear_display():
  961. * clear the screen buffers so that new prompt starts fresh.
  962. */
  963. protected void
  964. re_clear_display(EditLine *el)
  965. {
  966. int i;
  967. el->el_cursor.v = 0;
  968. el->el_cursor.h = 0;
  969. for (i = 0; i < el->el_term.t_size.v; i++)
  970. el->el_display[i][0] = '\0';
  971. el->el_refresh.r_oldcv = 0;
  972. }
  973. /* re_clear_lines():
  974. * Make sure all lines are *really* blank
  975. */
  976. protected void
  977. re_clear_lines(EditLine *el)
  978. {
  979. if (EL_CAN_CEOL) {
  980. int i;
  981. term_move_to_char(el, 0);
  982. for (i = 0; i <= el->el_refresh.r_oldcv; i++) {
  983. /* for each line on the screen */
  984. term_move_to_line(el, i);
  985. term_clear_EOL(el, el->el_term.t_size.h);
  986. }
  987. term_move_to_line(el, 0);
  988. } else {
  989. term_move_to_line(el, el->el_refresh.r_oldcv);
  990. /* go to last line */
  991. term__putc('\r'); /* go to BOL */
  992. term__putc('\n'); /* go to new line */
  993. }
  994. }