mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-11-04 07:21:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1210 lines
		
	
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1210 lines
		
	
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * zle_refresh.c - screen update
 | 
						|
 *
 | 
						|
 * This file is part of zsh, the Z shell.
 | 
						|
 *
 | 
						|
 * Copyright (c) 1992-1997 Paul Falstad
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Permission is hereby granted, without written agreement and without
 | 
						|
 * license or royalty fees, to use, copy, modify, and distribute this
 | 
						|
 * software and to distribute modified versions of this software for any
 | 
						|
 * purpose, provided that the above copyright notice and the following
 | 
						|
 * two paragraphs appear in all copies of this software.
 | 
						|
 *
 | 
						|
 * In no event shall Paul Falstad or the Zsh Development Group be liable
 | 
						|
 * to any party for direct, indirect, special, incidental, or consequential
 | 
						|
 * damages arising out of the use of this software and its documentation,
 | 
						|
 * even if Paul Falstad and the Zsh Development Group have been advised of
 | 
						|
 * the possibility of such damage.
 | 
						|
 *
 | 
						|
 * Paul Falstad and the Zsh Development Group specifically disclaim any
 | 
						|
 * warranties, including, but not limited to, the implied warranties of
 | 
						|
 * merchantability and fitness for a particular purpose.  The software
 | 
						|
 * provided hereunder is on an "as is" basis, and Paul Falstad and the
 | 
						|
 * Zsh Development Group have no obligation to provide maintenance,
 | 
						|
 * support, updates, enhancements, or modifications.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "zle.mdh"
 | 
						|
#include "zle_refresh.pro"
 | 
						|
 | 
						|
/* Expanded prompts */
 | 
						|
 | 
						|
/**/
 | 
						|
char *lpromptbuf, *rpromptbuf;
 | 
						|
 | 
						|
/* Text attributes after displaying prompts */
 | 
						|
 | 
						|
/**/
 | 
						|
unsigned pmpt_attr, rpmpt_attr;
 | 
						|
 | 
						|
/* number of lines displayed */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int nlnct;
 | 
						|
 | 
						|
/* Most lines of the buffer we've shown at once with the current list *
 | 
						|
 * showing.  == 0 if there is no list.  == -1 if a new list has just  *
 | 
						|
 * been put on the screen.  == -2 if zrefresh() needs to put up a new *
 | 
						|
 * list.                                                              */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int showinglist;
 | 
						|
 | 
						|
/* > 0 if a completion list is displayed below the prompt,
 | 
						|
 * < 0 if a list is displayed above the prompt. */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int listshown;
 | 
						|
 | 
						|
/* Length of last list displayed (if it is below the prompt). */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int lastlistlen;
 | 
						|
 | 
						|
/* Non-zero if ALWAYS_LAST_PROMPT has been used, meaning that the *
 | 
						|
 * screen below the buffer display should not be cleared by       *
 | 
						|
 * zrefresh(), but should be by trashzle().                       */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int clearflag;
 | 
						|
 | 
						|
/* Non-zero if zrefresh() should clear the list below the prompt. */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int clearlist;
 | 
						|
 | 
						|
/* Zle in trashed state - updates may be subtly altered */
 | 
						|
 | 
						|
/**/
 | 
						|
int trashedzle;
 | 
						|
 | 
						|
#ifdef HAVE_SELECT
 | 
						|
/* cost of last update */
 | 
						|
/**/
 | 
						|
int cost;
 | 
						|
 | 
						|
# define SELECT_ADD_COST(X)	cost += X
 | 
						|
# define zputc(a, b)		putc(a, b), cost++
 | 
						|
# define zwrite(a, b, c, d)	fwrite(a, b, c, d), cost += (b * c)
 | 
						|
#else
 | 
						|
# define SELECT_ADD_COST(X)
 | 
						|
# define zputc(a, b)		putc(a, b)
 | 
						|
# define zwrite(a, b, c, d)	fwrite(a, b, c, d)
 | 
						|
#endif
 | 
						|
 | 
						|
/* Oct/Nov 94: <mason> some code savagely redesigned to fix several bugs -
 | 
						|
   refreshline() & tc_rightcurs() majorly rewritten; zrefresh() fixed -
 | 
						|
   I've put my fingers into just about every routine in here -
 | 
						|
   any queries about updates to mason@primenet.com.au */
 | 
						|
 | 
						|
static char **nbuf = NULL,	/* new video buffer line-by-line char array */
 | 
						|
    **obuf = NULL;		/* old video buffer line-by-line char array */
 | 
						|
static int more_start,		/* more text before start of screen?	    */
 | 
						|
    more_end,			/* more stuff after end of screen?	    */
 | 
						|
    olnct,			/* previous number of lines		    */
 | 
						|
    ovln,			/* previous video cursor position line	    */
 | 
						|
    lpromptw, rpromptw,		/* prompt widths on screen                  */
 | 
						|
    lpromptwof,			/* left prompt width with real end position */
 | 
						|
    lprompth,			/* lines taken up by the prompt		    */
 | 
						|
    rprompth,			/* right prompt height                      */
 | 
						|
    vcs, vln,			/* video cursor position column & line	    */
 | 
						|
    vmaxln,			/* video maximum number of lines	    */
 | 
						|
    winw, winh, rwinh,		/* window width & height		    */
 | 
						|
    winpos;			/* singlelinezle: line's position in window */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
resetvideo(void)
 | 
						|
{
 | 
						|
    int ln;
 | 
						|
    static int lwinw = -1, lwinh = -1;	/* last window width & height */
 | 
						|
 
 | 
						|
    winw = columns;  /* terminal width */
 | 
						|
    if (termflags & TERM_SHORT)
 | 
						|
	winh = 1;
 | 
						|
    else
 | 
						|
	winh = (lines < 2) ? 24 : lines;
 | 
						|
    rwinh = lines;		/* keep the real number of lines */
 | 
						|
    winpos = vln = vmaxln = 0;
 | 
						|
    if (lwinw != winw || lwinh != winh) {
 | 
						|
	if (nbuf) {
 | 
						|
	    for (ln = 0; ln != lwinh; ln++) {
 | 
						|
		zfree(nbuf[ln], lwinw + 2);
 | 
						|
		zfree(obuf[ln], lwinw + 2);
 | 
						|
	    }
 | 
						|
	    free(nbuf);
 | 
						|
	    free(obuf);
 | 
						|
	}
 | 
						|
	nbuf = (char **)zcalloc((winh + 1) * sizeof(char *));
 | 
						|
	obuf = (char **)zcalloc((winh + 1) * sizeof(char *));
 | 
						|
	nbuf[0] = (char *)zalloc(winw + 2);
 | 
						|
	obuf[0] = (char *)zalloc(winw + 2);
 | 
						|
 | 
						|
	lwinw = winw;
 | 
						|
	lwinh = winh;
 | 
						|
    }
 | 
						|
    for (ln = 0; ln != winh + 1; ln++) {
 | 
						|
	if (nbuf[ln])
 | 
						|
	    *nbuf[ln] = '\0';
 | 
						|
	if (obuf[ln])
 | 
						|
	    *obuf[ln] = '\0';
 | 
						|
    }
 | 
						|
 | 
						|
    countprompt(lpromptbuf, &lpromptwof, &lprompth, 1);
 | 
						|
    countprompt(rpromptbuf, &rpromptw, &rprompth, 0);
 | 
						|
    if (lpromptwof != winw)
 | 
						|
	lpromptw = lpromptwof;
 | 
						|
    else {
 | 
						|
	lpromptw = 0;
 | 
						|
	lprompth++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (lpromptw) {
 | 
						|
    	memset(nbuf[0], ' ', lpromptw);
 | 
						|
	memset(obuf[0], ' ', lpromptw);
 | 
						|
	nbuf[0][lpromptw] = obuf[0][lpromptw] = '\0';
 | 
						|
    }
 | 
						|
 | 
						|
    vcs = lpromptw;
 | 
						|
    olnct = nlnct = 0;
 | 
						|
    if (showinglist > 0)
 | 
						|
	showinglist = -2;
 | 
						|
    trashedzle = 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Nov 96: <mason> changed to single line scroll
 | 
						|
 */
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
scrollwindow(int tline)
 | 
						|
{
 | 
						|
    int t0;
 | 
						|
    char *s;
 | 
						|
 | 
						|
    s = nbuf[tline];
 | 
						|
    for (t0 = tline; t0 < winh - 1; t0++)
 | 
						|
	nbuf[t0] = nbuf[t0 + 1];
 | 
						|
    nbuf[winh - 1] = s;
 | 
						|
    if (!tline)
 | 
						|
	more_start = 1;
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
/* this is the messy part. */
 | 
						|
/* this define belongs where it's used!!! */
 | 
						|
 | 
						|
#define nextline					\
 | 
						|
{							\
 | 
						|
    *s = '\0';						\
 | 
						|
    if (ln != winh - 1)					\
 | 
						|
	ln++;						\
 | 
						|
    else {						\
 | 
						|
	if (!canscroll)	{				\
 | 
						|
	    if (nvln != -1 && nvln != winh - 1		\
 | 
						|
		&& (numscrolls != onumscrolls - 1	\
 | 
						|
		    || nvln <= winh / 2))		\
 | 
						|
	        break;					\
 | 
						|
	    numscrolls++;				\
 | 
						|
	    canscroll = winh / 2;			\
 | 
						|
	}						\
 | 
						|
	canscroll--;					\
 | 
						|
	scrollwindow(0);				\
 | 
						|
	if (nvln != -1)					\
 | 
						|
	    nvln--;					\
 | 
						|
    }							\
 | 
						|
    if (!nbuf[ln])					\
 | 
						|
	nbuf[ln] = (char *)zalloc(winw + 2);		\
 | 
						|
    s = (unsigned char *)nbuf[ln];			\
 | 
						|
    sen = s + winw;					\
 | 
						|
}
 | 
						|
 | 
						|
#define snextline					\
 | 
						|
{							\
 | 
						|
    *s = '\0';						\
 | 
						|
    if (ln != winh - 1)					\
 | 
						|
	ln++;						\
 | 
						|
    else						\
 | 
						|
	if (tosln > ln) {				\
 | 
						|
	    tosln--;					\
 | 
						|
	    if (nvln > 1) {				\
 | 
						|
		scrollwindow(0);			\
 | 
						|
		nvln--;					\
 | 
						|
	    } else					\
 | 
						|
		more_end = 1;				\
 | 
						|
	} else if (tosln > 2 && nvln > 1) {		\
 | 
						|
	    tosln--;					\
 | 
						|
	    if (tosln <= nvln) {			\
 | 
						|
		scrollwindow(0);			\
 | 
						|
		nvln--;					\
 | 
						|
	    } else {					\
 | 
						|
		scrollwindow(tosln);			\
 | 
						|
		more_end = 1;				\
 | 
						|
	    }						\
 | 
						|
	} else {					\
 | 
						|
	    more_status = 1;				\
 | 
						|
	    scrollwindow(tosln + 1);			\
 | 
						|
	}						\
 | 
						|
    if (!nbuf[ln])					\
 | 
						|
	nbuf[ln] = (char *)zalloc(winw + 2);		\
 | 
						|
    s = (unsigned char *)nbuf[ln];			\
 | 
						|
    sen = s + winw;					\
 | 
						|
}
 | 
						|
 | 
						|
static int cleareol,		/* clear to end-of-line (if can't cleareod) */
 | 
						|
    clearf,			/* alwayslastprompt used immediately before */
 | 
						|
    put_rpmpt,			/* whether we should display right-prompt   */
 | 
						|
    oput_rpmpt,			/* whether displayed right-prompt last time */
 | 
						|
    oxtabs,			/* oxtabs - tabs expand to spaces if set    */
 | 
						|
    numscrolls, onumscrolls;
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
zrefresh(void)
 | 
						|
{
 | 
						|
    static int inlist;		/* avoiding recursion                        */
 | 
						|
    int canscroll = 0,		/* number of lines we are allowed to scroll  */
 | 
						|
	ln = 0,			/* current line we're working on	     */
 | 
						|
	more_status = 0,	/* more stuff in status line		     */
 | 
						|
	nvcs = 0, nvln = -1,	/* video cursor column and line		     */
 | 
						|
	t0 = -1,		/* tmp					     */
 | 
						|
	tosln = 0;		/* tmp in statusline stuff		     */
 | 
						|
    unsigned char *s,		/* pointer into the video buffer	     */
 | 
						|
	*t,			/* pointer into the real buffer		     */
 | 
						|
	*sen,			/* pointer to end of the video buffer (eol)  */
 | 
						|
	*scs;			/* pointer to cursor position in real buffer */
 | 
						|
    char **qbuf;		/* tmp					     */
 | 
						|
 | 
						|
    /* If this is called from listmatches() (indirectly via trashzle()), and *
 | 
						|
     * that was called from the end of zrefresh(), then we don't need to do  *
 | 
						|
     * anything.  All this `inlist' code is actually unnecessary, but it     *
 | 
						|
     * improves speed a little in a common case.                             */
 | 
						|
    if (inlist)
 | 
						|
	return;
 | 
						|
 | 
						|
    if (clearlist && listshown > 0) {
 | 
						|
	if (tccan(TCCLEAREOD)) {
 | 
						|
	    int ovln = vln, ovcs = vcs;
 | 
						|
	    char *nb = nbuf[vln];
 | 
						|
 | 
						|
	    nbuf[vln] = obuf[vln];
 | 
						|
	    moveto(nlnct, 0);
 | 
						|
	    tcout(TCCLEAREOD);
 | 
						|
	    moveto(ovln, ovcs);
 | 
						|
	    nbuf[vln] = nb;
 | 
						|
	} else {
 | 
						|
	    invalidatelist();
 | 
						|
	    moveto(0, 0);
 | 
						|
	    clearflag = 0;
 | 
						|
	    resetneeded = 1;
 | 
						|
	}
 | 
						|
	listshown = lastlistlen = 0;
 | 
						|
	if (showinglist != -2)
 | 
						|
	    showinglist = 0;
 | 
						|
    }
 | 
						|
    clearlist = 0;
 | 
						|
 | 
						|
#ifdef HAVE_SELECT
 | 
						|
    cost = 0;			/* reset */
 | 
						|
#endif
 | 
						|
 | 
						|
/* Nov 96: <mason>  I haven't checked how complete this is.  sgtty stuff may
 | 
						|
   or may not work */
 | 
						|
#if defined(SGTABTYPE)
 | 
						|
    oxtabs = ((SGTTYFLAG & SGTABTYPE) == SGTABTYPE);
 | 
						|
#else
 | 
						|
    oxtabs = 0;
 | 
						|
#endif
 | 
						|
 | 
						|
    cleareol = 0;		/* unset */
 | 
						|
    more_start = more_end = 0;	/* unset */
 | 
						|
    if (isset(SINGLELINEZLE) || lines < 3
 | 
						|
	|| (termflags & (TERM_NOUP | TERM_BAD | TERM_UNKNOWN)))
 | 
						|
	termflags |= TERM_SHORT;
 | 
						|
    else
 | 
						|
	termflags &= ~TERM_SHORT;
 | 
						|
    if (resetneeded) {
 | 
						|
	onumscrolls = 0;
 | 
						|
	zsetterm();
 | 
						|
#ifdef TIOCGWINSZ
 | 
						|
	if (winchanged) {
 | 
						|
	    moveto(0, 0);
 | 
						|
	    t0 = olnct;		/* this is to clear extra lines even when */
 | 
						|
	    winchanged = 0;	/* the terminal cannot TCCLEAREOD	  */
 | 
						|
	    listshown = 0;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	resetvideo();
 | 
						|
	resetneeded = 0;	/* unset */
 | 
						|
	oput_rpmpt = 0;		/* no right-prompt currently on screen */
 | 
						|
 | 
						|
	/* we probably should only have explicitly set attributes */
 | 
						|
	tsetcap(TCALLATTRSOFF, 0);
 | 
						|
	tsetcap(TCSTANDOUTEND, 0);
 | 
						|
	tsetcap(TCUNDERLINEEND, 0);
 | 
						|
 | 
						|
        if (!clearflag) {
 | 
						|
            if (tccan(TCCLEAREOD))
 | 
						|
                tcout(TCCLEAREOD);
 | 
						|
            else
 | 
						|
                cleareol = 1;   /* request: clear to end of line */
 | 
						|
	    if (listshown > 0)
 | 
						|
		listshown = 0;
 | 
						|
	}
 | 
						|
        if (t0 > -1)
 | 
						|
            olnct = (t0 < winh) ? t0 : winh;
 | 
						|
        if (termflags & TERM_SHORT)
 | 
						|
            vcs = 0;
 | 
						|
        else if (!clearflag && lpromptbuf[0]) {
 | 
						|
            zputs(lpromptbuf, shout);
 | 
						|
	    if (lpromptwof == winw)
 | 
						|
		zputs("\n", shout);	/* works with both hasam and !hasam */
 | 
						|
	} else {
 | 
						|
	    txtchange = pmpt_attr;
 | 
						|
	    if (txtchangeisset(TXTNOBOLDFACE))
 | 
						|
		tsetcap(TCALLATTRSOFF, 0);
 | 
						|
	    if (txtchangeisset(TXTNOSTANDOUT))
 | 
						|
		tsetcap(TCSTANDOUTEND, 0);
 | 
						|
	    if (txtchangeisset(TXTNOUNDERLINE))
 | 
						|
		tsetcap(TCUNDERLINEEND, 0);
 | 
						|
	    if (txtchangeisset(TXTBOLDFACE))
 | 
						|
		tsetcap(TCBOLDFACEBEG, 0);
 | 
						|
	    if (txtchangeisset(TXTSTANDOUT))
 | 
						|
		tsetcap(TCSTANDOUTBEG, 0);
 | 
						|
	    if (txtchangeisset(TXTUNDERLINE))
 | 
						|
		tsetcap(TCUNDERLINEBEG, 0);
 | 
						|
	}
 | 
						|
	if (clearflag) {
 | 
						|
	    zputc('\r', shout);
 | 
						|
	    vcs = 0;
 | 
						|
	    moveto(0, lpromptw);
 | 
						|
	}
 | 
						|
	fflush(shout);
 | 
						|
	clearf = clearflag;
 | 
						|
    } else if (winw != columns || rwinh != lines)
 | 
						|
	resetvideo();
 | 
						|
 | 
						|
/* now winw equals columns and winh equals lines 
 | 
						|
   width comparisons can be made with winw, height comparisons with winh */
 | 
						|
 | 
						|
    if (termflags & TERM_SHORT) {
 | 
						|
	singlerefresh();
 | 
						|
	goto singlelineout;
 | 
						|
    }
 | 
						|
 | 
						|
    if (cs < 0) {
 | 
						|
#ifdef DEBUG
 | 
						|
	fprintf(stderr, "BUG: negative cursor position\n");
 | 
						|
	fflush(stderr); 
 | 
						|
#endif
 | 
						|
	cs = 0;
 | 
						|
    }
 | 
						|
    scs = line + cs;
 | 
						|
    numscrolls = 0;
 | 
						|
 | 
						|
/* first, we generate the video line buffers so we know what to put on
 | 
						|
   the screen - also determine final cursor position (nvln, nvcs) */
 | 
						|
 | 
						|
    /* Deemed necessary by PWS 1995/05/15 due to kill-line problems */
 | 
						|
    if (!*nbuf)
 | 
						|
	*nbuf = (char *)zalloc(winw + 2);
 | 
						|
 | 
						|
    s = (unsigned char *)(nbuf[ln = 0] + lpromptw);
 | 
						|
    t = line;
 | 
						|
    sen = (unsigned char *)(*nbuf + winw);
 | 
						|
    for (; t < line+ll; t++) {
 | 
						|
	if (t == scs)			/* if cursor is here, remember it */
 | 
						|
	    nvcs = s - (unsigned char *)(nbuf[nvln = ln]);
 | 
						|
 | 
						|
	if (*t == '\n')	{		/* newline */
 | 
						|
	    nbuf[ln][winw + 1] = '\0';	/* text not wrapped */
 | 
						|
	    nextline
 | 
						|
	} else if (*t == '\t') {		/* tab */
 | 
						|
	    t0 = (char *)s - nbuf[ln];
 | 
						|
	    if ((t0 | 7) + 1 >= winw) {
 | 
						|
		nbuf[ln][winw + 1] = '\n';	/* text wrapped */
 | 
						|
		nextline
 | 
						|
	    } else
 | 
						|
		do
 | 
						|
		    *s++ = ' ';
 | 
						|
		while ((++t0) & 7);
 | 
						|
	} else if (icntrl(*t)) {	/* other control character */
 | 
						|
	    *s++ = '^';
 | 
						|
	    if (s == sen) {
 | 
						|
		nbuf[ln][winw + 1] = '\n';	/* text wrapped */
 | 
						|
		nextline
 | 
						|
	    }
 | 
						|
	    *s++ = (*t == 127) ? '?' : (*t | '@');
 | 
						|
	} else				/* normal character */
 | 
						|
	    *s++ = *t;
 | 
						|
	if (s == sen) {
 | 
						|
	    nbuf[ln][winw + 1] = '\n';	/* text wrapped */
 | 
						|
	    nextline
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
/* if we're really on the next line, don't fake it; do everything properly */
 | 
						|
    if (t == scs && (nvcs = s - (unsigned char *)(nbuf[nvln = ln])) == winw) {
 | 
						|
	nbuf[ln][winw + 1] = '\n';	/* text wrapped */
 | 
						|
	switch ('\0') { 	/* a sad hack to make the break */
 | 
						|
	case '\0':		/* in nextline work */
 | 
						|
	    nextline
 | 
						|
	}
 | 
						|
	*s = '\0';
 | 
						|
	nvcs = 0;
 | 
						|
	nvln++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (t != line + ll)
 | 
						|
	more_end = 1;
 | 
						|
 | 
						|
    if (statusline) {
 | 
						|
	tosln = ln + 1;
 | 
						|
	nbuf[ln][winw + 1] = '\0';	/* text not wrapped */
 | 
						|
	snextline
 | 
						|
	t = (unsigned char *)statusline;
 | 
						|
	for (; t < (unsigned char *)statusline + statusll; t++) {
 | 
						|
	    if (icntrl(*t)) {	/* simplified processing in the status line */
 | 
						|
		*s++ = '^';
 | 
						|
		if (s == sen) {
 | 
						|
		    nbuf[ln][winw + 1] = '\n';	/* text wrapped */
 | 
						|
		    snextline
 | 
						|
		}
 | 
						|
		*s++ = (*t == 127) ? '?' : (*t | '@');
 | 
						|
	    } else
 | 
						|
		*s++ = *t;
 | 
						|
	    if (s == sen) {
 | 
						|
		nbuf[ln][winw + 1] = '\n';	/* text wrapped */
 | 
						|
		snextline
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if (s == sen)
 | 
						|
	    snextline
 | 
						|
    }
 | 
						|
    *s = '\0';
 | 
						|
 | 
						|
/* insert <.... at end of last line if there is more text past end of screen */
 | 
						|
    if (more_end) {
 | 
						|
	if (!statusline)
 | 
						|
	    tosln = winh;
 | 
						|
	s = nbuf[tosln - 1];
 | 
						|
	sen = s + winw - 7;
 | 
						|
	for (; s < sen; s++) {
 | 
						|
	    if (*s == '\0') {
 | 
						|
		for (; s < sen; )
 | 
						|
		    *s++ = ' ';
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	strncpy(sen, " <.... ", 7);
 | 
						|
	nbuf[tosln - 1][winw] = nbuf[tosln - 1][winw + 1] = '\0';
 | 
						|
    }
 | 
						|
 | 
						|
/* insert <....> at end of first status line if status is too big */
 | 
						|
    if (more_status) {
 | 
						|
	s = nbuf[tosln];
 | 
						|
	sen = s + winw - 8;
 | 
						|
	for (; s < sen; s++) {
 | 
						|
	    if (*s == '\0') {
 | 
						|
		for (; s < sen; )
 | 
						|
		    *s++ = ' ';
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	strncpy(sen, " <....> ", 8);
 | 
						|
	nbuf[tosln][winw] = nbuf[tosln][winw + 1] = '\0';
 | 
						|
    }
 | 
						|
 | 
						|
    nlnct = ln + 1;
 | 
						|
    for (ln = nlnct; ln < winh; ln++)
 | 
						|
	zfree(nbuf[ln], winw + 2), nbuf[ln] = NULL;
 | 
						|
 | 
						|
/* determine whether the right-prompt exists and can fit on the screen */
 | 
						|
    if (!more_start) {
 | 
						|
	if (trashedzle && opts[TRANSIENTRPROMPT])
 | 
						|
	    put_rpmpt = 0;
 | 
						|
	else
 | 
						|
	    put_rpmpt = rprompth == 1 && rpromptbuf[0] &&
 | 
						|
		!strchr(rpromptbuf, '\t') &&
 | 
						|
		(int)strlen(nbuf[0]) + rpromptw < winw - 1;
 | 
						|
    } else {
 | 
						|
/* insert >.... on first line if there is more text before start of screen */
 | 
						|
	memset(nbuf[0], ' ', lpromptw);
 | 
						|
	t0 = winw - lpromptw;
 | 
						|
	t0 = t0 > 5 ? 5 : t0;
 | 
						|
	strncpy(nbuf[0] + lpromptw, ">....", t0);
 | 
						|
	memset(nbuf[0] + lpromptw + t0, ' ', winw - t0 - lpromptw);
 | 
						|
	nbuf[0][winw] = nbuf[0][winw + 1] = '\0';
 | 
						|
    }
 | 
						|
 | 
						|
    for (ln = 0; ln < nlnct; ln++) {
 | 
						|
	/* if we have more lines than last time, clear the newly-used lines */
 | 
						|
	if (ln >= olnct)
 | 
						|
	    cleareol = 1;
 | 
						|
 | 
						|
    /* if old line and new line are different,
 | 
						|
       see if we can insert/delete a line to speed up update */
 | 
						|
 | 
						|
	if (!clearf && ln > 0 && ln < olnct - 1 && !(hasam && vcs == winw) &&
 | 
						|
	    nbuf[ln] && obuf[ln] &&
 | 
						|
	    strncmp(nbuf[ln], obuf[ln], 16)) {
 | 
						|
	    if (tccan(TCDELLINE) && obuf[ln + 1] && obuf[ln + 1][0] &&
 | 
						|
		nbuf[ln] && !strncmp(nbuf[ln], obuf[ln + 1], 16)) {
 | 
						|
		moveto(ln, 0);
 | 
						|
		tcout(TCDELLINE);
 | 
						|
		zfree(obuf[ln], winw + 2);
 | 
						|
		for (t0 = ln; t0 != olnct; t0++)
 | 
						|
		    obuf[t0] = obuf[t0 + 1];
 | 
						|
		obuf[--olnct] = NULL;
 | 
						|
	    }
 | 
						|
	/* don't try to insert a line if olnct = vmaxln (vmaxln is the number
 | 
						|
	   of lines that have been displayed by this routine) so that we don't
 | 
						|
	   go off the end of the screen. */
 | 
						|
 | 
						|
	    else if (tccan(TCINSLINE) && olnct < vmaxln && nbuf[ln + 1] &&
 | 
						|
		     obuf[ln] && !strncmp(nbuf[ln + 1], obuf[ln], 16)) {
 | 
						|
		moveto(ln, 0);
 | 
						|
		tcout(TCINSLINE);
 | 
						|
		for (t0 = olnct; t0 != ln; t0--)
 | 
						|
		    obuf[t0] = obuf[t0 - 1];
 | 
						|
		obuf[ln] = NULL;
 | 
						|
		olnct++;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
    /* update the single line */
 | 
						|
	refreshline(ln);
 | 
						|
 | 
						|
    /* output the right-prompt if appropriate */
 | 
						|
	if (put_rpmpt && !ln && !oput_rpmpt) {
 | 
						|
	    oput_rpmpt = put_rpmpt;
 | 
						|
	    moveto(0, winw - 1 - rpromptw);
 | 
						|
	    zputs(rpromptbuf, shout);
 | 
						|
	    vcs = winw - 1;
 | 
						|
	/* reset character attributes to that set by the main prompt */
 | 
						|
	    txtchange = pmpt_attr;
 | 
						|
	    if (txtchangeisset(TXTNOBOLDFACE) && (rpmpt_attr & TXTBOLDFACE))
 | 
						|
		tsetcap(TCALLATTRSOFF, 0);
 | 
						|
	    if (txtchangeisset(TXTNOSTANDOUT) && (rpmpt_attr & TXTSTANDOUT))
 | 
						|
		tsetcap(TCSTANDOUTEND, 0);
 | 
						|
	    if (txtchangeisset(TXTNOUNDERLINE) && (rpmpt_attr & TXTUNDERLINE))
 | 
						|
		tsetcap(TCUNDERLINEEND, 0);
 | 
						|
	    if (txtchangeisset(TXTBOLDFACE) && (rpmpt_attr & TXTNOBOLDFACE))
 | 
						|
		tsetcap(TCBOLDFACEBEG, 0);
 | 
						|
	    if (txtchangeisset(TXTSTANDOUT) && (rpmpt_attr & TXTNOSTANDOUT))
 | 
						|
		tsetcap(TCSTANDOUTBEG, 0);
 | 
						|
	    if (txtchangeisset(TXTUNDERLINE) && (rpmpt_attr & TXTNOUNDERLINE))
 | 
						|
		tsetcap(TCUNDERLINEBEG, 0);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
/* if old buffer had extra lines, set them to be cleared and refresh them
 | 
						|
individually */
 | 
						|
 | 
						|
    if (olnct > nlnct) {
 | 
						|
	cleareol = 1;
 | 
						|
	for (ln = nlnct; ln < olnct; ln++)
 | 
						|
	    refreshline(ln);
 | 
						|
    }
 | 
						|
 | 
						|
/* reset character attributes */
 | 
						|
    if (clearf && postedit) {
 | 
						|
	if ((txtchange = pmpt_attr ? pmpt_attr : rpmpt_attr)) {
 | 
						|
	    if (txtchangeisset(TXTNOBOLDFACE))
 | 
						|
		tsetcap(TCALLATTRSOFF, 0);
 | 
						|
	    if (txtchangeisset(TXTNOSTANDOUT))
 | 
						|
		tsetcap(TCSTANDOUTEND, 0);
 | 
						|
	    if (txtchangeisset(TXTNOUNDERLINE))
 | 
						|
		tsetcap(TCUNDERLINEEND, 0);
 | 
						|
	    if (txtchangeisset(TXTBOLDFACE))
 | 
						|
		tsetcap(TCBOLDFACEBEG, 0);
 | 
						|
	    if (txtchangeisset(TXTSTANDOUT))
 | 
						|
		tsetcap(TCSTANDOUTBEG, 0);
 | 
						|
	    if (txtchangeisset(TXTUNDERLINE))
 | 
						|
		tsetcap(TCUNDERLINEBEG, 0);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    clearf = 0;
 | 
						|
 | 
						|
/* move to the new cursor position */
 | 
						|
    moveto(nvln, nvcs);
 | 
						|
 | 
						|
/* swap old and new buffers - better than freeing/allocating every time */
 | 
						|
    qbuf = nbuf;
 | 
						|
    nbuf = obuf;
 | 
						|
    obuf = qbuf;
 | 
						|
/* store current values so we can use them next time */
 | 
						|
    ovln = nvln;
 | 
						|
    olnct = nlnct;
 | 
						|
    onumscrolls = numscrolls;
 | 
						|
    if (nlnct > vmaxln)
 | 
						|
	vmaxln = nlnct;
 | 
						|
singlelineout:
 | 
						|
    fflush(shout);		/* make sure everything is written out */
 | 
						|
 | 
						|
    /* if we have a new list showing, note it; if part of the list has been
 | 
						|
    overwritten, redisplay it. */
 | 
						|
    if (showinglist == -2 || (showinglist > 0 && showinglist < nlnct)) {
 | 
						|
	inlist = 1;
 | 
						|
	listmatches();
 | 
						|
	inlist = 0;
 | 
						|
	zrefresh();
 | 
						|
    }
 | 
						|
    if (showinglist == -1)
 | 
						|
	showinglist = nlnct;
 | 
						|
}
 | 
						|
 | 
						|
#define tcinscost(X)   (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
 | 
						|
#define tcdelcost(X)   (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL])
 | 
						|
#define tc_delchars(X)	(void) tcmultout(TCDEL, TCMULTDEL, (X))
 | 
						|
#define tc_inschars(X)	(void) tcmultout(TCINS, TCMULTINS, (X))
 | 
						|
#define tc_upcurs(X)	(void) tcmultout(TCUP, TCMULTUP, (X))
 | 
						|
#define tc_leftcurs(X)	(void) tcmultout(TCLEFT, TCMULTLEFT, (X))
 | 
						|
 | 
						|
/* refresh one line, using whatever speed-up tricks are provided by the tty */
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
refreshline(int ln)
 | 
						|
{
 | 
						|
    char *nl, *ol, *p1;		/* line buffer pointers			 */
 | 
						|
    int ccs = 0,		/* temporary count for cursor position	 */
 | 
						|
	char_ins = 0,		/* number of characters inserted/deleted */
 | 
						|
	col_cleareol,		/* clear to end-of-line from this column */
 | 
						|
	i, j,			/* tmp					 */
 | 
						|
	ins_last,		/* insert pushed last character off line */
 | 
						|
	nllen, ollen,		/* new and old line buffer lengths	 */
 | 
						|
	rnllen;			/* real new line buffer length		 */
 | 
						|
 | 
						|
/* 0: setup */
 | 
						|
    nl = nbuf[ln];
 | 
						|
    rnllen = nllen = nl ? strlen(nl) : 0;
 | 
						|
    ol = obuf[ln] ? obuf[ln] : "";
 | 
						|
    ollen = strlen(ol);
 | 
						|
 | 
						|
/* optimisation: can easily happen for clearing old lines.  If the terminal has
 | 
						|
   the capability, then this is the easiest way to skip unnecessary stuff */
 | 
						|
    if (cleareol && !nllen && !(hasam && ln < nlnct - 1)
 | 
						|
	&& tccan(TCCLEAREOL)) {
 | 
						|
	moveto(ln, 0);
 | 
						|
	tcout(TCCLEAREOL);
 | 
						|
	return;	
 | 
						|
    }
 | 
						|
 | 
						|
/* 1: pad out the new buffer with spaces to contain _all_ of the characters
 | 
						|
      which need to be written. do this now to allow some pre-processing */
 | 
						|
 | 
						|
    if (cleareol 		/* request to clear to end of line */
 | 
						|
	|| (!nllen && (ln != 0 || !put_rpmpt))	/* no line buffer given */
 | 
						|
	|| (ln == 0 && (put_rpmpt != oput_rpmpt))) {	/* prompt changed */
 | 
						|
	p1 = zhalloc(winw + 2);
 | 
						|
	if (nllen)
 | 
						|
	    strncpy(p1, nl, nllen);
 | 
						|
	memset(p1 + nllen, ' ', winw - nllen);
 | 
						|
	p1[winw] = '\0';
 | 
						|
	p1[winw + 1] = (nllen < winw) ? '\0' : nl[winw + 1];
 | 
						|
	if (ln && nbuf[ln])
 | 
						|
	    memcpy(nl, p1, winw + 2);	/* next time obuf will be up-to-date */
 | 
						|
	else
 | 
						|
	    nl = p1;		/* don't keep the padding for prompt line */
 | 
						|
	nllen = winw;
 | 
						|
    } else if (ollen > nllen) { /* make new line at least as long as old */
 | 
						|
	p1 = zhalloc(ollen + 1);
 | 
						|
	strncpy(p1, nl, nllen);
 | 
						|
	memset(p1 + nllen, ' ', ollen - nllen);
 | 
						|
	p1[ollen] = '\0';
 | 
						|
	nl = p1;
 | 
						|
	nllen = ollen;
 | 
						|
    }
 | 
						|
 | 
						|
/* 2: see if we can clear to end-of-line, and if it's faster, work out where
 | 
						|
   to do it from - we can normally only do so if there's no right-prompt.
 | 
						|
   With automatic margins, we shouldn't do it if there is another line, in
 | 
						|
   case it messes up cut and paste. */
 | 
						|
 | 
						|
    if (hasam && ln < nlnct - 1 && rnllen == winw)
 | 
						|
	col_cleareol = -2;	/* clearing eol would be evil so don't */
 | 
						|
    else {
 | 
						|
	col_cleareol = -1;
 | 
						|
	if (tccan(TCCLEAREOL) && (nllen == winw || put_rpmpt != oput_rpmpt)) {
 | 
						|
	    for (i = nllen; i && nl[i - 1] == ' '; i--);
 | 
						|
	    for (j = ollen; j && ol[j - 1] == ' '; j--);
 | 
						|
	    if ((j > i + tclen[TCCLEAREOL])	/* new buf has enough spaces */
 | 
						|
		|| (nllen == winw && nl[winw - 1] == ' '))
 | 
						|
		col_cleareol = i;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
/* 2b: first a new trick for automargin niceness - good for cut and paste */
 | 
						|
 | 
						|
    if (hasam && vcs == winw) {
 | 
						|
	if (nbuf[vln] && nbuf[vln][vcs + 1] == '\n') {
 | 
						|
	    vln++, vcs = 1;
 | 
						|
            if (nbuf[vln]  && *nbuf[vln])
 | 
						|
		zputc(*nbuf[vln], shout);
 | 
						|
	    else
 | 
						|
		zputc(' ', shout);  /* I don't think this should happen */
 | 
						|
	    if (ln == vln) {	/* better safe than sorry */
 | 
						|
		nl++;
 | 
						|
		if (*ol)
 | 
						|
		    ol++;
 | 
						|
		ccs = 1;
 | 
						|
	    }			/* else  hmmm... I wonder what happened */
 | 
						|
	} else {
 | 
						|
	    vln++, vcs = 0;
 | 
						|
	    zputc('\n', shout);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    ins_last = 0;
 | 
						|
 | 
						|
/* 2c: if we're on the first line, start checking at the end of the prompt;
 | 
						|
   we shouldn't be doing anything within the prompt */
 | 
						|
 | 
						|
    if (ln == 0 && lpromptw) {
 | 
						|
	i = lpromptw - ccs;
 | 
						|
	j = strlen(ol);
 | 
						|
	nl += i;
 | 
						|
	ol += (i > j ? j : i);	/* if ol is too short, point it to '\0' */
 | 
						|
	ccs = lpromptw;
 | 
						|
    }
 | 
						|
 | 
						|
/* 3: main display loop - write out the buffer using whatever tricks we can */
 | 
						|
 | 
						|
    for (;;) {
 | 
						|
	if (*nl && *ol && nl[1] == ol[1]) /* skip only if second chars match */
 | 
						|
	/* skip past all matching characters */
 | 
						|
	    for (; *nl && (*nl == *ol); nl++, ol++, ccs++) ;
 | 
						|
 | 
						|
	if (!*nl) {
 | 
						|
	    if (ccs == winw && hasam && char_ins > 0 && ins_last
 | 
						|
		&& vcs != winw) {
 | 
						|
		nl--;           /* we can assume we can go back here */
 | 
						|
		moveto(ln, winw - 1);
 | 
						|
		zputc(*nl, shout);
 | 
						|
		vcs++;
 | 
						|
		return;         /* write last character in line */
 | 
						|
	    }
 | 
						|
	    if ((char_ins <= 0) || (ccs >= winw))    /* written everything */
 | 
						|
		return;
 | 
						|
	    if (tccan(TCCLEAREOL) && (char_ins >= tclen[TCCLEAREOL])
 | 
						|
	    	&& col_cleareol != -2)
 | 
						|
	    /* we've got junk on the right yet to clear */
 | 
						|
		col_cleareol = 0;	/* force a clear to end of line */
 | 
						|
	}
 | 
						|
 | 
						|
	moveto(ln, ccs);	/* move to where we do all output from */
 | 
						|
 | 
						|
    /* if we can finish quickly, do so */
 | 
						|
	if ((col_cleareol >= 0) && (ccs >= col_cleareol)) {
 | 
						|
	    tcout(TCCLEAREOL);
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
 | 
						|
    /* we've written out the new but yet to clear rubbish due to inserts */
 | 
						|
	if (!*nl) {
 | 
						|
	    i = (winw - ccs < char_ins) ? (winw - ccs) : char_ins;
 | 
						|
	    if (tccan(TCDEL) && (tcdelcost(i) <= i + 1))
 | 
						|
		tc_delchars(i);
 | 
						|
	    else {
 | 
						|
		vcs += i;
 | 
						|
		while (i-- > 0)
 | 
						|
		    zputc(' ', shout);
 | 
						|
	    }
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
 | 
						|
    /* if we've reached the end of the old buffer, then there are few tricks
 | 
						|
       we can do, so we just dump out what we must and clear if we can */
 | 
						|
	if (!*ol) {
 | 
						|
	    i = (col_cleareol >= 0) ? col_cleareol : nllen;
 | 
						|
	    i -= vcs;
 | 
						|
	    zwrite(nl, i, 1, shout);
 | 
						|
	    vcs += i;
 | 
						|
	    if (col_cleareol >= 0)
 | 
						|
		tcout(TCCLEAREOL);
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
 | 
						|
    /* inserting & deleting chars: we can if there's no right-prompt */
 | 
						|
	if ((ln || !put_rpmpt || !oput_rpmpt) 
 | 
						|
	    && (nl[1] && ol[1] && nl[1] != ol[1])) { 
 | 
						|
 | 
						|
	/* deleting characters - see if we can find a match series that
 | 
						|
	   makes it cheaper to delete intermediate characters
 | 
						|
	   eg. oldline: hifoobar \ hopefully cheaper here to delete two
 | 
						|
	       newline: foobar	 / characters, then we have six matches */
 | 
						|
	    if (tccan(TCDEL)) {
 | 
						|
		for (i = 1; *(ol + i); i++)
 | 
						|
		    if (tcdelcost(i) < pfxlen(ol + i, nl)) {
 | 
						|
			tc_delchars(i);
 | 
						|
			ol += i;
 | 
						|
			char_ins -= i;
 | 
						|
			i = 0;
 | 
						|
			break;
 | 
						|
		    }
 | 
						|
		if (!i)
 | 
						|
		    continue;
 | 
						|
	    }
 | 
						|
	/* inserting characters - characters pushed off the right should be
 | 
						|
	   annihilated, but we don't do this if we're on the last line lest
 | 
						|
	   undesired scrolling occurs due to `illegal' characters on screen */
 | 
						|
 | 
						|
	    if (tccan(TCINS) && (vln != lines - 1)) {	/* not on last line */
 | 
						|
		for (i = 1; *(nl + i); i++)
 | 
						|
		    if (tcinscost(i) < pfxlen(nl + i, ol)) {
 | 
						|
			tc_inschars(i);
 | 
						|
			zwrite(nl, i, 1, shout);
 | 
						|
			nl += i;
 | 
						|
			char_ins += i;
 | 
						|
			ccs = (vcs += i);
 | 
						|
		    /* if we've pushed off the right, truncate oldline */
 | 
						|
			for (i = 0; *(ol + i) && i < winw - ccs; i++);
 | 
						|
			if (i == winw - ccs) {
 | 
						|
			    *(ol + i) = '\0';
 | 
						|
			    ins_last = 1;
 | 
						|
			}
 | 
						|
			i = 0;
 | 
						|
			break;
 | 
						|
		    }
 | 
						|
		if (!i)
 | 
						|
		    continue;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    /* we can't do any fancy tricks, so just dump the single character
 | 
						|
       and keep on trying */
 | 
						|
	zputc(*nl, shout);
 | 
						|
	nl++, ol++;
 | 
						|
	ccs++, vcs++;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* move the cursor to line ln (relative to the prompt line),
 | 
						|
   absolute column cl; update vln, vcs - video line and column */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
moveto(int ln, int cl)
 | 
						|
{
 | 
						|
    int c;
 | 
						|
 | 
						|
    if (vcs == winw) {
 | 
						|
	vln++, vcs = 0;
 | 
						|
	if (!hasam) {
 | 
						|
	    zputc('\r', shout);
 | 
						|
	    zputc('\n', shout);
 | 
						|
	} else {
 | 
						|
	    if ((vln < nlnct) && nbuf[vln] && *nbuf[vln])
 | 
						|
		c = *nbuf[vln];
 | 
						|
	    else
 | 
						|
		c = ' ';
 | 
						|
	    zputc(c, shout);
 | 
						|
	    zputc('\r', shout);
 | 
						|
	    if ((vln < olnct) && obuf[vln] && *obuf[vln])
 | 
						|
		*obuf[vln] = c;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    if (ln == vln && cl == vcs)
 | 
						|
	return;
 | 
						|
 | 
						|
/* move up */
 | 
						|
    if (ln < vln) {
 | 
						|
	tc_upcurs(vln - ln);
 | 
						|
	vln = ln;
 | 
						|
    }
 | 
						|
/* move down; if we might go off the end of the screen, use newlines
 | 
						|
   instead of TCDOWN */
 | 
						|
 | 
						|
    while (ln > vln) {
 | 
						|
	if (vln < vmaxln - 1) {
 | 
						|
	    if (ln > vmaxln - 1) {
 | 
						|
		if (tc_downcurs(vmaxln - 1 - vln))
 | 
						|
		    vcs = 0;
 | 
						|
		vln = vmaxln - 1;
 | 
						|
	    } else {
 | 
						|
		if (tc_downcurs(ln - vln))
 | 
						|
		    vcs = 0;
 | 
						|
		vln = ln;
 | 
						|
		continue;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	zputc('\r', shout), vcs = 0; /* safety precaution */
 | 
						|
	while (ln > vln) {
 | 
						|
	    zputc('\n', shout);
 | 
						|
	    vln++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    if (cl != vcs)
 | 
						|
        singmoveto(cl);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int
 | 
						|
tcmultout(int cap, int multcap, int ct)
 | 
						|
{
 | 
						|
    if (tccan(multcap) && (!tccan(cap) || tclen[multcap] <= tclen[cap] * ct)) {
 | 
						|
	tcoutarg(multcap, ct);
 | 
						|
	return 1;
 | 
						|
    } else if (tccan(cap)) {
 | 
						|
	while (ct--)
 | 
						|
	    tcout(cap);
 | 
						|
	return 1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* ct: number of characters to move across */
 | 
						|
/**/
 | 
						|
static void
 | 
						|
tc_rightcurs(int ct)
 | 
						|
{
 | 
						|
    int cl,			/* ``desired'' absolute horizontal position */
 | 
						|
	i = vcs,		/* cursor position after initial movements  */
 | 
						|
	j;
 | 
						|
    char *t;
 | 
						|
 | 
						|
    cl = ct + vcs;
 | 
						|
 | 
						|
/* do a multright if we can - it's the most reliable */
 | 
						|
    if (tccan(TCMULTRIGHT)) {
 | 
						|
	tcoutarg(TCMULTRIGHT, ct);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
 | 
						|
/* do an absolute horizontal position if we can */
 | 
						|
    if (tccan(TCHORIZPOS)) {
 | 
						|
	tcoutarg(TCHORIZPOS, cl);
 | 
						|
	return;
 | 
						|
    }
 | 
						|
 | 
						|
/* XXX: should really check "it" in termcap and use / and % */
 | 
						|
/* try tabs if tabs are non destructive and multright is not possible */
 | 
						|
    if (!oxtabs && tccan(TCNEXTTAB) && ((vcs | 7) < cl)) {
 | 
						|
	i = (vcs | 7) + 1;
 | 
						|
	tcout(TCNEXTTAB);
 | 
						|
	for ( ; i + 8 <= cl; i += 8)
 | 
						|
	    tcout(TCNEXTTAB);
 | 
						|
	if ((ct = cl - i) == 0) /* number of chars still to move across */
 | 
						|
	    return;
 | 
						|
    }
 | 
						|
 | 
						|
/* otherwise _carefully_ write the contents of the video buffer.
 | 
						|
   if we're anywhere in the prompt, goto the left column and write the whole
 | 
						|
   prompt out unless ztrlen(lpromptbuf) == lpromptw : we can cheat then */
 | 
						|
    if (vln == 0 && i < lpromptw && !(termflags & TERM_SHORT)) {
 | 
						|
	if (strlen(lpromptbuf) == lpromptw)
 | 
						|
	    fputs(lpromptbuf + i, shout);
 | 
						|
	else if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpromptbuf)))
 | 
						|
	    /* it is cheaper to send TCRIGHT than reprint the whole prompt */
 | 
						|
	    for (ct = lpromptw - i; ct--; )
 | 
						|
		tcout(TCRIGHT);
 | 
						|
        else {
 | 
						|
	    if (i != 0)
 | 
						|
		zputc('\r', shout);
 | 
						|
	    tc_upcurs(lprompth - 1);
 | 
						|
	    zputs(lpromptbuf, shout);
 | 
						|
	    if (lpromptwof == winw)
 | 
						|
		zputs("\n", shout);	/* works with both hasam and !hasam */
 | 
						|
	}
 | 
						|
	i = lpromptw;
 | 
						|
	ct = cl - i;
 | 
						|
    }
 | 
						|
 | 
						|
    if (nbuf[vln]) {
 | 
						|
	for (j = 0, t = nbuf[vln]; *t && (j < i); j++, t++);
 | 
						|
	if (j == i)
 | 
						|
	    for ( ; *t && ct; ct--, t++)
 | 
						|
		zputc(*t, shout);
 | 
						|
    }
 | 
						|
    while (ct--)
 | 
						|
	zputc(' ', shout);	/* not my fault your terminal can't go right */
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static int
 | 
						|
tc_downcurs(int ct)
 | 
						|
{
 | 
						|
    int ret = 0;
 | 
						|
 | 
						|
    if (ct && !tcmultout(TCDOWN, TCMULTDOWN, ct)) {
 | 
						|
	while (ct--)
 | 
						|
	    zputc('\n', shout);
 | 
						|
	zputc('\r', shout), ret = -1;
 | 
						|
    }
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
tcout(int cap)
 | 
						|
{
 | 
						|
    tputs(tcstr[cap], 1, putshout);
 | 
						|
    SELECT_ADD_COST(tclen[cap]);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
tcoutarg(int cap, int arg)
 | 
						|
{
 | 
						|
    char *result;
 | 
						|
 | 
						|
    result = tgoto(tcstr[cap], arg, arg);
 | 
						|
    tputs(result, 1, putshout);
 | 
						|
    SELECT_ADD_COST(strlen(result));
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int
 | 
						|
clearscreen(char **args)
 | 
						|
{
 | 
						|
    tcout(TCCLEARSCREEN);
 | 
						|
    resetneeded = 1;
 | 
						|
    clearflag = 0;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int
 | 
						|
redisplay(char **args)
 | 
						|
{
 | 
						|
    moveto(0, 0);
 | 
						|
    zputc('\r', shout);		/* extra care */
 | 
						|
    tc_upcurs(lprompth - 1);
 | 
						|
    resetneeded = 1;
 | 
						|
    clearflag = 0;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
singlerefresh(void)
 | 
						|
{
 | 
						|
    char *vbuf, *vp,		/* video buffer and pointer    */
 | 
						|
	**qbuf,			/* tmp			       */
 | 
						|
	*refreshop = *obuf;	/* pointer to old video buffer */
 | 
						|
    int t0,			/* tmp			       */
 | 
						|
	vsiz,			/* size of new video buffer    */
 | 
						|
	nvcs = 0;		/* new video cursor column     */
 | 
						|
 | 
						|
    nlnct = 1;
 | 
						|
/* generate the new line buffer completely */
 | 
						|
    for (vsiz = 1 + lpromptw, t0 = 0; t0 != ll; t0++, vsiz++)
 | 
						|
	if (line[t0] == '\t')
 | 
						|
	    vsiz = (vsiz | 7) + 1;
 | 
						|
	else if (icntrl(line[t0]))
 | 
						|
	    vsiz++;
 | 
						|
    vbuf = (char *)zalloc(vsiz);
 | 
						|
 | 
						|
    if (cs < 0) {
 | 
						|
#ifdef DEBUG
 | 
						|
	fprintf(stderr, "BUG: negative cursor position\n");
 | 
						|
	fflush(stderr); 
 | 
						|
#endif
 | 
						|
	cs = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /* only use last part of prompt */
 | 
						|
    memcpy(vbuf, strchr(lpromptbuf, 0) - lpromptw, lpromptw);
 | 
						|
    vbuf[lpromptw] = '\0';
 | 
						|
    vp = vbuf + lpromptw;
 | 
						|
 | 
						|
    for (t0 = 0; t0 != ll; t0++) {
 | 
						|
	if (line[t0] == '\t')
 | 
						|
	    for (*vp++ = ' '; (vp - vbuf) & 7; )
 | 
						|
		*vp++ = ' ';
 | 
						|
	else if (line[t0] == '\n') {
 | 
						|
	    *vp++ = '\\';
 | 
						|
	    *vp++ = 'n';
 | 
						|
	} else if (line[t0] == 0x7f) {
 | 
						|
	    *vp++ = '^';
 | 
						|
	    *vp++ = '?';
 | 
						|
	} else if (icntrl(line[t0])) {
 | 
						|
	    *vp++ = '^';
 | 
						|
	    *vp++ = line[t0] | '@';
 | 
						|
	} else
 | 
						|
	    *vp++ = line[t0];
 | 
						|
	if (t0 == cs)
 | 
						|
	    nvcs = vp - vbuf - 1;
 | 
						|
    }
 | 
						|
    if (t0 == cs)
 | 
						|
	nvcs = vp - vbuf;
 | 
						|
    *vp = '\0';
 | 
						|
 | 
						|
/* determine which part of the new line buffer we want for the display */
 | 
						|
    if ((winpos && nvcs < winpos + 1) || (nvcs > winpos + winw - 2)) {
 | 
						|
	if ((winpos = nvcs - ((winw - hasam) / 2)) < 0)
 | 
						|
	    winpos = 0;
 | 
						|
    }
 | 
						|
    if (winpos)
 | 
						|
	vbuf[winpos] = '<';	/* line continues to the left */
 | 
						|
    if ((int)strlen(vbuf + winpos) > (winw - hasam)) {
 | 
						|
	vbuf[winpos + winw - hasam - 1] = '>';	/* line continues to right */
 | 
						|
	vbuf[winpos + winw - hasam] = '\0';
 | 
						|
    }
 | 
						|
    strcpy(nbuf[0], vbuf + winpos);
 | 
						|
    zfree(vbuf, vsiz);
 | 
						|
    nvcs -= winpos;
 | 
						|
 | 
						|
/* display the `visable' portion of the line buffer */
 | 
						|
    for (t0 = 0, vp = *nbuf;;) {
 | 
						|
    /* skip past all matching characters */
 | 
						|
	for (; *vp && *vp == *refreshop; t0++, vp++, refreshop++) ;
 | 
						|
 | 
						|
	if (!*vp && !*refreshop)
 | 
						|
	    break;
 | 
						|
 | 
						|
	singmoveto(t0);		/* move to where we do all output from */
 | 
						|
 | 
						|
	if (!*refreshop) {
 | 
						|
	    if ((t0 = strlen(vp)))
 | 
						|
		zwrite(vp, t0, 1, shout);
 | 
						|
	    vcs += t0;
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
	if (!*vp) {
 | 
						|
	    if (tccan(TCCLEAREOL))
 | 
						|
		tcout(TCCLEAREOL);
 | 
						|
	    else
 | 
						|
		for (; *refreshop++; vcs++)
 | 
						|
		    zputc(' ', shout);
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
	zputc(*vp, shout);
 | 
						|
	vcs++, t0++;
 | 
						|
	vp++, refreshop++;
 | 
						|
    }
 | 
						|
/* move to the new cursor position */
 | 
						|
    singmoveto(nvcs);
 | 
						|
 | 
						|
    qbuf = nbuf;
 | 
						|
    nbuf = obuf;
 | 
						|
    obuf = qbuf;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
singmoveto(int pos)
 | 
						|
{
 | 
						|
    if (pos == vcs)
 | 
						|
	return;
 | 
						|
 | 
						|
/* choose cheapest movements for ttys without multiple movement capabilities -
 | 
						|
   do this now because it's easier (to code) */
 | 
						|
 | 
						|
    if ((!tccan(TCMULTLEFT) || pos == 0) && (pos <= vcs / 2)) {
 | 
						|
	zputc('\r', shout);
 | 
						|
	vcs = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (pos < vcs)
 | 
						|
	tc_leftcurs(vcs - pos);
 | 
						|
    else if (pos > vcs)
 | 
						|
	tc_rightcurs(pos - vcs);
 | 
						|
 | 
						|
    vcs = pos;
 | 
						|
}
 |