Home | History | Annotate | Line # | Download | only in vi
vs_msg.c revision 1.6
      1  1.6  christos /*	$NetBSD: vs_msg.c,v 1.6 2014/01/26 21:43:45 christos Exp $ */
      2  1.1  christos /*-
      3  1.1  christos  * Copyright (c) 1993, 1994
      4  1.1  christos  *	The Regents of the University of California.  All rights reserved.
      5  1.1  christos  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      6  1.1  christos  *	Keith Bostic.  All rights reserved.
      7  1.1  christos  *
      8  1.1  christos  * See the LICENSE file for redistribution information.
      9  1.1  christos  */
     10  1.1  christos 
     11  1.1  christos #include "config.h"
     12  1.1  christos 
     13  1.6  christos #include <sys/cdefs.h>
     14  1.6  christos #if 0
     15  1.1  christos #ifndef lint
     16  1.1  christos 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 ";
     17  1.1  christos #endif /* not lint */
     18  1.6  christos #else
     19  1.6  christos __RCSID("$NetBSD: vs_msg.c,v 1.6 2014/01/26 21:43:45 christos Exp $");
     20  1.6  christos #endif
     21  1.1  christos 
     22  1.1  christos #include <sys/types.h>
     23  1.1  christos #include <sys/queue.h>
     24  1.1  christos #include <sys/time.h>
     25  1.1  christos 
     26  1.1  christos #include <bitstring.h>
     27  1.1  christos #include <ctype.h>
     28  1.1  christos #include <stdio.h>
     29  1.1  christos #include <stdlib.h>
     30  1.1  christos #include <string.h>
     31  1.1  christos #include <unistd.h>
     32  1.1  christos 
     33  1.1  christos #include "../common/common.h"
     34  1.1  christos #include "vi.h"
     35  1.1  christos 
     36  1.1  christos typedef enum {
     37  1.1  christos 	SCROLL_W,			/* User wait. */
     38  1.1  christos 	SCROLL_W_EX,			/* User wait, or enter : to continue. */
     39  1.1  christos 	SCROLL_W_QUIT			/* User wait, or enter q to quit. */
     40  1.1  christos 					/*
     41  1.1  christos 					 * SCROLL_W_QUIT has another semantic
     42  1.1  christos 					 * -- only wait if the screen is full
     43  1.1  christos 					 */
     44  1.1  christos } sw_t;
     45  1.1  christos 
     46  1.1  christos static void	vs_divider __P((SCR *));
     47  1.1  christos static void	vs_msgsave __P((SCR *, mtype_t, char *, size_t));
     48  1.1  christos static void	vs_output __P((SCR *, mtype_t, const char *, int));
     49  1.1  christos static void	vs_scroll __P((SCR *, int *, sw_t));
     50  1.1  christos static void	vs_wait __P((SCR *, int *, sw_t));
     51  1.1  christos 
     52  1.1  christos /*
     53  1.1  christos  * vs_busy --
     54  1.1  christos  *	Display, update or clear a busy message.
     55  1.1  christos  *
     56  1.1  christos  * This routine is the default editor interface for vi busy messages.  It
     57  1.1  christos  * implements a standard strategy of stealing lines from the bottom of the
     58  1.1  christos  * vi text screen.  Screens using an alternate method of displaying busy
     59  1.1  christos  * messages, e.g. X11 clock icons, should set their scr_busy function to the
     60  1.1  christos  * correct function before calling the main editor routine.
     61  1.1  christos  *
     62  1.1  christos  * PUBLIC: void vs_busy __P((SCR *, const char *, busy_t));
     63  1.1  christos  */
     64  1.1  christos void
     65  1.1  christos vs_busy(SCR *sp, const char *msg, busy_t btype)
     66  1.1  christos {
     67  1.1  christos 	GS *gp;
     68  1.1  christos 	VI_PRIVATE *vip;
     69  1.1  christos 	static const char flagc[] = "|/-\\";
     70  1.1  christos 	struct timeval tv;
     71  1.1  christos 	size_t len, notused;
     72  1.1  christos 	const char *p;
     73  1.1  christos 
     74  1.1  christos 	/* Ex doesn't display busy messages. */
     75  1.1  christos 	if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
     76  1.1  christos 		return;
     77  1.1  christos 
     78  1.1  christos 	gp = sp->gp;
     79  1.1  christos 	vip = VIP(sp);
     80  1.1  christos 
     81  1.1  christos 	/*
     82  1.1  christos 	 * Most of this routine is to deal with the screen sharing real estate
     83  1.1  christos 	 * between the normal edit messages and the busy messages.  Logically,
     84  1.1  christos 	 * all that's needed is something that puts up a message, periodically
     85  1.1  christos 	 * updates it, and then goes away.
     86  1.1  christos 	 */
     87  1.1  christos 	switch (btype) {
     88  1.1  christos 	case BUSY_ON:
     89  1.1  christos 		++vip->busy_ref;
     90  1.1  christos 		if (vip->totalcount != 0 || vip->busy_ref != 1)
     91  1.1  christos 			break;
     92  1.1  christos 
     93  1.1  christos 		/* Initialize state for updates. */
     94  1.1  christos 		vip->busy_ch = 0;
     95  1.1  christos 		(void)gettimeofday(&vip->busy_tv, NULL);
     96  1.1  christos 
     97  1.1  christos 		/* Save the current cursor. */
     98  1.1  christos 		(void)gp->scr_cursor(sp, &vip->busy_oldy, &vip->busy_oldx);
     99  1.1  christos 
    100  1.1  christos 		/* Display the busy message. */
    101  1.1  christos 		p = msg_cat(sp, msg, &len);
    102  1.1  christos 		(void)gp->scr_move(sp, LASTLINE(sp), 0);
    103  1.1  christos 		(void)gp->scr_addstr(sp, p, len);
    104  1.1  christos 		(void)gp->scr_cursor(sp, &notused, &vip->busy_fx);
    105  1.1  christos 		(void)gp->scr_clrtoeol(sp);
    106  1.1  christos 		(void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
    107  1.1  christos 		break;
    108  1.1  christos 	case BUSY_OFF:
    109  1.1  christos 		if (vip->busy_ref == 0)
    110  1.1  christos 			break;
    111  1.1  christos 		--vip->busy_ref;
    112  1.1  christos 
    113  1.1  christos 		/*
    114  1.1  christos 		 * If the line isn't in use for another purpose, clear it.
    115  1.1  christos 		 * Always return to the original position.
    116  1.1  christos 		 */
    117  1.1  christos 		if (vip->totalcount == 0 && vip->busy_ref == 0) {
    118  1.1  christos 			(void)gp->scr_move(sp, LASTLINE(sp), 0);
    119  1.1  christos 			(void)gp->scr_clrtoeol(sp);
    120  1.1  christos 		}
    121  1.1  christos 		(void)gp->scr_move(sp, vip->busy_oldy, vip->busy_oldx);
    122  1.1  christos 		break;
    123  1.1  christos 	case BUSY_UPDATE:
    124  1.1  christos 		if (vip->totalcount != 0 || vip->busy_ref == 0)
    125  1.1  christos 			break;
    126  1.1  christos 
    127  1.1  christos 		/* Update no more than every 1/8 of a second. */
    128  1.1  christos 		(void)gettimeofday(&tv, NULL);
    129  1.1  christos 		if (((tv.tv_sec - vip->busy_tv.tv_sec) * 1000000 +
    130  1.1  christos 		    (tv.tv_usec - vip->busy_tv.tv_usec)) < 125000)
    131  1.1  christos 			return;
    132  1.1  christos 		vip->busy_tv = tv;
    133  1.1  christos 
    134  1.1  christos 		/* Display the update. */
    135  1.1  christos 		if (vip->busy_ch == sizeof(flagc) - 1)
    136  1.1  christos 			vip->busy_ch = 0;
    137  1.1  christos 		(void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
    138  1.1  christos 		(void)gp->scr_addstr(sp, flagc + vip->busy_ch++, 1);
    139  1.1  christos 		(void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
    140  1.1  christos 		break;
    141  1.1  christos 	}
    142  1.1  christos 	(void)gp->scr_refresh(sp, 0);
    143  1.1  christos }
    144  1.1  christos 
    145  1.1  christos /*
    146  1.1  christos  * vs_home --
    147  1.1  christos  *	Home the cursor to the bottom row, left-most column.
    148  1.1  christos  *
    149  1.1  christos  * PUBLIC: void vs_home __P((SCR *));
    150  1.1  christos  */
    151  1.1  christos void
    152  1.1  christos vs_home(SCR *sp)
    153  1.1  christos {
    154  1.1  christos 	(void)sp->gp->scr_move(sp, LASTLINE(sp), 0);
    155  1.1  christos 	(void)sp->gp->scr_refresh(sp, 0);
    156  1.1  christos }
    157  1.1  christos 
    158  1.1  christos /*
    159  1.1  christos  * vs_update --
    160  1.1  christos  *	Update a command.
    161  1.1  christos  *
    162  1.1  christos  * PUBLIC: void vs_update __P((SCR *, const char *, const CHAR_T *));
    163  1.1  christos  */
    164  1.1  christos void
    165  1.1  christos vs_update(SCR *sp, const char *m1, const CHAR_T *m2)
    166  1.1  christos {
    167  1.1  christos 	GS *gp;
    168  1.1  christos 	size_t len, mlen, oldx, oldy;
    169  1.2  christos 	const char *np;
    170  1.1  christos 	size_t nlen;
    171  1.1  christos 
    172  1.1  christos 	gp = sp->gp;
    173  1.1  christos 
    174  1.1  christos 	/*
    175  1.1  christos 	 * This routine displays a message on the bottom line of the screen,
    176  1.1  christos 	 * without updating any of the command structures that would keep it
    177  1.1  christos 	 * there for any period of time, i.e. it is overwritten immediately.
    178  1.1  christos 	 *
    179  1.1  christos 	 * It's used by the ex read and ! commands when the user's command is
    180  1.1  christos 	 * expanded, and by the ex substitution confirmation prompt.
    181  1.1  christos 	 */
    182  1.1  christos 	if (F_ISSET(sp, SC_SCR_EXWROTE)) {
    183  1.1  christos 		if (m2 != NULL)
    184  1.1  christos 			INT2CHAR(sp, m2, STRLEN(m2) + 1, np, nlen);
    185  1.1  christos 		(void)ex_printf(sp,
    186  1.2  christos 		    "%s%s\n", m1 == NULL? "" : m1, m2 == NULL ? "" : np);
    187  1.1  christos 		(void)ex_fflush(sp);
    188  1.1  christos 	}
    189  1.1  christos 
    190  1.1  christos 	/*
    191  1.1  christos 	 * Save the cursor position, the substitute-with-confirmation code
    192  1.1  christos 	 * will have already set it correctly.
    193  1.1  christos 	 */
    194  1.1  christos 	(void)gp->scr_cursor(sp, &oldy, &oldx);
    195  1.1  christos 
    196  1.1  christos 	/* Clear the bottom line. */
    197  1.1  christos 	(void)gp->scr_move(sp, LASTLINE(sp), 0);
    198  1.1  christos 	(void)gp->scr_clrtoeol(sp);
    199  1.1  christos 
    200  1.1  christos 	/*
    201  1.1  christos 	 * XXX
    202  1.1  christos 	 * Don't let long file names screw up the screen.
    203  1.1  christos 	 */
    204  1.1  christos 	if (m1 != NULL) {
    205  1.1  christos 		mlen = len = strlen(m1);
    206  1.1  christos 		if (len > sp->cols - 2)
    207  1.1  christos 			mlen = len = sp->cols - 2;
    208  1.1  christos 		(void)gp->scr_addstr(sp, m1, mlen);
    209  1.1  christos 	} else
    210  1.1  christos 		len = 0;
    211  1.1  christos 	if (m2 != NULL) {
    212  1.1  christos 		mlen = STRLEN(m2);
    213  1.1  christos 		if (len + mlen > sp->cols - 2)
    214  1.1  christos 			mlen = (sp->cols - 2) - len;
    215  1.1  christos 		(void)gp->scr_waddstr(sp, m2, mlen);
    216  1.1  christos 	}
    217  1.1  christos 
    218  1.1  christos 	(void)gp->scr_move(sp, oldy, oldx);
    219  1.1  christos 	(void)gp->scr_refresh(sp, 0);
    220  1.1  christos }
    221  1.1  christos 
    222  1.1  christos /*
    223  1.1  christos  * vs_msg --
    224  1.1  christos  *	Display ex output or error messages for the screen.
    225  1.1  christos  *
    226  1.1  christos  * This routine is the default editor interface for all ex output, and all ex
    227  1.1  christos  * and vi error/informational messages.  It implements the standard strategy
    228  1.1  christos  * of stealing lines from the bottom of the vi text screen.  Screens using an
    229  1.1  christos  * alternate method of displaying messages, e.g. dialog boxes, should set their
    230  1.1  christos  * scr_msg function to the correct function before calling the editor.
    231  1.1  christos  *
    232  1.1  christos  * PUBLIC: void vs_msg __P((SCR *, mtype_t, char *, size_t));
    233  1.1  christos  */
    234  1.1  christos void
    235  1.1  christos vs_msg(SCR *sp, mtype_t mtype, char *line, size_t len)
    236  1.1  christos {
    237  1.1  christos 	GS *gp;
    238  1.1  christos 	VI_PRIVATE *vip;
    239  1.1  christos 	size_t maxcols, oldx, oldy, padding;
    240  1.1  christos 	const char *e, *s, *t;
    241  1.1  christos 
    242  1.1  christos 	gp = sp->gp;
    243  1.1  christos 	vip = VIP(sp);
    244  1.1  christos 
    245  1.1  christos 	/*
    246  1.1  christos 	 * Ring the bell if it's scheduled.
    247  1.1  christos 	 *
    248  1.1  christos 	 * XXX
    249  1.1  christos 	 * Shouldn't we save this, too?
    250  1.1  christos 	 */
    251  1.2  christos 	if (F_ISSET(sp, SC_TINPUT_INFO) || F_ISSET(gp, G_BELLSCHED)) {
    252  1.1  christos 		if (F_ISSET(sp, SC_SCR_VI)) {
    253  1.1  christos 			F_CLR(gp, G_BELLSCHED);
    254  1.1  christos 			(void)gp->scr_bell(sp);
    255  1.1  christos 		} else
    256  1.1  christos 			F_SET(gp, G_BELLSCHED);
    257  1.2  christos 	}
    258  1.1  christos 
    259  1.1  christos 	/*
    260  1.1  christos 	 * If vi is using the error line for text input, there's no screen
    261  1.1  christos 	 * real-estate for the error message.  Nothing to do without some
    262  1.1  christos 	 * information as to how important the error message is.
    263  1.1  christos 	 */
    264  1.1  christos 	if (F_ISSET(sp, SC_TINPUT_INFO))
    265  1.1  christos 		return;
    266  1.1  christos 
    267  1.1  christos 	/*
    268  1.1  christos 	 * Ex or ex controlled screen output.
    269  1.1  christos 	 *
    270  1.1  christos 	 * If output happens during startup, e.g., a .exrc file, we may be
    271  1.1  christos 	 * in ex mode but haven't initialized the screen.  Initialize here,
    272  1.1  christos 	 * and in this case, stay in ex mode.
    273  1.1  christos 	 *
    274  1.1  christos 	 * If the SC_SCR_EXWROTE bit is set, then we're switching back and
    275  1.1  christos 	 * forth between ex and vi, but the screen is trashed and we have
    276  1.1  christos 	 * to respect that.  Switch to ex mode long enough to put out the
    277  1.1  christos 	 * message.
    278  1.1  christos 	 *
    279  1.1  christos 	 * If the SC_EX_WAIT_NO bit is set, turn it off -- we're writing to
    280  1.1  christos 	 * the screen, so previous opinions are ignored.
    281  1.1  christos 	 */
    282  1.1  christos 	if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
    283  1.2  christos 		if (!F_ISSET(sp, SC_SCR_EX)) {
    284  1.1  christos 			if (F_ISSET(sp, SC_SCR_EXWROTE)) {
    285  1.1  christos 				if (sp->gp->scr_screen(sp, SC_EX))
    286  1.1  christos 					return;
    287  1.1  christos 			} else
    288  1.1  christos 				if (ex_init(sp))
    289  1.1  christos 					return;
    290  1.2  christos 		}
    291  1.1  christos 
    292  1.1  christos 		if (mtype == M_ERR)
    293  1.1  christos 			(void)gp->scr_attr(sp, SA_INVERSE, 1);
    294  1.1  christos 		(void)printf("%.*s", (int)len, line);
    295  1.1  christos 		if (mtype == M_ERR)
    296  1.1  christos 			(void)gp->scr_attr(sp, SA_INVERSE, 0);
    297  1.1  christos 		(void)fflush(stdout);
    298  1.1  christos 
    299  1.1  christos 		F_CLR(sp, SC_EX_WAIT_NO);
    300  1.1  christos 
    301  1.1  christos 		if (!F_ISSET(sp, SC_SCR_EX))
    302  1.1  christos 			(void)sp->gp->scr_screen(sp, SC_VI);
    303  1.1  christos 		return;
    304  1.1  christos 	}
    305  1.1  christos 
    306  1.1  christos 	/* If the vi screen isn't ready, save the message. */
    307  1.1  christos 	if (!F_ISSET(sp, SC_SCR_VI)) {
    308  1.1  christos 		(void)vs_msgsave(sp, mtype, line, len);
    309  1.1  christos 		return;
    310  1.1  christos 	}
    311  1.1  christos 
    312  1.1  christos 	/* Save the cursor position. */
    313  1.1  christos 	(void)gp->scr_cursor(sp, &oldy, &oldx);
    314  1.1  christos 
    315  1.1  christos 	/* If it's an ex output message, just write it out. */
    316  1.1  christos 	if (mtype == M_NONE) {
    317  1.1  christos 		vs_output(sp, mtype, line, len);
    318  1.1  christos 		goto ret;
    319  1.1  christos 	}
    320  1.1  christos 
    321  1.1  christos 	/*
    322  1.1  christos 	 * If it's a vi message, strip the trailing <newline> so we can
    323  1.1  christos 	 * try and paste messages together.
    324  1.1  christos 	 */
    325  1.1  christos 	if (line[len - 1] == '\n')
    326  1.1  christos 		--len;
    327  1.1  christos 
    328  1.1  christos 	/*
    329  1.1  christos 	 * If a message won't fit on a single line, try to split on a <blank>.
    330  1.1  christos 	 * If a subsequent message fits on the same line, write a separator
    331  1.1  christos 	 * and output it.  Otherwise, put out a newline.
    332  1.1  christos 	 *
    333  1.1  christos 	 * Need up to two padding characters normally; a semi-colon and a
    334  1.1  christos 	 * separating space.  If only a single line on the screen, add some
    335  1.1  christos 	 * more for the trailing continuation message.
    336  1.1  christos 	 *
    337  1.1  christos 	 * XXX
    338  1.1  christos 	 * Assume that periods and semi-colons take up a single column on the
    339  1.1  christos 	 * screen.
    340  1.1  christos 	 *
    341  1.1  christos 	 * XXX
    342  1.1  christos 	 * There are almost certainly pathological cases that will break this
    343  1.1  christos 	 * code.
    344  1.1  christos 	 */
    345  1.1  christos 	if (IS_ONELINE(sp))
    346  1.1  christos 		(void)msg_cmsg(sp, CMSG_CONT_S, &padding);
    347  1.1  christos 	else
    348  1.1  christos 		padding = 0;
    349  1.1  christos 	padding += 2;
    350  1.1  christos 
    351  1.1  christos 	maxcols = sp->cols - 1;
    352  1.2  christos 	if (vip->lcontinue != 0) {
    353  1.1  christos 		if (len + vip->lcontinue + padding > maxcols)
    354  1.1  christos 			vs_output(sp, vip->mtype, ".\n", 2);
    355  1.1  christos 		else  {
    356  1.1  christos 			vs_output(sp, vip->mtype, ";", 1);
    357  1.1  christos 			vs_output(sp, M_NONE, " ", 1);
    358  1.1  christos 		}
    359  1.2  christos 	}
    360  1.1  christos 	vip->mtype = mtype;
    361  1.1  christos 	for (s = line;; s = t) {
    362  1.2  christos 		for (; len > 0 && isblank((unsigned char)*s); --len, ++s);
    363  1.1  christos 		if (len == 0)
    364  1.1  christos 			break;
    365  1.1  christos 		if (len + vip->lcontinue > maxcols) {
    366  1.1  christos 			for (e = s + (maxcols - vip->lcontinue);
    367  1.2  christos 			    e > s && !isblank((unsigned char)*e); --e);
    368  1.1  christos 			if (e == s)
    369  1.1  christos 				 e = t = s + (maxcols - vip->lcontinue);
    370  1.1  christos 			else
    371  1.2  christos 				for (t = e; isblank((unsigned char)e[-1]); --e);
    372  1.1  christos 		} else
    373  1.1  christos 			e = t = s + len;
    374  1.1  christos 
    375  1.1  christos 		/*
    376  1.1  christos 		 * If the message ends in a period, discard it, we want to
    377  1.1  christos 		 * gang messages where possible.
    378  1.1  christos 		 */
    379  1.1  christos 		len -= t - s;
    380  1.1  christos 		if (len == 0 && (e - s) > 1 && s[(e - s) - 1] == '.')
    381  1.1  christos 			--e;
    382  1.1  christos 		vs_output(sp, mtype, s, e - s);
    383  1.1  christos 
    384  1.1  christos 		if (len != 0)
    385  1.1  christos 			vs_output(sp, M_NONE, "\n", 1);
    386  1.1  christos 
    387  1.1  christos 		if (INTERRUPTED(sp))
    388  1.1  christos 			break;
    389  1.1  christos 	}
    390  1.1  christos 
    391  1.1  christos ret:	(void)gp->scr_move(sp, oldy, oldx);
    392  1.1  christos 	(void)gp->scr_refresh(sp, 0);
    393  1.1  christos }
    394  1.1  christos 
    395  1.1  christos /*
    396  1.1  christos  * vs_output --
    397  1.1  christos  *	Output the text to the screen.
    398  1.1  christos  */
    399  1.1  christos static void
    400  1.1  christos vs_output(SCR *sp, mtype_t mtype, const char *line, int llen)
    401  1.1  christos {
    402  1.2  christos 	unsigned char *kp;
    403  1.1  christos 	GS *gp;
    404  1.1  christos 	VI_PRIVATE *vip;
    405  1.1  christos 	size_t chlen, notused;
    406  1.2  christos 	int ch, len, tlen;
    407  1.1  christos 	const char *p, *t;
    408  1.1  christos 	char *cbp, *ecbp, cbuf[128];
    409  1.1  christos 
    410  1.1  christos 	gp = sp->gp;
    411  1.1  christos 	vip = VIP(sp);
    412  1.2  christos 	for (p = line; llen > 0;) {
    413  1.1  christos 		/* Get the next physical line. */
    414  1.1  christos 		if ((p = memchr(line, '\n', llen)) == NULL)
    415  1.1  christos 			len = llen;
    416  1.1  christos 		else
    417  1.1  christos 			len = p - line;
    418  1.1  christos 
    419  1.1  christos 		/*
    420  1.1  christos 		 * The max is sp->cols characters, and we may have already
    421  1.1  christos 		 * written part of the line.
    422  1.1  christos 		 */
    423  1.1  christos 		if (len + vip->lcontinue > sp->cols)
    424  1.1  christos 			len = sp->cols - vip->lcontinue;
    425  1.1  christos 
    426  1.1  christos 		/*
    427  1.1  christos 		 * If the first line output, do nothing.  If the second line
    428  1.1  christos 		 * output, draw the divider line.  If drew a full screen, we
    429  1.1  christos 		 * remove the divider line.  If it's a continuation line, move
    430  1.1  christos 		 * to the continuation point, else, move the screen up.
    431  1.1  christos 		 */
    432  1.1  christos 		if (vip->lcontinue == 0) {
    433  1.1  christos 			if (!IS_ONELINE(sp)) {
    434  1.1  christos 				if (vip->totalcount == 1) {
    435  1.1  christos 					(void)gp->scr_move(sp,
    436  1.1  christos 					    LASTLINE(sp) - 1, 0);
    437  1.1  christos 					(void)gp->scr_clrtoeol(sp);
    438  1.1  christos 					(void)vs_divider(sp);
    439  1.1  christos 					F_SET(vip, VIP_DIVIDER);
    440  1.1  christos 					++vip->totalcount;
    441  1.1  christos 					++vip->linecount;
    442  1.1  christos 				}
    443  1.1  christos 				if (vip->totalcount == sp->t_maxrows &&
    444  1.1  christos 				    F_ISSET(vip, VIP_DIVIDER)) {
    445  1.1  christos 					--vip->totalcount;
    446  1.1  christos 					--vip->linecount;
    447  1.1  christos 					F_CLR(vip, VIP_DIVIDER);
    448  1.1  christos 				}
    449  1.1  christos 			}
    450  1.1  christos 			if (vip->totalcount != 0)
    451  1.1  christos 				vs_scroll(sp, NULL, SCROLL_W_QUIT);
    452  1.1  christos 
    453  1.1  christos 			(void)gp->scr_move(sp, LASTLINE(sp), 0);
    454  1.1  christos 			++vip->totalcount;
    455  1.1  christos 			++vip->linecount;
    456  1.1  christos 
    457  1.1  christos 			if (INTERRUPTED(sp))
    458  1.1  christos 				break;
    459  1.1  christos 		} else
    460  1.1  christos 			(void)gp->scr_move(sp, LASTLINE(sp), vip->lcontinue);
    461  1.1  christos 
    462  1.1  christos 		/* Error messages are in inverse video. */
    463  1.1  christos 		if (mtype == M_ERR)
    464  1.1  christos 			(void)gp->scr_attr(sp, SA_INVERSE, 1);
    465  1.1  christos 
    466  1.1  christos 		/* Display the line, doing character translation. */
    467  1.1  christos #define	FLUSH {								\
    468  1.1  christos 	*cbp = '\0';							\
    469  1.1  christos 	(void)gp->scr_addstr(sp, cbuf, cbp - cbuf);			\
    470  1.1  christos 	cbp = cbuf;							\
    471  1.1  christos }
    472  1.1  christos 		ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
    473  1.1  christos 		for (t = line, tlen = len; tlen--; ++t) {
    474  1.1  christos 			ch = *t;
    475  1.1  christos 			/*
    476  1.1  christos 			 * Replace tabs with spaces, there are places in
    477  1.1  christos 			 * ex that do column calculations without looking
    478  1.1  christos 			 * at <tabs> -- and all routines that care about
    479  1.1  christos 			 * <tabs> do their own expansions.  This catches
    480  1.1  christos 			 * <tabs> in things like tag search strings.
    481  1.1  christos 			 */
    482  1.1  christos 			if (ch == '\t')
    483  1.1  christos 				ch = ' ';
    484  1.1  christos 			chlen = KEY_LEN(sp, ch);
    485  1.1  christos 			if (cbp + chlen >= ecbp)
    486  1.1  christos 				FLUSH;
    487  1.1  christos 			for (kp = KEY_NAME(sp, ch); chlen--;)
    488  1.1  christos 				*cbp++ = *kp++;
    489  1.1  christos 		}
    490  1.1  christos 		if (cbp > cbuf)
    491  1.1  christos 			FLUSH;
    492  1.1  christos 		if (mtype == M_ERR)
    493  1.1  christos 			(void)gp->scr_attr(sp, SA_INVERSE, 0);
    494  1.1  christos 
    495  1.1  christos 		/* Clear the rest of the line. */
    496  1.1  christos 		(void)gp->scr_clrtoeol(sp);
    497  1.1  christos 
    498  1.1  christos 		/* If we loop, it's a new line. */
    499  1.1  christos 		vip->lcontinue = 0;
    500  1.1  christos 
    501  1.1  christos 		/* Reset for the next line. */
    502  1.1  christos 		line += len;
    503  1.1  christos 		llen -= len;
    504  1.1  christos 		if (p != NULL) {
    505  1.1  christos 			++line;
    506  1.1  christos 			--llen;
    507  1.1  christos 		}
    508  1.1  christos 	}
    509  1.1  christos 
    510  1.1  christos 	/* Set up next continuation line. */
    511  1.1  christos 	if (p == NULL)
    512  1.1  christos 		gp->scr_cursor(sp, &notused, &vip->lcontinue);
    513  1.1  christos }
    514  1.1  christos 
    515  1.1  christos /*
    516  1.1  christos  * vs_ex_resolve --
    517  1.1  christos  *	Deal with ex message output.
    518  1.1  christos  *
    519  1.1  christos  * This routine is called when exiting a colon command to resolve any ex
    520  1.1  christos  * output that may have occurred.
    521  1.1  christos  *
    522  1.1  christos  * PUBLIC: int vs_ex_resolve __P((SCR *, int *));
    523  1.1  christos  */
    524  1.1  christos int
    525  1.1  christos vs_ex_resolve(SCR *sp, int *continuep)
    526  1.1  christos {
    527  1.1  christos 	EVENT ev;
    528  1.1  christos 	GS *gp;
    529  1.1  christos 	VI_PRIVATE *vip;
    530  1.1  christos 	sw_t wtype;
    531  1.1  christos 
    532  1.1  christos 	gp = sp->gp;
    533  1.1  christos 	vip = VIP(sp);
    534  1.1  christos 	*continuep = 0;
    535  1.1  christos 
    536  1.1  christos 	/* If we ran any ex command, we can't trust the cursor position. */
    537  1.1  christos 	F_SET(vip, VIP_CUR_INVALID);
    538  1.1  christos 
    539  1.1  christos 	/* Terminate any partially written message. */
    540  1.1  christos 	if (vip->lcontinue != 0) {
    541  1.1  christos 		vs_output(sp, vip->mtype, ".", 1);
    542  1.1  christos 		vip->lcontinue = 0;
    543  1.1  christos 
    544  1.1  christos 		vip->mtype = M_NONE;
    545  1.1  christos 	}
    546  1.1  christos 
    547  1.1  christos 	/*
    548  1.1  christos 	 * If we switched out of the vi screen into ex, switch back while we
    549  1.1  christos 	 * figure out what to do with the screen and potentially get another
    550  1.1  christos 	 * command to execute.
    551  1.1  christos 	 *
    552  1.1  christos 	 * If we didn't switch into ex, we're not required to wait, and less
    553  1.1  christos 	 * than 2 lines of output, we can continue without waiting for the
    554  1.1  christos 	 * wait.
    555  1.1  christos 	 *
    556  1.1  christos 	 * Note, all other code paths require waiting, so we leave the report
    557  1.1  christos 	 * of modified lines until later, so that we won't wait for no other
    558  1.1  christos 	 * reason than a threshold number of lines were modified.  This means
    559  1.1  christos 	 * we display cumulative line modification reports for groups of ex
    560  1.1  christos 	 * commands.  That seems right to me (well, at least not wrong).
    561  1.1  christos 	 */
    562  1.1  christos 	if (F_ISSET(sp, SC_SCR_EXWROTE)) {
    563  1.1  christos 		if (sp->gp->scr_screen(sp, SC_VI))
    564  1.1  christos 			return (1);
    565  1.1  christos 	} else
    566  1.1  christos 		if (!F_ISSET(sp, SC_EX_WAIT_YES) && vip->totalcount < 2) {
    567  1.1  christos 			F_CLR(sp, SC_EX_WAIT_NO);
    568  1.1  christos 			return (0);
    569  1.1  christos 		}
    570  1.1  christos 
    571  1.1  christos 	/* Clear the required wait flag, it's no longer needed. */
    572  1.1  christos 	F_CLR(sp, SC_EX_WAIT_YES);
    573  1.1  christos 
    574  1.1  christos 	/*
    575  1.1  christos 	 * Wait, unless explicitly told not to wait or the user interrupted
    576  1.1  christos 	 * the command.  If the user is leaving the screen, for any reason,
    577  1.1  christos 	 * they can't continue with further ex commands.
    578  1.1  christos 	 */
    579  1.1  christos 	if (!F_ISSET(sp, SC_EX_WAIT_NO) && !INTERRUPTED(sp)) {
    580  1.1  christos 		wtype = F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE |
    581  1.1  christos 		    SC_FSWITCH | SC_SSWITCH) ? SCROLL_W : SCROLL_W_EX;
    582  1.1  christos 		if (F_ISSET(sp, SC_SCR_EXWROTE))
    583  1.1  christos 			vs_wait(sp, continuep, wtype);
    584  1.1  christos 		else
    585  1.1  christos 			vs_scroll(sp, continuep, wtype);
    586  1.1  christos 		if (*continuep)
    587  1.1  christos 			return (0);
    588  1.1  christos 	}
    589  1.1  christos 
    590  1.1  christos 	/* If ex wrote on the screen, refresh the screen image. */
    591  1.1  christos 	if (F_ISSET(sp, SC_SCR_EXWROTE))
    592  1.1  christos 		F_SET(vip, VIP_N_EX_PAINT);
    593  1.1  christos 
    594  1.1  christos 	/*
    595  1.1  christos 	 * If we're not the bottom of the split screen stack, the screen
    596  1.1  christos 	 * image itself is wrong, so redraw everything.
    597  1.1  christos 	 */
    598  1.3  christos 	if (TAILQ_NEXT(sp, q) != NULL)
    599  1.1  christos 		F_SET(sp, SC_SCR_REDRAW);
    600  1.1  christos 
    601  1.1  christos 	/* If ex changed the underlying file, the map itself is wrong. */
    602  1.1  christos 	if (F_ISSET(vip, VIP_N_EX_REDRAW))
    603  1.1  christos 		F_SET(sp, SC_SCR_REFORMAT);
    604  1.1  christos 
    605  1.1  christos 	/* Ex may have switched out of the alternate screen, return. */
    606  1.1  christos 	(void)gp->scr_attr(sp, SA_ALTERNATE, 1);
    607  1.1  christos 
    608  1.1  christos 	/*
    609  1.1  christos 	 * Whew.  We're finally back home, after what feels like years.
    610  1.1  christos 	 * Kiss the ground.
    611  1.1  christos 	 */
    612  1.1  christos 	F_CLR(sp, SC_SCR_EXWROTE | SC_EX_WAIT_NO);
    613  1.1  christos 
    614  1.1  christos 	/*
    615  1.1  christos 	 * We may need to repaint some of the screen, e.g.:
    616  1.1  christos 	 *
    617  1.1  christos 	 *	:set
    618  1.1  christos 	 *	:!ls
    619  1.1  christos 	 *
    620  1.1  christos 	 * gives us a combination of some lines that are "wrong", and a need
    621  1.1  christos 	 * for a full refresh.
    622  1.1  christos 	 */
    623  1.1  christos 	if (vip->totalcount > 1) {
    624  1.1  christos 		/* Set up the redraw of the overwritten lines. */
    625  1.1  christos 		ev.e_event = E_REPAINT;
    626  1.1  christos 		ev.e_flno = vip->totalcount >=
    627  1.1  christos 		    sp->rows ? 1 : sp->rows - vip->totalcount;
    628  1.1  christos 		ev.e_tlno = sp->rows;
    629  1.1  christos 
    630  1.1  christos 		/* Reset the count of overwriting lines. */
    631  1.1  christos 		vip->linecount = vip->lcontinue = vip->totalcount = 0;
    632  1.1  christos 
    633  1.1  christos 		/* Redraw. */
    634  1.1  christos 		(void)v_erepaint(sp, &ev);
    635  1.1  christos 	} else
    636  1.1  christos 		/* Reset the count of overwriting lines. */
    637  1.1  christos 		vip->linecount = vip->lcontinue = vip->totalcount = 0;
    638  1.1  christos 
    639  1.1  christos 	return (0);
    640  1.1  christos }
    641  1.1  christos 
    642  1.1  christos /*
    643  1.1  christos  * vs_resolve --
    644  1.1  christos  *	Deal with message output.
    645  1.1  christos  *
    646  1.1  christos  * PUBLIC: int vs_resolve __P((SCR *, SCR *, int));
    647  1.1  christos  */
    648  1.1  christos int
    649  1.1  christos vs_resolve(SCR *sp, SCR *csp, int forcewait)
    650  1.1  christos {
    651  1.1  christos 	EVENT ev;
    652  1.1  christos 	GS *gp;
    653  1.1  christos 	WIN *wp;
    654  1.1  christos 	MSGS *mp;
    655  1.1  christos 	VI_PRIVATE *vip;
    656  1.1  christos 	size_t oldy, oldx;
    657  1.1  christos 	int redraw;
    658  1.1  christos 
    659  1.1  christos 	/*
    660  1.1  christos 	 * Vs_resolve is called from the main vi loop and the refresh function
    661  1.1  christos 	 * to periodically ensure that the user has seen any messages that have
    662  1.1  christos 	 * been displayed and that any status lines are correct.  The sp screen
    663  1.1  christos 	 * is the screen we're checking, usually the current screen.  When it's
    664  1.1  christos 	 * not, csp is the current screen, used for final cursor positioning.
    665  1.1  christos 	 */
    666  1.1  christos 	gp = sp->gp;
    667  1.1  christos 	wp = sp->wp;
    668  1.1  christos 	vip = VIP(sp);
    669  1.1  christos 	if (csp == NULL)
    670  1.1  christos 		csp = sp;
    671  1.1  christos 
    672  1.1  christos 	/* Save the cursor position. */
    673  1.1  christos 	(void)gp->scr_cursor(csp, &oldy, &oldx);
    674  1.1  christos 
    675  1.1  christos 	/* Ring the bell if it's scheduled. */
    676  1.1  christos 	if (F_ISSET(gp, G_BELLSCHED)) {
    677  1.1  christos 		F_CLR(gp, G_BELLSCHED);
    678  1.1  christos 		(void)gp->scr_bell(sp);
    679  1.1  christos 	}
    680  1.1  christos 
    681  1.1  christos 	/* Display new file status line. */
    682  1.1  christos 	if (F_ISSET(sp, SC_STATUS)) {
    683  1.1  christos 		F_CLR(sp, SC_STATUS);
    684  1.1  christos 		msgq_status(sp, sp->lno, MSTAT_TRUNCATE);
    685  1.1  christos 	}
    686  1.1  christos 
    687  1.1  christos 	/* Report on line modifications. */
    688  1.1  christos 	mod_rpt(sp);
    689  1.1  christos 
    690  1.1  christos 	/*
    691  1.1  christos 	 * Flush any saved messages.  If the screen isn't ready, refresh
    692  1.1  christos 	 * it.  (A side-effect of screen refresh is that we can display
    693  1.1  christos 	 * messages.)  Once this is done, don't trust the cursor.  That
    694  1.1  christos 	 * extra refresh screwed the pooch.
    695  1.1  christos 	 */
    696  1.3  christos 	if (!LIST_EMPTY(&gp->msgq)) {
    697  1.1  christos 		if (!F_ISSET(sp, SC_SCR_VI) && vs_refresh(sp, 1))
    698  1.1  christos 			return (1);
    699  1.3  christos 		while ((mp = LIST_FIRST(&gp->msgq)) != NULL) {
    700  1.1  christos 			wp->scr_msg(sp, mp->mtype, mp->buf, mp->len);
    701  1.1  christos 			LIST_REMOVE(mp, q);
    702  1.1  christos 			free(mp->buf);
    703  1.1  christos 			free(mp);
    704  1.1  christos 		}
    705  1.1  christos 		F_SET(vip, VIP_CUR_INVALID);
    706  1.1  christos 	}
    707  1.1  christos 
    708  1.1  christos 	switch (vip->totalcount) {
    709  1.1  christos 	case 0:
    710  1.1  christos 		redraw = 0;
    711  1.1  christos 		break;
    712  1.1  christos 	case 1:
    713  1.1  christos 		/*
    714  1.1  christos 		 * If we're switching screens, we have to wait for messages,
    715  1.1  christos 		 * regardless.  If we don't wait, skip updating the modeline.
    716  1.1  christos 		 */
    717  1.1  christos 		if (forcewait)
    718  1.1  christos 			vs_scroll(sp, NULL, SCROLL_W);
    719  1.1  christos 		else
    720  1.1  christos 			F_SET(vip, VIP_S_MODELINE);
    721  1.1  christos 
    722  1.1  christos 		redraw = 0;
    723  1.1  christos 		break;
    724  1.1  christos 	default:
    725  1.1  christos 		/*
    726  1.1  christos 		 * If >1 message line in use, prompt the user to continue and
    727  1.1  christos 		 * repaint overwritten lines.
    728  1.1  christos 		 */
    729  1.1  christos 		vs_scroll(sp, NULL, SCROLL_W);
    730  1.1  christos 
    731  1.1  christos 		ev.e_event = E_REPAINT;
    732  1.1  christos 		ev.e_flno = vip->totalcount >=
    733  1.1  christos 		    sp->rows ? 1 : sp->rows - vip->totalcount;
    734  1.1  christos 		ev.e_tlno = sp->rows;
    735  1.1  christos 
    736  1.1  christos 		redraw = 1;
    737  1.1  christos 		break;
    738  1.1  christos 	}
    739  1.1  christos 
    740  1.1  christos 	/* Reset the count of overwriting lines. */
    741  1.1  christos 	vip->linecount = vip->lcontinue = vip->totalcount = 0;
    742  1.1  christos 
    743  1.1  christos 	/* Redraw. */
    744  1.1  christos 	if (redraw)
    745  1.1  christos 		(void)v_erepaint(sp, &ev);
    746  1.1  christos 
    747  1.1  christos 	/* Restore the cursor position. */
    748  1.1  christos 	(void)gp->scr_move(csp, oldy, oldx);
    749  1.1  christos 
    750  1.1  christos 	return (0);
    751  1.1  christos }
    752  1.1  christos 
    753  1.1  christos /*
    754  1.1  christos  * vs_scroll --
    755  1.1  christos  *	Scroll the screen for output.
    756  1.1  christos  */
    757  1.1  christos static void
    758  1.1  christos vs_scroll(SCR *sp, int *continuep, sw_t wtype)
    759  1.1  christos {
    760  1.1  christos 	GS *gp;
    761  1.1  christos 	VI_PRIVATE *vip;
    762  1.1  christos 
    763  1.1  christos 	gp = sp->gp;
    764  1.1  christos 	vip = VIP(sp);
    765  1.1  christos 	if (!IS_ONELINE(sp)) {
    766  1.1  christos 		/*
    767  1.1  christos 		 * Scroll the screen.  Instead of scrolling the entire screen,
    768  1.1  christos 		 * delete the line above the first line output so preserve the
    769  1.1  christos 		 * maximum amount of the screen.
    770  1.1  christos 		 */
    771  1.1  christos 		(void)gp->scr_move(sp, vip->totalcount <
    772  1.1  christos 		    sp->rows ? LASTLINE(sp) - vip->totalcount : 0, 0);
    773  1.1  christos 		(void)gp->scr_deleteln(sp);
    774  1.1  christos 
    775  1.1  christos 		/* If there are screens below us, push them back into place. */
    776  1.3  christos 		if (TAILQ_NEXT(sp, q) != NULL) {
    777  1.1  christos 			(void)gp->scr_move(sp, LASTLINE(sp), 0);
    778  1.1  christos 			(void)gp->scr_insertln(sp);
    779  1.1  christos 		}
    780  1.1  christos 	}
    781  1.1  christos 	if (wtype == SCROLL_W_QUIT && vip->linecount < sp->t_maxrows)
    782  1.1  christos 		return;
    783  1.1  christos 	vs_wait(sp, continuep, wtype);
    784  1.1  christos }
    785  1.1  christos 
    786  1.1  christos /*
    787  1.1  christos  * vs_wait --
    788  1.1  christos  *	Prompt the user to continue.
    789  1.1  christos  */
    790  1.1  christos static void
    791  1.1  christos vs_wait(SCR *sp, int *continuep, sw_t wtype)
    792  1.1  christos {
    793  1.1  christos 	EVENT ev;
    794  1.1  christos 	VI_PRIVATE *vip;
    795  1.1  christos 	const char *p;
    796  1.1  christos 	GS *gp;
    797  1.1  christos 	size_t len;
    798  1.1  christos 
    799  1.1  christos 	gp = sp->gp;
    800  1.1  christos 	vip = VIP(sp);
    801  1.1  christos 
    802  1.1  christos 	(void)gp->scr_move(sp, LASTLINE(sp), 0);
    803  1.1  christos 	if (IS_ONELINE(sp))
    804  1.1  christos 		p = msg_cmsg(sp, CMSG_CONT_S, &len);
    805  1.1  christos 	else
    806  1.1  christos 		switch (wtype) {
    807  1.1  christos 		case SCROLL_W_QUIT:
    808  1.1  christos 			p = msg_cmsg(sp, CMSG_CONT_Q, &len);
    809  1.1  christos 			break;
    810  1.1  christos 		case SCROLL_W_EX:
    811  1.1  christos 			p = msg_cmsg(sp, CMSG_CONT_EX, &len);
    812  1.1  christos 			break;
    813  1.1  christos 		case SCROLL_W:
    814  1.1  christos 			p = msg_cmsg(sp, CMSG_CONT, &len);
    815  1.1  christos 			break;
    816  1.1  christos 		default:
    817  1.1  christos 			abort();
    818  1.1  christos 			/* NOTREACHED */
    819  1.1  christos 		}
    820  1.1  christos 	(void)gp->scr_addstr(sp, p, len);
    821  1.1  christos 
    822  1.1  christos 	++vip->totalcount;
    823  1.1  christos 	vip->linecount = 0;
    824  1.1  christos 
    825  1.1  christos 	(void)gp->scr_clrtoeol(sp);
    826  1.1  christos 	(void)gp->scr_refresh(sp, 0);
    827  1.1  christos 
    828  1.1  christos 	/* Get a single character from the terminal. */
    829  1.1  christos 	if (continuep != NULL)
    830  1.1  christos 		*continuep = 0;
    831  1.1  christos 	for (;;) {
    832  1.1  christos 		if (v_event_get(sp, &ev, 0, 0))
    833  1.1  christos 			return;
    834  1.1  christos 		if (ev.e_event == E_CHARACTER)
    835  1.1  christos 			break;
    836  1.1  christos 		if (ev.e_event == E_INTERRUPT) {
    837  1.1  christos 			ev.e_c = CH_QUIT;
    838  1.1  christos 			F_SET(gp, G_INTERRUPTED);
    839  1.1  christos 			break;
    840  1.1  christos 		}
    841  1.1  christos 		(void)gp->scr_bell(sp);
    842  1.1  christos 	}
    843  1.1  christos 	switch (wtype) {
    844  1.1  christos 	case SCROLL_W_QUIT:
    845  1.1  christos 		if (ev.e_c == CH_QUIT)
    846  1.1  christos 			F_SET(gp, G_INTERRUPTED);
    847  1.1  christos 		break;
    848  1.1  christos 	case SCROLL_W_EX:
    849  1.1  christos 		if (ev.e_c == ':' && continuep != NULL)
    850  1.1  christos 			*continuep = 1;
    851  1.1  christos 		break;
    852  1.1  christos 	case SCROLL_W:
    853  1.1  christos 		break;
    854  1.1  christos 	}
    855  1.1  christos }
    856  1.1  christos 
    857  1.1  christos /*
    858  1.1  christos  * vs_divider --
    859  1.1  christos  *	Draw a dividing line between the screen and the output.
    860  1.1  christos  */
    861  1.1  christos static void
    862  1.1  christos vs_divider(SCR *sp)
    863  1.1  christos {
    864  1.1  christos 	GS *gp;
    865  1.1  christos 	size_t len;
    866  1.1  christos 
    867  1.1  christos #define	DIVIDESTR	"+=+=+=+=+=+=+=+"
    868  1.1  christos 	len =
    869  1.1  christos 	    sizeof(DIVIDESTR) - 1 > sp->cols ? sp->cols : sizeof(DIVIDESTR) - 1;
    870  1.1  christos 	gp = sp->gp;
    871  1.1  christos 	(void)gp->scr_attr(sp, SA_INVERSE, 1);
    872  1.1  christos 	(void)gp->scr_addstr(sp, DIVIDESTR, len);
    873  1.1  christos 	(void)gp->scr_attr(sp, SA_INVERSE, 0);
    874  1.1  christos }
    875  1.1  christos 
    876  1.1  christos /*
    877  1.1  christos  * vs_msgsave --
    878  1.1  christos  *	Save a message for later display.
    879  1.1  christos  */
    880  1.1  christos static void
    881  1.1  christos vs_msgsave(SCR *sp, mtype_t mt, char *p, size_t len)
    882  1.1  christos {
    883  1.1  christos 	GS *gp;
    884  1.1  christos 	MSGS *mp_c, *mp_n;
    885  1.1  christos 
    886  1.1  christos 	/*
    887  1.1  christos 	 * We have to handle messages before we have any place to put them.
    888  1.1  christos 	 * If there's no screen support yet, allocate a msg structure, copy
    889  1.1  christos 	 * in the message, and queue it on the global structure.  If we can't
    890  1.1  christos 	 * allocate memory here, we're genuinely screwed, dump the message
    891  1.1  christos 	 * to stderr in the (probably) vain hope that someone will see it.
    892  1.1  christos 	 */
    893  1.1  christos 	CALLOC_GOTO(sp, mp_n, MSGS *, 1, sizeof(MSGS));
    894  1.1  christos 	MALLOC_GOTO(sp, mp_n->buf, char *, len);
    895  1.1  christos 
    896  1.1  christos 	memmove(mp_n->buf, p, len);
    897  1.1  christos 	mp_n->len = len;
    898  1.1  christos 	mp_n->mtype = mt;
    899  1.1  christos 
    900  1.1  christos 	gp = sp->gp;
    901  1.3  christos 	if ((mp_c = LIST_FIRST(&gp->msgq)) == NULL) {
    902  1.1  christos 		LIST_INSERT_HEAD(&gp->msgq, mp_n, q);
    903  1.1  christos 	} else {
    904  1.3  christos 		while (LIST_NEXT(mp_c, q) != NULL)
    905  1.3  christos 			mp_c = LIST_NEXT(mp_c, q);
    906  1.1  christos 		LIST_INSERT_AFTER(mp_c, mp_n, q);
    907  1.1  christos 	}
    908  1.1  christos 	return;
    909  1.1  christos 
    910  1.1  christos alloc_err:
    911  1.1  christos 	if (mp_n != NULL)
    912  1.1  christos 		free(mp_n);
    913  1.1  christos 	(void)fprintf(stderr, "%.*s\n", (int)len, p);
    914  1.1  christos }
    915