mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-11-04 07:21:06 +01:00 
			
		
		
		
	For read -k and read -q where we use ZLE, we just want a single key and not full ZLE processing. So don't handle timed ZLE functions when preforming the read.
		
			
				
	
	
		
			1804 lines
		
	
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1804 lines
		
	
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * zle_misc.c - miscellaneous editor routines
 | 
						|
 *
 | 
						|
 * 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_misc.pro"
 | 
						|
 | 
						|
/* insert a zle string, with repetition and suffix removal */
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
doinsert(ZLE_STRING_T zstr, int len)
 | 
						|
{
 | 
						|
    ZLE_STRING_T s;
 | 
						|
    ZLE_CHAR_T c1 = *zstr;	     /* first character */
 | 
						|
    int neg = zmult < 0;             /* insert *after* the cursor? */
 | 
						|
    int m = neg ? -zmult : zmult;    /* number of copies to insert */
 | 
						|
    int count;
 | 
						|
 | 
						|
    UNMETACHECK();
 | 
						|
 | 
						|
    iremovesuffix(c1, 0);
 | 
						|
    invalidatelist();
 | 
						|
 | 
						|
    /* In overwrite mode, don't replace newlines. */
 | 
						|
    if (insmode || zleline[zlecs] == ZWC('\n'))
 | 
						|
	spaceinline(m * len);
 | 
						|
    else
 | 
						|
    {
 | 
						|
	int pos = zlecs, diff, i;
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
	/*
 | 
						|
	 * Calculate the number of character positions we are
 | 
						|
	 * going to be using.  The algorithm is that
 | 
						|
	 * anything that shows up as a logical single character
 | 
						|
	 * (i.e. even if control, or double width, or with combining
 | 
						|
	 * characters) is treated as 1 for the purpose of replacing
 | 
						|
	 * what's there already.
 | 
						|
	 *
 | 
						|
	 * This can cause inserting of a combining character in
 | 
						|
	 * places where it should overwrite, such as the start
 | 
						|
	 * of a line.  However, combining characters aren't
 | 
						|
	 * useful there anyway and this doesn't cause any
 | 
						|
	 * particular harm.
 | 
						|
	 */
 | 
						|
	for (i = 0, count = 0; i < len * m; i++) {
 | 
						|
	    if (!IS_COMBINING(zstr[i]))
 | 
						|
		count++;
 | 
						|
	}
 | 
						|
#else
 | 
						|
	count = len * m;
 | 
						|
#endif
 | 
						|
	/*
 | 
						|
	 * Ensure we replace a complete combining characterfor each
 | 
						|
	 * character we overwrite. Switch to inserting at first newline.
 | 
						|
	 */
 | 
						|
	for (i = count; pos < zlell && zleline[pos] != ZWC('\n') && i--; ) {
 | 
						|
	    INCPOS(pos);
 | 
						|
	}
 | 
						|
	/*
 | 
						|
	 * Calculate how many raw line places we need.
 | 
						|
	 * pos - zlecs is the raw line distance we're replacing,
 | 
						|
	 * m * len the number we're inserting.
 | 
						|
	 */
 | 
						|
	diff = pos - zlecs - m * len;
 | 
						|
	if (diff < 0) {
 | 
						|
	    spaceinline(-diff);
 | 
						|
	} else if (diff > 0) {
 | 
						|
	    /*
 | 
						|
	     * We use shiftchars() here because we don't
 | 
						|
	     * want combining char alignment fixed up: we
 | 
						|
	     * are going to write over any that remain.
 | 
						|
	     */
 | 
						|
	    shiftchars(zlecs, diff);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    while (m--)
 | 
						|
	for (s = zstr, count = len; count; s++, count--)
 | 
						|
	    zleline[zlecs++] = *s;
 | 
						|
    if (neg)
 | 
						|
	zlecs += zmult * len;
 | 
						|
    /* if we ended up on a combining character, skip over it */
 | 
						|
    CCRIGHT();
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int
 | 
						|
selfinsert(UNUSED(char **args))
 | 
						|
{
 | 
						|
    ZLE_CHAR_T tmp;
 | 
						|
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
    /* may be redundant with getkeymapcmd(), but other widgets call here too */
 | 
						|
    if (!lastchar_wide_valid)
 | 
						|
	if (getrestchar(lastchar, NULL, NULL) == WEOF)
 | 
						|
	    return 1;
 | 
						|
#endif
 | 
						|
    tmp = LASTFULLCHAR;
 | 
						|
    doinsert(&tmp, 1);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
fixunmeta(void)
 | 
						|
{
 | 
						|
    lastchar &= 0x7f;
 | 
						|
    if (lastchar == '\r')
 | 
						|
	lastchar = '\n';
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
    /*
 | 
						|
     * TODO: can we do this better?
 | 
						|
     * We need a wide character to insert.
 | 
						|
     * selfinsertunmeta is intrinsically problematic
 | 
						|
     * with multibyte input.
 | 
						|
     */
 | 
						|
    lastchar_wide = (ZLE_INT_T)lastchar;
 | 
						|
    lastchar_wide_valid = 1;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export int
 | 
						|
selfinsertunmeta(char **args)
 | 
						|
{
 | 
						|
    fixunmeta();
 | 
						|
    return selfinsert(args);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
deletechar(char **args)
 | 
						|
{
 | 
						|
    int n;
 | 
						|
    if (zmult < 0) {
 | 
						|
	int ret;
 | 
						|
	zmult = -zmult;
 | 
						|
	ret = backwarddeletechar(args);
 | 
						|
	zmult = -zmult;
 | 
						|
	return ret;
 | 
						|
    }
 | 
						|
 | 
						|
    n = zmult;
 | 
						|
    while (n--) {
 | 
						|
	if (zlecs == zlell)
 | 
						|
	    return 1;
 | 
						|
	INCCS();
 | 
						|
    }
 | 
						|
    backdel(zmult, 0);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
backwarddeletechar(char **args)
 | 
						|
{
 | 
						|
    if (zmult < 0) {
 | 
						|
	int ret;
 | 
						|
	zmult = -zmult;
 | 
						|
	ret = deletechar(args);
 | 
						|
	zmult = -zmult;
 | 
						|
	return ret;
 | 
						|
    }
 | 
						|
    backdel(zmult > zlecs ? zlecs : zmult, 0);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
killwholeline(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int i, fg, n = zmult;
 | 
						|
 | 
						|
    if (n < 0)
 | 
						|
	return 1;
 | 
						|
    while (n--) {
 | 
						|
	if ((fg = (zlecs && zlecs == zlell)))
 | 
						|
	    zlecs--;
 | 
						|
	while (zlecs && zleline[zlecs - 1] != '\n')
 | 
						|
	    zlecs--;
 | 
						|
	for (i = zlecs; i != zlell && zleline[i] != '\n'; i++);
 | 
						|
	forekill(i - zlecs + (i != zlell), fg ? (CUT_FRONT|CUT_RAW) : CUT_RAW);
 | 
						|
    }
 | 
						|
    clearlist = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
killbuffer(UNUSED(char **args))
 | 
						|
{
 | 
						|
    zlecs = 0;
 | 
						|
    forekill(zlell, CUT_RAW);
 | 
						|
    clearlist = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
backwardkillline(char **args)
 | 
						|
{
 | 
						|
    int i = 0, n = zmult;
 | 
						|
 | 
						|
    if (n < 0) {
 | 
						|
	int ret;
 | 
						|
	zmult = -n;
 | 
						|
	ret = killline(args);
 | 
						|
	zmult = n;
 | 
						|
	return ret;
 | 
						|
    }
 | 
						|
    while (n--) {
 | 
						|
	if (zlecs && zleline[zlecs - 1] == '\n')
 | 
						|
	    zlecs--, i++;
 | 
						|
	else
 | 
						|
	    while (zlecs && zleline[zlecs - 1] != '\n')
 | 
						|
		zlecs--, i++;
 | 
						|
    }
 | 
						|
    forekill(i, CUT_FRONT|CUT_RAW);
 | 
						|
    clearlist = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
/*
 | 
						|
 * Transpose the chunk of the line from start to middle with
 | 
						|
 * that from middle to end.
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
transpose_swap(int start, int middle, int end)
 | 
						|
{
 | 
						|
    int len1, len2;
 | 
						|
    ZLE_STRING_T first;
 | 
						|
 | 
						|
    len1 = middle - start;
 | 
						|
    len2 = end - middle;
 | 
						|
 | 
						|
    first = (ZLE_STRING_T)zalloc(len1 * ZLE_CHAR_SIZE);
 | 
						|
    ZS_memcpy(first, zleline + start, len1);
 | 
						|
    /* Move may be overlapping... */
 | 
						|
    ZS_memmove(zleline + start, zleline + middle, len2);
 | 
						|
    ZS_memcpy(zleline + start + len2, first, len1);
 | 
						|
    zfree(first, len1 * ZLE_CHAR_SIZE);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
gosmacstransposechars(UNUSED(char **args))
 | 
						|
{
 | 
						|
    if (zlecs < 2 || zleline[zlecs - 1] == '\n' || zleline[zlecs - 2] == '\n') {
 | 
						|
	int twice = (zlecs == 0 || zleline[zlecs - 1] == '\n');
 | 
						|
 | 
						|
	if (zlecs == zlell || zleline[zlecs] == '\n')
 | 
						|
	    return 1;
 | 
						|
 | 
						|
	INCCS();
 | 
						|
	if (twice) {
 | 
						|
	    if (zlecs == zlell || zleline[zlecs] == '\n')
 | 
						|
		return 1;
 | 
						|
	    INCCS();
 | 
						|
	}
 | 
						|
    }
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
    {
 | 
						|
	int start, middle;
 | 
						|
 | 
						|
	middle = zlecs;
 | 
						|
	DECPOS(middle);
 | 
						|
 | 
						|
	start = middle;
 | 
						|
	DECPOS(start);
 | 
						|
 | 
						|
	transpose_swap(start, middle, zlecs);
 | 
						|
    }
 | 
						|
#else
 | 
						|
    {
 | 
						|
	ZLE_CHAR_T cc = zleline[zlecs - 2];
 | 
						|
	zleline[zlecs - 2] = zleline[zlecs - 1];
 | 
						|
	zleline[zlecs - 1] = cc;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
transposechars(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int ct;
 | 
						|
    int n = zmult;
 | 
						|
    int neg = n < 0;
 | 
						|
 | 
						|
    if (neg)
 | 
						|
	n = -n;
 | 
						|
    while (n--) {
 | 
						|
	if (!(ct = zlecs) || zleline[zlecs - 1] == '\n') {
 | 
						|
	    if (zlell == zlecs || zleline[zlecs] == '\n')
 | 
						|
		return 1;
 | 
						|
	    if (!neg)
 | 
						|
		INCCS();
 | 
						|
	    INCPOS(ct);
 | 
						|
	}
 | 
						|
	if (neg) {
 | 
						|
	    if (zlecs && zleline[zlecs - 1] != '\n') {
 | 
						|
		DECCS();
 | 
						|
		if (ct > 1 && zleline[ct - 2] != '\n') {
 | 
						|
		    DECPOS(ct);
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	} else {
 | 
						|
	    if (zlecs != zlell && zleline[zlecs] != '\n')
 | 
						|
		INCCS();
 | 
						|
	}
 | 
						|
	if (ct == zlell || zleline[ct] == '\n') {
 | 
						|
	    DECPOS(ct);
 | 
						|
	}
 | 
						|
	if (ct < 1 || zleline[ct - 1] == '\n')
 | 
						|
	    return 1;
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
	{
 | 
						|
	    /*
 | 
						|
	     * We should keep any accents etc. on their original characters.
 | 
						|
	     */
 | 
						|
	    int start = ct, end = ct;
 | 
						|
	    DECPOS(start);
 | 
						|
	    INCPOS(end);
 | 
						|
 | 
						|
	    transpose_swap(start, ct, end);
 | 
						|
	}
 | 
						|
#else
 | 
						|
	{
 | 
						|
	    ZLE_CHAR_T cc = zleline[ct - 1];
 | 
						|
	    zleline[ct - 1] = zleline[ct];
 | 
						|
	    zleline[ct] = cc;
 | 
						|
	}
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
poundinsert(UNUSED(char **args))
 | 
						|
{
 | 
						|
    zlecs = 0;
 | 
						|
    vifirstnonblank(zlenoargs);
 | 
						|
    if (zleline[zlecs] != '#') {
 | 
						|
	spaceinline(1);
 | 
						|
	zleline[zlecs] = '#';
 | 
						|
	zlecs = findeol();
 | 
						|
	while(zlecs != zlell) {
 | 
						|
	    zlecs++;
 | 
						|
	    vifirstnonblank(zlenoargs);
 | 
						|
	    spaceinline(1);
 | 
						|
	    zleline[zlecs] = '#';
 | 
						|
	    zlecs = findeol();
 | 
						|
	}
 | 
						|
    } else {
 | 
						|
	foredel(1, 0);
 | 
						|
	zlecs = findeol();
 | 
						|
	while(zlecs != zlell) {
 | 
						|
	    zlecs++;
 | 
						|
	    vifirstnonblank(zlenoargs);
 | 
						|
	    if(zleline[zlecs] == '#')
 | 
						|
		foredel(1, 0);
 | 
						|
	    zlecs = findeol();
 | 
						|
	}
 | 
						|
    }
 | 
						|
    done = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
acceptline(UNUSED(char **args))
 | 
						|
{
 | 
						|
    done = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
acceptandhold(UNUSED(char **args))
 | 
						|
{
 | 
						|
    zpushnode(bufstack, zlelineasstring(zleline, zlell, 0, NULL, NULL, 0));
 | 
						|
    stackcs = zlecs;
 | 
						|
    done = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
killline(char **args)
 | 
						|
{
 | 
						|
    int i = 0, n = zmult;
 | 
						|
 | 
						|
    if (n < 0) {
 | 
						|
	int ret;
 | 
						|
	zmult = -n;
 | 
						|
	ret = backwardkillline(args);
 | 
						|
	zmult = n;
 | 
						|
	return ret;
 | 
						|
    }
 | 
						|
    while (n--) {
 | 
						|
	if (zleline[zlecs] == ZWC('\n'))
 | 
						|
	    zlecs++, i++;
 | 
						|
	else
 | 
						|
	    while (zlecs != zlell && zleline[zlecs] != ZWC('\n'))
 | 
						|
		zlecs++, i++;
 | 
						|
    }
 | 
						|
    backkill(i, CUT_RAW);
 | 
						|
    clearlist = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
void
 | 
						|
regionlines(int *start, int *end)
 | 
						|
{
 | 
						|
    int origcs = zlecs;
 | 
						|
 | 
						|
    UNMETACHECK();
 | 
						|
    if (zlecs < mark) {
 | 
						|
	*start = findbol();
 | 
						|
        zlecs = (mark > zlell) ? zlell : mark;
 | 
						|
	*end = findeol();
 | 
						|
    } else {
 | 
						|
	*end = findeol();
 | 
						|
        zlecs = mark;
 | 
						|
	*start = findbol();
 | 
						|
    }
 | 
						|
    zlecs = origcs;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
killregion(UNUSED(char **args))
 | 
						|
{
 | 
						|
    if (mark > zlell)
 | 
						|
	mark = zlell;
 | 
						|
    if (region_active == 2) {
 | 
						|
	int a, b;
 | 
						|
	regionlines(&a, &b);
 | 
						|
	zlecs = a;
 | 
						|
	region_active = 0;
 | 
						|
	cut(zlecs, b - zlecs, CUT_RAW);
 | 
						|
	shiftchars(zlecs, b - zlecs);
 | 
						|
	if (zlell) {
 | 
						|
	    if (zlecs == zlell)
 | 
						|
		DECCS();
 | 
						|
	    foredel(1, 0);
 | 
						|
	    vifirstnonblank(zlenoargs);
 | 
						|
	}
 | 
						|
    } else if (mark > zlecs) {
 | 
						|
	if (invicmdmode())
 | 
						|
	    INCPOS(mark);
 | 
						|
	forekill(mark - zlecs, CUT_RAW);
 | 
						|
    } else {
 | 
						|
	if (invicmdmode())
 | 
						|
	    INCCS();
 | 
						|
	backkill(zlecs - mark, CUT_FRONT|CUT_RAW);
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
copyregionaskill(char **args)
 | 
						|
{
 | 
						|
    int start, end;
 | 
						|
    if (*args) {
 | 
						|
        int len;
 | 
						|
        ZLE_STRING_T line = stringaszleline(*args, 0, &len, NULL, NULL);
 | 
						|
	cuttext(line, len, CUT_REPLACE);
 | 
						|
	free(line);
 | 
						|
    } else {
 | 
						|
	if (mark > zlell)
 | 
						|
	    mark = zlell;
 | 
						|
	if (mark > zlecs) {
 | 
						|
	    start = zlecs;
 | 
						|
	    end = mark;
 | 
						|
	} else {
 | 
						|
	    start = mark;
 | 
						|
	    end = zlecs;
 | 
						|
	}
 | 
						|
	if (invicmdmode())
 | 
						|
	    INCPOS(end);
 | 
						|
	cut(start, end - start, mark > zlecs ? 0 : CUT_FRONT);
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * kct: index into kill ring, or -1 for original cutbuffer of yank.
 | 
						|
 * yankcs marks the cursor position preceding the last yank
 | 
						|
 */
 | 
						|
static int kct, yankcs;
 | 
						|
 | 
						|
/**/
 | 
						|
int yankb, yanke; /* mark the start and end of last yank in editing buffer. */
 | 
						|
 | 
						|
/* The original cutbuffer, either cutbuf or one of the vi buffers. */
 | 
						|
static Cutbuffer kctbuf;
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
yank(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int n = zmult;
 | 
						|
 | 
						|
    if (n < 0)
 | 
						|
	return 1;
 | 
						|
    if (zmod.flags & MOD_VIBUF)
 | 
						|
	kctbuf = &vibuf[zmod.vibuf];
 | 
						|
    else
 | 
						|
	kctbuf = &cutbuf;
 | 
						|
    if (!kctbuf->buf)
 | 
						|
	return 1;
 | 
						|
    yankb = yankcs = mark = zlecs;
 | 
						|
    while (n--) {
 | 
						|
	kct = -1;
 | 
						|
	spaceinline(kctbuf->len);
 | 
						|
	ZS_memcpy(zleline + zlecs, kctbuf->buf, kctbuf->len);
 | 
						|
	zlecs += kctbuf->len;
 | 
						|
	yanke = zlecs;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* position: 0 is before, 1 after, 2 split the line */
 | 
						|
static void pastebuf(Cutbuffer buf, int mult, int position)
 | 
						|
{
 | 
						|
    int cc;
 | 
						|
    if (buf->flags & CUTBUFFER_LINE) {
 | 
						|
	if (position == 2) {
 | 
						|
	    if (!zlecs)
 | 
						|
		position = 0;
 | 
						|
	    else if (zlecs == zlell)
 | 
						|
		position = 1;
 | 
						|
	}
 | 
						|
	if (position == 2) {
 | 
						|
	    yankb = zlecs;
 | 
						|
	    spaceinline(buf->len + 2);
 | 
						|
	    zleline[zlecs++] = ZWC('\n');
 | 
						|
	    ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
 | 
						|
	    zlecs += buf->len;
 | 
						|
	    zleline[zlecs] = ZWC('\n');
 | 
						|
	    yanke = zlecs + 1;
 | 
						|
	} else if (position != 0) {
 | 
						|
	    yankb = zlecs = findeol();
 | 
						|
	    spaceinline(buf->len + 1);
 | 
						|
	    zleline[zlecs++] = ZWC('\n');
 | 
						|
	    yanke = zlecs + buf->len;
 | 
						|
	    ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
 | 
						|
	} else {
 | 
						|
	    yankb = zlecs = findbol();
 | 
						|
	    spaceinline(buf->len + 1);
 | 
						|
	    ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
 | 
						|
	    yanke = zlecs + buf->len + 1;
 | 
						|
	    zleline[zlecs + buf->len] = ZWC('\n');
 | 
						|
	}
 | 
						|
	vifirstnonblank(zlenoargs);
 | 
						|
    } else {
 | 
						|
	if (position == 1 && zlecs != findeol())
 | 
						|
	    INCCS();
 | 
						|
	yankb = zlecs;
 | 
						|
	cc = buf->len;
 | 
						|
	while (mult--) {
 | 
						|
	    spaceinline(cc);
 | 
						|
	    ZS_memcpy(zleline + zlecs, buf->buf, cc);
 | 
						|
	    zlecs += cc;
 | 
						|
	}
 | 
						|
	yanke = zlecs;
 | 
						|
	if (zlecs && invicmdmode())
 | 
						|
	    DECCS();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
viputbefore(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int n = zmult;
 | 
						|
 | 
						|
    startvichange(-1);
 | 
						|
    if (n < 0)
 | 
						|
	return 1;
 | 
						|
    if (zmod.flags & MOD_NULL)
 | 
						|
	return 0;
 | 
						|
    if (zmod.flags & MOD_VIBUF)
 | 
						|
	kctbuf = &vibuf[zmod.vibuf];
 | 
						|
    else
 | 
						|
	kctbuf = &cutbuf;
 | 
						|
    if (!kctbuf->buf)
 | 
						|
	return 1;
 | 
						|
    kct = -1;
 | 
						|
    yankcs = zlecs;
 | 
						|
    pastebuf(kctbuf, n, 0);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
viputafter(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int n = zmult;
 | 
						|
 | 
						|
    startvichange(-1);
 | 
						|
    if (n < 0)
 | 
						|
	return 1;
 | 
						|
    if (zmod.flags & MOD_NULL)
 | 
						|
	return 0;
 | 
						|
    if (zmod.flags & MOD_VIBUF)
 | 
						|
	kctbuf = &vibuf[zmod.vibuf];
 | 
						|
    else
 | 
						|
	kctbuf = &cutbuf;
 | 
						|
    if (!kctbuf->buf)
 | 
						|
	return 1;
 | 
						|
    kct = -1;
 | 
						|
    yankcs = zlecs;
 | 
						|
    pastebuf(kctbuf, n, 1);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
putreplaceselection(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int n = zmult;
 | 
						|
    struct cutbuffer prevbuf;
 | 
						|
    Cutbuffer putbuf;
 | 
						|
    int clear = 0;
 | 
						|
    int pos = 2;
 | 
						|
 | 
						|
    startvichange(-1);
 | 
						|
    if (n < 0 || zmod.flags & MOD_NULL)
 | 
						|
	return 1;
 | 
						|
    putbuf = (zmod.flags & MOD_VIBUF) ? &vibuf[zmod.vibuf] : &cutbuf;
 | 
						|
    if (!putbuf->buf)
 | 
						|
	return 1;
 | 
						|
    memcpy(&prevbuf, putbuf, sizeof(prevbuf));
 | 
						|
 | 
						|
    /* if "9 was specified, prevent killregion from freeing it */
 | 
						|
    if (zmod.vibuf == 35) {
 | 
						|
	putbuf->buf = 0;
 | 
						|
	clear = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    zmod.flags = 0; /* flags apply to paste not kill */
 | 
						|
    if (region_active == 2 && prevbuf.flags & CUTBUFFER_LINE) {
 | 
						|
	int a, b;
 | 
						|
	regionlines(&a, &b);
 | 
						|
	pos = (b == zlell);
 | 
						|
    }
 | 
						|
    killregion(zlenoargs);
 | 
						|
 | 
						|
    pastebuf(&prevbuf, n, pos);
 | 
						|
    if (clear)
 | 
						|
	free(prevbuf.buf);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
yankpop(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int kctstart = kct;
 | 
						|
    Cutbuffer buf;
 | 
						|
 | 
						|
    if (!(lastcmd & ZLE_YANK) || !kring || !kctbuf) {
 | 
						|
	kctbuf = NULL;
 | 
						|
	return 1;
 | 
						|
    }
 | 
						|
    do {
 | 
						|
	/*
 | 
						|
	 * This is supposed to make the yankpop loop
 | 
						|
	 *   original buffer -> kill ring in order -> original buffer -> ...
 | 
						|
	 * where the original buffer is -1 and the remainder are
 | 
						|
	 * indices into the kill ring, remember that we need to start
 | 
						|
	 * that at kringnum rather than zero.
 | 
						|
	 */
 | 
						|
	if (kct == -1)
 | 
						|
	    kct = kringnum;
 | 
						|
	else {
 | 
						|
	    int kctnew = (kct + kringsize - 1) % kringsize;
 | 
						|
	    if (kctnew == kringnum)
 | 
						|
		kct = -1;
 | 
						|
	    else
 | 
						|
		kct = kctnew;
 | 
						|
	}
 | 
						|
	if (kct == -1)
 | 
						|
	    buf = kctbuf;	/* Use original cutbuffer */
 | 
						|
	else
 | 
						|
	    buf = kring+kct;	/* Use somewhere in the kill ring */
 | 
						|
	/* Careful to prevent infinite looping */
 | 
						|
	if (kct == kctstart)
 | 
						|
	    return 1;
 | 
						|
	/*
 | 
						|
	 * Skip unset buffers instead of stopping as we used to do.
 | 
						|
	 * Also skip zero-length buffers.
 | 
						|
	 * There are two reasons for this:
 | 
						|
	 * 1. We now map the array $killring directly into the
 | 
						|
	 *    killring, instead of via some extra size-checking logic.
 | 
						|
	 *    When $killring has been set, a buffer will always have
 | 
						|
	 *    at least a zero-length string in it.
 | 
						|
	 * 2. The old logic was inconsistent; when the kill ring
 | 
						|
	 *    was full, we could loop round and round it, otherwise
 | 
						|
	 *    we just stopped when we hit the first empty buffer.
 | 
						|
	 */
 | 
						|
    } while (!buf->buf || *buf->buf == ZWC('\0'));
 | 
						|
 | 
						|
    zlecs = yankb;
 | 
						|
    foredel(yanke - yankb, CUT_RAW);
 | 
						|
    zlecs = yankcs;
 | 
						|
    pastebuf(buf, 1, !!(lastcmd & ZLE_YANKAFTER));
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export char *
 | 
						|
bracketedstring(void)
 | 
						|
{
 | 
						|
    static const char endesc[] = "\033[201~";
 | 
						|
    int endpos = 0;
 | 
						|
    size_t psize = 64;
 | 
						|
    char *pbuf = zalloc(psize);
 | 
						|
    size_t current = 0;
 | 
						|
    int next, timeout;
 | 
						|
 | 
						|
    while (endesc[endpos]) {
 | 
						|
	if (current + 1 >= psize)
 | 
						|
	    pbuf = zrealloc(pbuf, psize *= 2);
 | 
						|
	if ((next = getbyte(1L, &timeout, 1)) == EOF)
 | 
						|
	    break;
 | 
						|
	if (!endpos || next != endesc[endpos++])
 | 
						|
	    endpos = (next == *endesc);
 | 
						|
	if (imeta(next)) {
 | 
						|
	    pbuf[current++] = Meta;
 | 
						|
	    pbuf[current++] = next ^ 32;
 | 
						|
	} else if (next == '\r')
 | 
						|
	    pbuf[current++] = '\n';
 | 
						|
	else
 | 
						|
	    pbuf[current++] = next;
 | 
						|
    }
 | 
						|
    pbuf[current-endpos] = '\0';
 | 
						|
    return pbuf;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
bracketedpaste(char **args)
 | 
						|
{
 | 
						|
    char *pbuf = bracketedstring();
 | 
						|
 | 
						|
    if (*args) {
 | 
						|
	setsparam(*args, pbuf);
 | 
						|
    } else {
 | 
						|
	int n;
 | 
						|
	ZLE_STRING_T wpaste;
 | 
						|
	wpaste = stringaszleline((zmult == 1) ? pbuf :
 | 
						|
	    quotestring(pbuf, QT_SINGLE_OPTIONAL), 0, &n, NULL, NULL);
 | 
						|
	cuttext(wpaste, n, CUT_REPLACE);
 | 
						|
	if (!(zmod.flags & MOD_VIBUF)) {
 | 
						|
	    kct = -1;
 | 
						|
	    kctbuf = &cutbuf;
 | 
						|
	    zmult = 1;
 | 
						|
	    if (region_active)
 | 
						|
		killregion(zlenoargs);
 | 
						|
	    yankcs = yankb = zlecs;
 | 
						|
	    doinsert(wpaste, n);
 | 
						|
	    yanke = zlecs;
 | 
						|
	}
 | 
						|
	free(pbuf); free(wpaste);
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
overwritemode(UNUSED(char **args))
 | 
						|
{
 | 
						|
    insmode ^= 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
whatcursorposition(UNUSED(char **args))
 | 
						|
{
 | 
						|
    char msg[100];
 | 
						|
    char *s = msg, *mbstr;
 | 
						|
    int bol = findbol(), len;
 | 
						|
    ZLE_CHAR_T c = zleline[zlecs];
 | 
						|
 | 
						|
    if (zlecs == zlell)
 | 
						|
	strucpy(&s, "EOF");
 | 
						|
    else {
 | 
						|
	strucpy(&s, "Char: ");
 | 
						|
	switch (c) {
 | 
						|
	case ZWC(' '):
 | 
						|
	    strucpy(&s, "SPC");
 | 
						|
	    break;
 | 
						|
	case ZWC('\t'):
 | 
						|
	    strucpy(&s, "TAB");
 | 
						|
	    break;
 | 
						|
	case ZWC('\n'):
 | 
						|
	    strucpy(&s, "LFD");
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    /*
 | 
						|
	     * convert a single character, remembering it may
 | 
						|
	     * turn into a multibyte string or be metafied.
 | 
						|
	     */
 | 
						|
	    mbstr = zlelineasstring(zleline+zlecs, 1, 0, &len, NULL, 1);
 | 
						|
	    strcpy(s, mbstr);
 | 
						|
	    s += len;
 | 
						|
	}
 | 
						|
	sprintf(s, " (0%o, %u, 0x%x)", (unsigned int)c,
 | 
						|
		(unsigned int)c, (unsigned int)c);
 | 
						|
	s += strlen(s);
 | 
						|
    }
 | 
						|
    sprintf(s, "  point %d of %d(%d%%)  column %d", zlecs+1, zlell+1,
 | 
						|
	    zlell ? 100 * zlecs / zlell : 0, zlecs - bol);
 | 
						|
    showmsg(msg);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
undefinedkey(UNUSED(char **args))
 | 
						|
{
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
quotedinsert(char **args)
 | 
						|
{
 | 
						|
#ifndef HAS_TIO
 | 
						|
    struct sgttyb sob;
 | 
						|
 | 
						|
    sob = shttyinfo.sgttyb;
 | 
						|
    sob.sg_flags = (sob.sg_flags | RAW) & ~ECHO;
 | 
						|
    ioctl(SHTTY, TIOCSETN, &sob);
 | 
						|
#endif
 | 
						|
    getfullchar(0);
 | 
						|
#ifndef HAS_TIO
 | 
						|
    zsetterm();
 | 
						|
#endif
 | 
						|
    if (LASTFULLCHAR == ZLEEOF)
 | 
						|
	return 1;
 | 
						|
    else
 | 
						|
	return selfinsert(args);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
parsedigit(int inkey)
 | 
						|
{
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
    /*
 | 
						|
     * It's too dangerous to allow metafied input.  See
 | 
						|
     * universalargument for comments on (possibly suboptimal) handling
 | 
						|
     * of digits.  We are assuming ASCII is a subset of the multibyte
 | 
						|
     * encoding.
 | 
						|
     */
 | 
						|
#else
 | 
						|
    /* allow metafied as well as ordinary digits */
 | 
						|
    inkey &= 0x7f;
 | 
						|
#endif
 | 
						|
 | 
						|
    /* remember inkey is not a wide character */
 | 
						|
    if (zmod.base > 10) {
 | 
						|
	if (inkey >= 'a' && inkey < 'a' + zmod.base - 10)
 | 
						|
	    return inkey - 'a' + 10;
 | 
						|
	if (inkey >= 'A' && inkey < 'A' + zmod.base - 10)
 | 
						|
	    return inkey - 'A' + 10;
 | 
						|
	if (idigit(inkey))
 | 
						|
	    return inkey - '0';
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
    if (inkey >= '0' && inkey < '0' + zmod.base)
 | 
						|
	return inkey - '0';
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
digitargument(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int sign = (zmult < 0) ? -1 : 1;
 | 
						|
    int newdigit = parsedigit(lastchar);
 | 
						|
 | 
						|
    if (newdigit < 0)
 | 
						|
	return 1;
 | 
						|
 | 
						|
    if (!(zmod.flags & MOD_TMULT))
 | 
						|
	zmod.tmult = 0;
 | 
						|
    if (zmod.flags & MOD_NEG) {
 | 
						|
	/* If we just had a negative argument, this is the digit, *
 | 
						|
	 * rather than the -1 assumed by negargument()            */
 | 
						|
	zmod.tmult = sign * newdigit;
 | 
						|
	zmod.flags &= ~MOD_NEG;
 | 
						|
    } else
 | 
						|
	zmod.tmult = zmod.tmult * zmod.base + sign * newdigit;
 | 
						|
    zmod.flags |= MOD_TMULT;
 | 
						|
    prefixflag = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
negargument(UNUSED(char **args))
 | 
						|
{
 | 
						|
    if (zmod.flags & MOD_TMULT)
 | 
						|
	return 1;
 | 
						|
    zmod.tmult = -1;
 | 
						|
    zmod.flags |= MOD_TMULT|MOD_NEG;
 | 
						|
    prefixflag = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
universalargument(char **args)
 | 
						|
{
 | 
						|
    int digcnt = 0, pref = 0, minus = 1, gotk;
 | 
						|
    if (*args) {
 | 
						|
	zmod.mult = atoi(*args);
 | 
						|
	zmod.flags |= MOD_MULT;
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
    /*
 | 
						|
     * TODO: this is quite tricky to do when trying to maintain
 | 
						|
     * compatibility between the old input system and Unicode.
 | 
						|
     * We don't know what follows the digits, so if we try to
 | 
						|
     * read wide characters we may fail (e.g. we may come across an old
 | 
						|
     * \M-style binding).
 | 
						|
     *
 | 
						|
     * If we assume individual bytes are either explicitly ASCII or
 | 
						|
     * not (a la UTF-8), we get away with it; we can back up individual
 | 
						|
     * bytes and everything will work.  We may want to relax this
 | 
						|
     * assumption later.  ("Much later" - (C) Steven Singer,
 | 
						|
     * CSR BlueCore firmware, ca. 2000.)
 | 
						|
     *
 | 
						|
     * Hence for now this remains byte-by-byte.
 | 
						|
     */
 | 
						|
    while ((gotk = getbyte(0L, NULL, 1)) != EOF) {
 | 
						|
	if (gotk == '-' && !digcnt) {
 | 
						|
	    minus = -1;
 | 
						|
	    digcnt++;
 | 
						|
	} else {
 | 
						|
	    int newdigit = parsedigit(gotk);
 | 
						|
 | 
						|
	    if (newdigit >= 0) {
 | 
						|
		pref = pref * zmod.base + newdigit;
 | 
						|
		digcnt++;
 | 
						|
	    } else {
 | 
						|
		ungetbyte(gotk);
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (digcnt)
 | 
						|
	zmod.tmult = minus * (pref ? pref : 1);
 | 
						|
    else
 | 
						|
	zmod.tmult *= 4;
 | 
						|
    zmod.flags |= MOD_TMULT;
 | 
						|
    prefixflag = 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Set the base for a digit argument. */
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
argumentbase(char **args)
 | 
						|
{
 | 
						|
    int multbase;
 | 
						|
 | 
						|
    if (*args)
 | 
						|
	multbase = (int)zstrtol(*args, NULL, 0);
 | 
						|
    else
 | 
						|
	multbase = zmod.mult;
 | 
						|
 | 
						|
    if (multbase < 2 || multbase > ('9' - '0' + 1) + ('z' - 'a' + 1))
 | 
						|
	return 1;
 | 
						|
 | 
						|
    zmod.base = multbase;
 | 
						|
 | 
						|
    /* reset modifier, apart from base... */
 | 
						|
    zmod.flags = 0;
 | 
						|
    zmod.mult = 1;
 | 
						|
    zmod.tmult = 1;
 | 
						|
    zmod.vibuf = 0;
 | 
						|
 | 
						|
    /* ...but indicate we are still operating on a prefix argument. */
 | 
						|
    prefixflag = 1;
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
copyprevword(UNUSED(char **args))
 | 
						|
{
 | 
						|
    int len, t0 = zlecs, t1;
 | 
						|
 | 
						|
    if (zmult > 0) {
 | 
						|
	int count = zmult;
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
	    t1 = t0;
 | 
						|
 | 
						|
	    while (t0) {
 | 
						|
		int prev = t0;
 | 
						|
		DECPOS(prev);
 | 
						|
		if (ZC_iword(zleline[prev]))
 | 
						|
		    break;
 | 
						|
		t0 = prev;
 | 
						|
	    }
 | 
						|
	    while (t0) {
 | 
						|
		int prev = t0;
 | 
						|
		DECPOS(prev);
 | 
						|
		if (!ZC_iword(zleline[prev]))
 | 
						|
		    break;
 | 
						|
		t0 = prev;
 | 
						|
	    }
 | 
						|
 | 
						|
	    if (!--count)
 | 
						|
		break;
 | 
						|
	    if (t0 == 0)
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    else
 | 
						|
	return 1;
 | 
						|
    len = t1 - t0;
 | 
						|
    spaceinline(len);
 | 
						|
    ZS_memcpy(zleline + zlecs, zleline + t0, len);
 | 
						|
    zlecs += len;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
copyprevshellword(UNUSED(char **args))
 | 
						|
{
 | 
						|
    LinkList l;
 | 
						|
    LinkNode n;
 | 
						|
    int i;
 | 
						|
    char *p = NULL;
 | 
						|
 | 
						|
    if (zmult <= 0)
 | 
						|
	return 1;
 | 
						|
 | 
						|
    if ((l = bufferwords(NULL, NULL, &i, LEXFLAGS_ZLE))) {
 | 
						|
	i -= (zmult-1);
 | 
						|
	if (i < 0)
 | 
						|
	    return 1;
 | 
						|
        for (n = firstnode(l); n; incnode(n))
 | 
						|
            if (!i--) {
 | 
						|
                p = getdata(n);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
    }
 | 
						|
 | 
						|
    if (p) {
 | 
						|
	int len;
 | 
						|
	ZLE_STRING_T lineadd = stringaszleline(p, 0, &len, NULL, NULL);
 | 
						|
 | 
						|
	spaceinline(len);
 | 
						|
	ZS_memcpy(zleline + zlecs, lineadd, len);
 | 
						|
	zlecs += len;
 | 
						|
 | 
						|
	free(lineadd);
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
sendbreak(UNUSED(char **args))
 | 
						|
{
 | 
						|
    errflag |= ERRFLAG_ERROR|ERRFLAG_INT;
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
quoteregion(UNUSED(char **args))
 | 
						|
{
 | 
						|
    ZLE_STRING_T str;
 | 
						|
    size_t len;
 | 
						|
    int extra = invicmdmode();
 | 
						|
 | 
						|
    if (mark > zlell)
 | 
						|
	mark = zlell;
 | 
						|
    if (region_active == 2) {
 | 
						|
	int a, b;
 | 
						|
	regionlines(&a, &b);
 | 
						|
	zlecs = a;
 | 
						|
	mark = b;
 | 
						|
	extra = 0;
 | 
						|
    } else if (mark < zlecs) {
 | 
						|
	int tmp = mark;
 | 
						|
	mark = zlecs;
 | 
						|
	zlecs = tmp;
 | 
						|
    }
 | 
						|
    if (extra)
 | 
						|
	INCPOS(mark);
 | 
						|
    str = (ZLE_STRING_T)hcalloc((len = mark - zlecs) *
 | 
						|
	ZLE_CHAR_SIZE);
 | 
						|
    ZS_memcpy(str, zleline + zlecs, len);
 | 
						|
    foredel(len, CUT_RAW);
 | 
						|
    str = makequote(str, &len);
 | 
						|
    spaceinline(len);
 | 
						|
    ZS_memcpy(zleline + zlecs, str, len);
 | 
						|
    mark = zlecs;
 | 
						|
    zlecs += len;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
int
 | 
						|
quoteline(UNUSED(char **args))
 | 
						|
{
 | 
						|
    ZLE_STRING_T str;
 | 
						|
    size_t len = zlell;
 | 
						|
 | 
						|
    str = makequote(zleline, &len);
 | 
						|
    sizeline(len);
 | 
						|
    ZS_memcpy(zleline, str, len);
 | 
						|
    zlecs = zlell = len;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
static ZLE_STRING_T
 | 
						|
makequote(ZLE_STRING_T str, size_t *len)
 | 
						|
{
 | 
						|
    int qtct = 0;
 | 
						|
    ZLE_STRING_T l, ol;
 | 
						|
    ZLE_STRING_T end = str + *len;
 | 
						|
 | 
						|
    for (l = str; l < end; l++)
 | 
						|
	if (*l == ZWC('\''))
 | 
						|
	    qtct++;
 | 
						|
    *len += 2 + qtct*3;
 | 
						|
    l = ol = (ZLE_STRING_T)zhalloc(*len * ZLE_CHAR_SIZE);
 | 
						|
    *l++ = ZWC('\'');
 | 
						|
    for (; str < end; str++)
 | 
						|
	if (*str == ZWC('\'')) {
 | 
						|
	    *l++ = ZWC('\'');
 | 
						|
	    *l++ = ZWC('\\');
 | 
						|
	    *l++ = ZWC('\'');
 | 
						|
	    *l++ = ZWC('\'');
 | 
						|
	} else
 | 
						|
	    *l++ = *str;
 | 
						|
    *l++ = ZWC('\'');
 | 
						|
    return ol;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * cmdstr is the buffer used for execute-named-command converted
 | 
						|
 * to a metafied multibyte string.
 | 
						|
 */
 | 
						|
static char *namedcmdstr;
 | 
						|
static LinkList namedcmdll;
 | 
						|
static int namedcmdambig;
 | 
						|
 | 
						|
/**/
 | 
						|
static void
 | 
						|
scancompcmd(HashNode hn, UNUSED(int flags))
 | 
						|
{
 | 
						|
    int l;
 | 
						|
    Thingy t = (Thingy) hn;
 | 
						|
 | 
						|
    if(strpfx(namedcmdstr, t->nam)) {
 | 
						|
	addlinknode(namedcmdll, t->nam);
 | 
						|
	l = pfxlen(peekfirst(namedcmdll), t->nam);
 | 
						|
	if (l < namedcmdambig)
 | 
						|
	    namedcmdambig = l;
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#define NAMLEN 60
 | 
						|
 | 
						|
/*
 | 
						|
 * Local keymap used when reading a command name for the
 | 
						|
 * execute-named-command and where-is widgets.
 | 
						|
 */
 | 
						|
 | 
						|
/**/
 | 
						|
Keymap command_keymap;
 | 
						|
 | 
						|
/**/
 | 
						|
Thingy
 | 
						|
executenamedcommand(char *prmt)
 | 
						|
{
 | 
						|
    Thingy cmd, retval = NULL;
 | 
						|
    int l, len, feep = 0, listed = 0, curlist = 0;
 | 
						|
    int ols = (listshown && validlist), olll = lastlistlen;
 | 
						|
    char *cmdbuf, *ptr;
 | 
						|
    char *okeymap = ztrdup(curkeymapname);
 | 
						|
 | 
						|
    clearlist = 1;
 | 
						|
    /* prmt may be constant */
 | 
						|
    prmt = ztrdup(prmt);
 | 
						|
    l = strlen(prmt);
 | 
						|
    cmdbuf = (char *)zhalloc(l + NAMLEN + 2
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
			     + 2 * MB_CUR_MAX
 | 
						|
#endif
 | 
						|
			     );
 | 
						|
    strcpy(cmdbuf, prmt);
 | 
						|
    zsfree(prmt);
 | 
						|
    statusline = cmdbuf;
 | 
						|
    selectlocalmap(command_keymap);
 | 
						|
    selectkeymap("main", 1);
 | 
						|
    ptr = cmdbuf += l;
 | 
						|
    len = 0;
 | 
						|
    for (;;) {
 | 
						|
	*ptr = '_';
 | 
						|
	ptr[1] = '\0';
 | 
						|
	zrefresh();
 | 
						|
	if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
 | 
						|
	    statusline = NULL;
 | 
						|
	    selectkeymap(okeymap, 1);
 | 
						|
	    zsfree(okeymap);
 | 
						|
	    if ((listshown = ols)) {
 | 
						|
		showinglist = -2;
 | 
						|
		lastlistlen = olll;
 | 
						|
	    } else if (listed)
 | 
						|
		clearlist = listshown = 1;
 | 
						|
 | 
						|
	    retval = NULL;
 | 
						|
	    goto done;
 | 
						|
	}
 | 
						|
	if(cmd == Th(z_clearscreen)) {
 | 
						|
	    clearscreen(zlenoargs);
 | 
						|
	    if (curlist) {
 | 
						|
		int zmultsav = zmult;
 | 
						|
 | 
						|
		zmult = 1;
 | 
						|
		listlist(namedcmdll);
 | 
						|
		showinglist = 0;
 | 
						|
		zmult = zmultsav;
 | 
						|
	    }
 | 
						|
	} else if(cmd == Th(z_redisplay)) {
 | 
						|
	    redisplay(zlenoargs);
 | 
						|
	    if (curlist) {
 | 
						|
		int zmultsav = zmult;
 | 
						|
 | 
						|
		zmult = 1;
 | 
						|
		listlist(namedcmdll);
 | 
						|
		showinglist = 0;
 | 
						|
		zmult = zmultsav;
 | 
						|
	    }
 | 
						|
	} else if(cmd == Th(z_viquotedinsert)) {
 | 
						|
	    *ptr = '^';
 | 
						|
	    zrefresh();
 | 
						|
	    getfullchar(0);
 | 
						|
	    if(LASTFULLCHAR == ZLEEOF || !LASTFULLCHAR || len >= NAMLEN)
 | 
						|
		feep = 1;
 | 
						|
	    else {
 | 
						|
		int ret = zlecharasstring(LASTFULLCHAR, ptr);
 | 
						|
		len += ret;
 | 
						|
		ptr += ret;
 | 
						|
		curlist = 0;
 | 
						|
	    }
 | 
						|
	} else if(cmd == Th(z_quotedinsert)) {
 | 
						|
	    if(getfullchar(0) == ZLEEOF ||
 | 
						|
	       !LASTFULLCHAR || len == NAMLEN)
 | 
						|
		feep = 1;
 | 
						|
	    else {
 | 
						|
		int ret = zlecharasstring(LASTFULLCHAR, ptr);
 | 
						|
		len += ret;
 | 
						|
		ptr += ret;
 | 
						|
		curlist = 0;
 | 
						|
	    }
 | 
						|
	} else if(cmd == Th(z_backwarddeletechar) ||
 | 
						|
		  cmd == Th(z_vibackwarddeletechar)) {
 | 
						|
	    if (len) {
 | 
						|
		ptr = backwardmetafiedchar(cmdbuf, ptr, NULL);
 | 
						|
		len = ptr - cmdbuf;
 | 
						|
		curlist = 0;
 | 
						|
	    }
 | 
						|
	} else if(cmd == Th(z_killregion) || cmd == Th(z_backwardkillword) ||
 | 
						|
		  cmd == Th(z_vibackwardkillword)) {
 | 
						|
	    if (len)
 | 
						|
		curlist = 0;
 | 
						|
	    while (len) {
 | 
						|
		convchar_t cc;
 | 
						|
		ptr = backwardmetafiedchar(cmdbuf, ptr, &cc);
 | 
						|
		len = ptr - cmdbuf;
 | 
						|
		if (cc == ZWC('-'))
 | 
						|
		    break;
 | 
						|
	    }
 | 
						|
	} else if(cmd == Th(z_killwholeline) || cmd == Th(z_vikillline) ||
 | 
						|
	    	cmd == Th(z_backwardkillline)) {
 | 
						|
	    len = 0;
 | 
						|
	    ptr = cmdbuf;
 | 
						|
	    if (listed)
 | 
						|
		clearlist = listshown = 1;
 | 
						|
	    curlist = 0;
 | 
						|
	} else if (cmd == Th(z_bracketedpaste)) {
 | 
						|
	    char *insert = bracketedstring();
 | 
						|
	    size_t inslen = strlen(insert);
 | 
						|
	    if (len + inslen > NAMLEN)
 | 
						|
		feep = 1;
 | 
						|
	    else {
 | 
						|
		strcpy(ptr, insert);
 | 
						|
		len += inslen;
 | 
						|
		ptr += inslen;
 | 
						|
		if (listed) {
 | 
						|
		    clearlist = listshown = 1;
 | 
						|
		    listed = 0;
 | 
						|
		} else
 | 
						|
		    curlist = 0;
 | 
						|
	    }
 | 
						|
	    free(insert);
 | 
						|
	} else {
 | 
						|
	    if(cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) {
 | 
						|
		Thingy r;
 | 
						|
		unambiguous:
 | 
						|
		*ptr = 0;
 | 
						|
		r = rthingy(cmdbuf);
 | 
						|
		if (!(r->flags & DISABLED)) {
 | 
						|
		    unrefthingy(r);
 | 
						|
		    statusline = NULL;
 | 
						|
		    selectkeymap(okeymap, 1);
 | 
						|
		    zsfree(okeymap);
 | 
						|
		    if ((listshown = ols)) {
 | 
						|
			showinglist = -2;
 | 
						|
			lastlistlen = olll;
 | 
						|
		    } else if (listed)
 | 
						|
			clearlist = listshown = 1;
 | 
						|
 | 
						|
		    retval = r;
 | 
						|
		    goto done;
 | 
						|
		}
 | 
						|
		unrefthingy(r);
 | 
						|
	    }
 | 
						|
	    if(cmd == Th(z_selfinsertunmeta)) {
 | 
						|
		fixunmeta();
 | 
						|
		cmd = Th(z_selfinsert);
 | 
						|
	    }
 | 
						|
	    if (cmd == Th(z_listchoices) || cmd == Th(z_deletecharorlist) ||
 | 
						|
		cmd == Th(z_expandorcomplete) || cmd == Th(z_completeword) ||
 | 
						|
		cmd == Th(z_expandorcompleteprefix) || cmd == Th(z_vicmdmode) ||
 | 
						|
		cmd == Th(z_acceptline) || lastchar == ' ' || lastchar == '\t') {
 | 
						|
		namedcmdambig = 100;
 | 
						|
 | 
						|
		namedcmdll = newlinklist();
 | 
						|
 | 
						|
		*ptr = '\0';
 | 
						|
		namedcmdstr = cmdbuf;
 | 
						|
		scanhashtable(thingytab, 1, 0, DISABLED, scancompcmd, 0);
 | 
						|
		namedcmdstr = NULL;
 | 
						|
 | 
						|
		if (empty(namedcmdll)) {
 | 
						|
		    feep = 1;
 | 
						|
		    if (listed)
 | 
						|
			clearlist = listshown = 1;
 | 
						|
		    curlist = 0;
 | 
						|
		} else if (cmd == Th(z_listchoices) ||
 | 
						|
		    cmd == Th(z_deletecharorlist)) {
 | 
						|
		    int zmultsav = zmult;
 | 
						|
		    *ptr = '_';
 | 
						|
		    ptr[1] = '\0';
 | 
						|
		    zmult = 1;
 | 
						|
		    listlist(namedcmdll);
 | 
						|
		    listed = curlist = 1;
 | 
						|
		    showinglist = 0;
 | 
						|
		    zmult = zmultsav;
 | 
						|
		} else if (!nextnode(firstnode(namedcmdll))) {
 | 
						|
		    strcpy(ptr = cmdbuf, peekfirst(namedcmdll));
 | 
						|
		    len = strlen(ptr);
 | 
						|
		    ptr += len;
 | 
						|
		    if (cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode))
 | 
						|
			goto unambiguous;
 | 
						|
		} else {
 | 
						|
		    strcpy(cmdbuf, peekfirst(namedcmdll));
 | 
						|
		    ptr = cmdbuf + namedcmdambig;
 | 
						|
		    *ptr = '_';
 | 
						|
		    ptr[1] = '\0';
 | 
						|
		    if (isset(AUTOLIST) &&
 | 
						|
			!(isset(LISTAMBIGUOUS) && namedcmdambig > len)) {
 | 
						|
			int zmultsav = zmult;
 | 
						|
			if (isset(LISTBEEP))
 | 
						|
			    feep = 1;
 | 
						|
			zmult = 1;
 | 
						|
			listlist(namedcmdll);
 | 
						|
			listed = curlist = 1;
 | 
						|
			showinglist = 0;
 | 
						|
			zmult = zmultsav;
 | 
						|
		    }
 | 
						|
		    len = namedcmdambig;
 | 
						|
		}
 | 
						|
	    } else {
 | 
						|
		if (len == NAMLEN || cmd != Th(z_selfinsert))
 | 
						|
		    feep = 1;
 | 
						|
		else {
 | 
						|
#ifdef MULTIBYTE_SUPPORT
 | 
						|
		    if (!lastchar_wide_valid)
 | 
						|
			getrestchar(lastchar, NULL, NULL);
 | 
						|
		    if (lastchar_wide == WEOF)
 | 
						|
			feep = 1;
 | 
						|
		    else
 | 
						|
#endif
 | 
						|
		    if (ZC_icntrl(LASTFULLCHAR))
 | 
						|
			feep = 1;
 | 
						|
		    else {
 | 
						|
			int ret = zlecharasstring(LASTFULLCHAR, ptr);
 | 
						|
			len += ret;
 | 
						|
			ptr += ret;
 | 
						|
			if (listed) {
 | 
						|
			    clearlist = listshown = 1;
 | 
						|
			    listed = 0;
 | 
						|
			} else
 | 
						|
			    curlist = 0;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if (feep)
 | 
						|
	    handlefeep(zlenoargs);
 | 
						|
	feep = 0;
 | 
						|
    }
 | 
						|
 | 
						|
 done:
 | 
						|
    selectlocalmap(NULL);
 | 
						|
    return retval;
 | 
						|
}
 | 
						|
 | 
						|
/*****************/
 | 
						|
/* Suffix system */
 | 
						|
/*****************/
 | 
						|
 | 
						|
/*
 | 
						|
 * The completion system sometimes tentatively adds a suffix to a word,
 | 
						|
 * which can be removed depending on what is inserted next.  These
 | 
						|
 * functions provide the capability to handle a removable suffix.
 | 
						|
 *
 | 
						|
 * Any removable suffix consists of characters immediately before the
 | 
						|
 * cursor.  Whether it is removed depends on the next editing action.
 | 
						|
 * There can be more than one suffix simultaneously present, with
 | 
						|
 * different actions deleting different numbers of characters.
 | 
						|
 *
 | 
						|
 * If the next editing action changes the buffer other than by inserting
 | 
						|
 * characters, normally the suffix should be removed so as to leave a
 | 
						|
 * meaningful complete word.  The behaviour should be the same if the
 | 
						|
 * next character inserted is a word separator.  If the next character
 | 
						|
 * reasonably belongs where it is typed, or if the next editing action
 | 
						|
 * is a deletion, the suffix should not be removed.  Other reasons for
 | 
						|
 * suffix removal may have other behaviour.
 | 
						|
 *
 | 
						|
 * In order to maintain a consistent state, after a suffix has been added
 | 
						|
 * the table *must* be zeroed, one way or another, before the buffer is
 | 
						|
 * changed.  If the suffix is not being removed, call fixsuffix() to
 | 
						|
 * indicate that it is being permanently fixed.
 | 
						|
 */
 | 
						|
 | 
						|
struct suffixset;
 | 
						|
 | 
						|
/* An element of a suffix specification */
 | 
						|
struct suffixset {
 | 
						|
    struct suffixset *next;	/* Next in the list */
 | 
						|
    int tp;			/* The SUFTYP_* from enum suffixtype */
 | 
						|
    int flags;			/* Some of SUFFLAGS_* */
 | 
						|
    ZLE_STRING_T chars;		/* Set of characters to match (or not) */
 | 
						|
    int lenstr;			/* Length of chars */
 | 
						|
    int lensuf;			/* Length of suffix */
 | 
						|
};
 | 
						|
 | 
						|
/* The list of suffix structures */
 | 
						|
static struct suffixset *suffixlist;
 | 
						|
 | 
						|
/* Shell function to call to remove the suffix. */
 | 
						|
 | 
						|
/**/
 | 
						|
static char *suffixfunc;
 | 
						|
 | 
						|
/* Length associated with the suffix function */
 | 
						|
static int suffixfunclen;
 | 
						|
 | 
						|
/* Whether to remove suffix on uninsertable characters */
 | 
						|
/**/
 | 
						|
int suffixnoinsrem;
 | 
						|
 | 
						|
/* Length of the currently active, auto-removable suffix. */
 | 
						|
/**/
 | 
						|
mod_export int
 | 
						|
suffixlen;
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
addsuffix(int tp, int flags, ZLE_STRING_T chars, int lenstr, int lensuf)
 | 
						|
{
 | 
						|
    struct suffixset *newsuf = zalloc(sizeof(struct suffixset));
 | 
						|
    newsuf->next = suffixlist;
 | 
						|
    suffixlist = newsuf;
 | 
						|
 | 
						|
    newsuf->tp = tp;
 | 
						|
    newsuf->flags = flags;
 | 
						|
    if (lenstr) {
 | 
						|
	newsuf->chars = zalloc(lenstr*sizeof(ZLE_CHAR_T));
 | 
						|
	ZS_memcpy(newsuf->chars, chars, lenstr);
 | 
						|
    } else
 | 
						|
	newsuf->chars = NULL;
 | 
						|
    newsuf->lenstr = lenstr;
 | 
						|
    newsuf->lensuf = lensuf;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Same as addsuffix, but from metafied string */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
addsuffixstring(int tp, int flags, char *chars, int lensuf)
 | 
						|
{
 | 
						|
    int slen, alloclen;
 | 
						|
    ZLE_STRING_T suffixstr;
 | 
						|
 | 
						|
    /* string needs to be writable... I've been regretting this for years.. */
 | 
						|
    chars = ztrdup(chars);
 | 
						|
    suffixstr = stringaszleline(chars, 0, &slen, &alloclen, NULL);
 | 
						|
    addsuffix(tp, flags, suffixstr, slen, lensuf);
 | 
						|
    zfree(suffixstr, alloclen);
 | 
						|
    zsfree(chars);
 | 
						|
}
 | 
						|
 | 
						|
/* Set up suffix: the last n characters are a suffix that should be *
 | 
						|
 * removed in the usual word end conditions.                        */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
makesuffix(int n)
 | 
						|
{
 | 
						|
    char *suffixchars;
 | 
						|
 | 
						|
    if (!(suffixchars = getsparam_u("ZLE_REMOVE_SUFFIX_CHARS")))
 | 
						|
	suffixchars = " \t\n;&|";
 | 
						|
 | 
						|
    addsuffixstring(SUFTYP_POSSTR, 0, suffixchars, n);
 | 
						|
 | 
						|
    /* Do this second so it takes precedence */
 | 
						|
    if ((suffixchars = getsparam_u("ZLE_SPACE_SUFFIX_CHARS")) && *suffixchars)
 | 
						|
	addsuffixstring(SUFTYP_POSSTR, SUFFLAGS_SPACE, suffixchars, n);
 | 
						|
 | 
						|
    suffixlen = n;
 | 
						|
    suffixnoinsrem = 1;
 | 
						|
}
 | 
						|
 | 
						|
/* Set up suffix for parameter names: the last n characters are a suffix *
 | 
						|
 * that should be removed if the next character is one of the ones that  *
 | 
						|
 * needs to go immediately after the parameter name.  br indicates that  *
 | 
						|
 * the name is in braces (${PATH} instead of $PATH), so the extra        *
 | 
						|
 * characters that can only be used in braces are included.              */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
makeparamsuffix(int br, int n)
 | 
						|
{
 | 
						|
    ZLE_STRING_T charstr = ZWS(":[#%?-+=");
 | 
						|
    int lenstr = 0;
 | 
						|
 | 
						|
    if (br || unset(KSHARRAYS)) {
 | 
						|
	lenstr = 2;
 | 
						|
	if (br)
 | 
						|
	    lenstr += 6;
 | 
						|
    }
 | 
						|
    if (lenstr)
 | 
						|
	addsuffix(SUFTYP_POSSTR, 0, charstr, lenstr, n);
 | 
						|
}
 | 
						|
 | 
						|
/* Set up suffix given a string containing the characters on which to   *
 | 
						|
 * remove the suffix. */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
makesuffixstr(char *f, char *s, int n)
 | 
						|
{
 | 
						|
    if (f) {
 | 
						|
	zsfree(suffixfunc);
 | 
						|
	suffixfunc = ztrdup(f);
 | 
						|
	suffixfunclen = n;
 | 
						|
    } else if (s) {
 | 
						|
	int inv, i, z = 0;
 | 
						|
	ZLE_STRING_T ws, lasts, wptr;
 | 
						|
 | 
						|
	if (*s == '^' || *s == '!') {
 | 
						|
	    inv = 1;
 | 
						|
	    s++;
 | 
						|
	} else
 | 
						|
	    inv = 0;
 | 
						|
	s = getkeystring(s, &i, GETKEYS_SUFFIX, &z);
 | 
						|
	s = metafy(s, i, META_USEHEAP);
 | 
						|
	ws = stringaszleline(s, 0, &i, NULL, NULL);
 | 
						|
 | 
						|
	/* Remove suffix on uninsertable characters if  \- was given *
 | 
						|
	 * and the character class wasn't negated -- or vice versa.  */
 | 
						|
	suffixnoinsrem = z ^ inv;
 | 
						|
	suffixlen = n;
 | 
						|
 | 
						|
	lasts = wptr = ws;
 | 
						|
	while (i) {
 | 
						|
	    if (i >= 3 && wptr[1] == ZWC('-')) {
 | 
						|
		ZLE_CHAR_T str[2];
 | 
						|
 | 
						|
		if (wptr > lasts)
 | 
						|
		    addsuffix(inv ? SUFTYP_NEGSTR : SUFTYP_POSSTR, 0,
 | 
						|
			      lasts, wptr - lasts, n);
 | 
						|
		str[0] = *wptr;
 | 
						|
		str[1] = wptr[2];
 | 
						|
		addsuffix(inv ? SUFTYP_NEGRNG : SUFTYP_POSRNG, 0,
 | 
						|
			  str, 2, n);
 | 
						|
 | 
						|
		wptr += 3;
 | 
						|
		i -= 3;
 | 
						|
		lasts = wptr;
 | 
						|
	    } else {
 | 
						|
		wptr++;
 | 
						|
		i--;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if (wptr > lasts)
 | 
						|
	    addsuffix(inv ? SUFTYP_NEGSTR : SUFTYP_POSSTR, 0,
 | 
						|
		      lasts, wptr - lasts, n);
 | 
						|
	free(ws);
 | 
						|
    } else
 | 
						|
	makesuffix(n);
 | 
						|
}
 | 
						|
 | 
						|
/* Remove suffix, if there is one, when inserting character c. */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
iremovesuffix(ZLE_INT_T c, int keep)
 | 
						|
{
 | 
						|
    if (suffixfunc) {
 | 
						|
	Shfunc shfunc = getshfunc(suffixfunc);
 | 
						|
 | 
						|
	if (shfunc) {
 | 
						|
	    LinkList args = newlinklist();
 | 
						|
	    char buf[20];
 | 
						|
	    int osc = sfcontext;
 | 
						|
	    int wasmeta = (zlemetaline != 0);
 | 
						|
 | 
						|
	    if (wasmeta) {
 | 
						|
		/*
 | 
						|
		 * The suffix removal function runs as a normal
 | 
						|
		 * ZLE function, not a completion function, so
 | 
						|
		 * the line should be unmetafied if this was
 | 
						|
		 * called from completion.  (It may not be since
 | 
						|
		 * we may decide to remove the suffix later.)
 | 
						|
		 */
 | 
						|
		unmetafy_line();
 | 
						|
	    }
 | 
						|
 | 
						|
	    sprintf(buf, "%d", suffixfunclen);
 | 
						|
	    addlinknode(args, suffixfunc);
 | 
						|
	    addlinknode(args, buf);
 | 
						|
 | 
						|
	    startparamscope();
 | 
						|
	    makezleparams(0);
 | 
						|
	    sfcontext = SFC_COMPLETE;
 | 
						|
	    doshfunc(shfunc, args, 1);
 | 
						|
	    sfcontext = osc;
 | 
						|
	    endparamscope();
 | 
						|
 | 
						|
	    if (wasmeta)
 | 
						|
		metafy_line();
 | 
						|
	}
 | 
						|
	zsfree(suffixfunc);
 | 
						|
	suffixfunc = NULL;
 | 
						|
    } else {
 | 
						|
	int sl = 0, flags = 0;
 | 
						|
	struct suffixset *ss;
 | 
						|
 | 
						|
	if (c == NO_INSERT_CHAR) {
 | 
						|
	    sl = suffixnoinsrem ? suffixlen : 0;
 | 
						|
	} else {
 | 
						|
	    ZLE_CHAR_T ch = c;
 | 
						|
	    /*
 | 
						|
	     * Search for a match for ch in the suffix list.
 | 
						|
	     * We stop if we encounter a match in a positive or negative
 | 
						|
	     * list, using the suffix length specified or zero respectively.
 | 
						|
	     * If we reached the end and passed through a negative
 | 
						|
	     * list, we use the suffix length for that, else zero.
 | 
						|
	     * This would break if it were possible to have negative
 | 
						|
	     * sets with different suffix length:  that's not supposed
 | 
						|
	     * to happen.
 | 
						|
	     */
 | 
						|
	    int negsuflen = 0, found = 0;
 | 
						|
 | 
						|
	    for (ss = suffixlist; ss; ss = ss->next) {
 | 
						|
		switch (ss->tp) {
 | 
						|
		case SUFTYP_POSSTR:
 | 
						|
		    if (ZS_memchr(ss->chars, ch, ss->lenstr)) {
 | 
						|
			sl = ss->lensuf;
 | 
						|
			found = 1;
 | 
						|
		    }
 | 
						|
		    break;
 | 
						|
 | 
						|
		case SUFTYP_NEGSTR:
 | 
						|
		    if (ZS_memchr(ss->chars, ch, ss->lenstr)) {
 | 
						|
			sl = 0;
 | 
						|
			found = 1;
 | 
						|
		    } else {
 | 
						|
			negsuflen = ss->lensuf;
 | 
						|
		    }
 | 
						|
		    break;
 | 
						|
 | 
						|
		case SUFTYP_POSRNG:
 | 
						|
		    if (ss->chars[0] <= ch && ch <= ss->chars[1]) {
 | 
						|
			sl = ss->lensuf;
 | 
						|
			found = 1;
 | 
						|
		    }
 | 
						|
		    break;
 | 
						|
 | 
						|
		case SUFTYP_NEGRNG:
 | 
						|
		    if (ss->chars[0] <= ch && ch <= ss->chars[1]) {
 | 
						|
			sl = 0;
 | 
						|
			found = 1;
 | 
						|
		    } else {
 | 
						|
			negsuflen = ss->lensuf;
 | 
						|
		    }
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
		if (found) {
 | 
						|
		    flags = ss->flags;
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	    if (!found)
 | 
						|
		sl = negsuflen;
 | 
						|
	}
 | 
						|
	if (sl) {
 | 
						|
	    /* must be shifting wide character lengths */
 | 
						|
	    backdel(sl, CUT_RAW);
 | 
						|
	    if (flags & SUFFLAGS_SPACE)
 | 
						|
	    {
 | 
						|
		/* Add a space and advance over it */
 | 
						|
		spaceinline(1);
 | 
						|
		if (zlemetaline) {
 | 
						|
		    zlemetaline[zlemetacs++] = ' ';
 | 
						|
		} else {
 | 
						|
		    zleline[zlecs++] = ZWC(' ');
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    if (!keep)
 | 
						|
		invalidatelist();
 | 
						|
	}
 | 
						|
    }
 | 
						|
    fixsuffix();
 | 
						|
}
 | 
						|
 | 
						|
/* Fix the suffix in place, if there is one, making it non-removable. */
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export void
 | 
						|
fixsuffix(void)
 | 
						|
{
 | 
						|
    while (suffixlist) {
 | 
						|
	struct suffixset *next = suffixlist->next;
 | 
						|
 | 
						|
	if (suffixlist->lenstr)
 | 
						|
	    zfree(suffixlist->chars, suffixlist->lenstr * sizeof(ZLE_CHAR_T));
 | 
						|
	zfree(suffixlist, sizeof(struct suffixset));
 | 
						|
 | 
						|
	suffixlist = next;
 | 
						|
    }
 | 
						|
 | 
						|
    suffixfunclen = suffixnoinsrem = suffixlen = 0;
 | 
						|
}
 |