sbin/hammer: Have consistent naming for buffer variables
[dragonfly.git] / contrib / nvi2 / vi / vs_msg.c
blob2eb88e4e7e69e1abfc52a3d46acf399765bd9e36
1 /*-
2 * Copyright (c) 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: vs_msg.c,v 10.88 2013/03/19 09:59:03 zy Exp $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
20 #include <bitstring.h>
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
27 #include "../common/common.h"
28 #include "vi.h"
30 typedef enum {
31 SCROLL_W, /* User wait. */
32 SCROLL_W_EX, /* User wait, or enter : to continue. */
33 SCROLL_W_QUIT /* User wait, or enter q to quit. */
35 * SCROLL_W_QUIT has another semantic
36 * -- only wait if the screen is full
38 } sw_t;
40 static void vs_divider(SCR *);
41 static void vs_msgsave(SCR *, mtype_t, char *, size_t);
42 static void vs_output(SCR *, mtype_t, const char *, int);
43 static void vs_scroll(SCR *, int *, sw_t);
44 static void vs_wait(SCR *, int *, sw_t);
47 * vs_busy --
48 * Display, update or clear a busy message.
50 * This routine is the default editor interface for vi busy messages. It
51 * implements a standard strategy of stealing lines from the bottom of the
52 * vi text screen. Screens using an alternate method of displaying busy
53 * messages, e.g. X11 clock icons, should set their scr_busy function to the
54 * correct function before calling the main editor routine.
56 * PUBLIC: void vs_busy(SCR *, const char *, busy_t);
58 void
59 vs_busy(SCR *sp, const char *msg, busy_t btype)
61 GS *gp;
62 VI_PRIVATE *vip;
63 static const char flagc[] = "|/-\\";
64 struct timespec ts, ts_diff;
65 const struct timespec ts_min = { 0, 125000000 };
66 size_t len, notused;
67 const char *p;
69 /* Ex doesn't display busy messages. */
70 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
71 return;
73 gp = sp->gp;
74 vip = VIP(sp);
77 * Most of this routine is to deal with the screen sharing real estate
78 * between the normal edit messages and the busy messages. Logically,
79 * all that's needed is something that puts up a message, periodically
80 * updates it, and then goes away.
82 switch (btype) {
83 case BUSY_ON:
84 ++vip->busy_ref;
85 if (vip->totalcount != 0 || vip->busy_ref != 1)
86 break;
88 /* Initialize state for updates. */
89 vip->busy_ch = 0;
90 timepoint_steady(&vip->busy_ts);
92 /* Save the current cursor. */
93 (void)gp->scr_cursor(sp, &vip->busy_oldy, &vip->busy_oldx);
95 /* Display the busy message. */
96 p = msg_cat(sp, msg, &len);
97 (void)gp->scr_move(sp, LASTLINE(sp), 0);
98 (void)gp->scr_addstr(sp, p, len);
99 (void)gp->scr_cursor(sp, &notused, &vip->busy_fx);
100 (void)gp->scr_clrtoeol(sp);
101 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
102 break;
103 case BUSY_OFF:
104 if (vip->busy_ref == 0)
105 break;
106 --vip->busy_ref;
109 * If the line isn't in use for another purpose, clear it.
110 * Always return to the original position.
112 if (vip->totalcount == 0 && vip->busy_ref == 0) {
113 (void)gp->scr_move(sp, LASTLINE(sp), 0);
114 (void)gp->scr_clrtoeol(sp);
116 (void)gp->scr_move(sp, vip->busy_oldy, vip->busy_oldx);
117 break;
118 case BUSY_UPDATE:
119 if (vip->totalcount != 0 || vip->busy_ref == 0)
120 break;
122 /* Update no more than every 1/8 of a second. */
123 timepoint_steady(&ts);
124 ts_diff = ts;
125 timespecsub(&ts_diff, &vip->busy_ts);
126 if (timespeccmp(&ts_diff, &ts_min, <))
127 return;
128 vip->busy_ts = ts;
130 /* Display the update. */
131 if (vip->busy_ch == sizeof(flagc) - 1)
132 vip->busy_ch = 0;
133 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
134 (void)gp->scr_addstr(sp, flagc + vip->busy_ch++, 1);
135 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
136 break;
138 (void)gp->scr_refresh(sp, 0);
142 * vs_home --
143 * Home the cursor to the bottom row, left-most column.
145 * PUBLIC: void vs_home(SCR *);
147 void
148 vs_home(SCR *sp)
150 (void)sp->gp->scr_move(sp, LASTLINE(sp), 0);
151 (void)sp->gp->scr_refresh(sp, 0);
155 * vs_update --
156 * Update a command.
158 * PUBLIC: void vs_update(SCR *, const char *, const CHAR_T *);
160 void
161 vs_update(SCR *sp, const char *m1, const CHAR_T *m2)
163 GS *gp;
164 size_t len, mlen, oldx, oldy;
165 CONST char *np;
166 size_t nlen;
168 gp = sp->gp;
171 * This routine displays a message on the bottom line of the screen,
172 * without updating any of the command structures that would keep it
173 * there for any period of time, i.e. it is overwritten immediately.
175 * It's used by the ex read and ! commands when the user's command is
176 * expanded, and by the ex substitution confirmation prompt.
178 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
179 if (m2 != NULL)
180 INT2CHAR(sp, m2, STRLEN(m2) + 1, np, nlen);
181 (void)ex_printf(sp,
182 "%s\n", m1 == NULL? "" : m1, m2 == NULL ? "" : np);
183 (void)ex_fflush(sp);
187 * Save the cursor position, the substitute-with-confirmation code
188 * will have already set it correctly.
190 (void)gp->scr_cursor(sp, &oldy, &oldx);
192 /* Clear the bottom line. */
193 (void)gp->scr_move(sp, LASTLINE(sp), 0);
194 (void)gp->scr_clrtoeol(sp);
197 * XXX
198 * Don't let long file names screw up the screen.
200 if (m1 != NULL) {
201 mlen = len = strlen(m1);
202 if (len > sp->cols - 2)
203 mlen = len = sp->cols - 2;
204 (void)gp->scr_addstr(sp, m1, mlen);
205 } else
206 len = 0;
207 if (m2 != NULL) {
208 mlen = STRLEN(m2);
209 if (len + mlen > sp->cols - 2)
210 mlen = (sp->cols - 2) - len;
211 (void)gp->scr_waddstr(sp, m2, mlen);
214 (void)gp->scr_move(sp, oldy, oldx);
215 (void)gp->scr_refresh(sp, 0);
219 * vs_msg --
220 * Display ex output or error messages for the screen.
222 * This routine is the default editor interface for all ex output, and all ex
223 * and vi error/informational messages. It implements the standard strategy
224 * of stealing lines from the bottom of the vi text screen. Screens using an
225 * alternate method of displaying messages, e.g. dialog boxes, should set their
226 * scr_msg function to the correct function before calling the editor.
228 * PUBLIC: void vs_msg(SCR *, mtype_t, char *, size_t);
230 void
231 vs_msg(SCR *sp, mtype_t mtype, char *line, size_t len)
233 GS *gp;
234 VI_PRIVATE *vip;
235 size_t maxcols, oldx, oldy, padding;
236 const char *e, *s, *t;
238 gp = sp->gp;
239 vip = VIP(sp);
242 * Ring the bell if it's scheduled.
244 * XXX
245 * Shouldn't we save this, too?
247 if (F_ISSET(sp, SC_TINPUT_INFO) || F_ISSET(gp, G_BELLSCHED))
248 if (F_ISSET(sp, SC_SCR_VI)) {
249 F_CLR(gp, G_BELLSCHED);
250 (void)gp->scr_bell(sp);
251 } else
252 F_SET(gp, G_BELLSCHED);
255 * If vi is using the error line for text input, there's no screen
256 * real-estate for the error message. Nothing to do without some
257 * information as to how important the error message is.
259 if (F_ISSET(sp, SC_TINPUT_INFO))
260 return;
263 * Ex or ex controlled screen output.
265 * If output happens during startup, e.g., a .exrc file, we may be
266 * in ex mode but haven't initialized the screen. Initialize here,
267 * and in this case, stay in ex mode.
269 * If the SC_SCR_EXWROTE bit is set, then we're switching back and
270 * forth between ex and vi, but the screen is trashed and we have
271 * to respect that. Switch to ex mode long enough to put out the
272 * message.
274 * If the SC_EX_WAIT_NO bit is set, turn it off -- we're writing to
275 * the screen, so previous opinions are ignored.
277 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
278 if (!F_ISSET(sp, SC_SCR_EX))
279 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
280 if (sp->gp->scr_screen(sp, SC_EX))
281 return;
282 } else
283 if (ex_init(sp))
284 return;
286 if (mtype == M_ERR)
287 (void)gp->scr_attr(sp, SA_INVERSE, 1);
288 (void)printf("%.*s", (int)len, line);
289 if (mtype == M_ERR)
290 (void)gp->scr_attr(sp, SA_INVERSE, 0);
291 (void)fflush(stdout);
293 F_CLR(sp, SC_EX_WAIT_NO);
295 if (!F_ISSET(sp, SC_SCR_EX))
296 (void)sp->gp->scr_screen(sp, SC_VI);
297 return;
300 /* If the vi screen isn't ready, save the message. */
301 if (!F_ISSET(sp, SC_SCR_VI)) {
302 (void)vs_msgsave(sp, mtype, line, len);
303 return;
306 /* Save the cursor position. */
307 (void)gp->scr_cursor(sp, &oldy, &oldx);
309 /* If it's an ex output message, just write it out. */
310 if (mtype == M_NONE) {
311 vs_output(sp, mtype, line, len);
312 goto ret;
316 * If it's a vi message, strip the trailing <newline> so we can
317 * try and paste messages together.
319 if (line[len - 1] == '\n')
320 --len;
323 * If a message won't fit on a single line, try to split on a <blank>.
324 * If a subsequent message fits on the same line, write a separator
325 * and output it. Otherwise, put out a newline.
327 * Need up to two padding characters normally; a semi-colon and a
328 * separating space. If only a single line on the screen, add some
329 * more for the trailing continuation message.
331 * XXX
332 * Assume that periods and semi-colons take up a single column on the
333 * screen.
335 * XXX
336 * There are almost certainly pathological cases that will break this
337 * code.
339 if (IS_ONELINE(sp))
340 (void)msg_cmsg(sp, CMSG_CONT_S, &padding);
341 else
342 padding = 0;
343 padding += 2;
345 maxcols = sp->cols - 1;
346 if (vip->lcontinue != 0)
347 if (len + vip->lcontinue + padding > maxcols)
348 vs_output(sp, vip->mtype, ".\n", 2);
349 else {
350 vs_output(sp, vip->mtype, ";", 1);
351 vs_output(sp, M_NONE, " ", 1);
353 vip->mtype = mtype;
354 for (s = line;; s = t) {
355 for (; len > 0 && isblank(*s); --len, ++s);
356 if (len == 0)
357 break;
358 if (len + vip->lcontinue > maxcols) {
359 for (e = s + (maxcols - vip->lcontinue);
360 e > s && !isblank(*e); --e);
361 if (e == s)
362 e = t = s + (maxcols - vip->lcontinue);
363 else
364 for (t = e; isblank(e[-1]); --e);
365 } else
366 e = t = s + len;
369 * If the message ends in a period, discard it, we want to
370 * gang messages where possible.
372 len -= t - s;
373 if (len == 0 && (e - s) > 1 && s[(e - s) - 1] == '.')
374 --e;
375 vs_output(sp, mtype, s, e - s);
377 if (len != 0)
378 vs_output(sp, M_NONE, "\n", 1);
380 if (INTERRUPTED(sp))
381 break;
384 ret: (void)gp->scr_move(sp, oldy, oldx);
385 (void)gp->scr_refresh(sp, 0);
389 * vs_output --
390 * Output the text to the screen.
392 static void
393 vs_output(SCR *sp, mtype_t mtype, const char *line, int llen)
395 GS *gp;
396 VI_PRIVATE *vip;
397 size_t notused;
398 int len, rlen, tlen;
399 const char *p, *t;
400 char *cbp, *ecbp, cbuf[128];
402 gp = sp->gp;
403 vip = VIP(sp);
404 for (p = line, rlen = llen; llen > 0;) {
405 /* Get the next physical line. */
406 if ((p = memchr(line, '\n', llen)) == NULL)
407 len = llen;
408 else
409 len = p - line;
412 * The max is sp->cols characters, and we may have already
413 * written part of the line.
415 if (len + vip->lcontinue > sp->cols)
416 len = sp->cols - vip->lcontinue;
419 * If the first line output, do nothing. If the second line
420 * output, draw the divider line. If drew a full screen, we
421 * remove the divider line. If it's a continuation line, move
422 * to the continuation point, else, move the screen up.
424 if (vip->lcontinue == 0) {
425 if (!IS_ONELINE(sp)) {
426 if (vip->totalcount == 1) {
427 (void)gp->scr_move(sp,
428 LASTLINE(sp) - 1, 0);
429 (void)gp->scr_clrtoeol(sp);
430 (void)vs_divider(sp);
431 F_SET(vip, VIP_DIVIDER);
432 ++vip->totalcount;
433 ++vip->linecount;
435 if (vip->totalcount == sp->t_maxrows &&
436 F_ISSET(vip, VIP_DIVIDER)) {
437 --vip->totalcount;
438 --vip->linecount;
439 F_CLR(vip, VIP_DIVIDER);
442 if (vip->totalcount != 0)
443 vs_scroll(sp, NULL, SCROLL_W_QUIT);
445 (void)gp->scr_move(sp, LASTLINE(sp), 0);
446 ++vip->totalcount;
447 ++vip->linecount;
449 if (INTERRUPTED(sp))
450 break;
451 } else
452 (void)gp->scr_move(sp, LASTLINE(sp), vip->lcontinue);
454 /* Error messages are in inverse video. */
455 if (mtype == M_ERR)
456 (void)gp->scr_attr(sp, SA_INVERSE, 1);
458 /* Display the line, doing character translation. */
459 #define FLUSH { \
460 *cbp = '\0'; \
461 (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); \
462 cbp = cbuf; \
464 ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
465 for (t = line, tlen = len; tlen--; ++t) {
467 * Replace tabs with spaces, there are places in
468 * ex that do column calculations without looking
469 * at <tabs> -- and all routines that care about
470 * <tabs> do their own expansions. This catches
471 * <tabs> in things like tag search strings.
473 if (cbp + 1 >= ecbp)
474 FLUSH;
475 *cbp++ = *t == '\t' ? ' ' : *t;
477 if (cbp > cbuf)
478 FLUSH;
479 if (mtype == M_ERR)
480 (void)gp->scr_attr(sp, SA_INVERSE, 0);
482 /* Clear the rest of the line. */
483 (void)gp->scr_clrtoeol(sp);
485 /* If we loop, it's a new line. */
486 vip->lcontinue = 0;
488 /* Reset for the next line. */
489 line += len;
490 llen -= len;
491 if (p != NULL) {
492 ++line;
493 --llen;
497 /* Set up next continuation line. */
498 if (p == NULL)
499 gp->scr_cursor(sp, &notused, &vip->lcontinue);
503 * vs_ex_resolve --
504 * Deal with ex message output.
506 * This routine is called when exiting a colon command to resolve any ex
507 * output that may have occurred.
509 * PUBLIC: int vs_ex_resolve(SCR *, int *);
512 vs_ex_resolve(SCR *sp, int *continuep)
514 EVENT ev;
515 GS *gp;
516 VI_PRIVATE *vip;
517 sw_t wtype;
519 gp = sp->gp;
520 vip = VIP(sp);
521 *continuep = 0;
523 /* If we ran any ex command, we can't trust the cursor position. */
524 F_SET(vip, VIP_CUR_INVALID);
526 /* Terminate any partially written message. */
527 if (vip->lcontinue != 0) {
528 vs_output(sp, vip->mtype, ".", 1);
529 vip->lcontinue = 0;
531 vip->mtype = M_NONE;
535 * If we switched out of the vi screen into ex, switch back while we
536 * figure out what to do with the screen and potentially get another
537 * command to execute.
539 * If we didn't switch into ex, we're not required to wait, and less
540 * than 2 lines of output, we can continue without waiting for the
541 * wait.
543 * Note, all other code paths require waiting, so we leave the report
544 * of modified lines until later, so that we won't wait for no other
545 * reason than a threshold number of lines were modified. This means
546 * we display cumulative line modification reports for groups of ex
547 * commands. That seems right to me (well, at least not wrong).
549 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
550 if (sp->gp->scr_screen(sp, SC_VI))
551 return (1);
552 } else
553 if (!F_ISSET(sp, SC_EX_WAIT_YES) && vip->totalcount < 2) {
554 F_CLR(sp, SC_EX_WAIT_NO);
555 return (0);
558 /* Clear the required wait flag, it's no longer needed. */
559 F_CLR(sp, SC_EX_WAIT_YES);
562 * Wait, unless explicitly told not to wait or the user interrupted
563 * the command. If the user is leaving the screen, for any reason,
564 * they can't continue with further ex commands.
566 if (!F_ISSET(sp, SC_EX_WAIT_NO) && !INTERRUPTED(sp)) {
567 wtype = F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE |
568 SC_FSWITCH | SC_SSWITCH) ? SCROLL_W : SCROLL_W_EX;
569 if (F_ISSET(sp, SC_SCR_EXWROTE))
570 vs_wait(sp, continuep, wtype);
571 else
572 vs_scroll(sp, continuep, wtype);
573 if (*continuep)
574 return (0);
577 /* If ex wrote on the screen, refresh the screen image. */
578 if (F_ISSET(sp, SC_SCR_EXWROTE))
579 F_SET(vip, VIP_N_EX_PAINT);
582 * If we're not the bottom of the split screen stack, the screen
583 * image itself is wrong, so redraw everything.
585 if (TAILQ_NEXT(sp, q) != NULL)
586 F_SET(sp, SC_SCR_REDRAW);
588 /* If ex changed the underlying file, the map itself is wrong. */
589 if (F_ISSET(vip, VIP_N_EX_REDRAW))
590 F_SET(sp, SC_SCR_REFORMAT);
592 /* Ex may have switched out of the alternate screen, return. */
593 (void)gp->scr_attr(sp, SA_ALTERNATE, 1);
596 * Whew. We're finally back home, after what feels like years.
597 * Kiss the ground.
599 F_CLR(sp, SC_SCR_EXWROTE | SC_EX_WAIT_NO);
602 * We may need to repaint some of the screen, e.g.:
604 * :set
605 * :!ls
607 * gives us a combination of some lines that are "wrong", and a need
608 * for a full refresh.
610 if (vip->totalcount > 1) {
611 /* Set up the redraw of the overwritten lines. */
612 ev.e_event = E_REPAINT;
613 ev.e_flno = vip->totalcount >=
614 sp->rows ? 1 : sp->rows - vip->totalcount;
615 ev.e_tlno = sp->rows;
617 /* Reset the count of overwriting lines. */
618 vip->linecount = vip->lcontinue = vip->totalcount = 0;
620 /* Redraw. */
621 (void)vs_repaint(sp, &ev);
622 } else
623 /* Reset the count of overwriting lines. */
624 vip->linecount = vip->lcontinue = vip->totalcount = 0;
626 return (0);
630 * vs_resolve --
631 * Deal with message output.
633 * PUBLIC: int vs_resolve(SCR *, SCR *, int);
636 vs_resolve(SCR *sp, SCR *csp, int forcewait)
638 EVENT ev;
639 GS *gp;
640 MSGS *mp;
641 VI_PRIVATE *vip;
642 size_t oldy, oldx;
643 int redraw;
646 * Vs_resolve is called from the main vi loop and the refresh function
647 * to periodically ensure that the user has seen any messages that have
648 * been displayed and that any status lines are correct. The sp screen
649 * is the screen we're checking, usually the current screen. When it's
650 * not, csp is the current screen, used for final cursor positioning.
652 gp = sp->gp;
653 vip = VIP(sp);
654 if (csp == NULL)
655 csp = sp;
657 /* Save the cursor position. */
658 (void)gp->scr_cursor(csp, &oldy, &oldx);
660 /* Ring the bell if it's scheduled. */
661 if (F_ISSET(gp, G_BELLSCHED)) {
662 F_CLR(gp, G_BELLSCHED);
663 (void)gp->scr_bell(sp);
666 /* Display new file status line. */
667 if (F_ISSET(sp, SC_STATUS)) {
668 F_CLR(sp, SC_STATUS);
669 msgq_status(sp, sp->lno, MSTAT_TRUNCATE);
672 /* Report on line modifications. */
673 mod_rpt(sp);
676 * Flush any saved messages. If the screen isn't ready, refresh
677 * it. (A side-effect of screen refresh is that we can display
678 * messages.) Once this is done, don't trust the cursor. That
679 * extra refresh screwed the pooch.
681 if (!SLIST_EMPTY(gp->msgq)) {
682 if (!F_ISSET(sp, SC_SCR_VI) && vs_refresh(sp, 1))
683 return (1);
684 while ((mp = SLIST_FIRST(gp->msgq)) != NULL) {
685 gp->scr_msg(sp, mp->mtype, mp->buf, mp->len);
686 SLIST_REMOVE_HEAD(gp->msgq, q);
687 free(mp->buf);
688 free(mp);
690 F_SET(vip, VIP_CUR_INVALID);
693 switch (vip->totalcount) {
694 case 0:
695 redraw = 0;
696 break;
697 case 1:
699 * If we're switching screens, we have to wait for messages,
700 * regardless. If we don't wait, skip updating the modeline.
702 if (forcewait)
703 vs_scroll(sp, NULL, SCROLL_W);
704 else
705 F_SET(vip, VIP_S_MODELINE);
707 redraw = 0;
708 break;
709 default:
711 * If >1 message line in use, prompt the user to continue and
712 * repaint overwritten lines.
714 vs_scroll(sp, NULL, SCROLL_W);
716 ev.e_event = E_REPAINT;
717 ev.e_flno = vip->totalcount >=
718 sp->rows ? 1 : sp->rows - vip->totalcount;
719 ev.e_tlno = sp->rows;
721 redraw = 1;
722 break;
725 /* Reset the count of overwriting lines. */
726 vip->linecount = vip->lcontinue = vip->totalcount = 0;
728 /* Redraw. */
729 if (redraw)
730 (void)vs_repaint(sp, &ev);
732 /* Restore the cursor position. */
733 (void)gp->scr_move(csp, oldy, oldx);
735 return (0);
739 * vs_scroll --
740 * Scroll the screen for output.
742 static void
743 vs_scroll(SCR *sp, int *continuep, sw_t wtype)
745 GS *gp;
746 VI_PRIVATE *vip;
748 gp = sp->gp;
749 vip = VIP(sp);
750 if (!IS_ONELINE(sp)) {
752 * Scroll the screen. Instead of scrolling the entire screen,
753 * delete the line above the first line output so preserve the
754 * maximum amount of the screen.
756 (void)gp->scr_move(sp, vip->totalcount <
757 sp->rows ? LASTLINE(sp) - vip->totalcount : 0, 0);
758 (void)gp->scr_deleteln(sp);
760 /* If there are screens below us, push them back into place. */
761 if (TAILQ_NEXT(sp, q) != NULL) {
762 (void)gp->scr_move(sp, LASTLINE(sp), 0);
763 (void)gp->scr_insertln(sp);
766 if (wtype == SCROLL_W_QUIT && vip->linecount < sp->t_maxrows)
767 return;
768 vs_wait(sp, continuep, wtype);
772 * vs_wait --
773 * Prompt the user to continue.
775 static void
776 vs_wait(SCR *sp, int *continuep, sw_t wtype)
778 EVENT ev;
779 VI_PRIVATE *vip;
780 const char *p;
781 GS *gp;
782 size_t len;
784 gp = sp->gp;
785 vip = VIP(sp);
787 (void)gp->scr_move(sp, LASTLINE(sp), 0);
788 if (IS_ONELINE(sp))
789 p = msg_cmsg(sp, CMSG_CONT_S, &len);
790 else
791 switch (wtype) {
792 case SCROLL_W_QUIT:
793 p = msg_cmsg(sp, CMSG_CONT_Q, &len);
794 break;
795 case SCROLL_W_EX:
796 p = msg_cmsg(sp, CMSG_CONT_EX, &len);
797 break;
798 case SCROLL_W:
799 p = msg_cmsg(sp, CMSG_CONT, &len);
800 break;
801 default:
802 abort();
803 /* NOTREACHED */
805 (void)gp->scr_addstr(sp, p, len);
807 ++vip->totalcount;
808 vip->linecount = 0;
810 (void)gp->scr_clrtoeol(sp);
811 (void)gp->scr_refresh(sp, 0);
813 /* Get a single character from the terminal. */
814 if (continuep != NULL)
815 *continuep = 0;
816 for (;;) {
817 if (v_event_get(sp, &ev, 0, 0))
818 return;
819 if (ev.e_event == E_CHARACTER)
820 break;
821 if (ev.e_event == E_INTERRUPT) {
822 ev.e_c = CH_QUIT;
823 F_SET(gp, G_INTERRUPTED);
824 break;
826 (void)gp->scr_bell(sp);
828 switch (wtype) {
829 case SCROLL_W_QUIT:
830 if (ev.e_c == CH_QUIT)
831 F_SET(gp, G_INTERRUPTED);
832 break;
833 case SCROLL_W_EX:
834 if (ev.e_c == ':' && continuep != NULL)
835 *continuep = 1;
836 break;
837 case SCROLL_W:
838 break;
843 * vs_divider --
844 * Draw a dividing line between the screen and the output.
846 static void
847 vs_divider(SCR *sp)
849 GS *gp;
850 size_t len;
852 #define DIVIDESTR "+=+=+=+=+=+=+=+"
853 len =
854 sizeof(DIVIDESTR) - 1 > sp->cols ? sp->cols : sizeof(DIVIDESTR) - 1;
855 gp = sp->gp;
856 (void)gp->scr_attr(sp, SA_INVERSE, 1);
857 (void)gp->scr_addstr(sp, DIVIDESTR, len);
858 (void)gp->scr_attr(sp, SA_INVERSE, 0);
862 * vs_msgsave --
863 * Save a message for later display.
865 static void
866 vs_msgsave(SCR *sp, mtype_t mt, char *p, size_t len)
868 GS *gp;
869 MSGS *mp_c, *mp_n;
872 * We have to handle messages before we have any place to put them.
873 * If there's no screen support yet, allocate a msg structure, copy
874 * in the message, and queue it on the global structure. If we can't
875 * allocate memory here, we're genuinely screwed, dump the message
876 * to stderr in the (probably) vain hope that someone will see it.
878 CALLOC_GOTO(sp, mp_n, MSGS *, 1, sizeof(MSGS));
879 MALLOC_GOTO(sp, mp_n->buf, char *, len);
881 memmove(mp_n->buf, p, len);
882 mp_n->len = len;
883 mp_n->mtype = mt;
885 gp = sp->gp;
886 if (SLIST_EMPTY(gp->msgq)) {
887 SLIST_INSERT_HEAD(gp->msgq, mp_n, q);
888 } else {
889 SLIST_FOREACH(mp_c, gp->msgq, q)
890 if (SLIST_NEXT(mp_c, q) == NULL)
891 break;
892 SLIST_INSERT_AFTER(mp_c, mp_n, q);
894 return;
896 alloc_err:
897 if (mp_n != NULL)
898 free(mp_n);
899 (void)fprintf(stderr, "%.*s\n", (int)len, p);