static void gl_addchar(int c) /* adds the character c to the input buffer at current location */ { int i; if (gl_cnt >= BUF_SIZE - 2) { gl_putc('\a'); return; } if(mbcslocale) { mbstate_t mb_st; wchar_t wc; char s[9]; /* only 3 needed */ int res; int clen ; s[0] = c; clen = 1; res = 0; /* This is a DBCS locale, so input is 1 or 2 bytes. This loop should not be necessary. */ if((unsigned int) c >= (unsigned int) 0x80) { while(clen <= MB_CUR_MAX) { mbs_init(&mb_st); res = mbrtowc(&wc, s, clen, &mb_st); if(res >= 0) break; if(res == -1) gl_error("invalid multibyte character in mbcs_get_next"); /* so res == -2 */ c = gl_getc(); if(c == EOF) gl_error("EOF whilst reading MBCS char"); s[clen++] = c; } /* we've tried enough, so must be complete or invalid by now */ } if( res >= 0 ) { if (!(gl_overwrite == 0 || gl_pos == gl_cnt)) gl_del(0); for (i = gl_cnt; i >= gl_pos; i--) gl_buf[i+clen] = gl_buf[i]; for (i = 0; i < clen; i++) gl_buf[gl_pos + i] = s[i]; gl_fixup(gl_prompt, gl_pos, gl_pos+clen); } } else if (gl_overwrite == 0 || gl_pos == gl_cnt) { for (i = gl_cnt; i >= gl_pos; i--) gl_buf[i+1] = gl_buf[i]; gl_buf[gl_pos] = (char) c; gl_fixup(gl_prompt, gl_pos, gl_pos+1); } else { gl_buf[gl_pos] = (char) c; gl_extent = 1; gl_fixup(gl_prompt, gl_pos, gl_pos+1); } }
static void gl_killword(int direction) { int pos = gl_pos; int startpos = gl_pos; int tmp; int i; if (direction > 0) { /* forward */ while (!isspace(gl_buf[pos]) && pos < gl_cnt) pos++; while (isspace(gl_buf[pos]) && pos < gl_cnt) pos++; } else { /* backward */ if (pos > 0) pos--; while (isspace(gl_buf[pos]) && pos > 0) pos--; while (!isspace(gl_buf[pos]) && pos > 0) pos--; if (pos < gl_cnt && isspace(gl_buf[pos])) /* move onto word */ pos++; } if (pos < startpos) { tmp = pos; pos = startpos; startpos = tmp; } memcpy(gl_killbuf, gl_buf + startpos, (size_t) (pos - startpos)); gl_killbuf[pos - startpos] = '\0'; if (isspace(gl_killbuf[pos - startpos - 1])) gl_killbuf[pos - startpos - 1] = '\0'; gl_fixup(gl_prompt, -1, startpos); for (i=0, tmp=pos - startpos; i<tmp; i++) gl_del(0); } /* gl_killword */
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; }
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(); }
int getline(const char *prompt, char *buf, int buflen) { int c, loc, tmp; int mb_len; mbstate_t mb_st; int i; wchar_t wc; BUF_SIZE = buflen; gl_buf = buf; gl_buf[0] = '\0'; if (setjmp(gl_jmp)) { gl_newline(); gl_cleanup(); return 0; } gl_init(); gl_pos = 0; gl_prompt = (prompt)? prompt : ""; 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 (!iscntrl(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 0; /*NOTREACHED*/ break; case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */ break; case '\002': /* ^B */ if(mbcslocale) { mb_len = 0; mbs_init(&mb_st); for(i = 0; i < gl_pos ;) { mbrtowc(&wc, gl_buf+i, MB_CUR_MAX, &mb_st); mb_len = Ri18n_wcwidth(wc); i += (wc==0) ? 0 : mb_len; } gl_fixup(gl_prompt, -1, gl_pos - mb_len); } else gl_fixup(gl_prompt, -1, gl_pos-1); break; case '\003': /* ^C */ gl_fixup(gl_prompt, -1, gl_cnt); gl_puts("^C\n"); gl_kill(0); gl_fixup(gl_prompt, -2, BUF_SIZE); break; case '\004': /* ^D */ if (gl_cnt == 0) { gl_buf[0] = 0; gl_cleanup(); gl_putc('\n'); return 0; } else { gl_del(0); } break; case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */ break; case '\006': /* ^F */ if(mbcslocale) { if(gl_pos >= gl_cnt) break; mb_len = 0; mbs_init(&mb_st); for(i = 0; i<= gl_pos ;){ mbrtowc(&wc, gl_buf+i, MB_CUR_MAX, &mb_st); mb_len = Ri18n_wcwidth(wc); i += (wc==0) ? 0 : mb_len; } gl_fixup(gl_prompt, -1, gl_pos + mb_len); } else gl_fixup(gl_prompt, -1, gl_pos+1); 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 != -1 || 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 */ strncpy(gl_buf, gl_hist_next(), BUF_SIZE-2); gl_buf[BUF_SIZE-2] = '\0'; 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 */ strncpy(gl_buf, gl_hist_prev(),BUF_SIZE-2); gl_buf[BUF_SIZE-2] = '\0'; 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 '\027': gl_killword(-1); /* ^W */ break; case '\031': gl_yank(); /* ^Y */ break; case '\032': /* ^Z */ gl_newline(); gl_cleanup(); return 1; /*NOTREACHED*/ break; case '\033': /* ansi arrow keys */ c = gl_getc(); if (c == '[') { switch(c = gl_getc()) { case 'A': /* up */ strncpy(gl_buf, gl_hist_prev(), BUF_SIZE-2); gl_buf[BUF_SIZE-2] = '\0'; if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case 'B': /* down */ strncpy(gl_buf, gl_hist_next(), BUF_SIZE-2); gl_buf[BUF_SIZE-2] = '\0'; if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case 'C': /* right */ if(mbcslocale) { mb_len = 0; mbs_init(&mb_st); for(i = 0; i <= gl_pos ;) { mbrtowc(&wc, gl_buf+i, MB_CUR_MAX, &mb_st); mb_len = Ri18n_wcwidth(wc); i += (wc==0) ? 0 : mb_len; } gl_fixup(gl_prompt, -1, gl_pos + mb_len); } else gl_fixup(gl_prompt, -1, gl_pos+1); break; case 'D': /* left */ if(mbcslocale) { mb_len = 0; mbs_init(&mb_st); for(i = 0; i <= gl_pos ;) { mbrtowc(&wc, gl_buf+i, MB_CUR_MAX, &mb_st); mb_len = Ri18n_wcwidth(wc); i += (wc==0) ? 0 :mb_len; } gl_fixup(gl_prompt, -1, gl_pos - mb_len); } else gl_fixup(gl_prompt, -1, gl_pos-1); 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) gl_putc('\007'); break; } } } gl_newline(); gl_cleanup(); return 0; }