This is term.c in view mode; [Download] [Up]
/* * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved. * * Terminal interface. */ #include <signal.h> #include <errno.h> #include "config.h" #include "term.h" #include "keymap.h" #include "regexp.h" #ifdef RESIZING #include <sys/ioctl.h> /* for TIOCGWINSZ */ #ifdef SYSV_RESIZING #include <sys/stream.h> #include <sys/ptem.h> #endif extern int s_resized; #endif import int data_bits; import int batch_mode; struct msg_list { char *buf; struct msg_list *prev; }; static struct msg_list *msg_stack = NULL, *msg_ptr = NULL; export int message_history = 15; export char *term_name = NULL; export int show_current_time = 1; export int conf_dont_sleep = 0; export int prompt_length; export int terminal_speed = 0; export int slow_speed = 1200; export int any_message = 0; export int flow_control = 1; export int use_visible_bell = 1; /* if supported by terminal */ export int ignore_xon_xoff = 1; export int multi_key_guard_time = 2; /* tenths of a second */ export int guard_double_slash = 0; /* need /// or //+ to clear line */ export key_type help_key = '?'; export key_type comp1_key = SP; export key_type comp2_key = TAB; export key_type erase_key, kill_key; export key_type delword_key = CONTROL_('W'); static char bell_str[256] = "\007"; static appl_keypad_mode = 0; #ifdef USE_TERMINFO #include <curses.h> #ifndef auto_left_margin #include <term.h> #endif #define HAS_CAP(str) (str && *str) extern char *tgoto(); /* some systems don't have this in term.h */ #else #define USE_TERMCAP char *tgoto(); char PC; char *BC, *UP; short ospeed; static char XBC[64], XUP[64]; static char enter_ca_mode[64], exit_ca_mode[64]; static char cursor_home[64]; static char cursor_address[128]; static char clear_screen[64]; static char clr_eol[64]; static char clr_eos[64]; static char enter_standout_mode[64], exit_standout_mode[64]; static char enter_underline_mode[64], exit_underline_mode[64]; static char key_down[64], key_up[64], key_right[64], key_left[64]; static char keypad_local[64], keypad_xmit[64]; int magic_cookie_glitch; /* magic cookie size */ int ceol_standout_glitch; /* hp brain damage! */ #define putp(str) tputs(str, 0, outc) #define HAS_CAP(str) (*str) static outc(c) { putchar(c); } #endif /* USE_TERMCAP */ int Lines, Columns; /* screen size */ int cookie_size; /* size of magic cookie */ int two_cookies; /* space needed to enter&exit standout mode */ int STANDOUT; /* terminal got standout mode */ #ifdef FAKE_INTERRUPT #include <setjmp.h> extern jmp_buf fake_keyb_sig; extern int arm_fake_keyb_sig; extern char fake_keyb_siglist[]; #endif #ifdef HAVE_TERMIO #define KEY_BURST 50 /* read bursts of 50 chars (or timeout after 100 ms) */ #ifdef USE_TERMCAP #include <termio.h> #endif #undef CBREAK static struct termio norm_tty, raw_tty; #define IntrC norm_tty.c_cc[VINTR] #define EraseC norm_tty.c_cc[VERASE] #define KillC norm_tty.c_cc[VKILL] #define SuspC CONTROL_('Z') /* norm_tty.c_cc[SWTCH] */ #else /* V7/BSD TTY DRIVER */ #include <sgtty.h> static struct sgttyb norm_tty, raw_tty; static struct tchars norm_chars; #define IntrC norm_chars.t_intrc #define EraseC norm_tty.sg_erase #define KillC norm_tty.sg_kill #ifdef TIOCGLTC static struct ltchars spec_chars; #define SuspC spec_chars.t_suspc #else #define SuspC CONTROL_('Z') #endif #endif #ifdef USE_TERMCAP opt_cap(cap, buf) char *cap, *buf; { char *tgetstr(); *buf = NUL; return tgetstr(cap, &buf) != NULL; } get_cap(cap, buf) char *cap, *buf; { if (!opt_cap(cap, buf)) user_error("TERMCAP entry for %s has no '%s' capability", term_name, cap); } #endif /* USE_TERMCAP */ /* * timeout in n/10 seconds via SIGALRM */ micro_alarm(n) int n; { #ifdef HAVE_UALARM ualarm(n<=1 ? 100000 : n*100000, 0); /* 4.3 BSD ualarm() */ #else #ifdef MICRO_ALARM if (n <= 0) n = 1; MICRO_ALARM(n); /* System specific timeout */ #else alarm(n <= 10 ? 1 : (n+9)/10); /* Standard alarm() call */ #endif #endif } static int multi_keys = 0; static struct multi_key { key_type *cur_key; key_type *keys; key_type code; } multi_key_list[MULTI_KEYS]; enter_multi_key(code, keys) int code; key_type *keys; { register i; if (strlen((char *)keys) == 1) /* will ignore arrow keys overlaying these keys */ if (*keys == NL || *keys == CR || *keys == erase_key || *keys == kill_key || *keys == IntrC) return; /* lookup code to see if it is already defined... */ for (i = 0; i < multi_keys; i++) if (multi_key_list[i].code == (key_type)code) goto replace_key; i = multi_keys++; /* now i points to matching or empty slot */ if (i >= MULTI_KEYS) { /* should never happen */ log_entry('E', "too many multi keys"); return; } replace_key: multi_key_list[i].keys = keys; multi_key_list[i].code = code; } dump_multi_keys() { register i; register key_type *cp; clrdisp(); pg_init(0, 1); for (i = 0; i < multi_keys; i++) { if (pg_next() < 0) break; printf("%d\t%s\t", i, key_name(multi_key_list[i].code)); for (cp = multi_key_list[i].keys; *cp; cp++) { putchar(SP); fputs(key_name(*cp), stdout); } } pg_end(); } #ifdef RESIZING sig_type catch_winch(n) { struct winsize winsize; (void) signal(SIGWINCH, catch_winch); if (ioctl(0, TIOCGWINSZ, &winsize) >= 0 && (winsize.ws_row != Lines || winsize.ws_col != Columns)) { Lines = winsize.ws_row; Columns = winsize.ws_col; s_redraw = 1; s_resized = 1; } #ifdef FAKE_INTERRUPT if (fake_keyb_siglist[n] && arm_fake_keyb_sig) longjmp(fake_keyb_sig, 1); #endif } #endif /* RESIZING */ #ifdef SV_INTERRUPT #ifdef NO_SIGINTERRUPT static siginterrupt(signo, on) { struct sigvec sv; sv.sv_handler = signal (signo, SIG_DFL); sv.sv_mask = 0; sv.sv_flags = on ? SV_INTERRUPT : 0; sigvec (signo, &sv, 0); } #endif #endif #ifdef FAKE_INTERRUPT #define SV_INTERRUPT static siginterrupt (signo, on) { fake_keyb_siglist[signo] = on; } #endif static unsigned sp_table[] = { B9600, 960, #ifdef B19200 B19200, 1920, #else #ifdef EXTA EXTA, 1920, #endif #endif #ifdef B38400 B38400, 3840, #else #ifdef EXTB EXTB, 3840, #endif #endif B1200, 120, B2400, 240, B4800, 480, B300, 30, 0, 0 }; static set_term_speed(sp) register unsigned long sp; { register unsigned *tp; for (tp = sp_table; *tp; tp += 2) if (*tp == sp) { terminal_speed = tp[1]; return; } terminal_speed = 30; } static raw_not_ok_error() { if (batch_mode) return 0; user_error("Not prepared for terminal i/o"); } #define RAW_CHECK if (terminal_speed == 0) return raw_not_ok_error() #define BATCH_CHECK if (terminal_speed == 0) return 0 init_term(full) int full; { #ifdef USE_TERMCAP char tbuf[1024]; #endif if (batch_mode) { term_name = "batch"; close(0); open("/dev/null", 0); STANDOUT = 0; cookie_size = 1; return; } if ((term_name = getenv("TERM")) == NULL) { if (full) user_error("No TERM variable in environment"); else term_name = "unknown"; } if (!full) return; #ifdef HAVE_TERMIO ioctl(0, TCGETA, &norm_tty); #else ioctl(0, TIOCGETP, &norm_tty); #endif #ifdef USE_TERMINFO setupterm((char *)NULL, 1, (int *)NULL); Columns = columns; Lines = lines; cookie_size = magic_cookie_glitch; if (use_visible_bell && HAS_CAP(flash_screen)) strcpy(bell_str, flash_screen); else if (HAS_CAP(bell)) strcpy(bell_str, bell); if (! HAS_CAP(cursor_home)) cursor_home = copy_str(tgoto(cursor_address, 0, 0)); #else if (tgetent(tbuf, term_name) <= 0) user_error("Unknown terminal type: %s", term_name); if (opt_cap("bc", XBC)) BC = XBC; if (opt_cap("up", XUP)) UP = XUP; opt_cap("pc", cursor_address); /* temp. usage */ PC = cursor_address[0]; get_cap("cm", cursor_address); if (!opt_cap("ho", cursor_home)) strcpy(cursor_home, tgoto(cursor_address, 0, 0)); get_cap("cl", clear_screen); get_cap("ce", clr_eol); opt_cap("cd", clr_eos); Lines = tgetnum("li"); Columns = tgetnum("co"); opt_cap("so", enter_standout_mode); opt_cap("se", exit_standout_mode); opt_cap("us", enter_underline_mode); opt_cap("ue", exit_underline_mode); opt_cap("kd", key_down); opt_cap("ku", key_up); opt_cap("kr", key_right); opt_cap("kl", key_left); cookie_size = tgetnum("sg"); ceol_standout_glitch = tgetflag("xs"); opt_cap("ti", enter_ca_mode); opt_cap("te", exit_ca_mode); opt_cap("ks", keypad_xmit); /* used to turn "application cursor */ opt_cap("ke", keypad_local); /* key" mode on and off (sometimes) */ if (!use_visible_bell || !opt_cap("vb", bell_str)) if (!opt_cap("bl", bell_str)) strcpy(bell_str, "\007"); #endif /* !USE_TERMINFO */ #ifdef RESIZING { struct winsize winsize; if (ioctl(0, TIOCGWINSZ, &winsize) >= 0 && winsize.ws_row != 0 && winsize.ws_col != 0) { Lines = winsize.ws_row; Columns = winsize.ws_col; (void) signal(SIGWINCH, catch_winch); #ifdef SV_INTERRUPT siginterrupt(SIGWINCH, 1); /* make read from tty interruptable */ #endif /* SV_INTERRUPT */ } } #endif /* RESIZING */ STANDOUT = HAS_CAP(enter_standout_mode); if (STANDOUT) { if (cookie_size < 0) cookie_size = 0; two_cookies = 2 * cookie_size; } else cookie_size = two_cookies = 0; raw_tty = norm_tty; #ifdef HAVE_TERMIO raw_tty.c_iflag &= ~(BRKINT|INLCR|ICRNL|IGNCR|ISTRIP); raw_tty.c_iflag |= IGNBRK|IGNPAR; raw_tty.c_oflag &= ~OPOST; raw_tty.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|NOFLSH); /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */ raw_tty.c_cc[VEOF] = KEY_BURST; raw_tty.c_cc[VEOL] = ((raw_tty.c_cflag & CBAUD) > B1200) ? 1 : 2; set_term_speed((unsigned long)(raw_tty.c_cflag & CBAUD)); #else ioctl(0, TIOCGETC, &norm_chars); #ifdef TIOCGLTC ioctl(0, TIOCGLTC, &spec_chars); #endif ospeed = norm_tty.sg_ospeed; set_term_speed((unsigned long)ospeed); raw_tty.sg_flags &= ~(ECHO | CRMOD); #ifdef CBREAK #ifdef SV_INTERRUPT /* make read from tty interruptable */ siginterrupt(SIGTSTP, 1); /* this is necessary to redraw screen */ #endif raw_tty.sg_flags |= CBREAK; #else raw_tty.sg_flags |= RAW; #endif #ifdef SV_INTERRUPT siginterrupt(SIGALRM, 1); /* make read from tty interruptable */ #endif #endif erase_key = (key_type)EraseC; kill_key = (key_type)KillC; if (HAS_CAP(key_down)) enter_multi_key(K_down_arrow, (key_type *)key_down); if (HAS_CAP(key_up)) enter_multi_key(K_up_arrow, (key_type *)key_up); if (HAS_CAP(key_right)) enter_multi_key(K_right_arrow, (key_type *)key_right); if (HAS_CAP(key_left)) enter_multi_key(K_left_arrow, (key_type *)key_left); appl_keypad_mode = (HAS_CAP(keypad_xmit) && HAS_CAP(keypad_local)); if (!HAS_CAP(key_up)) appl_keypad_mode = 0; /* no cursor keys */ if (appl_keypad_mode) { /* Use of ks/ke isn't consistent, so we must guess what to do. */ /* If termcap expects keys to send ESC [, don't switch */ appl_keypad_mode = (key_up[0] != '\033' || key_up[1] != '['); } visual_on(); } home() { BATCH_CHECK; putp(cursor_home); } static int curxy_c = -1, curxy_l, savxy_c = -1, savxy_l; save_xy() { savxy_c = curxy_c; savxy_l = curxy_l; } restore_xy() { if (savxy_c < 0) return; gotoxy(savxy_c, savxy_l); fl; } gotoxy(c, l) int c, l; { BATCH_CHECK; curxy_c = c; curxy_l = l; putp(tgoto(cursor_address, c, l)); } clrdisp() { BATCH_CHECK; #ifdef USE_TERMINFO putp(clear_screen); /* tputs is broken on UNISYS I've been told */ #else tputs(clear_screen, Lines, outc); #endif curxy_c = savxy_c = -1; msg_ptr = msg_stack; } clrline() { BATCH_CHECK; putp(clr_eol); fl; } clrline_noflush() { BATCH_CHECK; putp(clr_eol); } clrpage(lineno) register int lineno; { register int olineno= lineno; BATCH_CHECK; if (HAS_CAP(clr_eos)) { #ifdef USE_TERMINFO putp(clr_eos); #else tputs(clr_eos, Lines - lineno, outc); #endif } else { clrline(); lineno++; for (; lineno < Lines; lineno++) { gotoxy(0, lineno); putp(clr_eol); } gotoxy(0, olineno); fl; } msg_ptr = msg_stack; } static char so_buf[512], *so_p; static int so_c, so_l, so_b, so_active = 0; so_gotoxy(c, l, blank) { if (!STANDOUT && c >= 0) { if (l >= 0) gotoxy(c, l); return 0; } so_active++; so_c = c; so_l = l; so_b = blank; so_p = so_buf; *so_p = NUL; return 1; /* not really true if not standout & c < 0 */ } /*VARARGS*/ so_printf(va_alist) va_dcl { use_vararg; start_vararg; so_vprintf(va_args1toN); end_vararg; } so_vprintf(va_tail) va_tdcl { char *fmt; fmt = va_arg1(char *); if (!so_active) { if (ceol_standout_glitch) highlight(0); vprintf(fmt, va_args2toN); return; } vsprintf(so_p, fmt, va_args2toN); while (*so_p) so_p++; } so_end() { int len; if (!so_active) return; if (so_l >= 0) { len = so_p - so_buf + two_cookies; if (so_c < 0) so_c = Columns - len - 2; if (so_c < 0) so_c = 0; if (len + so_c >= Columns) { len = Columns - so_c - two_cookies; so_buf[len] = NUL; } if (cookie_size) { gotoxy(so_c + len - cookie_size, so_l); putp(exit_standout_mode); } gotoxy(so_c, so_l); } if ((so_b & 1) && (!STANDOUT || !cookie_size)) putchar(SP); if (STANDOUT) { if (ceol_standout_glitch) clrline(); putp(enter_standout_mode); } fputs(so_buf, stdout); if (STANDOUT) putp(exit_standout_mode); if ((so_b & 2) && (!STANDOUT || !cookie_size)) putchar(SP); so_active = 0; } /*VARARGS*/ so_printxy(va_alist) va_dcl { int k, l; use_vararg; start_vararg; k = va_arg1(int); l = va_arg2(int); so_gotoxy(k, l, 0); so_vprintf(va_args3toN); so_end(); end_vararg; } underline(on) { if (cookie_size) return 0; if (! HAS_CAP(enter_underline_mode)) return 0; putp(on ? enter_underline_mode : exit_underline_mode); return 1; } highlight(on) { if (cookie_size) return 0; if (! HAS_CAP(enter_standout_mode)) return 0; putp(on ? enter_standout_mode : exit_standout_mode); return 1; } static int is_visual = 0; static int is_raw = 0; #ifdef HAVE_TERMIO #define RAW_MODE_ON ioctl(0, TCSETAW, &raw_tty) #define RAW_MODE_OFF ioctl(0, TCSETAW, &norm_tty) #else #define RAW_MODE_ON ioctl(0, TIOCSETP, &raw_tty) #define RAW_MODE_OFF ioctl(0, TIOCSETP, &norm_tty) #endif visual_on() { BATCH_CHECK; if (HAS_CAP(enter_ca_mode)) { putp(enter_ca_mode); is_visual = 1; } if (appl_keypad_mode) { putp(keypad_xmit); is_visual = 1; } } visual_off() { int was_raw = is_raw; if (terminal_speed == 0) return 0; if (is_visual) { if (appl_keypad_mode) putp(keypad_local); if (HAS_CAP(exit_ca_mode)) putp(exit_ca_mode); fl; is_visual = 0; } is_raw = 1; unset_raw(); return was_raw; } #ifdef CBREAK raw() { RAW_CHECK; if (is_raw == 1) return; is_raw = 1; RAW_MODE_ON; } no_raw() { return 0; } unset_raw() { if (is_raw == 0) return 0; RAW_CHECK; RAW_MODE_OFF; is_raw = 0; return 1; } #else /* not CBREAK */ static int must_set_raw = 1; raw() { RAW_CHECK; if (!flow_control) { if (!must_set_raw) return; must_set_raw = 0; } if (is_raw) return; RAW_MODE_ON; is_raw++; } no_raw() { if (!flow_control) return 0; if (!is_raw) return 0; RAW_CHECK; RAW_MODE_OFF; is_raw = 0; return 1; } unset_raw() { int was_raw = is_raw; if (is_raw) { RAW_CHECK; RAW_MODE_OFF; is_raw = 0; } if (!flow_control) must_set_raw = 1; return was_raw; } #endif /* CBREAK */ #ifndef KEY_BURST #define KEY_BURST 32 #endif #define RD_PUSHBACK 10 static char rd_buffer[KEY_BURST+RD_PUSHBACK]; /* Holds stuff from read */ static char *rd_ptr; static int rd_count = 0, rd_alarm = 0; #ifdef FAKE_INTERRUPT static jmp_buf fake_alarm_sig; #endif static sig_type rd_timeout() { rd_alarm = 1; #ifdef FAKE_INTERRUPT longjmp(fake_alarm_sig, 1); #endif } #define RD_TIMEOUT 0x1000 #define RD_INTERRUPT 0x1001 static int read_char_kbd(tmo) int tmo; /* timeout if no input arrives */ { if (rd_count <= 0) { if (tmo) { #ifdef FAKE_INTERRUPT if (setjmp(fake_alarm_sig)) goto tmout; #endif rd_alarm = 0; signal(SIGALRM, rd_timeout); micro_alarm(multi_key_guard_time); } rd_ptr = rd_buffer + RD_PUSHBACK; rd_count = read(0, rd_ptr, KEY_BURST); if (tmo) { if (rd_alarm) goto tmout; alarm(0); } if (rd_count < 0) { if (errno != EINTR) s_hangup++; return RD_INTERRUPT; } } --rd_count; return *rd_ptr++; tmout: rd_count = 0; return RD_TIMEOUT; } static unread_char(c) char c; { if (rd_ptr == rd_buffer) return; rd_count++; *--rd_ptr = c; } flush_input() { int arg; BATCH_CHECK; #ifdef HAVE_TERMIO ioctl(0, TCFLSH, 0); #else #ifdef FREAD arg = FREAD; ioctl(0, TIOCFLUSH, &arg); #else ioctl(0, TIOCFLUSH, 0); #endif #endif rd_count = 0; } int enable_stop = 1; static int do_macro_processing = 1; get_c() { key_type c, first_key; int key_cnt, mc, n; register struct multi_key *mk, *multi_match; register int i; next_key: if (s_hangup) return K_interrupt; if (do_macro_processing) switch (m_getc(&mc)) { case 0: break; case 1: return mc; case 2: return K_interrupt; } #ifdef RESIZING if (s_resized) goto redraw; #endif if (batch_mode) user_error("Attempt to read keyboard input in batch mode"); for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++) mk->cur_key = mk->keys; key_cnt = 0; #ifdef FAKE_INTERRUPT if (setjmp(fake_keyb_sig)) goto intr; arm_fake_keyb_sig = 1; #endif multi: switch (n = read_char_kbd(key_cnt)) { case RD_INTERRUPT: #ifdef CBREAK if (s_redraw) goto redraw; #endif #ifdef RESIZING if (s_resized) goto redraw; #endif goto intr; case RD_TIMEOUT: while (--key_cnt > 0) unread_char(multi_match->keys[key_cnt]); c = first_key; goto got_char; default: c = (key_type)n; if (data_bits < 8) c &= 0x7f; if (ignore_xon_xoff) if (c == CONTROL_('Q') || c == CONTROL_('S')) goto multi; break; } multi_match = NULL; for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++) { if (mk->cur_key == NUL) continue; if (*(mk->cur_key)++ != c) { mk->cur_key = NUL; continue; } if (*(mk->cur_key) == NUL) { c = mk->code; goto got_char; } multi_match = mk; } if (multi_match) { if (key_cnt == 0) first_key = c; key_cnt++; goto multi; } if (key_cnt) { if (key_cnt == 1 && first_key == 033) { unread_char(c); c = 033; goto got_char; } ding(); flush_input(); goto next_key; } got_char: #ifdef FAKE_INTERRUPT arm_fake_keyb_sig = 0; #endif c = global_key_map[c]; #ifndef CBREAK if (c == IntrC) return K_interrupt; /* don't flush */ if (c == SuspC) { if (enable_stop && suspend_nn()) goto redraw; goto next_key; } #endif return (int)c; intr: #ifdef FAKE_INTERRUPT arm_fake_keyb_sig = 0; #endif rd_count = 0; return K_interrupt; redraw: #ifdef RESIZING s_resized = 0; #endif s_redraw = 0; return GETC_COMMAND | K_REDRAW; } /* * read string with completion, pre-filling, and break on first char * * dflt is a string that will be use as default value if the * space bar is hit as the first character. * * prefill pre-fill the buffer with .... and print it * * break_chars return immediately if one of these characters * is entered as the first character. * * completion is a function that will fill the buffer with a value * see the group_completion and file_completion routines * for examples. */ char *get_s(dflt, prefill, break_chars, completion) char *dflt, *prefill, *break_chars; fct_type completion; { static key_type buf[GET_S_BUFFER]; register char *cp; register int i, c, lastc; char *ret_val = (char *)buf; int comp_used, comp_len; int ostop, max, did_help; int hit_count; switch (m_gets(buf)) { case 0: break; case 1: return (char *)buf; case 2: return NULL; } ostop = enable_stop; enable_stop = 0; do_macro_processing = 0; hit_count = 0; max = Columns - prompt_length; if (max >= FILENAME) max = FILENAME-1; i = comp_len = comp_used = did_help = 0; if (prefill && prefill[0]) { while (c = *prefill++) { if (i == max) break; putchar(c); buf[i] = c; i++; } fl; } if (dflt && *dflt == NUL) dflt = NULL; if (break_chars && *break_chars == NUL) break_chars = NULL; c = NUL; for(;;) { lastc = c; c = get_c(); if (c & GETC_COMMAND) continue; kill_prefill_hack: hit_count++; if (i == 0) { if (c == comp1_key && dflt) { while ((c = *dflt++) != NUL && i < max) { putchar(c); buf[i] = c; i++; } fl; dflt = NULL; continue; } if (cp = break_chars) { while (*cp) if (*cp++ == c) { buf[0] = c; buf[1] = NUL; goto out; } } } if (completion != NULL_FCT) { if (comp_used && c == erase_key) { if (comp_len) { i -= comp_len; while (--comp_len >= 0) putchar(BS); clrline(); } if (!CALL(completion)(buf, -(i+1)) && did_help) clrmsg(i); did_help = 0; comp_len = comp_used = 0; if (lastc == help_key) goto no_completion; continue; } if (c == comp1_key || c == comp2_key || c == help_key) { if (!comp_used || c == comp2_key || (c == help_key && lastc != c)) { buf[i] = NUL; if ((comp_used = CALL(completion)(buf, i)) == 0) { ding(); continue; } if (comp_used < 0) { comp_used = 0; goto no_completion; } comp_len = 0; } if (c == help_key) { if (CALL(completion)((char *)NULL, 1)) { gotoxy(prompt_length+i, prompt_line); fl; did_help = 1; } continue; } if (comp_len) { i -= comp_len; while (--comp_len >= 0) putchar(BS); clrline(); comp_len = 0; } switch ( CALL(completion)((char *)NULL, 0) ) { case 0: /* no possible completion */ comp_used = 0; ding(); continue; case 2: /* whole new alternative */ while (--i >= 0) putchar(BS); clrline(); /* fall thru */ case 1: /* completion */ comp_len = i; while (c = buf[i]) { if (i == max) break; putchar(c); i++; } fl; comp_len = i - comp_len; continue; } } if (comp_used) { if (!CALL(completion)(buf, -(i+1)) && did_help) clrmsg(i); did_help = 0; comp_len = comp_used = 0; } } no_completion: if (c == CR || c == NL) { buf[i] = NUL; break; } if (c == erase_key) { if (i <= 0) continue; i--; putchar(BS); putchar(' '); putchar(BS); fl; continue; } if (c == delword_key) { if (i <= 0) continue; buf[i-1] = 'X'; while (i > 0 && isalnum(buf[i-1])) { putchar(BS); i--; } clrline(); continue; } if (c == kill_key) { while (i > 0) { putchar(BS); i--; } clrline(); if (hit_count == 1 && dflt) { c = comp1_key; goto kill_prefill_hack; } continue; } if (c == K_interrupt) { ret_val = NULL; break; } if (data_bits == 8) { if (!iso8859(c)) continue; } else if (!isascii(c) || !isprint(c)) continue; if (i == max) continue; if (i > 0 && buf[i-1] == '/' && (c == '/' || c == '+')) { if (c != '/' || !guard_double_slash || (i > 1 && buf[i-2] == '/')) { extern int file_completion(); if (completion == file_completion) { while (i > 0) { putchar(BS); i--; } clrline(); } } } putchar(c); fl; buf[i] = c; i++; } out: enable_stop = ostop; do_macro_processing = 1; return ret_val; } export int list_offset = 0; list_completion(str) char *str; { static int cols, line; if (str == NULL) { cols = Columns; line = prompt_line + 1; if (line == Lines - 1) cols--; gotoxy(0, line); clrpage(line); return 1; } str += list_offset; for (;;) { cols -= strlen(str); if (cols >= 0) { printf("%s%s", str, cols > 0 ? " " : ""); cols--; return 1; } if (line >= Lines - 1) return 0; line++; cols = Columns; gotoxy(0, line); if (line == Lines - 1) cols--; } } yes(must_answer) int must_answer; { int c, help = 1, in_macro = 0; switch (m_yes()) { case 0: break; case 1: return 0; case 2: return 1; case 3: do_macro_processing = 0; in_macro++; break; } fl; for (;;) { if (!is_raw) { raw(); c = get_c(); unset_raw(); } else c = get_c(); if (c == 'y' || c == 'Y') { c = 1; break; } if (must_answer == 0 && (c == SP || c == CR || c == NL)) { c = 1; break; } if (c == 'n' || c == 'N') { c = 0; break; } if (c == K_interrupt) { c = -1; break; } if (help) { fputs(" y=YES n=NO", stdout); fl; prompt_length += 11; help = 0; } } if (in_macro) { if (c < 0) m_break(); do_macro_processing = 1; } return c; } ding() { BATCH_CHECK; putp(bell_str); fl; } display_file(name, modes) char *name; int modes; { FILE *f; register c, stand_on; int linecnt, headln_cnt, hdline, no_conf; char headline[128]; import char *help_directory; headline[0] = 0; hdline = 0; no_conf = 0; headln_cnt = -1; if (modes & CLEAR_DISPLAY) { gotoxy(0,0); clrdisp(); } linecnt = Lines - 1; chain: if (*name != '/') name = relative(help_directory, name); f = open_file(name, OPEN_READ); if (f == NULL) printf("\r\n\nFile %s is not available\n\n", name); else { stand_on = 0; while ((c = getc(f)) != EOF) { #ifdef HAVE_JOBCONTROL if (s_redraw) { no_conf = 1; break; } #endif no_conf = 0; if (c == '\1') { if (STANDOUT) { putp(stand_on ? exit_standout_mode : enter_standout_mode); stand_on = !stand_on; } continue; } if (c == '\2') { headln_cnt = 0; continue; } if (c == '\3') { headln_cnt = 0; while ((c = getc(f)) != EOF && c != NL) headline[headln_cnt++] = c; headline[headln_cnt++] = NUL; name = headline; fclose(f); goto chain; } if (c == '\4') { printf("%s", version_id); continue; } if (headln_cnt >= 0) headline[headln_cnt++] = c; if (hdline) { puts(headline); putchar(CR); hdline = 0; linecnt--; } putchar(c); if (c == NL) { putchar(CR); if (headln_cnt >= 0) { headline[--headln_cnt] = 0; headln_cnt = -1; } if (--linecnt == 0) { no_conf = 1; if (any_key(0) == K_interrupt) break; linecnt = Lines - 1; if (modes & CLEAR_DISPLAY) { gotoxy(0,0); clrdisp(); } hdline = headline[0]; } } } if (stand_on) putp(exit_standout_mode); fclose(f); } prompt_line = Lines-1; /* move prompt to last line */ if (!no_conf && (modes & CONFIRMATION)) any_key(prompt_line); } /*VARARGS*/ user_error(va_alist) va_dcl { char *fmt; use_vararg; if (terminal_speed != 0) { clrdisp(); visual_off(); fl; } start_vararg; fmt = va_arg1(char *); vprintf(fmt, va_args2toN); putchar(NL); end_vararg; nn_exit(1); } /*VARARGS*/ msg(va_alist) va_dcl { use_vararg; start_vararg; vmsg(va_args1toN); end_vararg; } push_msg(str) char *str; { register struct msg_list *mp, *newmsg; static int slots = 0; if (str != NULL) { if (slots > message_history) { for (mp = newmsg = msg_stack; mp->prev != NULL; mp = mp->prev) newmsg = mp; if (newmsg == mp) msg_stack = NULL; else { newmsg->prev = NULL; newmsg = mp; } freeobj(newmsg->buf); } else { slots++; newmsg = newobj(struct msg_list, 1); } newmsg->buf = copy_str(str); newmsg->prev = msg_stack; msg_stack = newmsg; } msg_ptr = msg_stack; } vmsg(va_tail) va_tdcl { char *errmsg, *fmt; fmt = va_arg1(char *); if (fmt) { char buf[512]; vsprintf(buf, fmt, va_args2toN); push_msg(buf); } if (msg_ptr) { errmsg = msg_ptr->buf; msg_ptr = msg_ptr->prev; } else { errmsg = "(no more messages)"; msg_ptr = msg_stack; } if (terminal_speed == 0) { printf("%s\n", errmsg); fl; return; } gotoxy(0, Lines-1); fputs(errmsg, stdout); clrline(); any_message = 1; gotoxy(prompt_length, prompt_line); fl; } clrmsg(col) int col; { BATCH_CHECK; gotoxy(0, prompt_line + 1); clrpage(prompt_line + 1); if (col >= 0) gotoxy(prompt_length + col, prompt_line); fl; any_message = 0; } /*VARARGS*/ prompt(va_alist) va_dcl { register char *cp; int stand_on; char *fmt; static char cur_p[FILENAME]; static char saved_p[FILENAME]; use_vararg; BATCH_CHECK; start_vararg; fmt = va_arg1(char *); if (fmt == P_VERSION) { gotoxy(0, prompt_line + 1); printf("Release %s ", version_id); clrline(); any_message++; if (prompt_line >= 0) gotoxy(prompt_length, prompt_line); goto out; } if (fmt == P_SAVE) { strcpy(saved_p, cur_p); goto out; } if (fmt == P_RESTORE) strcpy(cur_p, saved_p); if (prompt_line >= 0) gotoxy(0, prompt_line); if (fmt == P_MOVE) { clrline(); goto out; } if (fmt != P_REDRAW && fmt != P_RESTORE) vsprintf(cur_p, fmt, va_args2toN); putchar(CR); for (cp = cur_p, stand_on = 0, prompt_length = 0; *cp; cp++) { if (*cp == '\1') { if (cp[1] != '\1') { if (STANDOUT) { putp(stand_on ? exit_standout_mode : enter_standout_mode); stand_on = !stand_on; prompt_length += cookie_size; } continue; } cp++; } else if (*cp == '\2') { time_t t, tick_usage(); char *timestr; t = tick_usage(); if (show_current_time) { timestr = ctime(&t) + 11; timestr[5] = NUL; printf("-- %s ", timestr); prompt_length += 9; } if (unread_mail(t)) { printf("Mail "); prompt_length += 5; } continue; } putchar(*cp); prompt_length ++; } if (stand_on) { putp(exit_standout_mode); prompt_length += cookie_size; } clrline(); if (fmt == P_RESTORE) restore_xy(); else curxy_c = -1; out: end_vararg; } any_key(line) int line; { int was_raw, c, dmp; BATCH_CHECK; was_raw = is_raw; if (!is_raw) raw(); if (line == 0) line = -1; else if (line < 0) line = Lines + line; if (line != 10000) so_printxy(0, line, "Hit any key to continue"); clrline(); dmp = do_macro_processing; do_macro_processing = 0; c = get_c(); if (c == 'q' || c == 'Q') c = K_interrupt; do_macro_processing = dmp; if (!was_raw) unset_raw(); return c; } static pg_fline, pg_width, pg_maxw, pg_line, pg_col, pg_quit; export regexp *pg_regexp = NULL; export int pg_new_regexp = 0; pg_init(first_line, cols) int first_line, cols; { if (pg_regexp) { freeobj(pg_regexp); pg_regexp = NULL; } pg_new_regexp = 0; pg_fline = first_line; pg_line = pg_fline - 1; pg_quit = pg_col = 0; pg_width = Columns / cols; pg_maxw = pg_width * (cols - 1); } pg_scroll(n) int n; { pg_line += n; if (pg_line >= (Lines - 1)) { pg_line = 0; if (any_key(0) == K_interrupt) return 1; putchar(CR); clrline(); } return 0; } pg_next() { int c; if (batch_mode) { putchar(NL); return 0; } pg_line++; if (pg_line < Lines) { gotoxy(pg_col, pg_line); if (pg_line == Lines - 1 && pg_col == pg_maxw) { c = any_key(0); if (c == '/') { char *expr; putchar(CR); putchar('/'); clrline(); expr = get_s((char *)NULL, (char *)NULL, (char *)NULL, NULL_FCT); if (expr != NULL && *expr != NUL) { freeobj(pg_regexp); pg_regexp = regcomp(expr); pg_new_regexp = 1; } } gotoxy(0, pg_fline); clrpage(pg_fline); pg_col = 0; pg_line = pg_fline; if (c == K_interrupt) { pg_quit = 1; return -1; } return 1; } } else { pg_line = pg_fline; pg_col += pg_width; gotoxy(pg_col, pg_line); } return 0; } pg_indent(pos) int pos; { BATCH_CHECK; gotoxy(pg_col + pos, pg_line); } pg_end() { int c; if (pg_quit == 0 && pg_next() == 0) c = any_key(0); else c = K_interrupt; if (pg_regexp) { freeobj(pg_regexp); pg_regexp = NULL; } return c == K_interrupt ? -1 : 0; } user_delay(ticks) int ticks; { BATCH_CHECK; if (ticks <= 0 || conf_dont_sleep) { printf(" <>"); any_key(10000); } else { fl; sleep((unsigned)ticks); } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.