summaryrefslogblamecommitdiffstats
path: root/main/common/ledit_vt100.c
blob: 0298a58d5756294b1b2a8d363914c43b4ba810b3 (plain) (tree)
1
2
3
4


                                                                           
  



















                                                                           
                                                                  
















                                                                































                                                                               













                                                                          















































































































                                                                   











                                                                    
                                                 




                                  
                                                  




             








                                    
     













                                  
     







                              
      




                             




                 










                                




               


                  




               

















                                             




                 













                                








                                                        











                                              


                           
                                                         





                                                        


















                                 




              


















                                 





                                                                



                              
  
 


                              














                                             







                                    
          
 



                             









                                                                  
            
 


                                        
 




                        
 



                                                             
 


                        
 
                                         


      
/**************************************************************************
 *
 * Copyright (c) 2013 Alcatel-Lucent
 *
 * Alcatel Lucent licenses this file to You under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.  A copy of the License is contained the
 * file LICENSE at the top level of this repository.
 * You may also obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **************************************************************************
 *
 * ledit_vt.c:
 *
 *  This is an alternative to lineedit.c.  For those unfamiliar with the
 *  KSH VI-like editing, this is certainly a more intuitive mechanism
 *  for CLI edit.  It uses the VT100 terminal arrow keys for basic
 *  line and history traversal...
 *
 *   - UP/DOWN move through the CLI history.
 *   - RIGHT/LEFT move through the current line.
 *   - DEL deletes character that cursor is on top of.
 *
 * Original author:     Ed Sutter (ed.sutter@alcatel-lucent.com)
 *
 */

#include "config.h"
#if INCLUDE_LINEEDIT
#include <ctype.h>
#include "genlib.h"
#include "stddefs.h"
#include "cli.h"

#define GOT_NUTTIN  0
#define GOT_ESCAPE  1
#define GOT_BRACKET 2

#define HMAX            16
#define ESC             0x1B
#define CTLC            0x03
#define BACKSPACE       0x08

#define OPEN_BRACKET    '['
#define VT100_DEL       0x7f
#define VT100_UP        'A'
#define VT100_DOWN      'B'
#define VT100_RIGHT     'C'
#define VT100_LEFT      'D'

#define EDITFILELINE    1
#define EDITCMDLINE     2

static int      stridx;         /* store index */
static int      shwidx;         /* show index */
static int      srchidx;        /* search index */
static int      lastsize;       /* size of last command */
static char     curChar;        /* latest input character */
static char     *curPos;        /* current position on command line */
static char     *startOfLine;   /* start of command line */
static int      lineLen;        /* length of line */
static char     cmdhistory[HMAX+1][CMDLINESIZE];/* array for command history */

static void     shownext(void), showprev(void), ldelete(void), backspace(void);
static void     newchar(char c);
static void     backup(int count);

/* lineeditor():
 * This is a simpler version of lineeditor() (as found in lineedit.c).
 * It does not have the capability of the vi-like version; however, for
 * those not familiar with ksh, this one is probably a lot more intuitive.
 *
 * The line is modified in place so, if successful, the function
 * returns the same pointer but with its contents modified based
 * on the editor commands executed.
 * If failure, the function returns (char *)0.
 */
static char *
lineeditor(char *line_to_edit,int type)
{
    int state;

    if(type == EDITCMDLINE) {
        if(getchar() != OPEN_BRACKET) {
            putchar('\n');
            *line_to_edit = 0;
            return((char *)0);
        }
    }

    startOfLine = line_to_edit;
    curPos = line_to_edit;
    while(*curPos != ESC) {
        curPos++;
    }

    *curPos = 0;    /* Remove the escape character from the line */
    lineLen = (ulong)curPos - (ulong)startOfLine;
    if(lineLen > 0) {
        curPos--;
        putstr(" \b\b");
    } else {
        putstr(" \b");
    }

    state = GOT_BRACKET;
    lastsize = 0;
    shwidx = stridx;
    srchidx = stridx;
    while(1) {
        curChar = getchar();
        switch(curChar) {
        case CTLC:
            putchar('\n');
            *line_to_edit = 0;
            return((char *)0);
        case VT100_UP:
            if(state == GOT_BRACKET) {
                if(type == EDITCMDLINE) {
                    showprev();
                }
                state = GOT_NUTTIN;
            } else {
                newchar(curChar);
            }
            break;
        case VT100_DOWN:
            if(state == GOT_BRACKET) {
                if(type == EDITCMDLINE) {
                    shownext();
                }
                state = GOT_NUTTIN;
            } else {
                newchar(curChar);
            }
            break;
        case VT100_RIGHT:
            if(state == GOT_BRACKET) {
                if(curPos < startOfLine+lineLen) {
                    putchar(*curPos);
                    curPos++;
                }
                state = GOT_NUTTIN;
            } else {
                newchar(curChar);
            }
            break;
        case VT100_LEFT:
            if(state == GOT_BRACKET) {
                if(curPos > startOfLine) {
                    putchar('\b');
                    curPos--;
                }
                state = GOT_NUTTIN;
            } else {
                newchar(curChar);
            }
            break;
        case OPEN_BRACKET:
            if(state == GOT_ESCAPE) {
                state = GOT_BRACKET;
            } else {
                newchar(curChar);
            }
            break;
        case ESC:
            state = GOT_ESCAPE;
            break;
        case VT100_DEL:
            if(curPos != (startOfLine + lineLen)) {
                ldelete();
            }
            break;
        case '\b':
            if(curPos > startOfLine) {
                backspace();
            }
            break;
        case '\n':
        case '\r':
            putchar('\n');
            if(lineLen == 0) {
                return((char *)0);
            }
            *(char *)(startOfLine + lineLen) = '\0';
            return(startOfLine);
        default:
            newchar(curChar);
            break;
        }
    }
    return((char *)0);
}

