Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / nvi / vi / vs_msg.c
blob1b50bd32d167ecba0fc51dad96c253c6c73180b4
1 /* $NetBSD: vs_msg.c,v 1.2 2008/12/05 22:51:43 christos Exp $ */
3 /*-
4 * Copyright (c) 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7 * Keith Bostic. All rights reserved.
9 * See the LICENSE file for redistribution information.
12 #include "config.h"
14 #ifndef lint
15 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";
16 #endif /* not lint */
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/time.h>
22 #include <bitstring.h>
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
29 #include "../common/common.h"
30 #include "vi.h"
32 typedef enum {
33 SCROLL_W, /* User wait. */
34 SCROLL_W_EX, /* User wait, or enter : to continue. */
35 SCROLL_W_QUIT /* User wait, or enter q to quit. */
37 * SCROLL_W_QUIT has another semantic
38 * -- only wait if the screen is full
40 } sw_t;
42 static void vs_divider __P((SCR *));
43 static void vs_msgsave __P((SCR *, mtype_t, char *, size_t));
44 static void vs_output __P((SCR *, mtype_t, const char *, int));
45 static void vs_scroll __P((SCR *, int *, sw_t));
46 static void vs_wait __P((SCR *, int *, sw_t));
49 * vs_busy --
50 * Display, update or clear a busy message.
52 * This routine is the default editor interface for vi busy messages. It
53 * implements a standard strategy of stealing lines from the bottom of the
54 * vi text screen. Screens using an alternate method of displaying busy
55 * messages, e.g. X11 clock icons, should set their scr_busy function to the
56 * correct function before calling the main editor routine.
58 * PUBLIC: void vs_busy __P((SCR *, const char *, busy_t));
60 void
61 vs_busy(SCR *sp, const char *msg, busy_t btype)
63 GS *gp;
64 VI_PRIVATE *vip;
65 static const char flagc[] = "|/-\\";
66 struct timeval tv;
67 size_t len, notused;
68 const char *p;
70 /* Ex doesn't display busy messages. */
71 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
72 return;
74 gp = sp->gp;
75 vip = VIP(sp);
78 * Most of this routine is to deal with the screen sharing real estate
79 * between the normal edit messages and the busy messages. Logically,
80 * all that's needed is something that puts up a message, periodically
81 * updates it, and then goes away.
83 switch (btype) {
84 case BUSY_ON:
85 ++vip->busy_ref;
86 if (vip->totalcount != 0 || vip->busy_ref != 1)
87 break;
89 /* Initialize state for updates. */
90 vip->busy_ch = 0;
91 (void)gettimeofday(&vip->busy_tv, NULL);
93 /* Save the current cursor. */
94 (void)gp->scr_cursor(sp, &vip->busy_oldy, &vip->busy_oldx);
96 /* Display the busy message. */
97 p = msg_cat(sp, msg, &len);
98 (void)gp->scr_move(sp, LASTLINE(sp), 0);
99 (void)gp->scr_addstr(sp, p, len);
100 (void)gp->scr_cursor(sp, &notused, &vip->busy_fx);
101 (void)gp->scr_clrtoeol(sp);
102 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
103 break;
104 case BUSY_OFF:
105 if (vip->busy_ref == 0)
106 break;
107 --vip->busy_ref;
110 * If the line isn't in use for another purpose, clear it.
111 * Always return to the original position.
113 if (vip->totalcount == 0 && vip->busy_ref == 0) {
114 (void)gp->scr_move(sp, LASTLINE(sp), 0);
115 (void)gp->scr_clrtoeol(sp);
117 (void)gp->scr_move(sp, vip->busy_oldy, vip->busy_oldx);
118 break;
119 case BUSY_UPDATE:
120 if (vip->totalcount != 0 || vip->busy_ref == 0)
121 break;
123 /* Update no more than every 1/8 of a second. */
124 (void)gettimeofday(&tv, NULL);
125 if (((tv.tv_sec - vip->busy_tv.tv_sec) * 1000000 +
126 (tv.tv_usec - vip->busy_tv.tv_usec)) < 125000)
127 return;
128 vip->busy_tv = tv;
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 __P((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 __P((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%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 __P((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);
256 * If vi is using the error line for text input, there's no screen
257 * real-estate for the error message. Nothing to do without some
258 * information as to how important the error message is.
260 if (F_ISSET(sp, SC_TINPUT_INFO))
261 return;
264 * Ex or ex controlled screen output.
266 * If output happens during startup, e.g., a .exrc file, we may be
267 * in ex mode but haven't initialized the screen. Initialize here,
268 * and in this case, stay in ex mode.
270 * If the SC_SCR_EXWROTE bit is set, then we're switching back and
271 * forth between ex and vi, but the screen is trashed and we have
272 * to respect that. Switch to ex mode long enough to put out the
273 * message.
275 * If the SC_EX_WAIT_NO bit is set, turn it off -- we're writing to
276 * the screen, so previous opinions are ignored.
278 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
279 if (!F_ISSET(sp, SC_SCR_EX)) {
280 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
281 if (sp->gp->scr_screen(sp, SC_EX))
282 return;
283 } else
284 if (ex_init(sp))
285 return;
288 if (mtype == M_ERR)
289 (void)gp->scr_attr(sp, SA_INVERSE, 1);
290 (void)printf("%.*s", (int)len, line);
291 if (mtype == M_ERR)
292 (void)gp->scr_attr(sp, SA_INVERSE, 0);
293 (void)fflush(stdout);
295 F_CLR(sp, SC_EX_WAIT_NO);
297 if (!F_ISSET(sp, SC_SCR_EX))
298 (void)sp->gp->scr_screen(sp, SC_VI);
299 return;
302 /* If the vi screen isn't ready, save the message. */
303 if (!F_ISSET(sp, SC_SCR_VI)) {
304 (void)vs_msgsave(sp, mtype, line, len);
305 return;
308 /* Save the cursor position. */
309 (void)gp->scr_cursor(sp, &oldy, &oldx);
311 /* If it's an ex output message, just write it out. */
312 if (mtype == M_NONE) {
313 vs_output(sp, mtype, line, len);
314 goto ret;
318 * If it's a vi message, strip the trailing <newline> so we can
319 * try and paste messages together.
321 if (line[len - 1] == '\n')
322 --len;
325 * If a message won't fit on a single line, try to split on a <blank>.
326 * If a subsequent message fits on the same line, write a separator
327 * and output it. Otherwise, put out a newline.
329 * Need up to two padding characters normally; a semi-colon and a
330 * separating space. If only a single line on the screen, add some
331 * more for the trailing continuation message.
333 * XXX
334 * Assume that periods and semi-colons take up a single column on the
335 * screen.
337 * XXX
338 * There are almost certainly pathological cases that will break this
339 * code.
341 if (IS_ONELINE(sp))
342 (void)msg_cmsg(sp, CMSG_CONT_S, &padding);
343 else
344 padding = 0;
345 padding += 2;
347 maxcols = sp->cols - 1;
348 if (vip->lcontinue != 0) {
349 if (len + vip->lcontinue + padding > maxcols)
350 vs_output(sp, vip->mtype, ".\n", 2);
351 else {
352 vs_output(sp, vip->mtype, ";", 1);
353 vs_output(sp, M_NONE, " ", 1);
356 vip->mtype = mtype;
357 for (s = line;; s = t) {
358 for (; len > 0 && isblank(*s); --len, ++s);
359 if (len == 0)
360 break;
361 if (len + vip->lcontinue > maxcols) {
362 for (e = s + (maxcols - vip->lcontinue);
363 e > s && !isblank(*e); --e);
364 if (e == s)
365 e = t = s + (maxcols - vip->lcontinue);
366 else
367 for (t = e; isblank(e[-1]); --e);
368 } else
369 e = t = s + len;
372 * If the message ends in a period, discard it, we want to
373 * gang messages where possible.
375 len -= t - s;
376 if (len == 0 && (e - s) > 1 && s[(e - s) - 1] == '.')
377 --e;
378 vs_output(sp, mtype, s, e - s);
380 if (len != 0)
381 vs_output(sp, M_NONE, "\n", 1);
383 if (INTERRUPTED(sp))
384 break;
387 ret: (void)gp->scr_move(sp, oldy, oldx);
388 (void)gp->scr_refresh(sp, 0);
392 * vs_output --
393 * Output the text to the screen.
395 static void
396 vs_output(SCR *sp, mtype_t mtype, const char *line, int llen)
398 unsigned char *kp;
399 GS *gp;
400 VI_PRIVATE *vip;
401 size_t chlen, notused;
402 int ch, len, rlen, tlen;
403 const char *p, *t;
404 char *cbp, *ecbp, cbuf[128];
406 gp = sp->gp;
407 vip = VIP(sp);
408 for (p = line, rlen = llen; llen > 0;) {
409 /* Get the next physical line. */
410 if ((p = memchr(line, '\n', llen)) == NULL)
411 len = llen;
412 else
413 len = p - line;
416 * The max is sp->cols characters, and we may have already
417 * written part of the line.
419 if (len + vip->lcontinue > sp->cols)
420 len = sp->cols - vip->lcontinue;
423 * If the first line output, do nothing. If the second line
424 * output, draw the divider line. If drew a full screen, we
425 * remove the divider line. If it's a continuation line, move
426 * to the continuation point, else, move the screen up.
428 if (vip->lcontinue == 0) {
429 if (!IS_ONELINE(sp)) {
430 if (vip->totalcount == 1) {
431 (void)gp->scr_move(sp,
432 LASTLINE(sp) - 1, 0);
433 (void)gp->scr_clrtoeol(sp);
434 (void)vs_divider(sp);
435 F_SET(vip, VIP_DIVIDER);
436 ++vip->totalcount;
437 ++vip->linecount;
439 if (vip->totalcount == sp->t_maxrows &&
440 F_ISSET(vip, VIP_DIVIDER)) {
441 --vip->totalcount;
442 --vip->linecount;
443 F_CLR(vip, VIP_DIVIDER);
446 if (vip->totalcount != 0)
447 vs_scroll(sp, NULL, SCROLL_W_QUIT);
449 (void)gp->scr_move(sp, LASTLINE(sp), 0);
450 ++vip->totalcount;
451 ++vip->linecount;
453 if (INTERRUPTED(sp))
454 break;
455 } else
456 (void)gp->scr_move(sp, LASTLINE(sp), vip->lcontinue);
458 /* Error messages are in inverse video. */
459 if (mtype == M_ERR)
460 (void)gp->scr_attr(sp, SA_INVERSE, 1);
462 /* Display the line, doing character translation. */
463 #define FLUSH { \
464 *cbp = '\0'; \
465 (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); \
466 cbp = cbuf; \
468 ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
469 for (t = line, tlen = len; tlen--; ++t) {
470 ch = *t;
472 * Replace tabs with spaces, there are places in
473 * ex that do column calculations without looking
474 * at <tabs> -- and all routines that care about
475 * <tabs> do their own expansions. This catches
476 * <tabs> in things like tag search strings.
478 if (ch == '\t')
479 ch = ' ';
480 chlen = KEY_LEN(sp, ch);
481 if (cbp + chlen >= ecbp)
482 FLUSH;
483 for (kp = KEY_NAME(sp, ch); chlen--;)
484 *cbp++ = *kp++;
486 if (cbp > cbuf)
487 FLUSH;
488 if (mtype == M_ERR)
489 (void)gp->scr_attr(sp, SA_INVERSE, 0);
491 /* Clear the rest of the line. */
492 (void)gp->scr_clrtoeol(sp);
494 /* If we loop, it's a new line. */
495 vip->lcontinue = 0;
497 /* Reset for the next line. */
498 line += len;
499 llen -= len;
500 if (p != NULL) {
501 ++line;
502 --llen;
506 /* Set up next continuation line. */
507 if (p == NULL)
508 gp->scr_cursor(sp, &notused, &vip->lcontinue);
512 * vs_ex_resolve --
513 * Deal with ex message output.
515 * This routine is called when exiting a colon command to resolve any ex
516 * output that may have occurred.
518 * PUBLIC: int vs_ex_resolve __P((SCR *, int *));
521 vs_ex_resolve(SCR *sp, int *continuep)
523 EVENT ev;
524 GS *gp;
525 VI_PRIVATE *vip;
526 sw_t wtype;
528 gp = sp->gp;
529 vip = VIP(sp);
530 *continuep = 0;
532 /* If we ran any ex command, we can't trust the cursor position. */
533 F_SET(vip, VIP_CUR_INVALID);
535 /* Terminate any partially written message. */
536 if (vip->lcontinue != 0) {
537 vs_output(sp, vip->mtype, ".", 1);
538 vip->lcontinue = 0;
540 vip->mtype = M_NONE;
544 * If we switched out of the vi screen into ex, switch back while we
545 * figure out what to do with the screen and potentially get another
546 * command to execute.
548 * If we didn't switch into ex, we're not required to wait, and less
549 * than 2 lines of output, we can continue without waiting for the
550 * wait.
552 * Note, all other code paths require waiting, so we leave the report
553 * of modified lines until later, so that we won't wait for no other
554 * reason than a threshold number of lines were modified. This means
555 * we display cumulative line modification reports for groups of ex
556 * commands. That seems right to me (well, at least not wrong).
558 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
559 if (sp->gp->scr_screen(sp, SC_VI))
560 return (1);
561 } else
562 if (!F_ISSET(sp, SC_EX_WAIT_YES) && vip->totalcount < 2) {
563 F_CLR(sp, SC_EX_WAIT_NO);
564 return (0);
567 /* Clear the required wait flag, it's no longer needed. */
568 F_CLR(sp, SC_EX_WAIT_YES);
571 * Wait, unless explicitly told not to wait or the user interrupted
572 * the command. If the user is leaving the screen, for any reason,
573 * they can't continue with further ex commands.
575 if (!F_ISSET(sp, SC_EX_WAIT_NO) && !INTERRUPTED(sp)) {
576 wtype = F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE |
577 SC_FSWITCH | SC_SSWITCH) ? SCROLL_W : SCROLL_W_EX;
578 if (F_ISSET(sp, SC_SCR_EXWROTE))
579 vs_wait(sp, continuep, wtype);
580 else
581 vs_scroll(sp, continuep, wtype);
582 if (*continuep)
583 return (0);
586 /* If ex wrote on the screen, refresh the screen image. */
587 if (F_ISSET(sp, SC_SCR_EXWROTE))
588 F_SET(vip, VIP_N_EX_PAINT);
591 * If we're not the bottom of the split screen stack, the screen
592 * image itself is wrong, so redraw everything.
594 if (sp->q.cqe_next != (void *)&sp->wp->scrq)
595 F_SET(sp, SC_SCR_REDRAW);
597 /* If ex changed the underlying file, the map itself is wrong. */
598 if (F_ISSET(vip, VIP_N_EX_REDRAW))
599 F_SET(sp, SC_SCR_REFORMAT);
601 /* Ex may have switched out of the alternate screen, return. */
602 (void)gp->scr_attr(sp, SA_ALTERNATE, 1);
605 * Whew. We're finally back home, after what feels like years.
606 * Kiss the ground.
608 F_CLR(sp, SC_SCR_EXWROTE | SC_EX_WAIT_NO);
611 * We may need to repaint some of the screen, e.g.:
613 * :set
614 * :!ls
616 * gives us a combination of some lines that are "wrong", and a need
617 * for a full refresh.
619 if (vip->totalcount > 1) {
620 /* Set up the redraw of the overwritten lines. */
621 ev.e_event = E_REPAINT;
622 ev.e_flno = vip->totalcount >=
623 sp->rows ? 1 : sp->rows - vip->totalcount;
624 ev.e_tlno = sp->rows;
626 /* Reset the count of overwriting lines. */
627 vip->linecount = vip->lcontinue = vip->totalcount = 0;
629 /* Redraw. */
630 (void)v_erepaint(sp, &ev);
631 } else
632 /* Reset the count of overwriting lines. */
633 vip->linecount = vip->lcontinue = vip->totalcount = 0;
635 return (0);
639 * vs_resolve --
640 * Deal with message output.
642 * PUBLIC: int vs_resolve __P((SCR *, SCR *, int));
645 vs_resolve(SCR *sp, SCR *csp, int forcewait)
647 EVENT ev;
648 GS *gp;
649 WIN *wp;
650 MSGS *mp;
651 VI_PRIVATE *vip;
652 size_t oldy, oldx;
653 int redraw;
656 * Vs_resolve is called from the main vi loop and the refresh function
657 * to periodically ensure that the user has seen any messages that have
658 * been displayed and that any status lines are correct. The sp screen
659 * is the screen we're checking, usually the current screen. When it's
660 * not, csp is the current screen, used for final cursor positioning.
662 gp = sp->gp;
663 wp = sp->wp;
664 vip = VIP(sp);
665 if (csp == NULL)
666 csp = sp;
668 /* Save the cursor position. */
669 (void)gp->scr_cursor(csp, &oldy, &oldx);
671 /* Ring the bell if it's scheduled. */
672 if (F_ISSET(gp, G_BELLSCHED)) {
673 F_CLR(gp, G_BELLSCHED);
674 (void)gp->scr_bell(sp);
677 /* Display new file status line. */
678 if (F_ISSET(sp, SC_STATUS)) {
679 F_CLR(sp, SC_STATUS);
680 msgq_status(sp, sp->lno, MSTAT_TRUNCATE);
683 /* Report on line modifications. */
684 mod_rpt(sp);
687 * Flush any saved messages. If the screen isn't ready, refresh
688 * it. (A side-effect of screen refresh is that we can display
689 * messages.) Once this is done, don't trust the cursor. That
690 * extra refresh screwed the pooch.
692 if (gp->msgq.lh_first != NULL) {
693 if (!F_ISSET(sp, SC_SCR_VI) && vs_refresh(sp, 1))
694 return (1);
695 while ((mp = gp->msgq.lh_first) != NULL) {
696 wp->scr_msg(sp, mp->mtype, mp->buf, mp->len);
697 LIST_REMOVE(mp, q);
698 free(mp->buf);
699 free(mp);
701 F_SET(vip, VIP_CUR_INVALID);
704 switch (vip->totalcount) {
705 case 0:
706 redraw = 0;
707 break;
708 case 1:
710 * If we're switching screens, we have to wait for messages,
711 * regardless. If we don't wait, skip updating the modeline.
713 if (forcewait)
714 vs_scroll(sp, NULL, SCROLL_W);
715 else
716 F_SET(vip, VIP_S_MODELINE);
718 redraw = 0;
719 break;
720 default:
722 * If >1 message line in use, prompt the user to continue and
723 * repaint overwritten lines.
725 vs_scroll(sp, NULL, SCROLL_W);
727 ev.e_event = E_REPAINT;
728 ev.e_flno = vip->totalcount >=
729 sp->rows ? 1 : sp->rows - vip->totalcount;
730 ev.e_tlno = sp->rows;
732 redraw = 1;
733 break;
736 /* Reset the count of overwriting lines. */
737 vip->linecount = vip->lcontinue = vip->totalcount = 0;
739 /* Redraw. */
740 if (redraw)
741 (void)v_erepaint(sp, &ev);
743 /* Restore the cursor position. */
744 (void)gp->scr_move(csp, oldy, oldx);
746 return (0);
750 * vs_scroll --
751 * Scroll the screen for output.
753 static void
754 vs_scroll(SCR *sp, int *continuep, sw_t wtype)
756 GS *gp;
757 VI_PRIVATE *vip;
759 gp = sp->gp;
760 vip = VIP(sp);
761 if (!IS_ONELINE(sp)) {
763 * Scroll the screen. Instead of scrolling the entire screen,
764 * delete the line above the first line output so preserve the
765 * maximum amount of the screen.
767 (void)gp->scr_move(sp, vip->totalcount <
768 sp->rows ? LASTLINE(sp) - vip->totalcount : 0, 0);
769 (void)gp->scr_deleteln(sp);
771 /* If there are screens below us, push them back into place. */
772 if (sp->q.cqe_next != (void *)&sp->wp->scrq) {
773 (void)gp->scr_move(sp, LASTLINE(sp), 0);
774 (void)gp->scr_insertln(sp);
777 if (wtype == SCROLL_W_QUIT && vip->linecount < sp->t_maxrows)
778 return;
779 vs_wait(sp, continuep, wtype);
783 * vs_wait --
784 * Prompt the user to continue.
786 static void
787 vs_wait(SCR *sp, int *continuep, sw_t wtype)
789 EVENT ev;
790 VI_PRIVATE *vip;
791 const char *p;
792 GS *gp;
793 size_t len;
795 gp = sp->gp;
796 vip = VIP(sp);
798 (void)gp->scr_move(sp, LASTLINE(sp), 0);
799 if (IS_ONELINE(sp))
800 p = msg_cmsg(sp, CMSG_CONT_S, &len);
801 else
802 switch (wtype) {
803 case SCROLL_W_QUIT:
804 p = msg_cmsg(sp, CMSG_CONT_Q, &len);
805 break;
806 case SCROLL_W_EX:
807 p = msg_cmsg(sp, CMSG_CONT_EX, &len);
808 break;
809 case SCROLL_W:
810 p = msg_cmsg(sp, CMSG_CONT, &len);
811 break;
812 default:
813 abort();
814 /* NOTREACHED */
816 (void)gp->scr_addstr(sp, p, len);
818 ++vip->totalcount;
819 vip->linecount = 0;
821 (void)gp->scr_clrtoeol(sp);
822 (void)gp->scr_refresh(sp, 0);
824 /* Get a single character from the terminal. */
825 if (continuep != NULL)
826 *continuep = 0;
827 for (;;) {
828 if (v_event_get(sp, &ev, 0, 0))
829 return;
830 if (ev.e_event == E_CHARACTER)
831 break;
832 if (ev.e_event == E_INTERRUPT) {
833 ev.e_c = CH_QUIT;
834 F_SET(gp, G_INTERRUPTED);
835 break;
837 (void)gp->scr_bell(sp);
839 switch (wtype) {
840 case SCROLL_W_QUIT:
841 if (ev.e_c == CH_QUIT)
842 F_SET(gp, G_INTERRUPTED);
843 break;
844 case SCROLL_W_EX:
845 if (ev.e_c == ':' && continuep != NULL)
846 *continuep = 1;
847 break;
848 case SCROLL_W:
849 break;
854 * vs_divider --
855 * Draw a dividing line between the screen and the output.
857 static void
858 vs_divider(SCR *sp)
860 GS *gp;
861 size_t len;
863 #define DIVIDESTR "+=+=+=+=+=+=+=+"
864 len =
865 sizeof(DIVIDESTR) - 1 > sp->cols ? sp->cols : sizeof(DIVIDESTR) - 1;
866 gp = sp->gp;
867 (void)gp->scr_attr(sp, SA_INVERSE, 1);
868 (void)gp->scr_addstr(sp, DIVIDESTR, len);
869 (void)gp->scr_attr(sp, SA_INVERSE, 0);
873 * vs_msgsave --
874 * Save a message for later display.
876 static void
877 vs_msgsave(SCR *sp, mtype_t mt, char *p, size_t len)
879 GS *gp;
880 MSGS *mp_c, *mp_n;
883 * We have to handle messages before we have any place to put them.
884 * If there's no screen support yet, allocate a msg structure, copy
885 * in the message, and queue it on the global structure. If we can't
886 * allocate memory here, we're genuinely screwed, dump the message
887 * to stderr in the (probably) vain hope that someone will see it.
889 CALLOC_GOTO(sp, mp_n, MSGS *, 1, sizeof(MSGS));
890 MALLOC_GOTO(sp, mp_n->buf, char *, len);
892 memmove(mp_n->buf, p, len);
893 mp_n->len = len;
894 mp_n->mtype = mt;
896 gp = sp->gp;
897 if ((mp_c = gp->msgq.lh_first) == NULL) {
898 LIST_INSERT_HEAD(&gp->msgq, mp_n, q);
899 } else {
900 for (; mp_c->q.le_next != NULL; mp_c = mp_c->q.le_next);
901 LIST_INSERT_AFTER(mp_c, mp_n, q);
903 return;
905 alloc_err:
906 if (mp_n != NULL)
907 free(mp_n);
908 (void)fprintf(stderr, "%.*s\n", (int)len, p);