chared.c

Go to the documentation of this file.
00001 /* $NetBSD: chared.c,v 1.15 2002/03/18 16:00:50 christos Exp $ */
00002 
00003 /*-
00004  * Copyright (c) 1992, 1993
00005  * The Regents of the University of California.  All rights reserved.
00006  *
00007  * This code is derived from software contributed to Berkeley by
00008  * Christos Zoulas of Cornell University.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted provided that the following conditions
00012  * are met:
00013  * 1. Redistributions of source code must retain the above copyright
00014  *    notice, this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in the
00017  *    documentation and/or other materials provided with the distribution.
00018  * 3. All advertising materials mentioning features or use of this software
00019  *    must display the following acknowledgement:
00020  * This product includes software developed by the University of
00021  * California, Berkeley and its contributors.
00022  * 4. Neither the name of the University nor the names of its contributors
00023  *    may be used to endorse or promote products derived from this software
00024  *    without specific prior written permission.
00025  *
00026  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00027  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00029  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00030  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00031  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00032  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00033  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00034  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00035  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00036  * SUCH DAMAGE.
00037  */
00038 
00039 #include "config.h"
00040 #if !defined(lint) && !defined(SCCSID)
00041 #if 0
00042 static char sccsid[] = "@(#)chared.c   8.1 (Berkeley) 6/4/93";
00043 #else
00044 __RCSID("$NetBSD: chared.c,v 1.15 2002/03/18 16:00:50 christos Exp $");
00045 #endif
00046 #endif /* not lint && not SCCSID */
00047 
00048 /*
00049  * chared.c: Character editor utilities
00050  */
00051 #include <stdlib.h>
00052 #include "el.h"
00053 
00054 /* value to leave unused in line buffer */
00055 #define  EL_LEAVE 2
00056 
00057 /* cv_undo():
00058  * Handle state for the vi undo command
00059  */
00060 protected void
00061 cv_undo(EditLine *el,int action, size_t size, char *ptr)
00062 {
00063    c_undo_t *vu = &el->el_chared.c_undo;
00064    vu->action = action;
00065    vu->ptr    = ptr;
00066    vu->isize  = size;
00067    (void) memcpy(vu->buf, vu->ptr, size);
00068 #ifdef DEBUG_UNDO
00069    (void) fprintf(el->el_errfile, "Undo buffer \"%s\" size = +%d -%d\n",
00070           vu->ptr, vu->isize, vu->dsize);
00071 #endif
00072 }
00073 
00074 
00075 /* c_insert():
00076  * Insert num characters
00077  */
00078 protected void
00079 c_insert(EditLine *el, int num)
00080 {
00081    char *cp;
00082 
00083    if (el->el_line.lastchar + num >= el->el_line.limit)
00084       return;        /* can't go past end of buffer */
00085 
00086    if (el->el_line.cursor < el->el_line.lastchar) {
00087       /* if I must move chars */
00088       for (cp = el->el_line.lastchar; cp >= el->el_line.cursor; cp--)
00089          cp[num] = *cp;
00090    }
00091    el->el_line.lastchar += num;
00092 }
00093 
00094 
00095 /* c_delafter():
00096  * Delete num characters after the cursor
00097  */
00098 protected void
00099 c_delafter(EditLine *el, int num)
00100 {
00101 
00102    if (el->el_line.cursor + num > el->el_line.lastchar)
00103       num = el->el_line.lastchar - el->el_line.cursor;
00104 
00105    if (num > 0) {
00106       char *cp;
00107 
00108       if (el->el_map.current != el->el_map.emacs)
00109          cv_undo(el, INSERT, (size_t)num, el->el_line.cursor);
00110 
00111       for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++)
00112          *cp = cp[num];
00113 
00114       el->el_line.lastchar -= num;
00115    }
00116 }
00117 
00118 
00119 /* c_delbefore():
00120  * Delete num characters before the cursor
00121  */
00122 protected void
00123 c_delbefore(EditLine *el, int num)
00124 {
00125 
00126    if (el->el_line.cursor - num < el->el_line.buffer)
00127       num = el->el_line.cursor - el->el_line.buffer;
00128 
00129    if (num > 0) {
00130       char *cp;
00131 
00132       if (el->el_map.current != el->el_map.emacs)
00133          cv_undo(el, INSERT, (size_t)num,
00134              el->el_line.cursor - num);
00135 
00136       for (cp = el->el_line.cursor - num;
00137           cp <= el->el_line.lastchar;
00138           cp++)
00139          *cp = cp[num];
00140 
00141       el->el_line.lastchar -= num;
00142    }
00143 }
00144 
00145 
00146 /* ce__isword():
00147  * Return if p is part of a word according to emacs
00148  */
00149 protected int
00150 ce__isword(int p)
00151 {
00152    return (isalpha(p) || isdigit(p) || strchr("*?_-.[]~=", p) != NULL);
00153 }
00154 
00155 
00156 /* cv__isword():
00157  * Return if p is part of a word according to vi
00158  */
00159 protected int
00160 cv__isword(int p)
00161 {
00162    return (!isspace(p));
00163 }
00164 
00165 
00166 /* c__prev_word():
00167  * Find the previous word
00168  */
00169 protected char *
00170 c__prev_word(char *p, char *low, int n, int (*wtest)(int))
00171 {
00172    p--;
00173 
00174    while (n--) {
00175       while ((p >= low) && !(*wtest)((unsigned char) *p))
00176          p--;
00177       while ((p >= low) && (*wtest)((unsigned char) *p))
00178          p--;
00179    }
00180 
00181    /* cp now points to one character before the word */
00182    p++;
00183    if (p < low)
00184       p = low;
00185    /* cp now points where we want it */
00186    return (p);
00187 }
00188 
00189 
00190 /* c__next_word():
00191  * Find the next word
00192  */
00193 protected char *
00194 c__next_word(char *p, char *high, int n, int (*wtest)(int))
00195 {
00196    while (n--) {
00197       while ((p < high) && !(*wtest)((unsigned char) *p))
00198          p++;
00199       while ((p < high) && (*wtest)((unsigned char) *p))
00200          p++;
00201    }
00202    if (p > high)
00203       p = high;
00204    /* p now points where we want it */
00205    return (p);
00206 }
00207 
00208 /* cv_next_word():
00209  * Find the next word vi style
00210  */
00211 protected char *
00212 cv_next_word(EditLine *el, char *p, char *high, int n, int (*wtest)(int))
00213 {
00214    int test;
00215 
00216    while (n--) {
00217       test = (*wtest)((unsigned char) *p);
00218       while ((p < high) && (*wtest)((unsigned char) *p) == test)
00219          p++;
00220       /*
00221        * vi historically deletes with cw only the word preserving the
00222        * trailing whitespace! This is not what 'w' does..
00223        */
00224       if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
00225          while ((p < high) && isspace((unsigned char) *p))
00226             p++;
00227    }
00228 
00229    /* p now points where we want it */
00230    if (p > high)
00231       return (high);
00232    else
00233       return (p);
00234 }
00235 
00236 
00237 /* cv_prev_word():
00238  * Find the previous word vi style
00239  */
00240 protected char *
00241 cv_prev_word(EditLine *el, char *p, char *low, int n, int (*wtest)(int))
00242 {
00243    int test;
00244 
00245    while (n--) {
00246       p--;
00247       /*
00248        * vi historically deletes with cb only the word preserving the
00249        * leading whitespace! This is not what 'b' does..
00250        */
00251       if (el->el_chared.c_vcmd.action != (DELETE|INSERT))
00252          while ((p > low) && isspace((unsigned char) *p))
00253             p--;
00254       test = (*wtest)((unsigned char) *p);
00255       while ((p >= low) && (*wtest)((unsigned char) *p) == test)
00256          p--;
00257       p++;
00258       while (isspace((unsigned char) *p))
00259          p++;
00260    }
00261 
00262    /* p now points where we want it */
00263    if (p < low)
00264       return (low);
00265    else
00266       return (p);
00267 }
00268 
00269 
00270 #ifdef notdef
00271 /* c__number():
00272  * Ignore character p points to, return number appearing after that.
00273  *    A '$' by itself means a big number; "$-" is for negative; '^' means 1.
00274  *    Return p pointing to last char used.
00275  */
00276 protected char *
00277 c__number(
00278     char *p,   /* character position */
00279     int *num,  /* Return value   */
00280     int dval)  /* dval is the number to subtract from like $-3 */
00281 {
00282    int i;
00283    int sign = 1;
00284 
00285    if (*++p == '^') {
00286       *num = 1;
00287       return (p);
00288    }
00289    if (*p == '$') {
00290       if (*++p != '-') {
00291          *num = 0x7fffffff;   /* Handle $ */
00292          return (--p);
00293       }
00294       sign = -1;        /* Handle $- */
00295       ++p;
00296    }
00297    for (i = 0; isdigit((unsigned char) *p); i = 10 * i + *p++ - '0')
00298       continue;
00299    *num = (sign < 0 ? dval - i : i);
00300    return (--p);
00301 }
00302 #endif
00303 
00304 /* cv_delfini():
00305  * Finish vi delete action
00306  */
00307 protected void
00308 cv_delfini(EditLine *el)
00309 {
00310    int size;
00311    int oaction;
00312 
00313    if (el->el_chared.c_vcmd.action & INSERT)
00314       el->el_map.current = el->el_map.key;
00315 
00316    oaction = el->el_chared.c_vcmd.action;
00317    el->el_chared.c_vcmd.action = NOP;
00318 
00319    if (el->el_chared.c_vcmd.pos == 0)
00320       return;
00321 
00322 
00323    if (el->el_line.cursor > el->el_chared.c_vcmd.pos) {
00324       size = (int) (el->el_line.cursor - el->el_chared.c_vcmd.pos);
00325       c_delbefore(el, size);
00326       el->el_line.cursor = el->el_chared.c_vcmd.pos;
00327       re_refresh_cursor(el);
00328    } else if (el->el_line.cursor < el->el_chared.c_vcmd.pos) {
00329       size = (int)(el->el_chared.c_vcmd.pos - el->el_line.cursor);
00330       c_delafter(el, size);
00331    } else {
00332       size = 1;
00333       c_delafter(el, size);
00334    }
00335    switch (oaction) {
00336    case DELETE|INSERT:
00337       el->el_chared.c_undo.action = DELETE|INSERT;
00338       break;
00339    case DELETE:
00340       el->el_chared.c_undo.action = INSERT;
00341       break;
00342    case NOP:
00343    case INSERT:
00344    default:
00345       EL_ABORT((el->el_errfile, "Bad oaction %d\n", oaction));
00346       break;
00347    }
00348 
00349 
00350    el->el_chared.c_undo.ptr = el->el_line.cursor;
00351    el->el_chared.c_undo.dsize = size;
00352 }
00353 
00354 
00355 #ifdef notdef
00356 /* ce__endword():
00357  * Go to the end of this word according to emacs
00358  */
00359 protected char *
00360 ce__endword(char *p, char *high, int n)
00361 {
00362    p++;
00363 
00364    while (n--) {
00365       while ((p < high) && isspace((unsigned char) *p))
00366          p++;
00367       while ((p < high) && !isspace((unsigned char) *p))
00368          p++;
00369    }
00370 
00371    p--;
00372    return (p);
00373 }
00374 #endif
00375 
00376 
00377 /* cv__endword():
00378  * Go to the end of this word according to vi
00379  */
00380 protected char *
00381 cv__endword(char *p, char *high, int n)
00382 {
00383    p++;
00384 
00385    while (n--) {
00386       while ((p < high) && isspace((unsigned char) *p))
00387          p++;
00388 
00389       if (isalnum((unsigned char) *p))
00390          while ((p < high) && isalnum((unsigned char) *p))
00391             p++;
00392       else
00393          while ((p < high) && !(isspace((unsigned char) *p) ||
00394              isalnum((unsigned char) *p)))
00395             p++;
00396    }
00397    p--;
00398    return (p);
00399 }
00400 
00401 /* ch_init():
00402  * Initialize the character editor
00403  */
00404 protected int
00405 ch_init(EditLine *el)
00406 {
00407    el->el_line.buffer      = (char *) el_malloc(EL_BUFSIZ);
00408    if (el->el_line.buffer == NULL)
00409       return (-1);
00410 
00411    (void) memset(el->el_line.buffer, 0, EL_BUFSIZ);
00412    el->el_line.cursor      = el->el_line.buffer;
00413    el->el_line.lastchar    = el->el_line.buffer;
00414    el->el_line.limit    = &el->el_line.buffer[EL_BUFSIZ - 2];
00415 
00416    el->el_chared.c_undo.buf   = (char *) el_malloc(EL_BUFSIZ);
00417    if (el->el_chared.c_undo.buf == NULL)
00418       return (-1);
00419    (void) memset(el->el_chared.c_undo.buf, 0, EL_BUFSIZ);
00420    el->el_chared.c_undo.action   = NOP;
00421    el->el_chared.c_undo.isize = 0;
00422    el->el_chared.c_undo.dsize = 0;
00423    el->el_chared.c_undo.ptr   = el->el_line.buffer;
00424 
00425    el->el_chared.c_vcmd.action   = NOP;
00426    el->el_chared.c_vcmd.pos   = el->el_line.buffer;
00427    el->el_chared.c_vcmd.ins   = el->el_line.buffer;
00428 
00429    el->el_chared.c_kill.buf   = (char *) el_malloc(EL_BUFSIZ);
00430    if (el->el_chared.c_kill.buf == NULL)
00431       return (-1);
00432    (void) memset(el->el_chared.c_kill.buf, 0, EL_BUFSIZ);
00433    el->el_chared.c_kill.mark  = el->el_line.buffer;
00434    el->el_chared.c_kill.last  = el->el_chared.c_kill.buf;
00435 
00436    el->el_map.current      = el->el_map.key;
00437 
00438    el->el_state.inputmode     = MODE_INSERT; /* XXX: save a default */
00439    el->el_state.doingarg      = 0;
00440    el->el_state.metanext      = 0;
00441    el->el_state.argument      = 1;
00442    el->el_state.lastcmd    = ED_UNASSIGNED;
00443 
00444    el->el_chared.c_macro.nline   = NULL;
00445    el->el_chared.c_macro.level   = -1;
00446    el->el_chared.c_macro.macro   = (char **) el_malloc(EL_MAXMACRO *
00447        sizeof(char *));
00448    if (el->el_chared.c_macro.macro == NULL)
00449       return (-1);
00450    return (0);
00451 }
00452 
00453 /* ch_reset():
00454  * Reset the character editor
00455  */
00456 protected void
00457 ch_reset(EditLine *el)
00458 {
00459    el->el_line.cursor      = el->el_line.buffer;
00460    el->el_line.lastchar    = el->el_line.buffer;
00461 
00462    el->el_chared.c_undo.action   = NOP;
00463    el->el_chared.c_undo.isize = 0;
00464    el->el_chared.c_undo.dsize = 0;
00465    el->el_chared.c_undo.ptr   = el->el_line.buffer;
00466 
00467    el->el_chared.c_vcmd.action   = NOP;
00468    el->el_chared.c_vcmd.pos   = el->el_line.buffer;
00469    el->el_chared.c_vcmd.ins   = el->el_line.buffer;
00470 
00471    el->el_chared.c_kill.mark  = el->el_line.buffer;
00472 
00473    el->el_map.current      = el->el_map.key;
00474 
00475    el->el_state.inputmode     = MODE_INSERT; /* XXX: save a default */
00476    el->el_state.doingarg      = 0;
00477    el->el_state.metanext      = 0;
00478    el->el_state.argument      = 1;
00479    el->el_state.lastcmd    = ED_UNASSIGNED;
00480 
00481    el->el_chared.c_macro.level   = -1;
00482 
00483    el->el_history.eventno     = 0;
00484 }
00485 
00486 /* ch_enlargebufs():
00487  * Enlarge line buffer to be able to hold twice as much characters.
00488  * Returns 1 if successful, 0 if not.
00489  */
00490 protected int
00491 ch_enlargebufs(el, addlen)
00492    EditLine *el;
00493    size_t addlen;
00494 {
00495    size_t sz, newsz;
00496    char *newbuffer, *oldbuf, *oldkbuf;
00497 
00498    sz = el->el_line.limit - el->el_line.buffer + EL_LEAVE;
00499    newsz = sz * 2;
00500    /*
00501     * If newly required length is longer than current buffer, we need
00502     * to make the buffer big enough to hold both old and new stuff.
00503     */
00504    if (addlen > sz) {
00505       while(newsz - sz < addlen)
00506          newsz *= 2;
00507    }
00508 
00509    /*
00510     * Reallocate line buffer.
00511     */
00512    newbuffer = el_realloc(el->el_line.buffer, newsz);
00513    if (!newbuffer)
00514       return 0;
00515 
00516    /* zero the newly added memory, leave old data in */
00517    (void) memset(&newbuffer[sz], 0, newsz - sz);
00518        
00519    oldbuf = el->el_line.buffer;
00520 
00521    el->el_line.buffer = newbuffer;
00522    el->el_line.cursor = newbuffer + (el->el_line.cursor - oldbuf);
00523    el->el_line.lastchar = newbuffer + (el->el_line.lastchar - oldbuf);
00524    el->el_line.limit  = &newbuffer[newsz - EL_LEAVE];
00525 
00526    /*
00527     * Reallocate kill buffer.
00528     */
00529    newbuffer = el_realloc(el->el_chared.c_kill.buf, newsz);
00530    if (!newbuffer)
00531       return 0;
00532 
00533    /* zero the newly added memory, leave old data in */
00534    (void) memset(&newbuffer[sz], 0, newsz - sz);
00535 
00536    oldkbuf = el->el_chared.c_kill.buf;
00537 
00538    el->el_chared.c_kill.buf = newbuffer;
00539    el->el_chared.c_kill.last = newbuffer +
00540                (el->el_chared.c_kill.last - oldkbuf);
00541    el->el_chared.c_kill.mark = el->el_line.buffer +
00542                (el->el_chared.c_kill.mark - oldbuf);
00543 
00544    /*
00545     * Reallocate undo buffer.
00546     */
00547    newbuffer = el_realloc(el->el_chared.c_undo.buf, newsz);
00548    if (!newbuffer)
00549       return 0;
00550 
00551    /* zero the newly added memory, leave old data in */
00552    (void) memset(&newbuffer[sz], 0, newsz - sz);
00553 
00554    el->el_chared.c_undo.ptr = el->el_line.buffer +
00555                 (el->el_chared.c_undo.ptr - oldbuf);
00556    el->el_chared.c_undo.buf = newbuffer;
00557    
00558    if (!hist_enlargebuf(el, sz, newsz))
00559       return 0;
00560 
00561    return 1;
00562 }
00563 
00564 /* ch_end():
00565  * Free the data structures used by the editor
00566  */
00567 protected void
00568 ch_end(EditLine *el)
00569 {
00570    el_free((ptr_t) el->el_line.buffer);
00571    el->el_line.buffer = NULL;
00572    el->el_line.limit = NULL;
00573    el_free((ptr_t) el->el_chared.c_undo.buf);
00574    el->el_chared.c_undo.buf = NULL;
00575    el_free((ptr_t) el->el_chared.c_kill.buf);
00576    el->el_chared.c_kill.buf = NULL;
00577    el_free((ptr_t) el->el_chared.c_macro.macro);
00578    el->el_chared.c_macro.macro = NULL;
00579    ch_reset(el);
00580 }
00581 
00582 
00583 /* el_insertstr():
00584  * Insert string at cursorI
00585  */
00586 public int
00587 el_insertstr(EditLine *el, const char *s)
00588 {
00589    size_t len;
00590 
00591    if ((len = strlen(s)) == 0)
00592       return (-1);
00593    if (el->el_line.lastchar + len >= el->el_line.limit) {
00594       if (!ch_enlargebufs(el, len))
00595          return (-1);
00596    }
00597 
00598    c_insert(el, (int)len);
00599    while (*s)
00600       *el->el_line.cursor++ = *s++;
00601    return (0);
00602 }
00603 
00604 
00605 /* el_deletestr():
00606  * Delete num characters before the cursor
00607  */
00608 public void
00609 el_deletestr(EditLine *el, int n)
00610 {
00611    if (n <= 0)
00612       return;
00613 
00614    if (el->el_line.cursor < &el->el_line.buffer[n])
00615       return;
00616 
00617    c_delbefore(el, n);     /* delete before dot */
00618    el->el_line.cursor -= n;
00619    if (el->el_line.cursor < el->el_line.buffer)
00620       el->el_line.cursor = el->el_line.buffer;
00621 }
00622 
00623 /* c_gets():
00624  * Get a string
00625  */
00626 protected int
00627 c_gets(EditLine *el, char *buf)
00628 {
00629    char ch;
00630    int len = 0;
00631 
00632    for (ch = 0; ch == 0;) {
00633       if (el_getc(el, &ch) != 1)
00634          return (ed_end_of_file(el, 0));
00635       switch (ch) {
00636       case 0010:  /* Delete and backspace */
00637       case 0177:
00638          if (len > 1) {
00639             *el->el_line.cursor-- = '\0';
00640             el->el_line.lastchar = el->el_line.cursor;
00641             buf[len--] = '\0';
00642          } else {
00643             el->el_line.buffer[0] = '\0';
00644             el->el_line.lastchar = el->el_line.buffer;
00645             el->el_line.cursor = el->el_line.buffer;
00646             return (CC_REFRESH);
00647          }
00648          re_refresh(el);
00649          ch = 0;
00650          break;
00651 
00652       case 0033:  /* ESC */
00653       case '\r':  /* Newline */
00654       case '\n':
00655          break;
00656 
00657       default:
00658          if (len >= EL_BUFSIZ)
00659             term_beep(el);
00660          else {
00661             buf[len++] = ch;
00662             *el->el_line.cursor++ = ch;
00663             el->el_line.lastchar = el->el_line.cursor;
00664          }
00665          re_refresh(el);
00666          ch = 0;
00667          break;
00668       }
00669    }
00670    buf[len] = ch;
00671    return (len);
00672 }
00673 
00674 
00675 /* c_hpos():
00676  * Return the current horizontal position of the cursor
00677  */
00678 protected int
00679 c_hpos(EditLine *el)
00680 {
00681    char *ptr;
00682 
00683    /*
00684     * Find how many characters till the beginning of this line.
00685     */
00686    if (el->el_line.cursor == el->el_line.buffer)
00687       return (0);
00688    else {
00689       for (ptr = el->el_line.cursor - 1;
00690            ptr >= el->el_line.buffer && *ptr != '\n';
00691            ptr--)
00692          continue;
00693       return (el->el_line.cursor - ptr - 1);
00694    }
00695 }

Generated on Thu Apr 16 06:27:30 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6