Beispiel #1
0
static void 
search_back (int new_search)
{
    int    found = 0;
    char  *p, *loc;

    search_forw_flg = 0;
    if (gl_search_mode == 0) {
	search_last = hist_pos = hist_last;	
	search_update(0);	
	gl_search_mode = 1;
        gl_buf[0] = 0;
	gl_fixup(search_prompt, 0, 0);
    } else if (search_pos > 0) {
	while (!found) {
	    p = hist_prev();
	    if (*p == 0) {		/* not found, done looking */
	       gl_buf[0] = 0;
	       gl_fixup(search_prompt, 0, 0);
	       found = 1;
	    } else if ((loc = strstr(p, search_string)) != 0) {
	       strcpy(gl_buf, p);
	       gl_fixup(search_prompt, 0, (int)(loc - p));
	       if (new_search)
		   search_last = hist_pos;
	       found = 1;
	    } 
	}
    } else {
        gl_putc('\007');
    }
}
Beispiel #2
0
Datei: vt.c Projekt: Akehi/RTKLIB
/* handle escape sequence ----------------------------------------------------*/
static int seq_esc(vt_t *vt)
{
    if (vt->nesc<3) return 1;
    vt->nesc=0;
    if (!strncmp(vt->esc+1,"[A",2)) return hist_prev(vt); /* cursor up */
    if (!strncmp(vt->esc+1,"[B",2)) return hist_next(vt); /* cursor down */
    if (!strncmp(vt->esc+1,"[C",2)) return right_cur(vt); /* cursor right */
    if (!strncmp(vt->esc+1,"[D",2)) return left_cur (vt); /* cursor left */
    return 1;
}
Beispiel #3
0
static void ex_hist(void *none, Keyarg *arg)
{
  const char *ret = NULL;

  if (arg->arg == BACKWARD)
    ret = hist_prev();
  if (arg->arg == FORWARD)
    ret = hist_next();
  if (!ret)
    return;

  ex_cmd_populate(ret);
  ex.state = EX_HIST;
}
Beispiel #4
0
static int cread_line(const char *const prompt, char *buf, unsigned int *len,
		int timeout)
{
	unsigned long num = 0;
	unsigned long eol_num = 0;
	unsigned long wlen;
	char ichar;
	int insert = 1;
	int esc_len = 0;
	char esc_save[8];
	int init_len = strlen(buf);
	//int first = 1;

	if (init_len)
		cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);

	while (1) {
#if 0
#ifdef CONFIG_BOOT_RETRY_TIME
		while (!tstc()) {	/* while no incoming data */
			if (retry_time >= 0 && get_ticks() > endtime)
				return (-2);	/* timed out */
//			WATCHDOG_RESET();
		}
#endif
		if (first && timeout) {
			uint64_t etime = endtick(timeout);

			while (!tstc()) {	/* while no incoming data */
				if (get_ticks() >= etime)
					return -2;	/* timed out */
				WATCHDOG_RESET();
			}
			first = 0;
		}
#endif
		ichar = getcmd_getch();

		if ((ichar == '\n') || (ichar == '\r')) {
			serial_putchar('\n');
			break;
		}

		/*
		 * handle standard linux xterm esc sequences for arrow key, etc.
		 */
		if (esc_len != 0) {
			if (esc_len == 1) {
				if (ichar == '[') {
					esc_save[esc_len] = ichar;
					esc_len = 2;
				} else {
					cread_add_str(esc_save, esc_len, insert,
						      &num, &eol_num, buf, *len);
					esc_len = 0;
				}
				continue;
			}

			switch (ichar) {

			case 'D':	/* <- key */
				ichar = CTL_CH('b');
				esc_len = 0;
				break;
			case 'C':	/* -> key */
				ichar = CTL_CH('f');
				esc_len = 0;
				break;	/* pass off to ^F handler */
			case 'H':	/* Home key */
				ichar = CTL_CH('a');
				esc_len = 0;
				break;	/* pass off to ^A handler */
			case 'A':	/* up arrow */
				ichar = CTL_CH('p');
				esc_len = 0;
				break;	/* pass off to ^P handler */
			case 'B':	/* down arrow */
				ichar = CTL_CH('n');
				esc_len = 0;
				break;	/* pass off to ^N handler */
			default:
				esc_save[esc_len++] = ichar;
				cread_add_str(esc_save, esc_len, insert,
					      &num, &eol_num, buf, *len);
				esc_len = 0;
				continue;
			}
		}

		switch (ichar) {
		case 0x1b:
			if (esc_len == 0) {
				esc_save[esc_len] = ichar;
				esc_len = 1;
			} else {
				printf("impossible condition #876\n");
				esc_len = 0;
			}
			break;

		case CTL_CH('a'):
			BEGINNING_OF_LINE();
			break;
		case CTL_CH('c'):	/* ^C - break */
			*buf = '\0';	/* discard input */
			return (-1);
		case CTL_CH('f'):
			if (num < eol_num) {
				getcmd_putch(buf[num]);
				num++;
			}
			break;
		case CTL_CH('b'):
			if (num) {
				getcmd_putch(CTL_BACKSPACE);
				num--;
			}
			break;
		case CTL_CH('d'):
			if (num < eol_num) {
				wlen = eol_num - num - 1;
				if (wlen) {
					memmove(&buf[num], &buf[num+1], wlen);
					putnstr(buf + num, wlen);
				}

				getcmd_putch(' ');
				do {
					getcmd_putch(CTL_BACKSPACE);
				} while (wlen--);
				eol_num--;
			}
			break;
		case CTL_CH('k'):
			ERASE_TO_EOL();
			break;
		case CTL_CH('e'):
			REFRESH_TO_EOL();
			break;
		case CTL_CH('o'):
			insert = !insert;
			break;
		case CTL_CH('x'):
		case CTL_CH('u'):
			BEGINNING_OF_LINE();
			ERASE_TO_EOL();
			break;
		case DEL:
		case DEL7:
		case 8:
			if (num) {
				wlen = eol_num - num;
				num--;
				memmove(&buf[num], &buf[num+1], wlen);
				getcmd_putch(CTL_BACKSPACE);
				putnstr(buf + num, wlen);
				getcmd_putch(' ');
				do {
					getcmd_putch(CTL_BACKSPACE);
				} while (wlen--);
				eol_num--;
			}
			break;
		case CTL_CH('p'):
		case CTL_CH('n'):
		{
			char * hline;

			esc_len = 0;

			if (ichar == CTL_CH('p'))
				hline = hist_prev();
			else
				hline = hist_next();

			if (!hline) {
				getcmd_cbeep();
				continue;
			}

			/* nuke the current line */
			/* first, go home */
			BEGINNING_OF_LINE();

			/* erase to end of line */
			ERASE_TO_EOL();

			/* copy new line into place and display */
			strcpy(buf, hline);
			eol_num = strlen(buf);
			REFRESH_TO_EOL();
			continue;
		}
#ifdef CONFIG_AUTO_COMPLETE
		case '\t': {
			int num2, col;

			/* do not autocomplete when in the middle */
			if (num < eol_num) {
				getcmd_cbeep();
				break;
			}

			buf[num] = '\0';
			col = strlen(prompt) + eol_num;
			num2 = num;
			if (cmd_auto_complete(prompt, buf, &num2, &col)) {
				col = num2 - num;
				num += col;
				eol_num += col;
			}
			break;
		}
#endif
		default:
			cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
			break;
		}
	}
	*len = eol_num;
	buf[eol_num] = '\0';	/* lose the newline */

	if (buf[0] && buf[0] != CREAD_HIST_CHAR)
		cread_add_to_hist(buf);
	hist_cur = hist_add_idx;

	return 0;
}
Beispiel #5
0
 /*!
 * @brief read line into buffer
 */
static int cread_line(const char * const prompt, char * buf, uint8_t * len)
{
    uint8_t num = 0;
    uint8_t eol_num = 0;
    uint8_t wlen;
    char ichar = 0;
    uint8_t insert = 1;
    uint8_t esc_len = 0;
    char esc_save[8];
    uint8_t init_len = strlen(buf);
    if (init_len)
    {
        cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
    }
    while (1) 
    {
        do
        {
            ichar = sgetc();
        }while(!ichar);
        if ((ichar == '\n') || (ichar == '\r')) 
        {
            sputc('\r');sputc('\n');
            break;
        }
        /* handle standard linux xterm esc sequences for arrow key, etc.*/
        if (esc_len != 0)
        {
            if (esc_len == 1) 
            {
                if (ichar == '[')
                {
                    esc_save[esc_len] = ichar;
                    esc_len = 2;
                } 
                else
                {
                    cread_add_str(esc_save, esc_len, insert, &num, &eol_num, buf, *len);
                    esc_len = 0;
                }
                continue;
            } 
        switch (ichar) 
        {
            case 'D':	/* <- key */
                ichar = CTL_CH('b');
                esc_len = 0;
                break;
            case 'C':	/* -> key */
                ichar = CTL_CH('f');
                esc_len = 0;
                break;	/* pass off to ^F handler */
            case 'H':	/* Home key */
                ichar = CTL_CH('a');
                esc_len = 0;
                break;	/* pass off to ^A handler */
            case 'A':	/* up arrow */
                ichar = CTL_CH('p');
                esc_len = 0;
                break;	/* pass off to ^P handler */
            case 'B':	/* down arrow */
                ichar = CTL_CH('n');
                esc_len = 0;
                break;	/* pass off to ^N handler */
            default:
                esc_save[esc_len++] = ichar;
                cread_add_str(esc_save, esc_len, insert,
					      &num, &eol_num, buf, *len);
                esc_len = 0;
				continue;
        }
    }
    switch (ichar)
    {
        case 0x1b:
            if (esc_len == 0) 
            {
                esc_save[esc_len] = ichar;
                esc_len = 1;
            }
        else 
            {
                shell_printf("impossible condition #876\n");
                esc_len = 0;
            }
            break;
        case CTL_CH('a'):
            BEGINNING_OF_LINE()
            break;
        case CTL_CH('c'):	/* ^C - break */
            *buf = '\0';	/* discard input */
            return (-1);
            //break; /* have to follow MISRA */
        case CTL_CH('f'):
            if (num < eol_num)
            {
                sputc(buf[num]);
                num++;
            }
            break;
        case CTL_CH('b'):
            if (num)
            {
                sputc(CTL_BACKSPACE);
                num--;
            }
            break;
        case CTL_CH('d'):
            if (num < eol_num)
            {
                wlen = eol_num - num - 1;
                if (wlen)
                {
                    memmove(&buf[num], &buf[num+1], wlen);
                    putnstr(buf + num, wlen);
                }
                sputc(' ');
                do 
                {
                    sputc(CTL_BACKSPACE);
                } while (wlen--);
                eol_num--;
            }
            break;
        case CTL_CH('k'):
            ERASE_TO_EOL()
            break;
        case CTL_CH('e'):
            REFRESH_TO_EOL()
            break;
        case CTL_CH('o'):
            insert = !insert;
            break;
        case CTL_CH('x'):
        case CTL_CH('u'):
            BEGINNING_OF_LINE()
            ERASE_TO_EOL()
            break;
        case DEL:
        case DEL7:
        case 8:
            if (num)
            {
                wlen = eol_num - num;
                num--;
                memmove(&buf[num], &buf[num+1], wlen);
                sputc(CTL_BACKSPACE);
                putnstr(buf + num, wlen);
                sputc(' ');
                do
                {
                    sputc(CTL_BACKSPACE);
                } while (wlen--);
                eol_num--;
            }
            break;

        case CTL_CH('p'):
        case CTL_CH('n'):
#ifdef SHELL_CONFIG_USE_HIST
        {
            char * hline;
            esc_len = 0;
            if (ichar == CTL_CH('p'))
            {
                hline = hist_prev();
            }
            else
            {
                hline = hist_next();
            }
            if (!hline)
            {
                shell_beep();
                continue;
            }
            /* nuke the current line */
            /* first, go home */
            BEGINNING_OF_LINE()
            ERASE_TO_EOL()
            /* copy new line into place and display */
            strcpy(buf, hline);
            eol_num = strlen(buf);
            REFRESH_TO_EOL()
            continue;
            //break; /* have to follow MISRA */
        }
#else
        {
            continue;
        }
        
#endif /* SHELL_CONFIG_USE_HIST */
        case '\t': 
#ifdef SHELL_CONFIG_AUTO_COMPLETE
        {
            uint8_t num2, col;
            /* do not autocomplete when in the middle */
            if (num < eol_num)
            {
                shell_beep();
                break;
            }
            buf[num] = '\0';
            col = strlen(prompt) + eol_num;
            num2 = num;
            if (cmd_auto_complete(prompt, buf, &num2, &col))
            {
                col = num2 - num;
                num += col;
                eol_num += col;
            }
            break;
        }
#else
        {
            continue;
        }
#endif /* SHELL_CONFIG_AUTO_COMPLETE */
        default:
            cread_add_char(ichar, insert, &num, &eol_num, buf, *len);
            break;
        }
    }
    *len = eol_num;
    buf[eol_num] = '\0';	/* lose the newline */
#ifdef SHELL_CONFIG_USE_HIST
    if ((buf[0]) && (buf[0] != CREAD_HIST_CHAR))
    {
        cread_add_to_hist(buf);
    }
    hist_cur = hist_add_idx;
#endif
    return 0;
}
Beispiel #6
0
char *getline_int(char *prompt)
{
    int             c, loc, tmp;
    int	            sig;

    gl_init();	
    gl_prompt = (prompt)? prompt : "";
    gl_buf[0] = 0;
    if (gl_in_hook)
	gl_in_hook(gl_buf);
    gl_fixup(gl_prompt, -2, BUF_SIZE);
    while ((c = gl_getc()) >= 0) {
	gl_extent = 0;  	/* reset to full extent */
	if (isprint(c)) {
	    if (gl_search_mode)
	       search_addchar(c);
	    else
	       gl_addchar(c);
	} else {
	    if (gl_search_mode) {
	        if (c == '\033' || c == '\016' || c == '\020') {
	            search_term();
	            c = 0;     		/* ignore the character */
		} else if (c == '\010' || c == '\177') {
		    search_addchar(-1); /* unwind search string */
		    c = 0;
		} else if (c != '\022' && c != '\023') {
		    search_term();	/* terminate and handle char */
		}
	    }
	    switch (c) {
	      case '\n': case '\r': 			/* newline */
		gl_newline();
		gl_cleanup();
		return gl_buf;
		/*NOTREACHED*/
		break; 
	      case '\001': gl_fixup(gl_prompt, -1, 0);		/* ^A */
		break;
	      case '\002': gl_fixup(gl_prompt, -1, gl_pos-1);	/* ^B */
		break;
	      case '\004':					/* ^D */
		if (gl_cnt == 0) {
		    gl_buf[0] = 0;
		    gl_cleanup();
		    gl_putc('\n');
		    return gl_buf;
		} else {
		    gl_del(0);
		}
		break;
	      case '\005': gl_fixup(gl_prompt, -1, gl_cnt);	/* ^E */
		break;
	      case '\006': gl_fixup(gl_prompt, -1, gl_pos+1);	/* ^F */
		break;
	      case '\010': case '\177': gl_del(-1);	/* ^H and DEL */
		break;
	      case '\t':        				/* TAB */
                if (gl_tab_hook) {
		    tmp = gl_pos;
	            loc = gl_tab_hook(gl_buf, gl_strlen(gl_prompt), &tmp);
	            if (loc >= 0 || tmp != gl_pos)
	                gl_fixup(gl_prompt, loc, tmp);
                }
		break;
	      case '\013': gl_kill(gl_pos);			/* ^K */
		break;
	      case '\014': gl_redraw();				/* ^L */
		break;
	      case '\016': 					/* ^N */
		strcpy(gl_buf, hist_next());
                if (gl_in_hook)
	            gl_in_hook(gl_buf);
		gl_fixup(gl_prompt, 0, BUF_SIZE);
		break;
	      case '\017': gl_overwrite = !gl_overwrite;       	/* ^O */
		break;
	      case '\020': 					/* ^P */
		strcpy(gl_buf, hist_prev());
                if (gl_in_hook)
	            gl_in_hook(gl_buf);
		gl_fixup(gl_prompt, 0, BUF_SIZE);
		break;
	      case '\022': search_back(1);			/* ^R */
		break;
	      case '\023': search_forw(1);			/* ^S */
		break;
	      case '\024': gl_transpose();			/* ^T */
		break;
              case '\025': gl_kill(0);				/* ^U */
		break;
	      case '\031': gl_yank();				/* ^Y */
		break;
	      case '\033':				/* ansi arrow keys */
		c = gl_getc();
		if (c == '[') {
		    switch(c = gl_getc()) {
		      case 'A':             			/* up */
		        strcpy(gl_buf, hist_prev());
                        if (gl_in_hook)
	                    gl_in_hook(gl_buf);
		        gl_fixup(gl_prompt, 0, BUF_SIZE);
		        break;
		      case 'B':                         	/* down */
		        strcpy(gl_buf, hist_next());
                        if (gl_in_hook)
	                    gl_in_hook(gl_buf);
		        gl_fixup(gl_prompt, 0, BUF_SIZE);
		        break;
		      case 'C': gl_fixup(gl_prompt, -1, gl_pos+1); /* right */
		        break;
		      case 'D': gl_fixup(gl_prompt, -1, gl_pos-1); /* left */
		        break;
		      default: gl_putc('\007');         /* who knows */
		        break;
		    }
		} else if (c == 'f' || c == 'F') {
		    gl_word(1);
		} else if (c == 'b' || c == 'B') {
		    gl_word(-1);
		} else
		    gl_putc('\007');
		break;
	      default:		/* check for a terminal signal */
	        if (c > 0) {	/* ignore 0 (reset above) */
	            sig = 0;
#ifdef SIGINT
	            if (c == gl_intrc)
	                sig = SIGINT;
#endif
#ifdef SIGQUIT
	            if (c == gl_quitc)
	                sig = SIGQUIT;
#endif
#ifdef SIGTSTP
	            if (c == gl_suspc || c == gl_dsuspc)
	                sig = SIGTSTP;
#endif
                    if (sig != 0) {
	                gl_cleanup();
	                kill(0, sig);
	                gl_init();
	                gl_redraw();
			c = 0;
		    } 
		}
                if (c > 0)
		    gl_putc('\007');
		break;
	    }
	}
    }
    gl_cleanup();
    gl_buf[0] = 0;
    return gl_buf;
}
Beispiel #7
0
char *
tin_getline(
	const char *prompt,
	int number_only,	/* 1=positive numbers only, 2=negative too */
	const char *str,
	int max_chars,
	t_bool passwd,
	int which_hist)
{
	int c, i, loc, tmp, gl_max;
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	wint_t wc;
#else
	char *buf = gl_buf;
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */

	is_passwd = passwd;

	set_xclick_off();
	if (prompt == NULL)
		prompt = "";

	gl_buf[0] = 0;		/* used as end of input indicator */
	gl_fixup(-1, 0);	/* this resets gl_fixup */
	gl_width = cCOLS - strlen(prompt);
	gl_prompt = prompt;
	gl_pos = gl_cnt = 0;

	if (max_chars == 0) {
		if (number_only)
			gl_max = 6;
		else
			gl_max = BUF_SIZE;
	} else
		gl_max = max_chars;

	my_fputs(prompt, stdout);
	cursoron();
	my_flush();

	if (gl_in_hook) {
		loc = gl_in_hook(gl_buf);
		if (loc >= 0)
			gl_fixup(0, BUF_SIZE);
	}

	if (!cmd_line && gl_max == BUF_SIZE)
		CleartoEOLN();

#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	if (str != NULL) {
		wchar_t wbuf[LEN];

		if (mbstowcs(wbuf, str, ARRAY_SIZE(wbuf) - 1) != (size_t) -1) {
			wbuf[ARRAY_SIZE(wbuf) - 1] = (wchar_t) '\0';
			for (i = 0; wbuf[i]; i++)
				gl_addwchar(wbuf[i]);
		}
	}

	while ((wc = ReadWch()) != WEOF) {
		if ((gl_cnt < gl_max) && iswprint(wc)) {
			if (number_only) {
				if (iswdigit(wc)) {
					gl_addwchar(wc);
				/* Minus */
				} else if (number_only == 2 && gl_pos == 0 && wc == (wint_t) '-') {
					gl_addwchar(wc);
				} else {
					ring_bell();
				}
			} else
				gl_addwchar(wc);
		} else {
			c = (int) wc;
			switch (wc) {
#else
	if (str != NULL) {
		for (i = 0; str[i]; i++)
			gl_addchar(str[i]);
	}

	while ((c = ReadCh()) != EOF) {
		c &= 0xff;
		if ((gl_cnt < gl_max) && my_isprint(c)) {
			if (number_only) {
				if (isdigit(c)) {
					gl_addchar(c);
				/* Minus */
				} else if (number_only == 2 && gl_pos == 0 && c == '-') {
					gl_addchar(c);
				} else {
					ring_bell();
				}
			} else
				gl_addchar(c);
		} else {
			switch (c) {
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
				case ESC:	/* abort */
#ifdef HAVE_KEY_PREFIX
				case KEY_PREFIX:
#endif /* HAVE_KEY_PREFIX */
					switch (get_arrow_key(c)) {
						case KEYMAP_UP:
						case KEYMAP_PAGE_UP:
							hist_prev(which_hist);
							break;

						case KEYMAP_PAGE_DOWN:
						case KEYMAP_DOWN:
							hist_next(which_hist);
							break;

						case KEYMAP_RIGHT:
							gl_fixup(-1, gl_pos + 1);
							break;

						case KEYMAP_LEFT:
							gl_fixup(-1, gl_pos - 1);
							break;

						case KEYMAP_HOME:
							gl_fixup(-1, 0);
							break;

						case KEYMAP_END:
							gl_fixup(-1, gl_cnt);
							break;

						case KEYMAP_DEL:
							gl_del(0);
							break;

						case KEYMAP_INS:
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
							gl_addwchar((wint_t) ' ');
#else
							gl_addchar(' ');
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
							break;

						default:
							return (char *) 0;
					}
					break;

				case '\n':	/* newline */
				case '\r':
					gl_newline(which_hist);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
					wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
					return buf;

				case CTRL_A:
					gl_fixup(-1, 0);
					break;

				case CTRL_B:
					gl_fixup(-1, gl_pos - 1);
					break;

				case CTRL_D:
					if (gl_cnt == 0) {
						gl_buf[0] = 0;
						my_fputc('\n', stdout);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
						wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
						return buf;
					} else
						gl_del(0);
					break;

				case CTRL_E:
					gl_fixup(-1, gl_cnt);
					break;

				case CTRL_F:
					gl_fixup(-1, gl_pos + 1);
					break;

				case CTRL_H:
				case DEL:
					gl_del(-1);
					break;

				case TAB:
					if (gl_tab_hook) {
						tmp = gl_pos;
						loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp);
						if (loc >= 0 || tmp != gl_pos)
							gl_fixup(loc, tmp);
					}
					break;

				case CTRL_W:
					gl_kill_back_word();
					break;

				case CTRL_U:
					gl_fixup(-1, 0);
					/* FALLTHROUGH */
				case CTRL_K:
					gl_kill();
					break;

				case CTRL_L:
				case CTRL_R:
					gl_redraw();
					break;

				case CTRL_N:
					hist_next(which_hist);
					break;

				case CTRL_P:
					hist_prev(which_hist);
					break;

				default:
					ring_bell();
					break;
			}
		}
	}
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	return buf;
}


/*
 * adds the character c to the input buffer at current location if
 * the character is in the allowed template of characters
 */
static void
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
gl_addwchar(
	wint_t wc)
#else
gl_addchar(
	int c)
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
{
	int i;

	/*
	 * Crashing is always the worst solution IMHO. So as a quick hack,
	 * ignore characters silently, if buffer is full. To allow a final
	 * newline, leave space for one more character. Just a hack too.
	 * This was the original code:
	 *
	if (gl_cnt >= BUF_SIZE - 1) {
		error_message("tin_getline: input buffer overflow");
		giveup();
	}
	 */
	if (gl_cnt >= BUF_SIZE - 2)
		return;

	for (i = gl_cnt; i >= gl_pos; i--)
		gl_buf[i + 1] = gl_buf[i];

#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	gl_buf[gl_pos] = (wchar_t) wc;
#else
	gl_buf[gl_pos] = c;
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	gl_fixup(gl_pos, gl_pos + 1);
}


/*
 * Cleans up entire line before returning to caller. A \n is appended.
 * If line longer than screen, we redraw starting at beginning
 */
static void
gl_newline(
	int w)
{
	int change = gl_cnt;
	int len = gl_cnt;
	int loc = gl_width - 5;	/* shifts line back to start position */

	if (gl_cnt >= BUF_SIZE - 1) {
		/*
		 * Like above: avoid crashing if possible. gl_addchar() now
		 * leaves one space left for the newline, so this part of the
		 * code should never be reached. A proper implementation is
		 * desirable though.
		 */
		error_message("tin_getline: input buffer overflow");
		giveup();
	}
	hist_add(w);		/* only adds if nonblank */
	if (gl_out_hook) {
		change = gl_out_hook(gl_buf);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
		len = wcslen(gl_buf);
#else
		len = strlen(gl_buf);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	}
	if (loc > len)
		loc = len;
	gl_fixup(change, loc);	/* must do this before appending \n */
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	gl_buf[len] = (wchar_t) '\0';
#else
	gl_buf[len] = '\0';
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
}


/*
 * Delete a character. The loc variable can be:
 *    -1 : delete character to left of cursor
 *     0 : delete character under cursor
 */
static void
gl_del(
	int loc)
{
	int i;

	if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
		for (i = gl_pos + loc; i < gl_cnt; i++)
			gl_buf[i] = gl_buf[i + 1];
		gl_fixup(gl_pos + loc, gl_pos + loc);
	} else
		ring_bell();
}