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