diff options
| author | Steve Slaven <bpk@hoopajoo.net> | 2005-03-12 00:27:55 (GMT) | 
|---|---|---|
| committer | Steve Slaven <bpk@hoopajoo.net> | 2005-03-12 00:27:55 (GMT) | 
| commit | 77b250bfb63a28a8fe8a8da67de7354bce6e61ff (patch) | |
| tree | e28f72c18305016c19c608f5fce4432529e7673d /edit.c | |
| parent | 5dfb1906b299bf7c8a1ee3ba5cd1c9ea40648d89 (diff) | |
| download | powwow-77b250bfb63a28a8fe8a8da67de7354bce6e61ff.zip powwow-77b250bfb63a28a8fe8a8da67de7354bce6e61ff.tar.gz powwow-77b250bfb63a28a8fe8a8da67de7354bce6e61ff.tar.bz2 | |
Initial revisionv1.2.7
Diffstat (limited to 'edit.c')
| -rw-r--r-- | edit.c | 886 | 
1 files changed, 886 insertions, 0 deletions
| @@ -0,0 +1,886 @@ +/* + *  edit.c  --  line editing functions for powwow + * + *  Copyright (C) 1998 by Massimiliano Ghilardi + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include <sys/types.h> +#include <sys/time.h> + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "cmd.h" +#include "edit.h" +#include "tcp.h" +#include "tty.h" +#include "eval.h" +#include "log.h" + +static void insert_string	__P ((char *arg)); + +/* history buffer */ +char *hist[MAX_HIST];	/* saved history lines */ +int curline = 0;	/* current history line */ +int pickline = 0;	/* line to pick history from */ + +/* word completion list */ +wordnode words[MAX_WORDS]; +int wordindex = 0; + +edit_function internal_functions[] = { +    {(char *)0, (function_str)0, }, +    {"&enter-line", enter_line, }, +    {"&complete-word", complete_word, }, +    {"&complete-line", complete_line, }, +    {"&del-char-left", del_char_left, }, +    {"&del-char-right",  del_char_right, }, +    {"&prev-char", prev_char, }, +    {"&prev-line", prev_line, }, +    {"&next-char", next_char, }, +    {"&next-line", next_line, }, +    {"&to-history", to_history, }, +    {"&clear-line", clear_line, }, +    {"&redraw-line", redraw_line, }, +    {"&redraw-line-noprompt", redraw_line_noprompt, }, +    {"&begin-of-line", begin_of_line, }, +    {"&end-of-line", end_of_line, }, +    {"&kill-to-eol", kill_to_eol, }, +    {"&transpose", transpose_chars, }, +    {"&transpose-words", transpose_words, }, +    {"&suspend", (function_str)suspend_powwow, }, /* yep, it's an hack */ +    {"&del-word-left", del_word_left, }, +    {"&del-word-right", del_word_right, }, +    {"&prev-word", prev_word, }, +    {"&upcase-word", upcase_word, }, +    {"&downcase-word", downcase_word, }, +    {"&next-word", next_word, }, +    {"&insert-string", insert_string, }, +    {(char *)0, (function_str)0 } +}; + +int lookup_edit_name __P2 (char *,name, char **,arg) +{ +    int i, len, flen; +    char *fname, *extra = NULL; +     +    if ((fname = strchr(name, ' '))) +	len = fname - name; +    else +	len = strlen(name); +     +    for (i=1; (fname = internal_functions[i].name); i++) { +	flen = strlen(fname); +	if (flen == len && !strncmp(name, fname, flen)) { +	    extra = name + flen; +	    if (*extra == ' ') extra++; +	    if (!*extra) extra = NULL; +	    *arg = extra; +	    return i; +	} +    } +    *arg = extra; +    return 0; +} + +int lookup_edit_function __P1 (function_str,funct) +{ +    int i; +    function_str ffunct; +     +    for (i = 1; (ffunct = internal_functions[i].funct); i++) +	if (funct == ffunct) +	    return i; +     +    return 0; +} + +/* + * redisplay the prompt + * assume cursor is at beginning of line + */ +void draw_prompt __P0 (void) +{ +    if (promptlen && prompt_status == 1) { +	int e = error; +	error = 0; +	marked_prompt = ptraddmarks(marked_prompt, prompt->str); +	if (MEM_ERROR) { promptzero(); errmsg("malloc(prompt)"); return; } +	tty_puts(ptrdata(marked_prompt)); +	col0 = printstrlen(promptstr); /* same as printstrlen(marked_prompt) */ +	error = e; +    } +    prompt_status = 0; +} + +/* + * clear current input line (deleteprompt == 1 if to clear also prompt) + * cursor is left right after the prompt. + *  + * since we do not expect data from the user at this point, + * do not print edattrbeg now. + */ +void clear_input_line __P1 (int,deleteprompt) +{ +    /* +     * be careful: if prompt and/or input line have been erased from screen, +     * pos will be different from the actual cursor position +     */ +    if ((edlen && line_status == 0) || (promptlen && prompt_status == 0 && deleteprompt)) { +	int newcol = deleteprompt ? 0 : col0; +	int realpos = line_status == 0 ? pos : (prompt_status == 0 ? 0 : -col0); +	 +	tty_gotoxy_opt(CURCOL(realpos), CURLINE(realpos), newcol, line0); +	tty_puts(edattrend); +	if (line0 < lines - 1) +	    tty_puts(tty_clreoscr); +        else +	    tty_puts(tty_clreoln); +	col0 = newcol; +    } else { +	tty_puts(edattrend); +    } +    if (deleteprompt) +	status(1); +    else +	line_status = 1; +} + +/* + * clear input line, but do nothing else + */ +void clear_line __P1 (char *,dummy) +{ +    if (!edlen) +	return; +    clear_input_line(0); +    pickline = curline; +    *edbuf = '\0'; +    pos = edlen = 0; +} + +/* + * Redraw the input line and put the cursor at the current position. + * The cursor is assumed to be directly after the prompt. + */ +void draw_input_line __P0 (void) +{ +    int i, oldline0; +     +    if (line_status == 0 || linemode & LM_NOECHO) +	return; +     +    tty_puts(edattrbeg); +     +    if (edlen) { +	oldline0 = line0; +	if (edlen < cols_1 - col0) { +	    tty_puts(edbuf); +	} else { +	    tty_printf("%.*s", cols_1 - col0, edbuf); +	    for (i = cols_1 - col0; i <= edlen; i += cols_1) { +#ifdef BUG_ANSI +		if (edattrbg)  +		    tty_printf("%s\n%s%.*s", edattrend, edattrbeg, cols_1, edbuf + i); +		else +#endif +		    tty_printf("\n%.*s", cols_1, edbuf + i); +	    } +	} +	line0 = lines - (edlen + col0) / cols_1 - 1; +	if (line0 > oldline0) +	    line0 = oldline0; +	if ((i = CURLINE(pos)) < 0) +	    line0 -= i; +	else if (i > lines - 1) +	    line0 -= i - lines + 1; +	tty_gotoxy_opt(CURCOL(edlen), CURLINE(edlen), CURCOL(pos), CURLINE(pos)); +    } +    line_status = 0; +} + +/* + * redraw the input line + */ +void redraw_line __P1 (char *,dummy) +{ +    clear_input_line(1); +} + +/* + * redraw the input line, clearing the prompt + */ +void redraw_line_noprompt __P1 (char *,dummy) +{ +    clear_input_line(0); +    tty_putc('\n'); +    if (line0 < lines - 1) +	line0++; +    status(-1); +} + +/* + * GH: transpose two words to the left + */ +void transpose_words __P1 (char *,dummy) +{ +    /* other refers to the word to the left, this is the one we are at */ +     +    int this_so, other_so, this_eo, other_eo; +    char buf[BUFSIZE]; +    int n; +     +    if (pos > 2) { +	 +	this_eo = this_so = pos; +	/* optionally traceback to find a word */ +	while (this_so && strchr(DELIM, edbuf[this_so])) +	    this_so--; +	 +	/* now find where the current word ends */ +	while (this_eo < edlen && !strchr(DELIM, edbuf[this_eo])) +	    this_eo++; +	 +	/* found a word; now find its start */ +	while (this_so > 0 && !strchr(DELIM, edbuf[this_so - 1])) +	    this_so--; +	 +	if (this_so < 2) +	    return;		/* impossible that there's another word */ +	 +	other_so = this_so - 1; +	while (other_so >= 0 && strchr(DELIM, edbuf[other_so])) +	    other_so--; +	if (other_so < 0) +	    return; +	other_eo = other_so + 1; +	while (other_so > 0 && !strchr(DELIM, edbuf[other_so - 1])) +	    other_so--; +	 +	sprintf(buf, "%.*s%.*s%.*s", +		this_eo - this_so, edbuf + this_so,  +		this_so - other_eo, edbuf + other_eo, +		other_eo - other_so, edbuf + other_so); +	 +	input_moveto(other_so); +	for (n = 0; buf[n]; input_overtype_follow(buf[n++])) +	    ; +    } +} + +/* + * transpose two characters to the left + */ +void transpose_chars __P1 (char *,dummy) +{ +    int i, j; +    char c; +    if (pos > 1 || (pos > 0 && pos < edlen)) { +        if (pos < edlen) { +	    j = pos; +	    i = pos - 1; +	} else { +	    j = pos - 1; +	    i = pos - 2; +	} +	c = edbuf[j]; edbuf[j] = edbuf[i]; edbuf[i] = c; +	 +	if (line_status == 0) { +	    tty_gotoxy_opt(CURCOL(pos), CURLINE(pos), CURCOL(i), CURLINE(i)); +	    tty_putc(edbuf[i]); +	    tty_gotoxy_opt(CURCOL(i+1), CURLINE(i+1), CURCOL(j), CURLINE(j)); +	    tty_putc(edbuf[j]); +	    if (pos < edlen) { +		pos++; +		tty_gotoxy_opt(CURCOL(j+1), CURLINE(j+1), CURCOL(pos), CURLINE(pos)); +	    } +	} else +	    pos++; +    } +} + +/* + * erase everything to the end of line + */ +void kill_to_eol __P1 (char *,dummy) +{ +    if (line_status == 0) { +	if (edattrbg)  +	    tty_printf("%s%s", edattrend, tty_clreoln); +	else  +	    tty_puts(tty_clreoln); +	if (CURLINE(edlen) > CURLINE(pos)) { +	    tty_printf("\n%s", tty_clreoscr); +	    tty_gotoxy_opt(0, CURLINE(pos) + 1, CURCOL(pos), CURLINE(pos)); +	} +	if (edattrbg) +	    tty_puts(edattrbeg); +    } +    edbuf[edlen = pos] = '\0'; +} + +/* + * move cursor to end of line + */ +void end_of_line __P1 (char *,dummy) +{ +    input_moveto(edlen); +} + +/* + * move cursor to beginning of line + */ +void begin_of_line __P1 (char *,dummy) +{ +    input_moveto(0); +} + +/* + * delete a character to the right + */ +void del_char_right __P1 (char *,dummy) +{ +    input_delete_nofollow_chars(1); +} + +/* + * delete a character to the left + */ +void del_char_left __P1 (char *,dummy) +{ +    if (pos) { +	input_moveto(pos-1); +	input_delete_nofollow_chars(1); +    } +} + +/* + * move a line into history, but don't do anything else + */ +void to_history __P1 (char *,dummy) +{ +    if (!edlen) +	return; +    clear_input_line(0); +    put_history(edbuf); +    pickline = curline; +    *edbuf = '\0'; +    pos = edlen = 0; +} + +/* + * put string in history at current position + * (string is assumed to be trashable) + */ +void put_history __P1 (char *,str) +{ +    char *p; +    if (hist[curline]) free(hist[curline]); +    if (!(hist[curline] = my_strdup(str))) { +	errmsg("malloc"); +	return; +    } +     +    if (++curline == MAX_HIST) +	curline = 0; +     +    /* split into words and put into completion list */ +    for (p = strtok(str, DELIM); p;  +	 p = strtok(NULL, DELIM)) { +        if (strlen(p) >= MIN_WORDLEN &&  +	    p[0] != '#') /* no commands/short words */ +	    put_word(p); +    } +} + +/* + * move a node before wordindex, i.e. make it the last word + */ +static void demote_word __P1 (int,i) +{ +    words[words[i].prev].next = words[i].next; +    words[words[i].next].prev = words[i].prev; +    words[i].prev = words[words[i].next = wordindex].prev; +    words[wordindex].prev = words[words[wordindex].prev].next = i; +} + +/* + * match and complete a word referring to the word list + */ +void complete_word __P1 (char *,dummy) +{ +    /* +     * GH: rewritten to allow circulating through history with repetitive command +     *     code stolen from cancan 2.6.3a +     *        curr_word:   index into words[] +     *        comp_len     length of current completition +     *        root_len     length of the root word (before the completition) +     *        root         start of the root word +     */	 +     +    static int curr_word, comp_len = 0, root_len = 0; +    char *root, *p; +    int k, n; +     +    /* find word start */ +    if (last_edit_cmd == (function_any)complete_word && comp_len) { +	k = comp_len; +	input_moveto(pos - k); +	n = pos - root_len; +    } else { +	for (n = pos; n > 0 && !IS_DELIM(edbuf[n - 1]); n--) +	    ; +	k = 0; +	curr_word = wordindex; +	root_len = pos - n; +    } +    root = edbuf + n; comp_len = 0; +     +    /* k = chars to delete,  n = position of starting word */ +     +    /* scan word list for next match */ +    while ((p = words[curr_word = words[curr_word].next].word)) { +	if (!strncasecmp(p, root, root_len) && +	    *(p += root_len) && +	    (n = strlen(p)) + edlen < BUFSIZE) { +	    comp_len = n; +	    for (; k && n; k--, n--) +		input_overtype_follow(*p++); +	    if (n > 0) +		input_insert_follow_chars(p, n); +	    break; +	} +    } +    if (k > 0) +	input_delete_nofollow_chars(k); +     +    /* delete duplicate instances of the word */ +    if (p && !(words[k = curr_word].flags & WORD_UNIQUE)) { +	words[k].flags |= WORD_UNIQUE; +	p = words[k].word;   +	n = words[k].next; +	while (words[k = n].word) { +	    n = words[k].next; +	    if (!strcmp(p, words[k].word)) { +		demote_word(k); +		free(words[k].word); +		words[k].word = 0; +		words[curr_word].flags |= words[k].flags;	/* move retain flag */ +		if ((words[k].flags &= WORD_UNIQUE)) +		    break; +	    } +	} +    } +} + +/* + * match and complete entire lines backwards in history + * GH: made repeated complete_line cycle through history + */ +void complete_line __P1 (char *,dummy) +{ +    static int curr_line = MAX_HIST-1, root_len = 0, first_line = 0; +    int i; +     +    if (last_edit_cmd != (function_any)complete_line) { +	root_len = edlen; +	first_line = curr_line = curline; +    } +     +    for (i = curr_line - 1; i != curr_line; i--) { +	if (i < 0) i = MAX_HIST - 1; +	if (i == first_line) +	    break; +	if (hist[i] && !strncmp(edbuf, hist[i], root_len)) +	    break; +    } +    if (i != curr_line) { +	clear_input_line(0); +	if (i == first_line) { +	    edbuf[root_len] = 0; +	    edlen = root_len; +	} else { +	    strcpy(edbuf, hist[i]); +	    edlen = strlen(edbuf); +	} +	pos = edlen; +	curr_line = i; +    } +} + +/* + * GH: word history handling stolen from cancan 2.6.3a + */ + +static void default_completions __P0 (void) +{ +    char buf[BUFSIZE]; +    cmdstruct *p; +    int i; +    for (i = 0, buf[0] = '#', p = commands; p->name; p++) +	if (p->funct /*&& strlen(p->name) >= 3*/ ) { +	    if (++i >= MAX_WORDS) break; +	    strcpy(buf + 1, p->name); +	    if (!(words[i].word = my_strdup(buf))) +		syserr("malloc"); +	    words[i].flags = WORD_UNIQUE | WORD_RETAIN; +	} +    for (i = MAX_WORDS; i--; words[i].prev = i - 1, words[i].next = i + 1) +	; +    words[0].prev = MAX_WORDS - 1; +    words[MAX_WORDS - 1].next = 0; +} + +/* + * put word in word completion ring + */ +void put_word __P1 (char *,s) +{ +    int r = wordindex; +    if (!(words[r].word = my_strdup(s))) { +	errmsg("malloc"); +	return; +    } +    words[r].flags = 0; +    while (words[r = words[r].prev].flags & WORD_RETAIN) +	; +    demote_word(r); +    wordindex = r; +    if (words[r].word) {  +	free(words[r].word);  +	words[r].word = 0;  +    } +} + +/* + * GH: set delimeters[DELIM_CUSTOM] + */ +void set_custom_delimeters __P1 (char *,s) +{ +    char *old = delim_list[DELIM_CUSTOM]; +    if (!(delim_list[DELIM_CUSTOM] = my_strdup(s))) +	errmsg("malloc"); +    else { +	if (old) +	    free(old); +	delim_len[DELIM_CUSTOM] = strlen(s); +	delim_mode = DELIM_CUSTOM; +    } +} + +/* + * enter a line + */ +void enter_line __P1 (char *,dummy) +{ +    char *p; +     +    if (line_status == 0) +	input_moveto(edlen); +    else { +	if (prompt_status != 0) +	    col0 = 0; +	draw_input_line(); +    } +    PRINTF("%s\n", edattrend); +     +    line0 = CURLINE(edlen); +    if (line0 < lines - 1) line0++; +     +    if (recordfile) +	fprintf(recordfile, "%s\n", edbuf); +     +    col0 = error = pos = line_status = 0; +     +    if (!*edbuf || (verbatim && *edbuf != '#')) +	tcp_write(tcp_fd, edbuf); +    else +	parse_user_input(edbuf, 1);     +    history_done = 0; +     +    /* don't put identical lines in history, nor empty ones */ +    p = hist[curline ? curline - 1 : MAX_HIST - 1]; +    if (!p || (edlen > 0 && strcmp(edbuf, p))) +	put_history(edbuf); +    pickline = curline; +    if (*inserted_next) { +	strcpy(edbuf, inserted_next); +	inserted_next[0] = '\0'; +	line_status = 1; +    } else if (*prefixstr) { +	strcpy(edbuf, prefixstr); +	line_status = 1; +    } else +	edbuf[0] = '\0'; +    pos = edlen = strlen(edbuf); +} + +/* + * move one word forward + */ +void next_word __P1 (char *,dummy) +{ +    int i; +    for (i = pos; edbuf[i] && !isalnum(edbuf[i]); i++) +	; +    while (isalnum(edbuf[i])) +	i++; +    input_moveto(i); +} + +/* + * move one word backward + */ +void prev_word __P1 (char *,dummy) +{ +    int i; +    for (i = pos; i && !isalnum(edbuf[i - 1]); i--) +	; +    while (i && isalnum(edbuf[i - 1])) +	i--; +    input_moveto(i); +} + +/* + * delete word to the right + */ +void del_word_right __P1 (char *,dummy) +{ +    int i; +    for (i = pos; edbuf[i] && !isalnum(edbuf[i]); i++) +	; +    while (isalnum(edbuf[i])) +	i++; +    input_delete_nofollow_chars(i - pos); +} + +/* + * delete word to the left + */ +void del_word_left __P1 (char *,dummy) +{ +    int i; +    for (i = pos; i && !isalnum(edbuf[i - 1]); i--) +	; +    while (i && isalnum(edbuf[i - 1])) +	i--; +    i = pos - i; +    input_moveto(pos - i); +    input_delete_nofollow_chars(i); +} + +/* + * GH: make word upcase + */ +void upcase_word __P1 (char *,dummy) +{ +    int opos = pos; +     +    if (last_edit_cmd == (function_any)upcase_word) +	pos = 0; +    else { +	while (pos > 0 && IS_DELIM(edbuf[pos])) pos--; +	while (pos > 0 && !IS_DELIM(edbuf[pos - 1])) pos--; +    } +    input_moveto(pos); +    while (!IS_DELIM(edbuf[pos]) || +	   (last_edit_cmd == (function_any)upcase_word && edbuf[pos])) +	input_overtype_follow(toupper(edbuf[pos])); +    input_moveto(opos); +} + +/* + * GH: make word downcase + */ +void downcase_word __P1 (char *,dummy) +{ +    int opos = pos; +     +    if (last_edit_cmd == (function_any)downcase_word) +	pos = 0; +    else { +	while (pos > 0 && IS_DELIM(edbuf[pos])) pos--; +	while (pos > 0 && !IS_DELIM(edbuf[pos - 1])) pos--; +    } +    input_moveto(pos); +    while (!IS_DELIM(edbuf[pos]) || +	   (last_edit_cmd == (function_any)downcase_word && edbuf[pos])) { +	input_overtype_follow(tolower(edbuf[pos])); +    } +    input_moveto(opos); +} + +/* + * get previous line from history list + */ +void prev_line __P1 (char *,dummy) +{ +    int i = pickline - 1; +    if (i < 0) i = MAX_HIST - 1; +    if (hist[i]) { +	if (hist[pickline] && strcmp(hist[pickline], edbuf)) { +	    free(hist[pickline]); +	    hist[pickline] = NULL; +	} +	if (!hist[pickline]) { +	    if (!(hist[pickline] = my_strdup(edbuf))) { +		errmsg("malloc"); +		return; +	    } +	} +	pickline = i; +	clear_input_line(0); +	strcpy(edbuf, hist[pickline]); +	pos = edlen = strlen(edbuf); +    } +} + +/* + * get next line from history list + */ +void next_line __P1 (char *,dummy) +{ +    int i = pickline + 1; +    if (i == MAX_HIST) i = 0; +    if (hist[i]) { +	if (hist[pickline] && strcmp(hist[pickline], edbuf)) { +	    free(hist[pickline]); +	    hist[pickline] = NULL; +	} +	if (!hist[pickline]) { +	    if (!(hist[pickline] = my_strdup(edbuf))) { +		errmsg("malloc"); +		return; +	    } +	} +	pickline = i; +	clear_input_line(0); +	strcpy(edbuf, hist[pickline]); +	edlen = pos = strlen(edbuf); +    } +} + +/* + * move one char backward + */ +void prev_char __P1 (char *,dummy) +{ +    input_moveto(pos-1); +} + +/* + * move one char forward + */ +void next_char __P1 (char *,dummy) +{ +    input_moveto(pos+1); +} + +/* + * Flash cursor at parentheses that matches c inserted before current pos + */ +static void flashparen __P1 (char,c) +{ +    int lev, i; +    if (line_status != 0) +	return; +    for (i = pos - 1, lev = 0; i >= 0; i--) { +	if (ISRPAREN(edbuf[i])) { +	    lev++; +	} else if (ISLPAREN(edbuf[i])) { +	    lev--; +	    if (!lev) { +		if (LPAREN(c) == edbuf[i]) +		    break; +		else +		    i = -1; +	    } +	} +    } +    if (i >= 0) { +	tty_gotoxy_opt(CURCOL(pos), CURLINE(pos), CURCOL(i), CURLINE(i)); +	flashback = 1; +	excursion = i; +    } +} + +/* + * put cursor back where it belongs + */ +void putbackcursor __P0 (void) +{ +    if (line_status == 0) +	tty_gotoxy_opt(CURCOL(excursion), CURLINE(excursion), CURCOL(pos), CURLINE(pos)); +    flashback = 0; +} + +/* + * insert a typed character on screen (if it is printable) + */ +void insert_char __P1 (char,c) +{ +    if (((c & 0x80) || (c >= ' ' && c <= '~')) && edlen < BUFSIZE - 2) { +	if (flashback) putbackcursor(); +	input_insert_follow_chars(&c, 1); +	if (ISRPAREN(c)) +	    flashparen(c); +    } +} + +static void insert_string __P1 (char *,arg) +{ +    char buf[BUFSIZE]; +    int len; +     +    if (!arg || !*arg) +	return; +     +    my_strncpy(buf, arg, BUFSIZE-1); +    unescape(buf); +    len = strlen(buf); +     +    if (len > 1) { +	if (flashback) putbackcursor(); +	input_insert_follow_chars(buf, len); +    } else if (len == 1) +	insert_char(buf[0]); /* also flash matching parentheses */ +} + +/* + * execute string as if typed + */ +void key_run_command __P1 (char *,cmd) +{ +    clear_input_line(opt_compact && !echo_key); +    if (echo_key) { +	tty_printf("%s%s%s\n", edattrbeg, cmd, edattrend); +    } else if (!opt_compact) +        tty_putc('\n'); +     +    status(1); +    error = 0; +     +    if (recordfile) +	fprintf(recordfile, "%s\n", edbuf); +     +    parse_instruction(cmd, 1, 0, 1); +    history_done = 0; +} + +void edit_bootstrap __P0 (void) +{ +    default_completions(); +} + | 
