📄 cmdedit.c
字号:
free(matches[j]); matches[j]=0; } j=num_matches; num_matches = 0; for(i=0; i<j; i++) if(matches[i]) { if(!strcmp(matches[i], "./")) matches[i][1]=0; else if(!strcmp(matches[i], "../")) matches[i][2]=0; matches[num_matches++]=matches[i]; } } /* Did we find exactly one match? */ if (!matches || num_matches > 1) { char *tmp1; beep(); if (!matches) return; /* not found */ /* sort */ qsort(matches, num_matches, sizeof(char *), match_compare); /* find minimal match */ tmp = xstrdup(matches[0]); for (tmp1 = tmp; *tmp1; tmp1++) for (len_found = 1; len_found < num_matches; len_found++) if (matches[len_found][(tmp1 - tmp)] != *tmp1) { *tmp1 = 0; break; } if (*tmp == 0) { /* have unique */ free(tmp); return; } } else { /* one match */ tmp = matches[0]; /* for next completion current found */ *lastWasTab = FALSE; } len_found = strlen(tmp); /* have space to placed match? */ if ((len_found - strlen(matchBuf) + len) < BUFSIZ) { /* before word for match */ command_ps[cursor - recalc_pos] = 0; /* save tail line */ strcpy(matchBuf, command_ps + cursor); /* add match */ strcat(command_ps, tmp); /* add tail */ strcat(command_ps, matchBuf); /* back to begin word for match */ input_backward(recalc_pos); /* new pos */ recalc_pos = cursor + len_found; /* new len */ len = strlen(command_ps); /* write out the matched command */ redraw(cmdedit_y, len - recalc_pos); } if (tmp != matches[0]) free(tmp); } else { /* Ok -- the last char was a TAB. Since they * just hit TAB again, print a list of all the * available choices... */ if (matches && num_matches > 0) { int i, col, l; int sav_cursor = cursor; /* change goto_new_line() */ /* Go to the next line */ goto_new_line(); for (i = 0, col = 0; i < num_matches; i++) { l = strlen(matches[i]); if (l < 14) l = 14; printf("%-14s ", matches[i]); if ((l += 2) > 16) while (l % 16) { putchar(' '); l++; } col += l; col -= (col / cmdedit_termw) * cmdedit_termw; if (col > 60 && matches[i + 1] != NULL) { putchar('\n'); col = 0; } } /* Go to the next line and rewrite */ putchar('\n'); redraw(0, len - sav_cursor); } }}#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */static void get_previous_history(struct history **hp, struct history *p){ if ((*hp)->s) free((*hp)->s); (*hp)->s = xstrdup(command_ps); *hp = p;}static inline void get_next_history(struct history **hp){ get_previous_history(hp, (*hp)->n);}enum { ESC = 27, DEL = 127,};/* * This function is used to grab a character buffer * from the input file descriptor and allows you to * a string with full command editing (sortof like * a mini readline). * * The following standard commands are not implemented: * ESC-b -- Move back one word * ESC-f -- Move forward one word * ESC-d -- Delete back one word * ESC-h -- Delete forward one word * CTL-t -- Transpose two characters * * Furthermore, the "vi" command editing keys are not implemented. * */ int cmdedit_read_input(char *prompt, char command[BUFSIZ]){ int break_out = 0; int lastWasTab = FALSE; unsigned char c = 0; struct history *hp = his_end; /* prepare before init handlers */ cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ len = 0; command_ps = command; getTermSettings(0, (void *) &initial_settings); memcpy(&new_settings, &initial_settings, sizeof(struct termios)); new_settings.c_lflag &= ~ICANON; /* unbuffered input */ /* Turn off echoing and CTRL-C, so we can trap it */ new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG);#ifndef linux /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; /* Turn off CTRL-C, so we can trap it */# ifndef _POSIX_VDISABLE# define _POSIX_VDISABLE '\0'# endif new_settings.c_cc[VINTR] = _POSIX_VDISABLE; #endif command[0] = 0; setTermSettings(0, (void *) &new_settings); handlers_sets |= SET_RESET_TERM; /* Now initialize things */ cmdedit_init(); /* Print out the command prompt */ parse_prompt(prompt); while (1) { fflush(stdout); /* buffered out to fast */ if (safe_read(0, &c, 1) < 1) /* if we can't read input then exit */ goto prepare_to_die; switch (c) { case '\n': case '\r': /* Enter */ goto_new_line(); break_out = 1; break; case 1: /* Control-a -- Beginning of line */ input_backward(cursor); break; case 2: /* Control-b -- Move back one character */ input_backward(1); break; case 3: /* Control-c -- stop gathering input */ goto_new_line(); command[0] = 0; len = 0; lastWasTab = FALSE; put_prompt(); break; case 4: /* Control-d -- Delete one character, or exit * if the len=0 and no chars to delete */ if (len == 0) {prepare_to_die:#if !defined(CONFIG_ASH) printf("exit"); goto_new_line(); /* cmdedit_reset_term() called in atexit */ exit(EXIT_SUCCESS);#else break_out = -1; /* for control stoped jobs */ break;#endif } else { input_delete(); } break; case 5: /* Control-e -- End of line */ input_end(); break; case 6: /* Control-f -- Move forward one character */ input_forward(); break; case '\b': case DEL: /* Control-h and DEL */ input_backspace(); break; case '\t':#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION input_tab(&lastWasTab);#endif break; case 11: /* Control-k -- clear to end of line */ *(command + cursor) = 0; len = cursor; printf("\033[J"); break; case 12: { /* Control-l -- clear screen */ int old_cursor = cursor; printf("\033[H"); redraw(0, len-old_cursor); } break; case 14: /* Control-n -- Get next command in history */ if (hp && hp->n && hp->n->s) { get_next_history(&hp); goto rewrite_line; } else { beep(); } break; case 16: /* Control-p -- Get previous command from history */ if (hp && hp->p) { get_previous_history(&hp, hp->p); goto rewrite_line; } else { beep(); } break; case 21: /* Control-U -- Clear line before cursor */ if (cursor) { strcpy(command, command + cursor); redraw(cmdedit_y, len -= cursor); } break; case ESC:{ /* escape sequence follows */ if (safe_read(0, &c, 1) < 1) goto prepare_to_die; /* different vt100 emulations */ if (c == '[' || c == 'O') { if (safe_read(0, &c, 1) < 1) goto prepare_to_die; } switch (c) {#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION case '\t': /* Alt-Tab */ input_tab(&lastWasTab); break;#endif case 'A': /* Up Arrow -- Get previous command from history */ if (hp && hp->p) { get_previous_history(&hp, hp->p); goto rewrite_line; } else { beep(); } break; case 'B': /* Down Arrow -- Get next command in history */ if (hp && hp->n && hp->n->s) { get_next_history(&hp); goto rewrite_line; } else { beep(); } break; /* Rewrite the line with the selected history item */ rewrite_line: /* change command */ len = strlen(strcpy(command, hp->s)); /* redraw and go to end line */ redraw(cmdedit_y, 0); break; case 'C': /* Right Arrow -- Move forward one character */ input_forward(); break; case 'D': /* Left Arrow -- Move back one character */ input_backward(1); break; case '3': /* Delete */ input_delete(); break; case '1': case 'H': /* Home (Ctrl-A) */ input_backward(cursor); break; case '4': case 'F': /* End (Ctrl-E) */ input_end(); break; default: if (!(c >= '1' && c <= '9')) c = 0; beep(); } if (c >= '1' && c <= '9') do if (safe_read(0, &c, 1) < 1) goto prepare_to_die; while (c != '~'); break; } default: /* If it's regular input, do the normal thing */#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT /* Control-V -- Add non-printable symbol */ if (c == 22) { if (safe_read(0, &c, 1) < 1) goto prepare_to_die; if (c == 0) { beep(); break; } } else#endif if (!Isprint(c)) /* Skip non-printable characters */ break; if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ break; len++; if (cursor == (len - 1)) { /* Append if at the end of the line */ *(command + cursor) = c; *(command + cursor + 1) = 0; cmdedit_set_out_char(0); } else { /* Insert otherwise */ int sc = cursor; memmove(command + sc + 1, command + sc, len - sc); *(command + sc) = c; sc++; /* rewrite from cursor */ input_end(); /* to prev x pos + 1 */ input_backward(cursor - sc); } break; } if (break_out) /* Enter is the command terminator, no more input. */ break; if (c != '\t') lastWasTab = FALSE; } setTermSettings(0, (void *) &initial_settings); handlers_sets &= ~SET_RESET_TERM; /* Handle command history log */ if (len) { /* no put empty line */ struct history *h = his_end; char *ss; ss = xstrdup(command); /* duplicate */ if (h == 0) { /* No previous history -- this memory is never freed */ h = his_front = xmalloc(sizeof(struct history)); h->n = xmalloc(sizeof(struct history)); h->p = NULL; h->s = ss; h->n->p = h; h->n->n = NULL; h->n->s = NULL; his_end = h->n; history_counter++; } else { /* Add a new history command -- this memory is never freed */ h->n = xmalloc(sizeof(struct history)); h->n->p = h; h->n->n = NULL; h->n->s = NULL; h->s = ss; his_end = h->n; /* After max history, remove the oldest command */ if (history_counter >= MAX_HISTORY) { struct history *p = his_front->n; p->p = NULL; free(his_front->s); free(his_front); his_front = p; } else { history_counter++; } }#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) num_ok_lines++;#endif } if(break_out>0) { command[len++] = '\n'; /* set '\n' */ command[len] = 0; }#if defined(CONFIG_FEATURE_CLEAN_UP) && defined(CONFIG_FEATURE_COMMAND_TAB_COMPLETION) input_tab(0); /* strong free */#endif#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) free(cmdedit_prompt);#endif cmdedit_reset_term(); return len;}#endif /* CONFIG_FEATURE_COMMAND_EDITING */#ifdef TESTconst char *applet_name = "debug stuff usage";const char *memory_exhausted = "Memory exhausted";#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT#include <locale.h>#endifint main(int argc, char **argv){ char buff[BUFSIZ]; char *prompt =#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";#else "% ";#endif#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT setlocale(LC_ALL, "");#endif while(1) { int l; cmdedit_read_input(prompt, buff); l = strlen(buff); if(l==0) break; if(l > 0 && buff[l-1] == '\n') buff[l-1] = 0; printf("*** cmdedit_read_input() returned line =%s=\n", buff); } printf("*** cmdedit_read_input() detect ^C\n"); return 0;}#endif /* TEST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -