Annotation of coherent/d/usr/bin/elvis/vi.c, revision 1.1.1.1

1.1       root        1: /* vi.c */
                      2: 
                      3: /* Author:
                      4:  *     Steve Kirkendall
                      5:  *     16820 SW Tallac Way
                      6:  *     Beaverton, OR 97006
                      7:  *     [email protected], or ...uunet!tektronix!psueea!jove!kirkenda
                      8:  */
                      9: 
                     10: 
                     11: #include "config.h"
                     12: #include <ctype.h>
                     13: #include "vi.h"
                     14: 
                     15: 
                     16: 
                     17: /* This array describes what each key does */
                     18: #define NO_FUNC                (MARK (*)())0
                     19: #define NO_ARGS                0
                     20: #define CURSOR_COUNT   1
                     21: #define CURSOR         2
                     22: #define CURSOR_CNT_KEY 3
                     23: #define CURSOR_MOVED   4
                     24: #define CURSOR_EOL     5
                     25: #define ZERO           6
                     26: #define DIGIT          7
                     27: #define CURSOR_TEXT    8
                     28: #define CURSOR_CNT_CMD 9
                     29: #define KEYWORD                10
                     30: #define NO_FLAGS       0x00
                     31: #define        MVMT            0x01    /* this is a movement command */
                     32: #define PTMV           0x02    /* this can be *part* of a movement command */
                     33: #define FRNT           0x04    /* after move, go to front of line */
                     34: #define INCL           0x08    /* include last char when used with c/d/y */
                     35: #define LNMD           0x10    /* use line mode of c/d/y */
                     36: #define NCOL           0x20    /* this command can't change the column# */
                     37: #define NREL           0x40    /* this is "non-relative" -- set the '' mark */
                     38: #define SDOT           0x80    /* set the "dot" variables, for the "." cmd */
                     39: static struct keystru
                     40: {
                     41:        MARK    (*func)();      /* the function to run */
                     42:        uchar   args;           /* description of the args needed */
                     43:        uchar   flags;          /* other stuff */
                     44: }
                     45:        vikeys[] =
                     46: {
                     47: /* NUL not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     48: /* ^A  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     49: /* ^B  page backward   */      {m_scroll,      CURSOR_CNT_CMD, FRNT},
                     50: /* ^C  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     51: /* ^D  scroll dn 1/2page*/     {m_scroll,      CURSOR_CNT_CMD, NCOL},
                     52: /* ^E  scroll up       */      {m_scroll,      CURSOR_CNT_CMD, NCOL},
                     53: /* ^F  page forward    */      {m_scroll,      CURSOR_CNT_CMD, FRNT},
                     54: /* ^G  show file status        */      {v_status,      NO_ARGS,        NO_FLAGS},
                     55: /* ^H  move left, like h*/     {m_left,        CURSOR_COUNT,   MVMT},
                     56: /* ^I  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     57: /* ^J  move down       */      {m_updnto,      CURSOR_CNT_CMD, MVMT|LNMD},
                     58: /* ^K  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     59: /* ^L  redraw screen   */      {v_redraw,      NO_ARGS,        NO_FLAGS},
                     60: /* ^M  mv front next ln */     {m_updnto,      CURSOR_CNT_CMD, MVMT|FRNT|LNMD},
                     61: /* ^N  move down       */      {m_updnto,      CURSOR_CNT_CMD, MVMT|LNMD},
                     62: /* ^O  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     63: /* ^P  move up         */      {m_updnto,      CURSOR_CNT_CMD, MVMT|LNMD},
                     64: /* ^Q  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     65: /* ^R  redraw screen   */      {v_redraw,      NO_ARGS,        NO_FLAGS},
                     66: /* ^S  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     67: /* ^T  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     68: /* ^U  scroll up 1/2page*/     {m_scroll,      CURSOR_CNT_CMD, NCOL},
                     69: /* ^V  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     70: /* ^W  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     71: /* ^X  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     72: /* ^Y  scroll down     */      {m_scroll,      CURSOR_CNT_CMD, NCOL},
                     73: /* ^Z  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     74: /* ESC not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     75: /* ^\  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     76: /* ^]  keyword is tag  */      {v_tag,         KEYWORD,        NO_FLAGS},
                     77: /* ^^  previous file   */      {v_switch,      CURSOR,         NO_FLAGS},
                     78: /* ^_  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     79: /* SPC move right,like l*/     {m_right,       CURSOR_COUNT,   MVMT},
                     80: /*  !  run thru filter */      {v_filter,      CURSOR_MOVED,   FRNT|LNMD|INCL},
                     81: /*  "  select cut buffer*/     {v_selcut,      CURSOR_CNT_KEY, PTMV},
                     82: #ifndef NO_EXTENSIONS
                     83: /*  #  increment number        */      {v_increment,   KEYWORD,        SDOT},
                     84: #else
                     85: /*  #  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     86: #endif
                     87: /*  $  move to rear    */      {m_rear,        CURSOR,         MVMT|INCL},
                     88: /*  %  move to match   */      {m_match,       CURSOR,         MVMT|INCL},
                     89: /*  &  repeat subst    */      {v_again,       CURSOR_MOVED,   SDOT|NCOL|LNMD|INCL},
                     90: /*  '  move to a mark  */      {m_tomark,      CURSOR_CNT_KEY, MVMT|FRNT|NREL|LNMD|INCL},
                     91: #ifndef NO_SENTENCE
                     92: /*  (  mv back sentence        */      {m_bsentence,   CURSOR_COUNT,   MVMT},
                     93: /*  )  mv fwd sentence */      {m_fsentence,   CURSOR_COUNT,   MVMT},
                     94: #else
                     95: /*  (  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     96: /*  )  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                     97: #endif
                     98: #ifndef NO_ERRLIST
                     99: /*  *  errlist         */      {v_errlist,     CURSOR,         FRNT|NREL},
                    100: #else
                    101: /*  *  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    102: #endif
                    103: /*  +  mv front next ln */     {m_updnto,      CURSOR_CNT_CMD, MVMT|FRNT|LNMD},
                    104: #ifndef NO_CHARSEARCH
                    105: /*  ,  reverse [fFtT] cmd*/    {m__ch,         CURSOR_CNT_CMD, MVMT|INCL},
                    106: #else
                    107: /*  ,  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    108: #endif
                    109: /*  -  mv front prev ln        */      {m_updnto,      CURSOR_CNT_CMD, MVMT|FRNT|LNMD},
                    110: /*  .  special...      */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    111: /*  /  forward search  */      {m_fsrch,       CURSOR_TEXT,    MVMT|NREL},
                    112: /*  0  part of count?  */      {NO_FUNC,       ZERO,           MVMT|PTMV},
                    113: /*  1  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    114: /*  2  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    115: /*  3  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    116: /*  4  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    117: /*  5  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    118: /*  6  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    119: /*  7  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    120: /*  8  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    121: /*  9  part of count   */      {NO_FUNC,       DIGIT,          PTMV},
                    122: /*  :  run single EX cmd*/     {v_1ex,         CURSOR_TEXT,    NO_FLAGS},
                    123: #ifndef NO_CHARSEARCH
                    124: /*  ;  repeat [fFtT] cmd*/     {m__ch,         CURSOR_CNT_CMD, MVMT|INCL},
                    125: #else
                    126: /*  ;  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    127: #endif
                    128: /*  <  shift text left */      {v_lshift,      CURSOR_MOVED,   SDOT|FRNT|LNMD|INCL},
                    129: /*  =  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    130: /*  >  shift text right        */      {v_rshift,      CURSOR_MOVED,   SDOT|FRNT|LNMD|INCL},
                    131: /*  ?  backward search */      {m_bsrch,       CURSOR_TEXT,    MVMT|NREL},
                    132: #ifndef NO_AT
                    133: /*  @  execute a cutbuf */     {v_at,          CURSOR_CNT_KEY, NO_FLAGS},
                    134: #else
                    135: /*  @  undefined       */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    136: #endif
                    137: /*  A  append at EOL   */      {v_insert,      CURSOR_CNT_CMD, SDOT},
                    138: /*  B  move back Word  */      {m_bword,       CURSOR_CNT_CMD, MVMT},
                    139: /*  C  change to EOL   */      {v_change,      CURSOR_EOL,     SDOT},
                    140: /*  D  delete to EOL   */      {v_delete,      CURSOR_EOL,     SDOT},
                    141: /*  E  move end of Word        */      {m_eword,       CURSOR_CNT_CMD, MVMT|INCL},
                    142: #ifndef NO_CHARSEARCH
                    143: /*  F  move bk to char */      {m_Fch,         CURSOR_CNT_KEY, MVMT|INCL},
                    144: #else
                    145: /*  F  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    146: #endif
                    147: /*  G  move to line #  */      {m_updnto,      CURSOR_CNT_CMD, MVMT|NREL|LNMD|FRNT|INCL},
                    148: /*  H  move to row     */      {m_row,         CURSOR_CNT_CMD, MVMT|FRNT},
                    149: /*  I  insert at front */      {v_insert,      CURSOR_CNT_CMD, SDOT},
                    150: /*  J  join lines      */      {v_join,        CURSOR_COUNT,   SDOT},
                    151: #ifndef NO_EXTENSIONS
                    152: /*  K  look up keyword */      {v_keyword,     KEYWORD,        NO_FLAGS},
                    153: #else
                    154: /*  K  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    155: #endif
                    156: /*  L  move to last row        */      {m_row,         CURSOR_CNT_CMD, MVMT|FRNT},
                    157: /*  M  move to mid row */      {m_row,         CURSOR_CNT_CMD, MVMT|FRNT},
                    158: /*  N  reverse prev srch*/     {m_Nsrch,       CURSOR,         MVMT},
                    159: /*  O  insert above line*/     {v_insert,      CURSOR_CNT_CMD, SDOT},
                    160: /*  P  paste before    */      {v_paste,       CURSOR_CNT_CMD, NO_FLAGS},
                    161: /*  Q  quit to EX mode */      {v_quit,        NO_ARGS,        NO_FLAGS},
                    162: /*  R  overtype                */      {v_overtype,    CURSOR,         SDOT},
                    163: /*  S  change line     */      {v_change,      CURSOR_MOVED,   SDOT},
                    164: #ifndef NO_CHARSEARCH
                    165: /*  T  move bk to char */      {m_Tch,         CURSOR_CNT_KEY, MVMT|INCL},
                    166: #else
                    167: /*  T  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    168: #endif
                    169: /*  U  undo whole line */      {v_undoline,    CURSOR,         FRNT},
                    170: /*  V  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    171: /*  W  move forward Word*/     {m_fword,       CURSOR_CNT_CMD, MVMT},
                    172: /*  X  delete to left  */      {v_xchar,       CURSOR_CNT_CMD, SDOT},
                    173: /*  Y  yank text       */      {v_yank,        CURSOR_MOVED,   NCOL},
                    174: /*  Z  save file & exit        */      {v_xit,         CURSOR_CNT_KEY, NO_FLAGS},
                    175: /*  [  move back section*/     {m_bsection,    CURSOR_CNT_KEY, MVMT|LNMD|NREL},
                    176: /*  \  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    177: /*  ]  move fwd section */     {m_fsection,    CURSOR_CNT_KEY, MVMT|LNMD|NREL},
                    178: /*  ^  move to front   */      {m_front,       CURSOR,         MVMT},
                    179: /*  _  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    180: /*  `  move to mark    */      {m_tomark,      CURSOR_CNT_KEY, MVMT|NREL},
                    181: /*  a  append at cursor        */      {v_insert,      CURSOR_CNT_CMD, SDOT},
                    182: /*  b  move back word  */      {m_bword,       CURSOR_CNT_CMD, MVMT},
                    183: /*  c  change text     */      {v_change,      CURSOR_MOVED,   SDOT},
                    184: /*  d  delete op       */      {v_delete,      CURSOR_MOVED,   SDOT|NCOL},
                    185: /*  e  move end word   */      {m_eword,       CURSOR_CNT_CMD, MVMT|INCL},
                    186: #ifndef NO_CHARSEARCH
                    187: /*  f  move fwd for char*/     {m_fch,         CURSOR_CNT_KEY, MVMT|INCL},
                    188: #else
                    189: /*  f  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    190: #endif
                    191: /*  g  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    192: /*  h  move left       */      {m_left,        CURSOR_COUNT,   MVMT},
                    193: /*  i  insert at cursor        */      {v_insert,      CURSOR_CNT_CMD, SDOT},
                    194: /*  j  move down       */      {m_updnto,      CURSOR_CNT_CMD, MVMT|NCOL|LNMD},
                    195: /*  k  move up         */      {m_updnto,      CURSOR_CNT_CMD, MVMT|NCOL|LNMD},
                    196: /*  l  move right      */      {m_right,       CURSOR_COUNT,   MVMT},
                    197: /*  m  define a mark   */      {v_mark,        CURSOR_CNT_KEY, NO_FLAGS},
                    198: /*  n  repeat prev srch        */      {m_nsrch,       CURSOR,         MVMT},
                    199: /*  o  insert below line*/     {v_insert,      CURSOR_CNT_CMD, SDOT},
                    200: /*  p  paste after     */      {v_paste,       CURSOR_CNT_CMD, NO_FLAGS},
                    201: /*  q  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    202: /*  r  replace chars   */      {v_replace,     CURSOR_CNT_KEY, SDOT},
                    203: /*  s  subst N chars   */      {v_subst,       CURSOR_COUNT,   SDOT},
                    204: #ifndef NO_CHARSEARCH
                    205: /*  t  move fwd to char        */      {m_tch,         CURSOR_CNT_KEY, MVMT|INCL},
                    206: #else
                    207: /*  t  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    208: #endif
                    209: /*  u  undo            */      {v_undo,        CURSOR,         NO_FLAGS},
                    210: /*  v  not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    211: /*  w  move fwd word   */      {m_fword,       CURSOR_CNT_CMD, MVMT},
                    212: /*  x  delete character        */      {v_xchar,       CURSOR_CNT_CMD, SDOT},
                    213: /*  y  yank text       */      {v_yank,        CURSOR_MOVED,   NCOL},
                    214: /*  z  adjust scrn row */      {m_z,           CURSOR_CNT_KEY, NCOL},
                    215: /*  {  back paragraph  */      {m_bparagraph,  CURSOR_COUNT,   MVMT|LNMD},
                    216: /*  |  move to column  */      {m_tocol,       CURSOR_COUNT,   NREL},
                    217: /*  }  fwd paragraph   */      {m_fparagraph,  CURSOR_COUNT,   MVMT|LNMD},
                    218: /*  ~  upper/lowercase */      {v_ulcase,      CURSOR_COUNT,   SDOT},
                    219: /* DEL not defined     */      {NO_FUNC,       NO_ARGS,        NO_FLAGS},
                    220: };
                    221: 
                    222: 
                    223: 
                    224: void vi()
                    225: {
                    226:        REG int                 key;    /* keystroke from user */
                    227:        long                    count;  /* numeric argument to some functions */
                    228:        REG struct keystru      *keyptr;/* pointer to vikeys[] element */
                    229:        MARK                    tcurs;  /* temporary cursor */
                    230:        int                     prevkey;/* previous key, if d/c/y/</>/! */
                    231:        MARK                    range;  /* start of range for d/c/y/</>/! */
                    232:        char                    text[100];
                    233:        int                     dotkey; /* last "key" of a change */
                    234:        int                     dotpkey;/* last "prevkey" of a change */
                    235:        int                     dotkey2;/* last extra "getkey()" of a change */
                    236:        int                     dotcnt; /* last "count" of a change */
                    237:        int                     firstkey;
                    238:        REG int                 i;
                    239: 
                    240:        /* tell the redraw() function to start from scratch */
                    241:        redraw(MARK_UNSET, FALSE);
                    242: 
                    243: #ifdef lint
                    244:        /* lint says that "range" might be used before it is set.  This
                    245:         * can't really happen due to the way "range" and "prevkey" are used,
                    246:         * but lint doesn't know that.  This line is here ONLY to keep lint
                    247:         * happy.
                    248:         */
                    249:        range = 0L;
                    250: #endif
                    251: 
                    252:        /* safeguard against '.' with no previous command */
                    253:        dotkey = 0;
                    254: 
                    255:        /* go immediately into insert mode, if ":set inputmode" */
                    256:        firstkey = 0;
                    257: #ifndef NO_EXTENSIONS
                    258:        if (*o_inputmode)
                    259:        {
                    260:                firstkey = 'i';
                    261:        }
                    262: #endif
                    263: 
                    264:        /* Repeatedly handle VI commands */
                    265:        for (count = 0, prevkey = '\0'; mode == MODE_VI; )
                    266:        {
                    267:                /* if we've moved off the undoable line, then we can't undo it at all */
                    268:                if (markline(cursor) != U_line)
                    269:                {
                    270:                        U_line = 0L;
                    271:                }
                    272: 
                    273:                /* report any changes from the previous command */
                    274:                if (rptlines >= *o_report)
                    275:                {
                    276:                        redraw(cursor, FALSE);
                    277:                        msg("%ld lines %s", rptlines, rptlabel);
                    278:                }
                    279:                rptlines = 0L;
                    280: 
                    281:                /* get the next command key.  It must be ASCII */
                    282:                if (firstkey)
                    283:                {
                    284:                        key = firstkey;
                    285:                        firstkey = 0;
                    286:                }
                    287:                else
                    288:                {
                    289:                        do
                    290:                        {
                    291:                                key = getkey(WHEN_VICMD);
                    292:                        } while (key < 0 || key > 127);
                    293:                }
                    294: 
                    295:                /* change cw and cW commands to ce and cE, respectively */
                    296:                /* (Why?  because the real vi does it that way!) */
                    297:                if (prevkey == 'c')
                    298:                {
                    299:                        if (key == 'w')
                    300:                                key = 'e';
                    301:                        else if (key == 'W')
                    302:                                key = 'E';
                    303: 
                    304:                        /* wouldn't work right at the end of a word unless we
                    305:                         * backspace one character before doing the move.  This
                    306:                         * will fix most cases.  !!! but not all.
                    307:                         */
                    308:                        if (markidx(cursor) > 0 && (key == 'e' || key == 'E'))
                    309:                        {
                    310:                                cursor--;
                    311:                        }
                    312:                }
                    313: 
                    314:                /* look up the structure describing this command */
                    315:                keyptr = &vikeys[key];
                    316: 
                    317:                /* if we're in the middle of a d/c/y/</>/! command, reject
                    318:                 * anything but movement or a doubled version like "dd".
                    319:                 */
                    320:                if (prevkey && key != prevkey && !(keyptr->flags & (MVMT|PTMV)))
                    321:                {
                    322:                        beep();
                    323:                        prevkey = 0;
                    324:                        count = 0;
                    325:                        continue;
                    326:                }
                    327: 
                    328:                /* set the "dot" variables, if we're supposed to */
                    329:                if ((keyptr->flags & SDOT)
                    330:                 || (prevkey && vikeys[prevkey].flags & SDOT))
                    331:                {
                    332:                        dotkey = key;
                    333:                        dotpkey = prevkey;
                    334:                        dotkey2 = '\0';
                    335:                        dotcnt = count;
                    336: 
                    337:                        /* remember the line before any changes are made */
                    338:                        if (U_line != markline(cursor))
                    339:                        {
                    340:                                U_line = markline(cursor);
                    341:                                strcpy(U_text, fetchline(U_line));
                    342:                        }
                    343:                }
                    344: 
                    345:                /* if this is "." then set other vars from the "dot" vars */
                    346:                if (key == '.')
                    347:                {
                    348:                        key = dotkey;
                    349:                        keyptr = &vikeys[key];
                    350:                        prevkey = dotpkey;
                    351:                        if (prevkey)
                    352:                        {
                    353:                                range = cursor;
                    354:                        }
                    355:                        if (count == 0)
                    356:                        {
                    357:                                count = dotcnt;
                    358:                        }
                    359:                        doingdot = TRUE;
                    360: 
                    361:                        /* remember the line before any changes are made */
                    362:                        if (U_line != markline(cursor))
                    363:                        {
                    364:                                U_line = markline(cursor);
                    365:                                strcpy(U_text, fetchline(U_line));
                    366:                        }
                    367:                }
                    368:                else
                    369:                {
                    370:                        doingdot = FALSE;
                    371:                }
                    372: 
                    373:                /* process the key as a command */
                    374:                tcurs = cursor;
                    375:                switch (keyptr->args)
                    376:                {
                    377:                  case ZERO:
                    378:                        if (count == 0)
                    379:                        {
                    380:                                tcurs = cursor & ~(BLKSIZE - 1);
                    381:                                break;
                    382:                        }
                    383:                        /* else fall through & treat like other digits... */
                    384: 
                    385:                  case DIGIT:
                    386:                        count = count * 10 + key - '0';
                    387:                        break;
                    388: 
                    389:                  case KEYWORD:
                    390:                        /* if not on a keyword, fail */
                    391:                        pfetch(markline(cursor));
                    392:                        key = markidx(cursor);
                    393:                        if (isascii(ptext[key])
                    394:                                && !isalnum(ptext[key]) && ptext[key] != '_')
                    395:                        {
                    396:                                tcurs = MARK_UNSET;
                    397:                                break;
                    398:                        }
                    399: 
                    400:                        /* find the start of the keyword */
                    401:                        while (key > 0 && (!isascii(ptext[key-1]) ||
                    402:                        isalnum(ptext[key - 1]) || ptext[key - 1] == '_'))
                    403:                        {
                    404:                                key--;
                    405:                        }
                    406:                        tcurs = (cursor & ~(BLKSIZE - 1)) + key;
                    407: 
                    408:                        /* copy it into a buffer, and NUL-terminate it */
                    409:                        i = 0;
                    410:                        do
                    411:                        {
                    412:                                text[i++] = ptext[key++];
                    413:                        } while (!isascii(ptext[key]) || isalnum(ptext[key]) || ptext[key] == '_');
                    414:                        text[i] = '\0';
                    415: 
                    416:                        /* call the function */
                    417:                        tcurs = (*keyptr->func)(text, tcurs, count);
                    418:                        count = 0L;
                    419:                        break;
                    420: 
                    421:                  case NO_ARGS:
                    422:                        if (keyptr->func)
                    423:                        {
                    424:                                (*keyptr->func)();
                    425:                        }
                    426:                        else
                    427:                        {
                    428:                                beep();
                    429:                        }
                    430:                        count = 0L;
                    431:                        break;
                    432:        
                    433:                  case CURSOR_COUNT:
                    434:                        tcurs = (*keyptr->func)(cursor, count);
                    435:                        count = 0L;
                    436:                        break;
                    437:        
                    438:                  case CURSOR:
                    439:                        tcurs = (*keyptr->func)(cursor);
                    440:                        count = 0L;
                    441:                        break;
                    442: 
                    443:                  case CURSOR_CNT_KEY:
                    444:                        if (doingdot)
                    445:                        {
                    446:                                tcurs = (*keyptr->func)(cursor, count, dotkey2);
                    447:                        }
                    448:                        else
                    449:                        {
                    450:                                /* get a key */
                    451:                                i = getkey(0);
                    452:                                if (i == '\033') /* ESC */
                    453:                                {
                    454:                                        count = 0;
                    455:                                        tcurs = MARK_UNSET;
                    456:                                        break; /* exit from "case CURSOR_CNT_KEY" */
                    457:                                }
                    458:                                else if (i == ('V' & 0x1f))
                    459:                                {
                    460:                                        i = getkey(0);
                    461:                                }
                    462: 
                    463:                                /* if part of an SDOT command, remember it */
                    464:                                 if (keyptr->flags & SDOT
                    465:                                 || (prevkey && vikeys[prevkey].flags & SDOT))
                    466:                                {
                    467:                                        dotkey2 = i;
                    468:                                }
                    469: 
                    470:                                /* do it */
                    471:                                tcurs = (*keyptr->func)(cursor, count, i);
                    472:                        }
                    473:                        count = 0L;
                    474:                        break;
                    475:        
                    476:                  case CURSOR_MOVED:
                    477:                        /* '&' and uppercase keys always act like doubled */
                    478:                        if (key == '&' || isascii(key) && isupper(key))
                    479:                        {
                    480:                                prevkey = key;
                    481:                        }
                    482: 
                    483:                        if (prevkey)
                    484:                        {
                    485:                                /* doubling up a command */
                    486:                                if (!count) count = 1L;
                    487:                                range = cursor;
                    488:                                tcurs = range + MARK_AT_LINE(count - 1L);
                    489:                                count = 0L;
                    490:                        }
                    491:                        else
                    492:                        {
                    493:                                prevkey = key;
                    494:                                range = cursor;
                    495:                                key = -1; /* so we don't think we doubled yet */
                    496:                        }
                    497:                        break;
                    498: 
                    499:                  case CURSOR_EOL:
                    500:                        prevkey = key;
                    501:                        /* a zero-length line needs special treatment */
                    502:                        pfetch(markline(cursor));
                    503:                        if (plen == 0)
                    504:                        {
                    505:                                /* act on a zero-length section of text */
                    506:                                range = tcurs = cursor;
                    507:                                key = ' ';
                    508:                        }
                    509:                        else
                    510:                        {
                    511:                                /* act like CURSOR_MOVED with '$' movement */
                    512:                                range = cursor;
                    513:                                tcurs = m_rear(cursor, 1L);
                    514:                                key = '$';
                    515:                        }
                    516:                        count = 0L;
                    517:                        keyptr = &vikeys[key];
                    518:                        break;
                    519: 
                    520:                  case CURSOR_TEXT:
                    521:                        do
                    522:                        {       
                    523:                                text[0] = key;
                    524:                                if (vgets(key, text + 1, sizeof text - 1) >= 0)
                    525:                                {
                    526:                                        /* reassure user that <CR> was hit */
                    527:                                        qaddch('\r');
                    528:                                        refresh();
                    529: 
                    530:                                        /* call the function with the text */
                    531:                                        tcurs = (*keyptr->func)(cursor, text);
                    532:                                }
                    533:                                else
                    534:                                {
                    535:                                        if (exwrote || mode == MODE_COLON)
                    536:                                        {
                    537:                                                redraw(MARK_UNSET, FALSE);
                    538:                                        }
                    539:                                        mode = MODE_VI;
                    540:                                }
                    541:                        } while (mode == MODE_COLON);
                    542:                        count = 0L;
                    543:                        break;
                    544: 
                    545:                  case CURSOR_CNT_CMD:
                    546:                        tcurs = (*keyptr->func)(cursor, count, key);
                    547:                        count = 0L;
                    548:                        break;
                    549:                }
                    550: 
                    551:                /* if that command took us out of vi mode, then exit the loop
                    552:                 * NOW, without tweaking the cursor or anything.  This is very
                    553:                 * important when mode == MODE_QUIT.
                    554:                 */
                    555:                if (mode != MODE_VI)
                    556:                {
                    557:                        break;
                    558:                }
                    559: 
                    560:                /* now move the cursor, as appropriate */
                    561:                if (keyptr->args == CURSOR_MOVED)
                    562:                {
                    563:                        /* the < and > keys have FRNT,
                    564:                         * but it shouldn't be applied yet
                    565:                         */
                    566:                        tcurs = adjmove(cursor, tcurs, 0);
                    567:                }
                    568:                else
                    569:                {
                    570:                        tcurs = adjmove(cursor, tcurs, (int)keyptr->flags);
                    571:                }
                    572: 
                    573:                /* was that the end of a d/c/y/</>/! command? */
                    574:                if (prevkey && (prevkey == key || (keyptr->flags & MVMT)) && count == 0L)
                    575:                {
                    576:                        /* if the movement command failed, cancel operation */
                    577:                        if (tcurs == MARK_UNSET)
                    578:                        {
                    579:                                prevkey = 0;
                    580:                                count = 0;
                    581:                                continue;
                    582:                        }
                    583: 
                    584:                        /* make sure range=front and tcurs=rear.  Either way,
                    585:                         * leave cursor=range since that's where we started.
                    586:                         */
                    587:                        cursor = range;
                    588:                        if (tcurs < range)
                    589:                        {
                    590:                                range = tcurs;
                    591:                                tcurs = cursor;
                    592:                        }
                    593: 
                    594: 
                    595:                        /* adjust for line mode & inclusion of last char/line */
                    596:                        i = (keyptr->flags | vikeys[prevkey].flags);
                    597:                        if (key == prevkey)
                    598:                        {
                    599:                                i |= (INCL|LNMD);
                    600:                        }
                    601:                        switch (i & (INCL|LNMD))
                    602:                        {
                    603:                          case INCL:
                    604:                                tcurs++;
                    605:                                break;
                    606: 
                    607:                          case INCL|LNMD:
                    608:                                tcurs += BLKSIZE;
                    609:                                /* fall through... */
                    610: 
                    611:                          case LNMD:
                    612:                                range &= ~(BLKSIZE - 1);
                    613:                                tcurs &= ~(BLKSIZE - 1);
                    614:                                break;
                    615:                        }
                    616: 
                    617:                        /* run the function */
                    618:                        tcurs = (*vikeys[prevkey].func)(range, tcurs);
                    619:                        (void)adjmove(cursor, cursor, 0);
                    620:                        cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags);
                    621: 
                    622:                        /* cleanup */
                    623:                        prevkey = 0;
                    624:                }
                    625:                else if (!prevkey)
                    626:                {
                    627:                        cursor = tcurs;
                    628:                }
                    629:        }
                    630: }
                    631: 
                    632: /* This function adjusts the MARK value that they return; here we make sure
                    633:  * it isn't past the end of the line, and that the column hasn't been
                    634:  * *accidentally* changed.
                    635:  */
                    636: MARK adjmove(old, new, flags)
                    637:        MARK            old;    /* the cursor position before the command */
                    638:        REG MARK        new;    /* the cursor position after the command */
                    639:        int             flags;  /* various flags regarding cursor mvmt */
                    640: {
                    641:        static int      colno;  /* the column number that we want */
                    642:        REG char        *text;  /* used to scan through the line's text */
                    643:        REG int         i;
                    644: 
                    645: #ifdef DEBUG
                    646:        watch();
                    647: #endif
                    648: 
                    649:        /* if the command failed, bag it! */
                    650:        if (new == MARK_UNSET)
                    651:        {
                    652:                beep();
                    653:                return old;
                    654:        }
                    655: 
                    656:        /* if this is a non-relative movement, set the '' mark */
                    657:        if (flags & NREL)
                    658:        {
                    659:                mark[26] = old;
                    660:        }
                    661: 
                    662:        /* make sure it isn't past the end of the file */
                    663:        if (markline(new) < 1)
                    664:        {
                    665:                new = MARK_FIRST;
                    666:        }
                    667:        else if (markline(new) > nlines)
                    668:        {
                    669:                new = MARK_LAST;
                    670:        }
                    671: 
                    672:        /* fetch the new line */
                    673:        pfetch(markline(new));
                    674: 
                    675:        /* move to the front, if we're supposed to */
                    676:        if (flags & FRNT)
                    677:        {
                    678:                new = m_front(new, 1L);
                    679:        }
                    680: 
                    681:        /* change the column#, or change the mark to suit the column# */
                    682:        if (!(flags & NCOL))
                    683:        {
                    684:                /* change the column# */
                    685:                i = markidx(new);
                    686:                if (i == BLKSIZE - 1)
                    687:                {
                    688:                        new &= ~(BLKSIZE - 1);
                    689:                        if (plen > 0)
                    690:                        {
                    691:                                new += plen - 1;
                    692:                        }
                    693:                        colno = BLKSIZE * 8; /* one heck of a big colno */
                    694:                }
                    695:                else if (plen > 0)
                    696:                {
                    697:                        if (i >= plen)
                    698:                        {
                    699:                                new = (new & ~(BLKSIZE - 1)) + plen - 1;
                    700:                        }
                    701:                        colno = idx2col(new, ptext, FALSE);
                    702:                }
                    703:                else
                    704:                {
                    705:                        new &= ~(BLKSIZE - 1);
                    706:                        colno = 0;
                    707:                }
                    708:        }
                    709:        else
                    710:        {
                    711:                /* adjust the mark to get as close as possible to column# */
                    712:                for (i = 0, text = ptext; i <= colno && *text; text++)
                    713:                {
                    714:                        if (*text == '\t' && !*o_list)
                    715:                        {
                    716:                                i += *o_tabstop - (i % *o_tabstop);
                    717:                        }
                    718:                        else if (UCHAR(*text) < ' ' || *text == 127)
                    719:                        {
                    720:                                i += 2;
                    721:                        }
                    722: #ifndef NO_CHARATTR
                    723:                        else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2])
                    724:                        {
                    725:                                text += 2; /* plus one more in "for()" stmt */
                    726:                        }
                    727: #endif
                    728:                        else
                    729:                        {
                    730:                                i++;
                    731:                        }
                    732:                }
                    733:                if (text > ptext)
                    734:                {
                    735:                        text--;
                    736:                }
                    737:                new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext);
                    738:        }
                    739: 
                    740:        return new;
                    741: }
                    742: 
                    743: 
                    744: #ifdef DEBUG
                    745: watch()
                    746: {
                    747:        static wasset;
                    748: 
                    749:        if (*origname)
                    750:        {
                    751:                wasset = TRUE;
                    752:        }
                    753:        else if (wasset)
                    754:        {
                    755:                msg("origname was clobbered");
                    756:                endwin();
                    757:                abort();
                    758:        }
                    759: 
                    760:        if (nlines == 0)
                    761:        {
                    762:                msg("nlines=0");
                    763:                endwin();
                    764:                abort();
                    765:        }
                    766: }
                    767: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.