boot中的行编辑功能

来源:互联网 发布:画平面示意图软件 编辑:程序博客网 时间:2024/05/29 08:06

一 行编辑的由来

在和程序交互的过程中,用户输入难免会出错,如果不小心键入失误而不能修改,那该是一种很不友好的体验,于是行编辑出现了,用户在输入过程中可以删除,粘贴,移动光标,在光标处插入,可以翻看历史命令,只有当用户确认输入是正确无误,才按回车将输入结果提交给程序。

如果行编辑功能由用户程序来实现,那么将增加用户程序编程的难度,而且很多行编辑功能基本是相似的,于是linux就把它放在了内核中,也就是常说的行规程(line discipline), 终端类型不同,对应的line discipline也不一样,用户进程每次通过tty读取line discipline处理后的一行数据,另外用户也可以通过termios配置line discipline的行为,当然了这种配置是有限的,如果用户程序希望定制自己特有的行编辑功能,如一些编辑软件vi,shell等等,可以将tty设置为raw模式,这将跳过line discipline处理直接读取输入的原始值,而将行编辑功能交由特定的用户程序来处理,如readline库就是其中一个使用非常广泛的处理行编辑的开源库。

本文主要讲解boot中行编辑功能的实现,功能较简单。


二 行编辑的实现

#define CTRL(x) ((x)-'@')#define VKEY(x)(0x100|(x))#define VKEY_UPVKEY(1)#define VKEY_DOWNVKEY(2)#define VKEY_LEFTVKEY(3)#define VKEY_RIGHTVKEY(4)#define VKEY_PGUPVKEY(5)#define VKEY_PGDNVKEY(6)#define VKEY_HOMEVKEY(7)#define VKEY_ENDVKEY(8)#define VKEY_F1VKEY(0x10)#define VKEY_F2VKEY(0x11)#define VKEY_F3VKEY(0x12)#define VKEY_F4VKEY(0x13)#define VKEY_F5VKEY(0x14)#define VKEY_F6VKEY(0x15)#define VKEY_F7VKEY(0x16)#define VKEY_F8VKEY(0x17)#define VKEY_F9VKEY(0x18)#define VKEY_F10VKEY(0x19)#define VKEY_F11VKEY(0x1A)#define VKEY_F12VKEY(0x1B)#define VKEY_ESC27int console_readline(char *prompt,char *str,int maxlen){    int reading = 1;    int ch;    int idx = 0;    int len = 0;    int t;    int klen;    int recall;    int nosave = 0;    char *x;    char env[10];    console_inreadline++;    recall = console_nextsave;    if (console_savedlines[console_nextsave]) {KFREE(console_savedlines[console_nextsave]);console_savedlines[console_nextsave] = NULL;}    console_savedlines[console_nextsave] = strdup("");    if (prompt && *prompt) console_write(prompt,strlen(prompt));    POLL();    while (reading) {/* * If someone used console_log (above) or hit Control-C (below), * redisplay the prompt and the string we've got so far. */if (console_redisplay) {    if (prompt && *prompt) console_write(prompt,strlen(prompt));    console_write(str,idx);    console_redisplay = 0;    continue;    }/* * if nobody's typed anything, keep polling */if (console_status() == 0) {    POLL();    continue;    }/* * Get the char from the keyboard */ch = console_readkey();if (ch < 0) break;if (ch == 0) continue;/* * And dispatch it.  Lots of yucky character manipulation follows */switch (ch) {    case CTRL('C'):/* Ctrl-C - cancel line */console_write("^C\r\n",4);console_redisplay = 1;nosave = 1;idx = 0;len = 0;break;    case 0x7f:/* Backspace, Delete */    case CTRL('H'):if (idx > 0) {    nosave = 0;    len--;    idx--;    console_write("\b",1);    if (len != idx) {for (t = idx; t < len; t++) str[t] = str[t+1];console_write(&str[idx],len-idx);console_whiteout(1);console_backspace(len-idx);}    else {console_whiteout(1);}    }break;    case CTRL('D'):/* Ctrl-D */if ((idx > 0) && (len != idx)) {    nosave = 0;    len--;    for (t = idx; t < len; t++) str[t] = str[t+1];    console_write(&str[idx],len-idx);    console_whiteout(1);    console_backspace(len-idx);    }break;    case CTRL('B'):/* cursor left */    case VKEY_LEFT:if (idx > 0) {    idx--;    console_backspace(1);    }break;    case CTRL('F'):/* cursor right */    case VKEY_RIGHT:if (idx < len) {    console_write(&str[idx],1);    idx++;    }break;    case CTRL('A'):/* cursor to BOL */console_backspace(idx);idx = 0;break;    case CTRL('E'):/* cursor to EOL */if (len-idx > 0) console_write(&str[idx],len-idx);idx = len;break;    case CTRL('K'):/* Kill to EOL */if (idx != len) {    str[len] = '\0';    if (console_killbuffer) KFREE(console_killbuffer);    console_killbuffer = strdup(&str[idx]);    console_whiteout(len-idx);    len = idx;    nosave = 0;    }break;    case CTRL('Y'):/* Yank killed data */if (console_killbuffer == NULL) break;klen = strlen(console_killbuffer);if (klen == 0) break;if (len + klen > maxlen) break;nosave = 0;for (t = len + klen; t > idx; t--) {    str[t-1] = str[t-klen-1];    }for (t = 0; t < klen; t++) str[t+idx] = console_killbuffer[t];len += klen;console_write(&str[idx],len-idx);idx += klen;console_backspace(len-idx-1);break;    case CTRL('R'):/* Redisplay line */str[len] = 0;console_crlf();if (prompt && *prompt) console_write(prompt,strlen(prompt));console_write(str,len);console_backspace(len-idx);break;    case CTRL('U'):/* Cancel line */console_backspace(idx);console_eraseeol();if (len > 0) nosave = 1;idx = 0;len = 0;break;    case CTRL('M'):/* terminate */    case CTRL('J'):console_crlf();reading = 0;break;    case CTRL('P'):    case VKEY_UP:/* recall previous line */t = recall;t--;if (t < 0) t = MAXSAVELINES-1;if (console_savedlines[t] == NULL) break;recall = t;console_backspace(idx);strcpy(str,console_savedlines[recall]);len = idx = strlen(console_savedlines[recall]);console_eraseeol();console_write(str,len);nosave = 1;break;    case CTRL('N'):    case VKEY_DOWN:/* Recall next line */t = recall; t++;if (t == MAXSAVELINES) t = 0;if (console_savedlines[t] == NULL) break;recall = t;console_backspace(idx);strcpy(str,console_savedlines[recall]);len = idx = strlen(console_savedlines[recall]);console_eraseeol();console_write(str,len);nosave = 1;break;    case VKEY_F1:    case VKEY_F2:    case VKEY_F3:    case VKEY_F4:    case VKEY_F5:    case VKEY_F6:    case VKEY_F7:    case VKEY_F8:    case VKEY_F9:    case VKEY_F10:    case VKEY_F11:    case VKEY_F12:sprintf(env,"F%d",ch-VKEY_F1+1);x = env_getenv(env);if (x) {    console_backspace(idx);    strcpy(str,x);    idx = len = strlen(str);    console_eraseeol();    console_write(str,len);    console_crlf();    reading = 0;    nosave = 1;    }/* * If F12 is undefined, it means "repeat last command" */if (ch == VKEY_F12) {    t = recall;    t--;    if (t < 0) t = MAXSAVELINES-1;    if (console_savedlines[t] == NULL) break;    recall = t;    console_backspace(idx);    strcpy(str,console_savedlines[recall]);    len = idx = strlen(console_savedlines[recall]);    console_eraseeol();    console_write(str,len);    console_crlf();    reading = 0;    nosave = 1;    }break;    default:/* insert character */if (ch >= ' ') {    if (idx < (maxlen-1)) {nosave = 0;for (t = len; t > idx; t--) {    str[t] = str[t-1];    }str[idx] = ch;len++;if (len != idx) {    if(g_enable_printf) /*------skyworth add*/    {    console_write(&str[idx],len-idx);    }    console_backspace(len-idx-1);    }idx++;}    }break;    }}    POLL();    console_inreadline--;    str[len] = 0;    if ((len != 0) && !nosave) {if (console_savedlines[console_nextsave]) {    KFREE(console_savedlines[console_nextsave]);    }console_savedlines[console_nextsave] = strdup(str);console_nextsave++;if (console_nextsave == MAXSAVELINES) console_nextsave = 0;}    return len;}int console_readkey(void){    unsigned char ch;    int num;    GETCHAR(ch);    switch (ch) {case VKEY_ESC:    GETCHAR(ch);    switch (ch) {case 'O':    GETCHAR(ch);    switch (ch) {case 'P':    return VKEY_F1;case 'Q':    return VKEY_F2;case 'R':    return VKEY_F3;case 'S':    return VKEY_F4;}    return (int)ch;case '[':    GETCHAR(ch);    if ((ch >= '0') && (ch <= '9')) {console_readnum(&num,&ch);if (ch == '~') {    switch (num) {case 2:    return VKEY_HOME;case 3:    return VKEY_PGUP;case 5:    if (console_mode == XTERM) return VKEY_PGUP;    return VKEY_END;case 6:    if (console_mode == XTERM) return VKEY_PGDN;    return VKEY_PGDN;case 11:    return VKEY_F1;case 12:    return VKEY_F2;case 13:    return VKEY_F3;case 14:    return VKEY_F4;case 15:    return VKEY_F5;case 17:    return VKEY_F6;case 18:    return VKEY_F7;case 19:    return VKEY_F8;case 20:    return VKEY_F9;case 21:    return VKEY_F10;case 23:    return VKEY_F11;case 24:    return VKEY_F12;}    return (int)ch;    }}    else {switch (ch) {    case 'A':return VKEY_UP;    case 'B':return VKEY_DOWN;    case 'C':return VKEY_RIGHT;    case 'D':return VKEY_LEFT;    case 'F':return VKEY_HOME;    case 'H':return VKEY_END;    default:return (int) ch;    }}default:    return (int)ch;}default:    return (int) ch;}}static void console_readnum(int *num,unsigned char *ch){    int total = 0;    for (;;) {total = (total * 10) + (*ch - '0');while (console_read(ch,1) != 1) { POLL(); }if (!((*ch >= '0') && (*ch <= '9'))) break;}    *num = total;}static void console_backspace(int n){    int t;    for (t = 0; t < n; t++) console_write("\b",1);}static void console_whiteout(int n){    int t;    for (t = 0; t < n; t++) console_write(" ",1);    for (t = 0; t < n; t++) console_write("\b",1);}static void console_eraseeol(void){    console_write("\033[K",3);}static void console_crlf(void){    console_write("\r\n",2);}

上述代码我就不做过多解释了,一看就会明白,这里主要提一下console_readkey(), 为啥返回的是Int型而不是char型呢,这主要涉及到转义序列, 普通字符直接转化为int返回了

len为输入的总的字符数,idx为当前光标所在的位置,console_write()用于回显和光标的移动
原创粉丝点击