/* line_edit() & file_line_edit():
 * These two functions are simply front-ends to the lineeditor()
 * function.  The line_edit() function is called by the command line
 * interface and file_line_edit() is called by the flash file editor
 * to provide a convenient single line editor when modifying a file.
 */

char *
line_edit(char *line_to_edit)
{
    return(lineeditor(line_to_edit,EDITCMDLINE));
}

char *
file_line_edit(char *line_to_edit)
{
    return(lineeditor(line_to_edit,EDITFILELINE));
}

static void
ldelete(void)
{
    char    *eol, *now;
    int cnt;

    if(lineLen == 0) {
        return;
    }
    cnt = 0;
    eol = startOfLine + lineLen - 1;
    now = curPos;
#if 0
    if(curPos != eol) {
        while(curPos <= eol) {
            *curPos = *(curPos+1);
            curPos++;
            cnt++;
        }
        putbytes(now,cnt-1);
        putchar(' ');
        backup((int)cnt);
    } else {
        putstr(" \b\b");
        *eol = '\0';
        now--;
    }
#else
    while(curPos <= eol) {
        *curPos = *(curPos+1);
        curPos++;
        cnt++;
    }
    putbytes(now,cnt-1);
    putchar(' ');
    backup((int)cnt);
#endif
    curPos = now;
    lineLen--;
    if(lineLen == 0) {
        curPos = startOfLine;
    }
}

static void
backup(int count)
{
    char    string[CMDLINESIZE];
    int i;

    if(count <= 0) {
        return;
    }
    *string = '\0';
    for(i=0; i<count; i++) {
        strcat(string,"\b");
    }
    putbytes(string,count);
}

static void
backspace(void)
{
    curPos--;
    putchar('\b');
    ldelete();
}

static void
newchar(char c)
{
    char    string[CMDLINESIZE];

    if(curPos == startOfLine + lineLen) {
        putchar(c);
        *curPos++ = c;
        lineLen++;
    } else {
        if(!isprint(c)) {
            return;
        }
        putchar(c);
        putstr(curPos);
        backup((int)strlen(curPos));
        strncpy(string,curPos,CMDLINESIZE-1);
        *curPos++ = c;
        strcpy(curPos,string);
        lineLen++;
    }
}

static void
lerase(int count)
{
    char    string[CMDLINESIZE];
    int i;

    if(count <= 0) {
        return;
    }
    *string = '\0';
    for(i=0; i<count; i++) {
        strcat(string," ");
    }
    for(i=0; i<count; i++) {
        strcat(string,"\b");
    }
    putbytes(string,count*2);
}

/* showdone():
 * Used as common completion code for the showprev() and
 * shownext() functions below.
 */
static void
showdone(int idx)
{
    if(idx == HMAX) {
        printf("History buffer empty.\007\n");
        return;
    }

    backup((int)(curPos - startOfLine));
    lineLen = strlen(cmdhistory[shwidx]);
    putbytes(cmdhistory[shwidx],lineLen);
    lerase((int)(lastsize-lineLen));
    strcpy(startOfLine,cmdhistory[shwidx]);
    curPos = startOfLine + lineLen;
    lastsize = lineLen;
}

/* showprev() & shownext():
 * Show previous or next command in history list based on
 * the current position in the list being established by
 * the shwidx variable.
 */
static void
showprev(void)
{
    int i;

    if(shwidx == 0) {
        shwidx = HMAX-1;
    } else {
        shwidx--;
    }

    for(i=0; i<HMAX; i++) {
        if(*cmdhistory[shwidx]) {
            break;
        }
        if(shwidx == 0) {
            shwidx = HMAX-1;
        } else {
            shwidx--;
        }
    }
    showdone(i);
}

static void
shownext(void)
{
    int i;

    if(shwidx == HMAX-1) {
        shwidx = 0;
    } else {
        shwidx++;
    }

    for(i=0; i<HMAX; i++) {
        if(*cmdhistory[shwidx]) {
            break;
        }
        if(shwidx == HMAX) {
            shwidx = 0;
        } else {
            shwidx++;
        }
    }
    showdone(i);
}

/* History():
 * Command used at the CLI to allow the user to dump the content
 * of the history buffer.
 */
char *HistoryHelp[] = {
    "Display command history",
    "",
    0,
};

int
History(int argc,char *argv[])
{
    int i;

    for(i=stridx; i<HMAX; i++) {
        if(cmdhistory[i][0]) {
            printf("%s\n",cmdhistory[i]);
        }
    }
    if(stridx) {
        for(i=0; i<stridx; i++) {
            if(cmdhistory[i][0]) {
                printf("%s\n",cmdhistory[i]);
            }
        }
    }
    return(CMD_SUCCESS);
}

/* historyinit():
 * Initialize the command history...
 */
void
historyinit()
{
    int i;

    shwidx = stridx = 0;
    for(i=0; i<HMAX; i++) {
        cmdhistory[i][0] = 0;
    }
}

/* historylog():
 * This function is called by the CLI retrieval code to store away
 * the command in the CLI history list, a circular queue
 * (size HMAX) of most recent commands.
 */
void
historylog(char *cmdline)
{
    int idx;

    if(strlen(cmdline) >= CMDLINESIZE) {
        return;
    }

    if(stridx == 0) {
        idx = HMAX-1;
    } else {
        idx = stridx -1;
    }

    /* don't store if this command is same as last command */
    if(strcmp(cmdhistory[idx],cmdline) == 0) {
        return;
    }

    if(stridx == HMAX) {
        stridx = 0;
    }

    strcpy(cmdhistory[stridx++],cmdline);
}

#endif