📄 readline.c
字号:
size_t len, from_len; size_t size; if (*cmd == '&' && (from == NULL || to == NULL)) continue; else if (*cmd == 's') { delim = *(++cmd), cmd++; size = 16; what = realloc(from, size); if (what == NULL) { free(from); return 0; } len = 0; for (; *cmd && *cmd != delim; cmd++) { if (*cmd == '\\' && cmd[1] == delim) cmd++; if (len >= size) { char *nwhat; nwhat = realloc(what, (size <<= 1)); if (nwhat == NULL) { free(what); return 0; } what = nwhat; } what[len++] = *cmd; } what[len] = '\0'; from = what; if (*what == '\0') { free(what); if (search) { from = strdup(search); if (from == NULL) return 0; } else { from = NULL; return (-1); } } cmd++; /* shift after delim */ if (!*cmd) continue; size = 16; with = realloc(to, size); if (with == NULL) { free(to); return -1; } len = 0; from_len = strlen(from); for (; *cmd && *cmd != delim; cmd++) { if (len + from_len + 1 >= size) { char *nwith; size += from_len + 1; nwith = realloc(with, size); if (nwith == NULL) { free(with); return -1; } with = nwith; } if (*cmd == '&') { /* safe */ (void)strcpy(&with[len], from); len += from_len; continue; } if (*cmd == '\\' && (*(cmd + 1) == delim || *(cmd + 1) == '&')) cmd++; with[len++] = *cmd; } with[len] = '\0'; to = with; } aptr = _rl_compat_sub(tmp, from, to, g_on); if (aptr) { free(tmp); tmp = aptr; } g_on = 0; } } *result = tmp; return (p_on? 2:1);}/* * csh-style history expansion */inthistory_expand(char *str, char **output){ int ret = 0; size_t idx, i, size; char *tmp, *result; if (h == NULL || e == NULL) rl_initialize(); if (history_expansion_char == 0) { *output = strdup(str); return(0); } *output = NULL; if (str[0] == history_subst_char) { /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ *output = malloc(strlen(str) + 4 + 1); if (*output == NULL) return 0; (*output)[0] = (*output)[1] = history_expansion_char; (*output)[2] = ':'; (*output)[3] = 's'; (void)strcpy((*output) + 4, str); str = *output; } else { *output = strdup(str); if (*output == NULL) return 0; }#define ADD_STRING(what, len) \ { \ if (idx + len + 1 > size) { \ char *nresult = realloc(result, (size += len + 1));\ if (nresult == NULL) { \ free(*output); \ return 0; \ } \ result = nresult; \ } \ (void)strncpy(&result[idx], what, len); \ idx += len; \ result[idx] = '\0'; \ } result = NULL; size = idx = 0; for (i = 0; str[i];) { int qchar, loop_again; size_t len, start, j; qchar = 0; loop_again = 1; start = j = i;loop: for (; str[j]; j++) { if (str[j] == '\\' && str[j + 1] == history_expansion_char) { (void)strcpy(&str[j], &str[j + 1]); continue; } if (!loop_again) { if (isspace((unsigned char) str[j]) || str[j] == qchar) break; } if (str[j] == history_expansion_char && !strchr(history_no_expand_chars, str[j + 1]) && (!history_inhibit_expansion_function || (*history_inhibit_expansion_function)(str, (int)j) == 0)) break; } if (str[j] && loop_again) { i = j; qchar = (j > 0 && str[j - 1] == '"' )? '"':0; j++; if (str[j] == history_expansion_char) j++; loop_again = 0; goto loop; } len = i - start; tmp = &str[start]; ADD_STRING(tmp, len); if (str[i] == '\0' || str[i] != history_expansion_char) { len = j - i; tmp = &str[i]; ADD_STRING(tmp, len); if (start == 0) ret = 0; else ret = 1; break; } ret = _history_expand_command (str, i, (j - i), &tmp); if (ret > 0 && tmp) { len = strlen(tmp); ADD_STRING(tmp, len); free(tmp); } i = j; } /* ret is 2 for "print only" option */ if (ret == 2) { add_history(result);#ifdef GDB_411_HACK /* gdb 4.11 has been shipped with readline, where */ /* history_expand() returned -1 when the line */ /* should not be executed; in readline 2.1+ */ /* it should return 2 in such a case */ ret = -1;#endif } free(*output); *output = result; return (ret);}/** Return a string consisting of arguments of "str" from "start" to "end".*/char *history_arg_extract(int start, int end, const char *str){ size_t i, len, max; char **arr, *result; arr = history_tokenize(str); if (!arr) return(NULL); if (arr && *arr == NULL) { free(arr); return(NULL); } for (max = 0; arr[max]; max++) continue; max--; if (start == '$') start = max; if (end == '$') end = max; if (end < 0) end = max + end + 1; if (start < 0) start = end; if (start < 0 || end < 0 || start > max || end > max || start > end) return(NULL); for (i = start, len = 0; i <= end; i++) len += strlen(arr[i]) + 1; len++; result = malloc(len); if (result == NULL) return NULL; for (i = start, len = 0; i <= end; i++) { (void)strcpy(result + len, arr[i]); len += strlen(arr[i]); if (i < end) result[len++] = ' '; } result[len] = 0; for (i = 0; arr[i]; i++) free(arr[i]); free(arr); return(result);}/* * Parse the string into individual tokens, * similar to how shell would do it. */char **history_tokenize(const char *str){ int size = 1, idx = 0, i, start; size_t len; char **result = NULL, *temp, delim = '\0'; for (i = 0; str[i];) { while (isspace((unsigned char) str[i])) i++; start = i; for (; str[i];) { if (str[i] == '\\') { if (str[i+1] != '\0') i++; } else if (str[i] == delim) delim = '\0'; else if (!delim && (isspace((unsigned char) str[i]) || strchr("()<>;&|$", str[i]))) break; else if (!delim && strchr("'`\"", str[i])) delim = str[i]; if (str[i]) i++; } if (idx + 2 >= size) { char **nresult; size <<= 1; nresult = realloc(result, size * sizeof(char *)); if (nresult == NULL) { free(result); return NULL; } result = nresult; } len = i - start; temp = malloc(len + 1); if (temp == NULL) { for (i = 0; i < idx; i++) free(result[i]); free(result); return NULL; } (void)strncpy(temp, &str[start], len); temp[len] = '\0'; result[idx++] = temp; result[idx] = NULL; if (str[i]) i++; } return (result);}/* * limit size of history record to ``max'' events */voidstifle_history(int max){ HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); if (history(h, &ev, H_SETSIZE, max) == 0) max_input_history = max;}/* * "unlimit" size of history - set the limit to maximum allowed int value */intunstifle_history(void){ HistEvent ev; int omax; history(h, &ev, H_SETSIZE, INT_MAX); omax = max_input_history; max_input_history = INT_MAX; return (omax); /* some value _must_ be returned */}inthistory_is_stifled(void){ /* cannot return true answer */ return (max_input_history != INT_MAX);}/* * read history from a file given */intread_history(const char *filename){ HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); return (history(h, &ev, H_LOAD, filename) == -1);}/* * write history to a file given */intwrite_history(const char *filename){ HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); return (history(h, &ev, H_SAVE, filename) == -1);}/* * returns history ``num''th event * * returned pointer points to static variable */HIST_ENTRY *history_get(int num){ static HIST_ENTRY she; HistEvent ev; int curr_num; if (h == NULL || e == NULL) rl_initialize(); /* save current position */ if (history(h, &ev, H_CURR) != 0) return (NULL); curr_num = ev.num; /* start from most recent */ if (history(h, &ev, H_FIRST) != 0) return (NULL); /* error */ /* look backwards for event matching specified offset */ if (history(h, &ev, H_NEXT_EVENT, num)) return (NULL); she.line = ev.str; she.data = NULL; /* restore pointer to where it was */ (void)history(h, &ev, H_SET, curr_num); return (&she);}/* * add the line to history table */intadd_history(const char *line){ HistEvent ev; if (h == NULL || e == NULL) rl_initialize(); (void)history(h, &ev, H_ENTER, line); if (history(h, &ev, H_GETSIZE) == 0) history_length = ev.num; return (!(history_length > 0)); /* return 0 if all is okay */}/* * clear the history list - delete all entries */voidclear_history(void){ HistEvent ev; history(h, &ev, H_CLEAR);}/* * returns offset of the current history event */intwhere_history(void){ HistEvent ev; int curr_num, off; if (history(h, &ev, H_CURR) != 0) return (0); curr_num = ev.num; history(h, &ev, H_FIRST); off = 1; while (ev.num != curr_num && history(h, &ev, H_NEXT) == 0) off++; return (off);}/* * returns current history event or NULL if there is no such event */HIST_ENTRY *current_history(void){ return (_move_history(H_CURR));}/* * returns total number of bytes history events' data are using */inthistory_total_bytes(void){ HistEvent ev; int curr_num, size; if (history(h, &ev, H_CURR) != 0) return (-1); curr_num = ev.num; history(h, &ev, H_FIRST); size = 0; do size += strlen(ev.str); while (history(h, &ev, H_NEXT) == 0); /* get to the same position as before */ history(h, &ev, H_PREV_EVENT, curr_num); return (size);}/* * sets the position in the history list to ``pos'' */inthistory_set_pos(int pos){ HistEvent ev; int curr_num; if (pos > history_length || pos < 0) return (-1); history(h, &ev, H_CURR); curr_num = ev.num; if (history(h, &ev, H_SET, pos)) { history(h, &ev, H_SET, curr_num); return(-1); } return (0);}/* * returns previous event in history and shifts pointer accordingly */HIST_ENTRY *previous_history(void){ return (_move_history(H_PREV));}/* * returns next event in history and shifts pointer accordingly */HIST_ENTRY *next_history(void){ return (_move_history(H_NEXT));}/* * searches for first history event containing the str */inthistory_search(const char *str, int direction){ HistEvent ev; const char *strp; int curr_num; if (history(h, &ev, H_CURR) != 0) return (-1); curr_num = ev.num; for (;;) { if ((strp = strstr(ev.str, str)) != NULL) return (int) (strp - ev.str); if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) break; } history(h, &ev, H_SET, curr_num); return (-1);}/* * searches for first history event beginning with str */inthistory_search_prefix(const char *str, int direction){ HistEvent ev; return (history(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str));}/* * search for event in history containing str, starting at offset * abs(pos); continue backward, if pos<0, forward otherwise *//* ARGSUSED */inthistory_search_pos(const char *str, int direction __attribute__((__unused__)), int pos){ HistEvent ev; int curr_num, off; off = (pos > 0) ? pos : -pos; pos = (pos > 0) ? 1 : -1; if (history(h, &ev, H_CURR) != 0) return (-1); curr_num = ev.num; if (history_set_pos(off) != 0 || history(h, &ev, H_CURR) != 0) return (-1); for (;;) { if (strstr(ev.str, str)) return (off); if (history(h, &ev, (pos < 0) ? H_PREV : H_NEXT) != 0) break; } /* set "current" pointer back to previous state */ history(h, &ev, (pos < 0) ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); return (-1);}/********************************//* completion functions *//* * does tilde expansion of strings of type ``~user/foo'' * if ``user'' isn't valid user name or ``txt'' doesn't start * w/ '~', returns pointer to strdup()ed copy of ``txt'' * * it's callers's responsibility to free() returned string */char *tilde_expand(char *txt){ struct passwd *pass; char *temp; size_t len = 0; if (txt[0] != '~') return (strdup(txt)); temp = strchr(txt + 1, '/'); if (temp == NULL) { temp = strdup(txt + 1); if (temp == NULL) return NULL; } else { len = temp - txt + 1; /* text until string after slash */ temp = malloc(len); if (temp == NULL) return NULL; (void)strncpy(temp, txt + 1, len - 2); temp[len - 2] = '\0'; } pass = getpwnam(temp); free(temp); /* value no more needed */ if (pass == NULL) return (strdup(txt)); /* update pointer txt to point at string immedially following */ /* first slash */ txt += len; temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); if (temp == NULL) return NULL; (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); return (temp);}/* * return first found file name starting by the ``text'' or NULL if no * such file can be found * value of ``state'' is ignored * * it's caller's responsibility to free returned string */char *filename_completion_function(const char *text, int state){ static DIR *dir = NULL; static char *filename = NULL, *dirname = NULL; static size_t filename_len = 0; struct dirent *entry; char *temp; size_t len; if (state == 0 || dir == NULL) { temp = strrchr(text, '/');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -