📄 rl.c
字号:
/* New for v2.0: readline support -- daw *//* this is the main bunch of code for readline; lots of misc stuff here */#ifdef HAVE_STRING_H#include <string.h>#else#ifdef HAVE_STRINGS_H#include <strings.h>#endif#endif#include <sys/types.h>#include <sys/time.h>#include <stdio.h>#include <errno.h>#include <readline/readline.h>#include "tintin.h"/* note: changed to allow autodetection/manual change of screensize, //SN */static int SPLITLINE;static int COLS;/* this gets set when user hits control-z, so we don't worry about EINTR */int ignore_interrupt;/* what column we were at in the top window; only for split mode */static int topwin_col = 0;#define ISAPROMPT(x) (strchr((x), '>'))/* some readline stuff */int (*rl_event_hook)();int (*rl_completion_entry_function)();extern int _rl_last_c_pos;extern int _rl_eof_char;extern int readline_echoing_p;extern int history_expand();extern int errno;extern struct session *sessionlist, *activesession;extern int is_split;extern int redraw;extern int puts_echoing;extern struct session *parse_input();extern struct session *newactive_session();extern char *rltab_generate();extern char *rlhist_expand();void tintin_puts();extern char *getenv();extern char *tgetstr();extern char *get_arg_in_braces();static voidctrl_r_redraw(count, key) int count; int key;{ if (is_split) { goto_rowcol(SPLITLINE+1, 0); erase_toeol(); } else printf("\n"); fflush(stdout); _rl_last_c_pos = 0; rl_forced_update_display();}static void readmud();/* for use with rl_event_hook */static voidbait(/* void */){ fd_set readfds; struct session *s, *t; struct timeval to; int rv, maybe_redraw; FD_ZERO(&readfds); while (!FD_ISSET(0, &readfds)) { FD_ZERO(&readfds); FD_SET(0, &readfds); /* stdin */ for (s=sessionlist; s; s=s->next) FD_SET(s->socket, &readfds); to.tv_sec = checktick(); /* 100 */ to.tv_usec = 0; ignore_interrupt = 0; rv = select(FD_SETSIZE, &readfds, NULL, NULL, &to); if (rv == 0) continue; /* timeout */ else if (rv < 0 && errno == EINTR && ignore_interrupt) continue; /* user hit ^Z; don't worry, be happy */ else if (rv < 0) syserr("select"); maybe_redraw = 0; for (s=sessionlist; s; s=t) { t = s->next; /* s may be free()d out from under us */ if (FD_ISSET(s->socket, &readfds)) { readmud(s); maybe_redraw = 1; } } if (maybe_redraw && redraw && !is_split) ctrl_r_redraw(); }}voidinitrl(/* void */){ rl_readline_name = "tintin++"; rl_completion_entry_function = (int (*)()) rltab_generate; using_history(); stifle_history(HISTORY_SIZE); rl_variable_bind("horizontal-scroll-mode", "on"); rl_bind_key('\022', ctrl_r_redraw); /* control-r */ rl_bind_key_in_map('\022', ctrl_r_redraw, vi_movement_keymap); rl_bind_key_in_map('\022', ctrl_r_redraw, vi_insertion_keymap); rl_event_hook = (int (*)()) bait; /* * a hack to let ^d work like it used to in old tt++: * by default, readline won't let you rebind the eof * character when it's at the start of the line, so * let's pull the wool over readline. * bug: remember to undo the stty! check portability! */ _rl_eof_char = '\001'; /* control-b : something innocuous */ system("stty eof '^b'"); rl_bind_key('\004', rl_get_previous_history); /* control-d */ rl_bind_key_in_map('\004', rl_get_previous_history, vi_movement_keymap); rl_bind_key_in_map('\004', rl_get_previous_history,vi_insertion_keymap);}/* Autodetect screensize: Code gotten from v1.64DEV *//* //SN */void setSCREENSIZE(p_line,p_cols) int *p_line, *p_cols;{ register char *s; if ((s = getenv("LINES")) != (char *) 0) *p_line = atoi(s); else *p_line = tgetnum("li"); if (*p_line <= 0) *p_line = 24; if ((s = getenv("COLUMNS")) != (char *) 0) *p_cols = atoi(s); else *p_cols = tgetnum("co"); if (*p_cols <= 0) *p_cols = 80;}/* Changed to allow screensize detection/manual set, //SN *//* turn on split mode */static voidinitsplit(/* void */){ SPLITLINE--; is_split = 1; topwin_col = 0; reset(); erase_screen(); scroll_region(1, SPLITLINE-1); goto_rowcol(SPLITLINE, 0); printf(" ---- "); goto_rowcol(SPLITLINE+1, 0); save_pos(); fflush(stdout);}/* Removed the wrap-at-end-of-screen code, //SN */static voidprintline(s, isaprompt) char *s;{ topwin_col = 0; puts(s);}voidmainloop(/* void */){ char *line; initrl(); /* Already done in main() initsplit(); */ for (;;) { line = readline(""); if (line == NULL) syserr("readline() == NULL"); line = rlhist_expand(line); if (line == NULL) continue; if (is_split) goto_rowcol(SPLITLINE-1, topwin_col); /* commands will echo to the top screen */ if (is_split) printline(line, 0); activesession = parse_input(line, activesession); if (is_split) { goto_rowcol(SPLITLINE+1, 0); erase_toeol(); fflush(stdout); } free(line); }}/* an uncalled noop -- for now */static voidsee_prompt(b, l) char *b; int l;{ /* soon this will try to recognize prompts and process them */ /* maybe use IACGA */}/* data waiting on this mud session; read & display it; do the dirty work */static voidreadmud(s) struct session *s;{ char thebuffer[2*BUFFER_SIZE+1], *buf, *p, *q; char linebuf[BUFFER_SIZE], header[BUFFER_SIZE]; int rv, i, headerlen; buf = thebuffer + BUFFER_SIZE; rv = read_buffer_mud(buf, s); if (rv == 0) { cleanup_session(s); if (s == activesession) activesession = newactive_session(); return; } else if (rv < 0) syserr("readmud: read"); buf[++rv] = '\0'; if (s == activesession) header[0] = '\0'; else if (s->snoopstatus) sprintf(header, "%s%% ", s->name); else return; headerlen = strlen(header); if (s->old_more_coming) { p = s->last_line; buf -= strlen(p); while (*p) *buf++ = *p++; buf -= strlen(s->last_line); s->last_line[0] = '\0'; } logit(s, buf); if (is_split) { save_pos(); goto_rowcol(SPLITLINE-1, topwin_col); } /* separate into lines and print away */ for (p=buf; p && *p; p=q) { if ((q = strchr(p, '\n')) == NULL && s->more_coming) break; if (q) { *q++ = '\0'; if (*q == '\r') /* ignore \r's */ q++; } strcpy(linebuf, p); do_one_line(linebuf, s); /* changes linebuf */ if (strcmp(linebuf, ".") != 0) { strcat(header, linebuf); printline(header, (q == NULL) && ISAPROMPT(header)); header[headerlen] = '\0'; } } if (p && *p) strcpy(s->last_line, p); if (is_split) restore_pos(); fflush(stdout); /* q: do we need to do some sort of redraw here? i don't think so */ /* a: no, i do it at the end of mainloop() [for now] */}/* * output to screen should go through this function * the output is NOT checked for actions or anything */voidtintin_puts2(cptr, ses) char *cptr; struct session *ses;{ char *p; if ((ses != activesession && ses != 0) || !puts_echoing) return; if (is_split) { goto_rowcol(SPLITLINE-1, topwin_col); } printline(cptr, 0); fflush(stdout); /* q: do we need to do some sort of redraw here? i don't think so */ /* a: right now, i think so */ if (redraw && !is_split) ctrl_r_redraw();}/***********************************************//* the #statusline command * By Sverre Normann *//***********************************************//* Syntax: #statusline {text} *//***********************************************//* Used to write the statusline in split-mode *//***********************************************/void statusline_command(arg, ses) char *arg; struct session *ses;{ char left[BUFFER_SIZE], temp[BUFFER_SIZE]; if (is_split) { arg=get_arg_in_braces(arg, left, 1); substitute_vars(left,temp); substitute_myvars(temp,left,ses); goto_rowcol(SPLITLINE, topwin_col); erase_toeol(); printf(left); goto_rowcol(SPLITLINE-1, 0); } else { tintin_puts2("#Error using #statusline: Split mode not set!",ses); } } /* * output to screen should go through this function * the output IS treated as though it came from the mud */voidtintin_puts(cptr, ses) char *cptr; struct session *ses;{ /* bug! doesn't do_one_line() sometimes send output to stdout? */ /* bug: doesn't do_one_line() modify it's input? are we ok here? */ if (ses) do_one_line(cptr, ses); tintin_puts2(cptr, ses); }/* nobody needs tintin_puts3 anymore*//* get a clean screen without the split crap; useful for ^Z, quitting, etc */voidcleanscreen(/* void */){ /* i think term_echo() was unportable. try to avoid using echo.c */ /* term_echo(); */ system("stty echo"); /* a hack, admittedly */ /* undo the "stty eof '^b'" from initrl() */ system("stty eof '^d'"); if (!is_split) return; scroll_region(1, 24); erase_screen(); reset(); fflush(stdout);}/* undo cleanscreen(); useful after ^Z */voiddirtyscreen(/* void */){ if (is_split) initsplit(); /* put the eof = ^b back; see cleanscreen() and initrl() */ system("stty eof '^b'");}/* quit tintin++ and print a message */voidquitmsg(m) char *m;{ struct session *s; for (s=sessionlist; s; s=s->next) cleanup_session(s); cleanscreen(); if (m) printf("%s\n", m); printf("Goodbye from tintin++.\n"); exit(0);}/* quit tintin++ fast! for use with signal() */voidmyquitsig(/* void */){ quitmsg(NULL);}/* note: split command was changed to allow automatic/manual setting of screen size *//* - no arguments -> automatic detection *//* - else -> params are given on the format {lines,columns} *//* //SN */voidsplit_command(arg,ses) char *arg; struct session *ses;{ char lines[BUFFER_SIZE], cols[BUFFER_SIZE], temp[BUFFER_SIZE]; int c,l; if (is_split) { tintin_puts2("#Error in #split: Already in split mode.",ses); } else { arg=get_arg_in_braces(arg, lines, 0); substitute_vars(lines,temp); substitute_myvars(temp,lines,ses); if (!*lines) { setSCREENSIZE(&SPLITLINE,&COLS); initsplit(); } else { if (sscanf(lines,"%d,%d",&l,&c)!=2) tintin_puts2("#Error. Syntax: #split {lines,columns} Params optional.",ses); else { SPLITLINE=l; COLS=c; initsplit(); } } }}voidunsplit_command(/* void */){ cleanscreen(); is_split = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -