distrib: run libtoolize
[nvi.git] / vi / vs_msg.c
blobe756a1cb814320e8e31e2c03fb17ad58c2c70ec1
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.85 2001/07/29 19:07:31 skimo Exp $ (Berkeley) $Date: 2001/07/29 19:07:31 $";
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 __P((SCR *));
41 static void vs_msgsave __P((SCR *, mtype_t, char *, size_t));
42 static void vs_output __P((SCR *, mtype_t, const char *, int));
43 static void vs_scroll __P((SCR *, int *, sw_t));
44 static void vs_wait __P((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 __P((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 timeval tv;
65 size_t len, notused;
66 const char *p;
68 /* Ex doesn't display busy messages. */
69 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
70 return;
72 gp = sp->gp;
73 vip = VIP(sp);
76 * Most of this routine is to deal with the screen sharing real estate
77 * between the normal edit messages and the busy messages. Logically,
78 * all that's needed is something that puts up a message, periodically
79 * updates it, and then goes away.
81 switch (btype) {
82 case BUSY_ON:
83 ++vip->busy_ref;
84 if (vip->totalcount != 0 || vip->busy_ref != 1)
85 break;
87 /* Initialize state for updates. */
88 vip->busy_ch = 0;
89 (void)gettimeofday(&vip->busy_tv, NULL);
91 /* Save the current cursor. */
92 (void)gp->scr_cursor(sp, &vip->busy_oldy, &vip->busy_oldx);
94 /* Display the busy message. */
95 p = msg_cat(sp, msg, &len);
96 (void)gp->scr_move(sp, LASTLINE(sp), 0);
97 (void)gp->scr_addstr(sp, p, len);
98 (void)gp->scr_cursor(sp, &notused, &vip->busy_fx);
99 (void)gp->scr_clrtoeol(sp);
100 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
101 break;
102 case BUSY_OFF:
103 if (vip->busy_ref == 0)
104 break;
105 --vip->busy_ref;
108 * If the line isn't in use for another purpose, clear it.
109 * Always return to the original position.
111 if (vip->totalcount == 0 && vip->busy_ref == 0) {
112 (void)gp->scr_move(sp, LASTLINE(sp), 0);
113 (void)gp->scr_clrtoeol(sp);
115 (void)gp->scr_move(sp, vip->busy_oldy, vip->busy_oldx);
116 break;
117 case BUSY_UPDATE:
118 if (vip->totalcount != 0 || vip->busy_ref == 0)
119 break;
121 /* Update no more than every 1/8 of a second. */
122 (void)gettimeofday(&tv, NULL);
123 if (((tv.tv_sec - vip->busy_tv.tv_sec) * 1000000 +
124 (tv.tv_usec - vip->busy_tv.tv_usec)) < 125000)
125 return;
126 vip->busy_tv = tv;
128 /* Display the update. */
129 if (vip->busy_ch == sizeof(flagc) - 1)
130 vip->busy_ch = 0;
131 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
132 (void)gp->scr_addstr(sp, flagc + vip->busy_ch++, 1);
133 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
134 break;
136 (void)gp->scr_refresh(sp, 0);
140 * vs_home --
141 * Home the cursor to the bottom row, left-most column.
143 * PUBLIC: void vs_home __P((SCR *));
145 void
146 vs_home(SCR *sp)
148 (void)sp->gp->scr_move(sp, LASTLINE(sp), 0);
149 (void)sp->gp->scr_refresh(sp, 0);
153 * vs_update --
154 * Update a command.
156 * PUBLIC: void vs_update __P((SCR *, const char *, const CHAR_T *));
158 void
159 vs_update(SCR *sp, const char *m1, const CHAR_T *m2)
161 GS *gp;
162 size_t len, mlen, oldx, oldy;
163 CONST char *np;
164 size_t nlen;
166 gp = sp->gp;
169 * This routine displays a message on the bottom line of the screen,
170 * without updating any of the command structures that would keep it
171 * there for any period of time, i.e. it is overwritten immediately.
173 * It's used by the ex read and ! commands when the user's command is
174 * expanded, and by the ex substitution confirmation prompt.
176 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
177 if (m2 != NULL)
178 INT2CHAR(sp, m2, STRLEN(m2) + 1, np, nlen);
179 (void)ex_printf(sp,
180 "%s\n", m1 == NULL? "" : m1, m2 == NULL ? "" : np);
181 (void)ex_fflush(sp);
185 * Save the cursor position, the substitute-with-confirmation code
186 * will have already set it correctly.
188 (void)gp->scr_cursor(sp, &oldy, &oldx);
190 /* Clear the bottom line. */
191 (void)gp->scr_move(sp, LASTLINE(sp), 0);
192 (void)gp->scr_clrtoeol(sp);
195 * XXX
196 * Don't let long file names screw up the screen.
198 if (m1 != NULL) {
199 mlen = len = strlen(m1);
200 if (len > sp->cols - 2)
201 mlen = len = sp->cols - 2;
202 (void)gp->scr_addstr(sp, m1, mlen);
203 } else
204 len = 0;
205 if (m2 != NULL) {
206 mlen = STRLEN(m2);
207 if (len + mlen > sp->cols - 2)
208 mlen = (sp->cols - 2) - len;
209 (void)gp->scr_waddstr(sp, m2, mlen);
212 (void)gp->scr_move(sp, oldy, oldx);
213 (void)gp->scr_refresh(sp, 0);
217 * vs_msg --
218 * Display ex output or error messages for the screen.
220 * This routine is the default editor interface for all ex output, and all ex
221 * and vi error/informational messages. It implements the standard strategy
222 * of stealing lines from the bottom of the vi text screen. Screens using an
223 * alternate method of displaying messages, e.g. dialog boxes, should set their
224 * scr_msg function to the correct function before calling the editor.
226 * PUBLIC: void vs_msg __P((SCR *, mtype_t, char *, size_t));
228 void
229 vs_msg(SCR *sp, mtype_t mtype, char *line, size_t len)
231 GS *gp;
232 VI_PRIVATE *vip;
233 size_t maxcols, oldx, oldy, padding;
234 const char *e, *s, *t;
236 gp = sp->gp;
237 vip = VIP(sp);
240 * Ring the bell if it's scheduled.
242 * XXX
243 * Shouldn't we save this, too?
245 if (F_ISSET(sp, SC_TINPUT_INFO) || F_ISSET(gp, G_BELLSCHED))
246 if (F_ISSET(sp, SC_SCR_VI)) {
247 F_CLR(gp, G_BELLSCHED);
248 (void)gp->scr_bell(sp);
249 } else
250 F_SET(gp, G_BELLSCHED);
253 * If vi is using the error line for text input, there's no screen
254 * real-estate for the error message. Nothing to do without some
255 * information as to how important the error message is.
257 if (F_ISSET(sp, SC_TINPUT_INFO))
258 return;
261 * Ex or ex controlled screen output.
263 * If output happens during startup, e.g., a .exrc file, we may be
264 * in ex mode but haven't initialized the screen. Initialize here,
265 * and in this case, stay in ex mode.
267 * If the SC_SCR_EXWROTE bit is set, then we're switching back and
268 * forth between ex and vi, but the screen is trashed and we have
269 * to respect that. Switch to ex mode long enough to put out the
270 * message.
272 * If the SC_EX_WAIT_NO bit is set, turn it off -- we're writing to
273 * the screen, so previous opinions are ignored.
275 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
276 if (!F_ISSET(sp, SC_SCR_EX))
277 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
278 if (sp->gp->scr_screen(sp, SC_EX))
279 return;
280 } else
281 if (ex_init(sp))
282 return;
284 if (mtype == M_ERR)
285 (void)gp->scr_attr(sp, SA_INVERSE, 1);
286 (void)printf("%.*s", (int)len, line);
287 if (mtype == M_ERR)
288 (void)gp->scr_attr(sp, SA_INVERSE, 0);
289 (void)fflush(stdout);
291 F_CLR(sp, SC_EX_WAIT_NO);
293 if (!F_ISSET(sp, SC_SCR_EX))
294 (void)sp->gp->scr_screen(sp, SC_VI);
295 return;
298 /* If the vi screen isn't ready, save the message. */
299 if (!F_ISSET(sp, SC_SCR_VI)) {
300 (void)vs_msgsave(sp, mtype, line, len);
301 return;
304 /* Save the cursor position. */
305 (void)gp->scr_cursor(sp, &oldy, &oldx);
307 /* If it's an ex output message, just write it out. */
308 if (mtype == M_NONE) {
309 vs_output(sp, mtype, line, len);
310 goto ret;
314 * If it's a vi message, strip the trailing <newline> so we can
315 * try and paste messages together.
317 if (line[len - 1] == '\n')
318 --len;
321 * If a message won't fit on a single line, try to split on a <blank>.
322 * If a subsequent message fits on the same line, write a separator
323 * and output it. Otherwise, put out a newline.
325 * Need up to two padding characters normally; a semi-colon and a
326 * separating space. If only a single line on the screen, add some
327 * more for the trailing continuation message.
329 * XXX
330 * Assume that periods and semi-colons take up a single column on the
331 * screen.
333 * XXX
334 * There are almost certainly pathological cases that will break this
335 * code.
337 if (IS_ONELINE(sp))
338 (void)msg_cmsg(sp, CMSG_CONT_S, &padding);
339 else
340 padding = 0;
341 padding += 2;
343 maxcols = sp->cols - 1;
344 if (vip->lcontinue != 0)
345 if (len + vip->lcontinue + padding > maxcols)
346 vs_output(sp, vip->mtype, ".\n", 2);
347 else {
348 vs_output(sp, vip->mtype, ";", 1);
349 vs_output(sp, M_NONE, " ", 1);
351 vip->mtype = mtype;
352 for (s = line;; s = t) {
353 for (; len > 0 && isblank(*s); --len, ++s);
354 if (len == 0)
355 break;
356 if (len + vip->lcontinue > maxcols) {
357 for (e = s + (maxcols - vip->lcontinue);
358 e > s && !isblank(*e); --e);
359 if (e == s)
360 e = t = s + (maxcols - vip->lcontinue);
361 else
362 for (t = e; isblank(e[-1]); --e);
363 } else
364 e = t = s + len;
367 * If the message ends in a period, discard it, we want to
368 * gang messages where possible.
370 len -= t - s;
371 if (len == 0 && (e - s) > 1 && s[(e - s) - 1] == '.')
372 --e;
373 vs_output(sp, mtype, s, e - s);
375 if (len != 0)
376 vs_output(sp, M_NONE, "\n", 1);
378 if (INTERRUPTED(sp))
379 break;
382 ret: (void)gp->scr_move(sp, oldy, oldx);
383 (void)gp->scr_refresh(sp, 0);
387 * vs_output --
388 * Output the text to the screen.
390 static void
391 vs_output(SCR *sp, mtype_t mtype, const char *line, int llen)
393 char *kp;
394 GS *gp;
395 VI_PRIVATE *vip;
396 size_t chlen, notused;
397 int ch, len, rlen, tlen;
398 const char *p, *t;
399 char *cbp, *ecbp, cbuf[128];
401 gp = sp->gp;
402 vip = VIP(sp);
403 for (p = line, rlen = llen; llen > 0;) {
404 /* Get the next physical line. */
405 if ((p = memchr(line, '\n', llen)) == NULL)
406 len = llen;
407 else
408 len = p - line;
411 * The max is sp->cols characters, and we may have already
412 * written part of the line.
414 if (len + vip->lcontinue > sp->cols)
415 len = sp->cols - vip->lcontinue;
418 * If the first line output, do nothing. If the second line
419 * output, draw the divider line. If drew a full screen, we
420 * remove the divider line. If it's a continuation line, move
421 * to the continuation point, else, move the screen up.
423 if (vip->lcontinue == 0) {
424 if (!IS_ONELINE(sp)) {
425 if (vip->totalcount == 1) {
426 (void)gp->scr_move(sp,
427 LASTLINE(sp) - 1, 0);
428 (void)gp->scr_clrtoeol(sp);
429 (void)vs_divider(sp);
430 F_SET(vip, VIP_DIVIDER);
431 ++vip->totalcount;
432 ++vip->linecount;
434 if (vip->totalcount == sp->t_maxrows &&
435 F_ISSET(vip, VIP_DIVIDER)) {
436 --vip->totalcount;
437 --vip->linecount;
438 F_CLR(vip, VIP_DIVIDER);
441 if (vip->totalcount != 0)
442 vs_scroll(sp, NULL, SCROLL_W_QUIT);
444 (void)gp->scr_move(sp, LASTLINE(sp), 0);
445 ++vip->totalcount;
446 ++vip->linecount;
448 if (INTERRUPTED(sp))
449 break;
450 } else
451 (void)gp->scr_move(sp, LASTLINE(sp), vip->lcontinue);
453 /* Error messages are in inverse video. */
454 if (mtype == M_ERR)
455 (void)gp->scr_attr(sp, SA_INVERSE, 1);
457 /* Display the line, doing character translation. */
458 #define FLUSH { \
459 *cbp = '\0'; \
460 (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); \
461 cbp = cbuf; \
463 ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
464 for (t = line, tlen = len; tlen--; ++t) {
465 ch = *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 (ch == '\t')
474 ch = ' ';
475 chlen = KEY_LEN(sp, ch);
476 if (cbp + chlen >= ecbp)
477 FLUSH;
478 for (kp = KEY_NAME(sp, ch); chlen--;)
479 *cbp++ = *kp++;
481 if (cbp > cbuf)
482 FLUSH;
483 if (mtype == M_ERR)
484 (void)gp->scr_attr(sp, SA_INVERSE, 0);
486 /* Clear the rest of the line. */
487 (void)gp->scr_clrtoeol(sp);
489 /* If we loop, it's a new line. */
490 vip->lcontinue = 0;
492 /* Reset for the next line. */
493 line += len;
494 llen -= len;
495 if (p != NULL) {
496 ++line;
497 --llen;
501 /* Set up next continuation line. */
502 if (p == NULL)
503 gp->scr_cursor(sp, &notused, &vip->lcontinue);
507 * vs_ex_resolve --
508 * Deal with ex message output.
510 * This routine is called when exiting a colon command to resolve any ex
511 * output that may have occurred.
513 * PUBLIC: int vs_ex_resolve __P((SCR *, int *));
516 vs_ex_resolve(SCR *sp, int *continuep)
518 EVENT ev;
519 GS *gp;
520 VI_PRIVATE *vip;
521 sw_t wtype;
523 gp = sp->gp;
524 vip = VIP(sp);
525 *continuep = 0;
527 /* If we ran any ex command, we can't trust the cursor position. */
528 F_SET(vip, VIP_CUR_INVALID);
530 /* Terminate any partially written message. */
531 if (vip->lcontinue != 0) {
532 vs_output(sp, vip->mtype, ".", 1);
533 vip->lcontinue = 0;
535 vip->mtype = M_NONE;
539 * If we switched out of the vi screen into ex, switch back while we
540 * figure out what to do with the screen and potentially get another
541 * command to execute.
543 * If we didn't switch into ex, we're not required to wait, and less
544 * than 2 lines of output, we can continue without waiting for the
545 * wait.
547 * Note, all other code paths require waiting, so we leave the report
548 * of modified lines until later, so that we won't wait for no other
549 * reason than a threshold number of lines were modified. This means
550 * we display cumulative line modification reports for groups of ex
551 * commands. That seems right to me (well, at least not wrong).
553 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
554 if (sp->gp->scr_screen(sp, SC_VI))
555 return (1);
556 } else
557 if (!F_ISSET(sp, SC_EX_WAIT_YES) && vip->totalcount < 2) {
558 F_CLR(sp, SC_EX_WAIT_NO);
559 return (0);
562 /* Clear the required wait flag, it's no longer needed. */
563 F_CLR(sp, SC_EX_WAIT_YES);
566 * Wait, unless explicitly told not to wait or the user interrupted
567 * the command. If the user is leaving the screen, for any reason,
568 * they can't continue with further ex commands.
570 if (!F_ISSET(sp, SC_EX_WAIT_NO) && !INTERRUPTED(sp)) {
571 wtype = F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE |
572 SC_FSWITCH | SC_SSWITCH) ? SCROLL_W : SCROLL_W_EX;
573 if (F_ISSET(sp, SC_SCR_EXWROTE))
574 vs_wait(sp, continuep, wtype);
575 else
576 vs_scroll(sp, continuep, wtype);
577 if (*continuep)
578 return (0);
581 /* If ex wrote on the screen, refresh the screen image. */
582 if (F_ISSET(sp, SC_SCR_EXWROTE))
583 F_SET(vip, VIP_N_EX_PAINT);
586 * If we're not the bottom of the split screen stack, the screen
587 * image itself is wrong, so redraw everything.
589 if (sp->q.cqe_next != (void *)&sp->wp->scrq)
590 F_SET(sp, SC_SCR_REDRAW);
592 /* If ex changed the underlying file, the map itself is wrong. */
593 if (F_ISSET(vip, VIP_N_EX_REDRAW))
594 F_SET(sp, SC_SCR_REFORMAT);
596 /* Ex may have switched out of the alternate screen, return. */
597 (void)gp->scr_attr(sp, SA_ALTERNATE, 1);
600 * Whew. We're finally back home, after what feels like years.
601 * Kiss the ground.
603 F_CLR(sp, SC_SCR_EXWROTE | SC_EX_WAIT_NO);
606 * We may need to repaint some of the screen, e.g.:
608 * :set
609 * :!ls
611 * gives us a combination of some lines that are "wrong", and a need
612 * for a full refresh.
614 if (vip->totalcount > 1) {
615 /* Set up the redraw of the overwritten lines. */
616 ev.e_event = E_REPAINT;
617 ev.e_flno = vip->totalcount >=
618 sp->rows ? 1 : sp->rows - vip->totalcount;
619 ev.e_tlno = sp->rows;
621 /* Reset the count of overwriting lines. */
622 vip->linecount = vip->lcontinue = vip->totalcount = 0;
624 /* Redraw. */
625 (void)v_erepaint(sp, &ev);
626 } else
627 /* Reset the count of overwriting lines. */
628 vip->linecount = vip->lcontinue = vip->totalcount = 0;
630 return (0);
634 * vs_resolve --
635 * Deal with message output.
637 * PUBLIC: int vs_resolve __P((SCR *, SCR *, int));
640 vs_resolve(SCR *sp, SCR *csp, int forcewait)
642 EVENT ev;
643 GS *gp;
644 WIN *wp;
645 MSGS *mp;
646 VI_PRIVATE *vip;
647 size_t oldy, oldx;
648 int redraw;
651 * Vs_resolve is called from the main vi loop and the refresh function
652 * to periodically ensure that the user has seen any messages that have
653 * been displayed and that any status lines are correct. The sp screen
654 * is the screen we're checking, usually the current screen. When it's
655 * not, csp is the current screen, used for final cursor positioning.
657 gp = sp->gp;
658 wp = sp->wp;
659 vip = VIP(sp);
660 if (csp == NULL)
661 csp = sp;
663 /* Save the cursor position. */
664 (void)gp->scr_cursor(csp, &oldy, &oldx);
666 /* Ring the bell if it's scheduled. */
667 if (F_ISSET(gp, G_BELLSCHED)) {
668 F_CLR(gp, G_BELLSCHED);
669 (void)gp->scr_bell(sp);
672 /* Display new file status line. */
673 if (F_ISSET(sp, SC_STATUS)) {
674 F_CLR(sp, SC_STATUS);
675 msgq_status(sp, sp->lno, MSTAT_TRUNCATE);
678 /* Report on line modifications. */
679 mod_rpt(sp);
682 * Flush any saved messages. If the screen isn't ready, refresh
683 * it. (A side-effect of screen refresh is that we can display
684 * messages.) Once this is done, don't trust the cursor. That
685 * extra refresh screwed the pooch.
687 if (gp->msgq.lh_first != NULL) {
688 if (!F_ISSET(sp, SC_SCR_VI) && vs_refresh(sp, 1))
689 return (1);
690 while ((mp = gp->msgq.lh_first) != NULL) {
691 wp->scr_msg(sp, mp->mtype, mp->buf, mp->len);
692 LIST_REMOVE(mp, q);
693 free(mp->buf);
694 free(mp);
696 F_SET(vip, VIP_CUR_INVALID);
699 switch (vip->totalcount) {
700 case 0:
701 redraw = 0;
702 break;
703 case 1:
705 * If we're switching screens, we have to wait for messages,
706 * regardless. If we don't wait, skip updating the modeline.
708 if (forcewait)
709 vs_scroll(sp, NULL, SCROLL_W);
710 else
711 F_SET(vip, VIP_S_MODELINE);
713 redraw = 0;
714 break;
715 default:
717 * If >1 message line in use, prompt the user to continue and
718 * repaint overwritten lines.
720 vs_scroll(sp, NULL, SCROLL_W);
722 ev.e_event = E_REPAINT;
723 ev.e_flno = vip->totalcount >=
724 sp->rows ? 1 : sp->rows - vip->totalcount;
725 ev.e_tlno = sp->rows;
727 redraw = 1;
728 break;
731 /* Reset the count of overwriting lines. */
732 vip->linecount = vip->lcontinue = vip->totalcount = 0;
734 /* Redraw. */
735 if (redraw)
736 (void)v_erepaint(sp, &ev);
738 /* Restore the cursor position. */
739 (void)gp->scr_move(csp, oldy, oldx);
741 return (0);
745 * vs_scroll --
746 * Scroll the screen for output.
748 static void
749 vs_scroll(SCR *sp, int *continuep, sw_t wtype)
751 GS *gp;
752 VI_PRIVATE *vip;
754 gp = sp->gp;
755 vip = VIP(sp);
756 if (!IS_ONELINE(sp)) {
758 * Scroll the screen. Instead of scrolling the entire screen,
759 * delete the line above the first line output so preserve the
760 * maximum amount of the screen.
762 (void)gp->scr_move(sp, vip->totalcount <
763 sp->rows ? LASTLINE(sp) - vip->totalcount : 0, 0);
764 (void)gp->scr_deleteln(sp);
766 /* If there are screens below us, push them back into place. */
767 if (sp->q.cqe_next != (void *)&sp->wp->scrq) {
768 (void)gp->scr_move(sp, LASTLINE(sp), 0);
769 (void)gp->scr_insertln(sp);
772 if (wtype == SCROLL_W_QUIT && vip->linecount < sp->t_maxrows)
773 return;
774 vs_wait(sp, continuep, wtype);
778 * vs_wait --
779 * Prompt the user to continue.
781 static void
782 vs_wait(SCR *sp, int *continuep, sw_t wtype)
784 EVENT ev;
785 VI_PRIVATE *vip;
786 const char *p;
787 GS *gp;
788 size_t len;
790 gp = sp->gp;
791 vip = VIP(sp);
793 (void)gp->scr_move(sp, LASTLINE(sp), 0);
794 if (IS_ONELINE(sp))
795 p = msg_cmsg(sp, CMSG_CONT_S, &len);
796 else
797 switch (wtype) {
798 case SCROLL_W_QUIT:
799 p = msg_cmsg(sp, CMSG_CONT_Q, &len);
800 break;
801 case SCROLL_W_EX:
802 p = msg_cmsg(sp, CMSG_CONT_EX, &len);
803 break;
804 case SCROLL_W:
805 p = msg_cmsg(sp, CMSG_CONT, &len);
806 break;
807 default:
808 abort();
809 /* NOTREACHED */
811 (void)gp->scr_addstr(sp, p, len);
813 ++vip->totalcount;
814 vip->linecount = 0;
816 (void)gp->scr_clrtoeol(sp);
817 (void)gp->scr_refresh(sp, 0);
819 /* Get a single character from the terminal. */
820 if (continuep != NULL)
821 *continuep = 0;
822 for (;;) {
823 if (v_event_get(sp, &ev, 0, 0))
824 return;
825 if (ev.e_event == E_CHARACTER)
826 break;
827 if (ev.e_event == E_INTERRUPT) {
828 ev.e_c = CH_QUIT;
829 F_SET(gp, G_INTERRUPTED);
830 break;
832 (void)gp->scr_bell(sp);
834 switch (wtype) {
835 case SCROLL_W_QUIT:
836 if (ev.e_c == CH_QUIT)
837 F_SET(gp, G_INTERRUPTED);
838 break;
839 case SCROLL_W_EX:
840 if (ev.e_c == ':' && continuep != NULL)
841 *continuep = 1;
842 break;
843 case SCROLL_W:
844 break;
849 * vs_divider --
850 * Draw a dividing line between the screen and the output.
852 static void
853 vs_divider(SCR *sp)
855 GS *gp;
856 size_t len;
858 #define DIVIDESTR "+=+=+=+=+=+=+=+"
859 len =
860 sizeof(DIVIDESTR) - 1 > sp->cols ? sp->cols : sizeof(DIVIDESTR) - 1;
861 gp = sp->gp;
862 (void)gp->scr_attr(sp, SA_INVERSE, 1);
863 (void)gp->scr_addstr(sp, DIVIDESTR, len);
864 (void)gp->scr_attr(sp, SA_INVERSE, 0);
868 * vs_msgsave --
869 * Save a message for later display.
871 static void
872 vs_msgsave(SCR *sp, mtype_t mt, char *p, size_t len)
874 GS *gp;
875 MSGS *mp_c, *mp_n;
878 * We have to handle messages before we have any place to put them.
879 * If there's no screen support yet, allocate a msg structure, copy
880 * in the message, and queue it on the global structure. If we can't
881 * allocate memory here, we're genuinely screwed, dump the message
882 * to stderr in the (probably) vain hope that someone will see it.
884 CALLOC_GOTO(sp, mp_n, MSGS *, 1, sizeof(MSGS));
885 MALLOC_GOTO(sp, mp_n->buf, char *, len);
887 memmove(mp_n->buf, p, len);
888 mp_n->len = len;
889 mp_n->mtype = mt;
891 gp = sp->gp;
892 if ((mp_c = gp->msgq.lh_first) == NULL) {
893 LIST_INSERT_HEAD(&gp->msgq, mp_n, q);
894 } else {
895 for (; mp_c->q.le_next != NULL; mp_c = mp_c->q.le_next);
896 LIST_INSERT_AFTER(mp_c, mp_n, q);
898 return;
900 alloc_err:
901 if (mp_n != NULL)
902 free(mp_n);
903 (void)fprintf(stderr, "%.*s\n", (int)len, p);