/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Christos Zoulas of Cornell University.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* ce__isword():
* Return if p is part of a word according to emacs
*/
libedit_private int
ce__isword(wint_t p)
{
return iswalnum(p) || wcschr(L"*?_-.[]~=", p) != NULL;
}
/* cv__isword():
* Return if p is part of a word according to vi
*/
libedit_private int
cv__isword(wint_t p)
{
if (iswalnum(p) || p == L'_')
return 1;
if (iswgraph(p))
return 2;
return 0;
}
/* cv__isWord():
* Return if p is part of a big word according to vi
*/
libedit_private int
cv__isWord(wint_t p)
{
return !iswspace(p);
}
/* c__prev_word():
* Find the previous word
*/
libedit_private wchar_t *
c__prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t))
{
p--;
while (n--) {
while ((p >= low) && !(*wtest)(*p))
p--;
while ((p >= low) && (*wtest)(*p))
p--;
}
/* cp now points to one character before the word */
p++;
if (p < low)
p = low;
/* cp now points where we want it */
return p;
}
/* c__next_word():
* Find the next word
*/
libedit_private wchar_t *
c__next_word(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t))
{
while (n--) {
while ((p < high) && !(*wtest)(*p))
p++;
while ((p < high) && (*wtest)(*p))
p++;
}
if (p > high)
p = high;
/* p now points where we want it */
return p;
}
/* cv_next_word():
* Find the next word vi style
*/
libedit_private wchar_t *
cv_next_word(EditLine *el, wchar_t *p, wchar_t *high, int n,
int (*wtest)(wint_t))
{
int test;
while (n--) {
test = (*wtest)(*p);
while ((p < high) && (*wtest)(*p) == test)
p++;
/*
* vi historically deletes with cw only the word preserving the
* trailing whitespace! This is not what 'w' does..
*/
if (n || el->el_chared.c_vcmd.action != (DELETE|INSERT))
while ((p < high) && iswspace(*p))
p++;
}
/* p now points where we want it */
if (p > high)
return high;
else
return p;
}
/* cv_prev_word():
* Find the previous word vi style
*/
libedit_private wchar_t *
cv_prev_word(wchar_t *p, wchar_t *low, int n, int (*wtest)(wint_t))
{
int test;
p--;
while (n--) {
while ((p > low) && iswspace(*p))
p--;
test = (*wtest)(*p);
while ((p >= low) && (*wtest)(*p) == test)
p--;
if (p < low)
return low;
}
p++;
/* p now points where we want it */
if (p < low)
return low;
else
return p;
}
/* cv_delfini():
* Finish vi delete action
*/
libedit_private void
cv_delfini(EditLine *el)
{
int size;
int action = el->el_chared.c_vcmd.action;
if (action & INSERT)
el->el_map.current = el->el_map.key;
if (el->el_chared.c_vcmd.pos == 0)
/* sanity */
return;
/* cv__endword():
* Go to the end of this word according to vi
*/
libedit_private wchar_t *
cv__endword(wchar_t *p, wchar_t *high, int n, int (*wtest)(wint_t))
{
int test;
p++;
while (n--) {
while ((p < high) && iswspace(*p))
p++;
test = (*wtest)(*p);
while ((p < high) && (*wtest)(*p) == test)
p++;
}
p--;
return p;
}
/* ch_init():
* Initialize the character editor
*/
libedit_private int
ch_init(EditLine *el)
{
el->el_line.buffer = el_calloc(EL_BUFSIZ,
sizeof(*el->el_line.buffer));
if (el->el_line.buffer == NULL)
return -1;
/* ch_enlargebufs():
* Enlarge line buffer to be able to hold twice as much characters.
* Returns 1 if successful, 0 if not.
*/
libedit_private int
ch_enlargebufs(EditLine *el, size_t addlen)
{
size_t sz, newsz;
wchar_t *newbuffer, *oldbuf, *oldkbuf;
sz = (size_t)(el->el_line.limit - el->el_line.buffer + EL_LEAVE);
newsz = sz * 2;
/*
* If newly required length is longer than current buffer, we need
* to make the buffer big enough to hold both old and new stuff.
*/
if (addlen > sz) {
while(newsz - sz < addlen)
newsz *= 2;
}
/*
* Reallocate line buffer.
*/
newbuffer = el_realloc(el->el_line.buffer, newsz * sizeof(*newbuffer));
if (!newbuffer)
return 0;
/* zero the newly added memory, leave old data in */
(void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer));
oldbuf = el->el_line.buffer;
el->el_line.buffer = newbuffer;
el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
/* don't set new size until all buffers are enlarged */
el->el_line.limit = &newbuffer[sz - EL_LEAVE];
/* zero the newly added memory, leave old data in */
(void) memset(&newbuffer[sz], 0, (newsz - sz) * sizeof(*newbuffer));
el->el_chared.c_undo.buf = newbuffer;
/* Safe to set enlarged buffer size */
el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE];
if (el->el_chared.c_resizefun)
(*el->el_chared.c_resizefun)(el, el->el_chared.c_resizearg);
return 1;
}
/* ch_end():
* Free the data structures used by the editor
*/
libedit_private void
ch_end(EditLine *el)
{
el_free(el->el_line.buffer);
el->el_line.buffer = NULL;
el->el_line.limit = NULL;
el_free(el->el_chared.c_undo.buf);
el->el_chared.c_undo.buf = NULL;
el_free(el->el_chared.c_redo.buf);
el->el_chared.c_redo.buf = NULL;
el->el_chared.c_redo.pos = NULL;
el->el_chared.c_redo.lim = NULL;
el->el_chared.c_redo.cmd = ED_UNASSIGNED;
el_free(el->el_chared.c_kill.buf);
el->el_chared.c_kill.buf = NULL;
ch_reset(el);
}
/* el_insertstr():
* Insert string at cursor
*/
int
el_winsertstr(EditLine *el, const wchar_t *s)
{
size_t len;
if (s == NULL || (len = wcslen(s)) == 0)
return -1;
if (el->el_line.lastchar + len >= el->el_line.limit) {
if (!ch_enlargebufs(el, len))
return -1;
}
c_insert(el, (int)len);
while (*s)
*el->el_line.cursor++ = *s++;
return 0;
}
/* el_deletestr():
* Delete num characters before the cursor
*/
void
el_deletestr(EditLine *el, int n)
{
if (n <= 0)
return;
if (el->el_line.cursor < &el->el_line.buffer[n])
return;
c_delbefore(el, n); /* delete before dot */
el->el_line.cursor -= n;
if (el->el_line.cursor < el->el_line.buffer)
el->el_line.cursor = el->el_line.buffer;
}
/* el_deletestr1():
* Delete characters between start and end
*/
int
el_deletestr1(EditLine *el, int start, int end)
{
size_t line_length, len;
wchar_t *p1, *p2;
if (start >= (int)line_length || end >= (int)line_length)
return 0;
len = (size_t)(end - start);
if (len > line_length - (size_t)end)
len = line_length - (size_t)end;
p1 = el->el_line.buffer + start;
p2 = el->el_line.buffer + end;
for (size_t i = 0; i < len; i++) {
*p1++ = *p2++;
el->el_line.lastchar--;
}
if (el->el_line.cursor < el->el_line.buffer)
el->el_line.cursor = el->el_line.buffer;
return end - start;
}
/* el_wreplacestr():
* Replace the contents of the line with the provided string
*/
int
el_wreplacestr(EditLine *el, const wchar_t *s)
{
size_t len;
wchar_t * p;
if (s == NULL || (len = wcslen(s)) == 0)
return -1;
if (el->el_line.buffer + len >= el->el_line.limit) {
if (!ch_enlargebufs(el, len))
return -1;
}
p = el->el_line.buffer;
for (size_t i = 0; i < len; i++)
*p++ = *s++;