123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695 |
- /* $NetBSD: chared.c,v 1.15 2002/03/18 16:00:50 christos Exp $ */
- /*-
- * 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. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. 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.
- */
- #include "config.h"
- #if !defined(lint) && !defined(SCCSID)
- #if 0
- static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93";
- #else
- __RCSID("$NetBSD: chared.c,v 1.15 2002/03/18 16:00:50 christos Exp $");
- #endif
- #endif /* not lint && not SCCSID */
- /*
- * chared.c: Character editor utilities
- */
- #include <stdlib.h>
- #include "el.h"
- /* value to leave unused in line buffer */
- #define EL_LEAVE 2
- /* cv_undo():
- * Handle state for the vi undo command
- */
- protected void
- cv_undo(EditLine *el,int action, size_t size, char *ptr)
- {
- c_undo_t *vu = &el->el_chared.c_undo;
- vu->action = action;
- vu->ptr = ptr;
- vu->isize = size;
- (void) memcpy(vu->buf, vu->ptr, size);
- #ifdef DEBUG_UNDO
- (void) fprintf(el->el_errfile, "Undo buffer \"%s\" size = +%d -%d\n",
- vu->ptr, vu->isize, vu->dsize);
- #endif
- }
- /* c_insert():
- * Insert num characters
- */
- protected void
- c_insert(EditLine *el, int num)
- {
- char *cp;
- if (el->el_line.lastchar + num >= el->el_line.limit)
- return; /* can't go past end of buffer */
- if (el->el_line.cursor < el->el_line.lastchar) {
- /* if I must move chars */
- for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
- cp[num] = *cp;
- }
- el->el_line.lastchar += num;
- }
- /* c_delafter():
- * Delete num characters after the cursor
- */
- protected void
- c_delafter(EditLine *el, int num)
- {
- if (el->el_line.cursor + num > el->el_line.lastchar)
- num = el->el_line.lastchar - el->el_line.cursor;
- if (num > 0) {
- char *cp;
- if (el->el_map.current != el->el_map.emacs)
- cv_undo(el, INSERT, (size_t)num, el->el_line.cursor);
- for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
- *cp = cp[num];
- el->el_line.lastchar -= num;
- }
- }
- /* c_delbefore():
- * Delete num characters before the cursor
- */
- protected void
- c_delbefore(EditLine *el, int num)
- {
- if (el->el_line.cursor - num < el->el_line.buffer)
- num = el->el_line.cursor - el->el_line.buffer;
- if (num > 0) {
- char *cp;
- if (el->el_map.current != el->el_map.emacs)
- cv_undo(el, INSERT, (size_t)num,
- el->el_line.cursor - num);
- for (cp = el->el_line.cursor - num;
- cp <= el->el_line.lastchar;
- cp++)
- *cp = cp[num];
- el->el_line.lastchar -= num;
- }
- }
- /* ce__isword():
- * Return if p is part of a word according to emacs
- */
- protected int
- ce__isword(int p)
- {
- return (isalpha(p) || isdigit(p) || strchr("*?_-.[]~=", p) != NULL);
- }
- /* cv__isword():
- * Return if p is part of a word according to vi
- */
- protected int
- cv__isword(int p)
- {
- return (!isspace(p));
- }
- /* c__prev_word():
- * Find the previous word
- */
- protected char *
- c__prev_word(char *p, char *low, int n, int (*wtest)(int))
- {
- p--;
- while (n--) {
- while ((p >= low) && !(*wtest)((unsigned char) *p))
- p--;
- while ((p >= low) && (*wtest)((unsigned char) *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
- */
- protected char *
- c__next_word(char *p, char *high, int n, int (*wtest)(int))
- {
- while (n--) {
- while ((p < high) && !(*wtest)((unsigned char) *p))
- p++;
- while ((p < high) && (*wtest)((unsigned char) *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
- */
- protected char *
- cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int))
- {
- int test;
- while (n--) {
- test = (*wtest)((unsigned char) *p);
- while ((p < high) && (*wtest)((unsigned char) *p) == test)
- p++;
- /*
- * vi historically deletes with cw only the word preserving the
- * trailing whitespace! This is not what 'w' does..
- */
- if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
- while ((p < high) && isspace((unsigned char) *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
- */
- protected char *
- cv_prev_word(EditLine *el, char *p, char *low, int n, int (*wtest)(int))
- {
- int test;
- while (n--) {
- p--;
- /*
- * vi historically deletes with cb only the word preserving the
- * leading whitespace! This is not what 'b' does..
- */
- if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
- while ((p > low) && isspace((unsigned char) *p))
- p--;
- test = (*wtest)((unsigned char) *p);
- while ((p >= low) && (*wtest)((unsigned char) *p) == test)
- p--;
- p++;
- while (isspace((unsigned char) *p))
- p++;
- }
- /* p now points where we want it */
- if (p < low)
- return (low);
- else
- return (p);
- }
- #ifdef notdef
- /* c__number():
- * Ignore character p points to, return number appearing after that.
- * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
- * Return p pointing to last char used.
- */
- protected char *
- c__number(
- char *p, /* character position */
- int *num, /* Return value */
- int dval) /* dval is the number to subtract from like $-3 */
- {
- int i;
- int sign = 1;
- if (*++p == '^') {
- *num = 1;
- return (p);
- }
- if (*p == '$') {
- if (*++p != '-') {
- *num = 0x7fffffff; /* Handle $ */
- return (--p);
- }
- sign = -1; /* Handle $- */
- ++p;
- }
- for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
- continue;
- *num = (sign < 0 ? dval - i : i);
- return (--p);
- }
- #endif
- /* cv_delfini():
- * Finish vi delete action
- */
- protected void
- cv_delfini(EditLine *el)
- {
- int size;
- int oaction;
- if (el->el_chared.c_vcmd.action & INSERT)
- el->el_map.current = el->el_map.key;
- oaction = el->el_chared.c_vcmd.action;
- el->el_chared.c_vcmd.action = NOP;
- if (el->el_chared.c_vcmd.pos == 0)
- return;
- if (el->el_line.cursor > el->el_chared.c_vcmd.pos) {
- size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos);
- c_delbefore(el, size);
- el->el_line.cursor = el->el_chared.c_vcmd.pos;
- re_refresh_cursor(el);
- } else if (el->el_line.cursor < el->el_chared.c_vcmd.pos) {
- size = (int)(el->el_chared.c_vcmd.pos - el->el_line.cursor);
- c_delafter(el, size);
- } else {
- size = 1;
- c_delafter(el, size);
- }
- switch (oaction) {
- case DELETE|INSERT:
- el->el_chared.c_undo.action = DELETE|INSERT;
- break;
- case DELETE:
- el->el_chared.c_undo.action = INSERT;
- break;
- case NOP:
- case INSERT:
- default:
- EL_ABORT((el->el_errfile, "Bad oaction %d\n", oaction));
- break;
- }
- el->el_chared.c_undo.ptr = el->el_line.cursor;
- el->el_chared.c_undo.dsize = size;
- }
- #ifdef notdef
- /* ce__endword():
- * Go to the end of this word according to emacs
- */
- protected char *
- ce__endword(char *p, char *high, int n)
- {
- p++;
- while (n--) {
- while ((p < high) && isspace((unsigned char) *p))
- p++;
- while ((p < high) && !isspace((unsigned char) *p))
- p++;
- }
- p--;
- return (p);
- }
- #endif
- /* cv__endword():
- * Go to the end of this word according to vi
- */
- protected char *
- cv__endword(char *p, char *high, int n)
- {
- p++;
- while (n--) {
- while ((p < high) && isspace((unsigned char) *p))
- p++;
- if (isalnum((unsigned char) *p))
- while ((p < high) && isalnum((unsigned char) *p))
- p++;
- else
- while ((p < high) && !(isspace((unsigned char) *p) ||
- isalnum((unsigned char) *p)))
- p++;
- }
- p--;
- return (p);
- }
- /* ch_init():
- * Initialize the character editor
- */
- protected int
- ch_init(EditLine *el)
- {
- el->el_line.buffer = (char *) el_malloc(EL_BUFSIZ);
- if (el->el_line.buffer == NULL)
- return (-1);
- (void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
- el->el_line.cursor = el->el_line.buffer;
- el->el_line.lastchar = el->el_line.buffer;
- el->el_line.limit = &el->el_line.buffer[EL_BUFSIZ - 2];
- el->el_chared.c_undo.buf = (char *) el_malloc(EL_BUFSIZ);
- if (el->el_chared.c_undo.buf == NULL)
- return (-1);
- (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
- el->el_chared.c_undo.action = NOP;
- el->el_chared.c_undo.isize = 0;
- el->el_chared.c_undo.dsize = 0;
- el->el_chared.c_undo.ptr = el->el_line.buffer;
- el->el_chared.c_vcmd.action = NOP;
- el->el_chared.c_vcmd.pos = el->el_line.buffer;
- el->el_chared.c_vcmd.ins = el->el_line.buffer;
- el->el_chared.c_kill.buf = (char *) el_malloc(EL_BUFSIZ);
- if (el->el_chared.c_kill.buf == NULL)
- return (-1);
- (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
- el->el_chared.c_kill.mark = el->el_line.buffer;
- el->el_chared.c_kill.last = el->el_chared.c_kill.buf;
- el->el_map.current = el->el_map.key;
- el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
- el->el_state.doingarg = 0;
- el->el_state.metanext = 0;
- el->el_state.argument = 1;
- el->el_state.lastcmd = ED_UNASSIGNED;
- el->el_chared.c_macro.nline = NULL;
- el->el_chared.c_macro.level = -1;
- el->el_chared.c_macro.macro = (char **) el_malloc(EL_MAXMACRO *
- sizeof(char *));
- if (el->el_chared.c_macro.macro == NULL)
- return (-1);
- return (0);
- }
- /* ch_reset():
- * Reset the character editor
- */
- protected void
- ch_reset(EditLine *el)
- {
- el->el_line.cursor = el->el_line.buffer;
- el->el_line.lastchar = el->el_line.buffer;
- el->el_chared.c_undo.action = NOP;
- el->el_chared.c_undo.isize = 0;
- el->el_chared.c_undo.dsize = 0;
- el->el_chared.c_undo.ptr = el->el_line.buffer;
- el->el_chared.c_vcmd.action = NOP;
- el->el_chared.c_vcmd.pos = el->el_line.buffer;
- el->el_chared.c_vcmd.ins = el->el_line.buffer;
- el->el_chared.c_kill.mark = el->el_line.buffer;
- el->el_map.current = el->el_map.key;
- el->el_state.inputmode = MODE_INSERT; /* XXX: save a default */
- el->el_state.doingarg = 0;
- el->el_state.metanext = 0;
- el->el_state.argument = 1;
- el->el_state.lastcmd = ED_UNASSIGNED;
- el->el_chared.c_macro.level = -1;
- el->el_history.eventno = 0;
- }
- /* ch_enlargebufs():
- * Enlarge line buffer to be able to hold twice as much characters.
- * Returns 1 if successful, 0 if not.
- */
- protected int
- ch_enlargebufs(el, addlen)
- EditLine *el;
- size_t addlen;
- {
- size_t sz, newsz;
- char *newbuffer, *oldbuf, *oldkbuf;
- sz = 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);
- if (!newbuffer)
- return 0;
- /* zero the newly added memory, leave old data in */
- (void) memset(&newbuffer[sz], 0, newsz - sz);
- 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);
- el->el_line.limit = &newbuffer[newsz - EL_LEAVE];
- /*
- * Reallocate kill buffer.
- */
- newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz);
- if (!newbuffer)
- return 0;
- /* zero the newly added memory, leave old data in */
- (void) memset(&newbuffer[sz], 0, newsz - sz);
- oldkbuf = el->el_chared.c_kill.buf;
- el->el_chared.c_kill.buf = newbuffer;
- el->el_chared.c_kill.last = newbuffer +
- (el->el_chared.c_kill.last - oldkbuf);
- el->el_chared.c_kill.mark = el->el_line.buffer +
- (el->el_chared.c_kill.mark - oldbuf);
- /*
- * Reallocate undo buffer.
- */
- newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz);
- if (!newbuffer)
- return 0;
- /* zero the newly added memory, leave old data in */
- (void) memset(&newbuffer[sz], 0, newsz - sz);
- el->el_chared.c_undo.ptr = el->el_line.buffer +
- (el->el_chared.c_undo.ptr - oldbuf);
- el->el_chared.c_undo.buf = newbuffer;
- if (!hist_enlargebuf(el, sz, newsz))
- return 0;
- return 1;
- }
- /* ch_end():
- * Free the data structures used by the editor
- */
- protected void
- ch_end(EditLine *el)
- {
- el_free((ptr_t) el->el_line.buffer);
- el->el_line.buffer = NULL;
- el->el_line.limit = NULL;
- el_free((ptr_t) el->el_chared.c_undo.buf);
- el->el_chared.c_undo.buf = NULL;
- el_free((ptr_t) el->el_chared.c_kill.buf);
- el->el_chared.c_kill.buf = NULL;
- el_free((ptr_t) el->el_chared.c_macro.macro);
- el->el_chared.c_macro.macro = NULL;
- ch_reset(el);
- }
- /* el_insertstr():
- * Insert string at cursorI
- */
- public int
- el_insertstr(EditLine *el, const char *s)
- {
- size_t len;
- if ((len = strlen(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
- */
- public 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;
- }
- /* c_gets():
- * Get a string
- */
- protected int
- c_gets(EditLine *el, char *buf)
- {
- char ch;
- int len = 0;
- for (ch = 0; ch == 0;) {
- if (el_getc(el, &ch) != 1)
- return (ed_end_of_file(el, 0));
- switch (ch) {
- case 0010: /* Delete and backspace */
- case 0177:
- if (len > 1) {
- *el->el_line.cursor-- = '\0';
- el->el_line.lastchar = el->el_line.cursor;
- buf[len--] = '\0';
- } else {
- el->el_line.buffer[0] = '\0';
- el->el_line.lastchar = el->el_line.buffer;
- el->el_line.cursor = el->el_line.buffer;
- return (CC_REFRESH);
- }
- re_refresh(el);
- ch = 0;
- break;
- case 0033: /* ESC */
- case '\r': /* Newline */
- case '\n':
- break;
- default:
- if (len >= EL_BUFSIZ)
- term_beep(el);
- else {
- buf[len++] = ch;
- *el->el_line.cursor++ = ch;
- el->el_line.lastchar = el->el_line.cursor;
- }
- re_refresh(el);
- ch = 0;
- break;
- }
- }
- buf[len] = ch;
- return (len);
- }
- /* c_hpos():
- * Return the current horizontal position of the cursor
- */
- protected int
- c_hpos(EditLine *el)
- {
- char *ptr;
- /*
- * Find how many characters till the beginning of this line.
- */
- if (el->el_line.cursor == el->el_line.buffer)
- return (0);
- else {
- for (ptr = el->el_line.cursor - 1;
- ptr >= el->el_line.buffer && *ptr != '\n';
- ptr--)
- continue;
- return (el->el_line.cursor - ptr - 1);
- }
- }
|