📄 editline.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Simmule Turner and Rich Salz. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. * * This software is not subject to any license of the American Telephone * and Telegraph Company or of the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * 1. The authors are not responsible for the consequences of use of this * software, no matter how awful, even if they arise from flaws in it. * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Since few users ever read sources, * credits must appear in the documentation. * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. Since few users * ever read sources, credits must appear in the documentation. * 4. This notice may not be removed or altered. *//*** Main editing routines for editline library.*/#include "editline.h"#include <signal.h>#include <ctype.h>/*** Manifest constants.*/#define SCREEN_WIDTH 80#define SCREEN_ROWS 24#define NO_ARG (-1)#define DEL 127#define CTL(x) ((x) & 0x1F)#define ISCTL(x) ((x) && (x) < ' ')#define UNCTL(x) ((x) + 64)#define META(x) ((x) | 0x80)#define ISMETA(x) ((x) & 0x80)#define UNMETA(x) ((x) & 0x7F)#if !defined(HIST_SIZE)#define HIST_SIZE 20#endif /* !defined(HIST_SIZE) *//*** Command status codes.*/typedef enum _STATUS { CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal} STATUS;/*** The type of case-changing to perform.*/typedef enum _CASE { TOupper, TOlower} CASE;/*** Key to command mapping.*/typedef struct _KEYMAP { CHAR Key; STATUS (*Function)();} KEYMAP;/*** Command history structure.*/typedef struct _HISTORY { int Size; int Pos; CHAR *Lines[HIST_SIZE];} HISTORY;/*** Globals.*/int rl_eof;int rl_erase;int rl_intr;int rl_kill;int rl_quit;STATIC CHAR NIL[] = "";STATIC CONST CHAR *Input = NIL;STATIC CHAR *Line;STATIC CONST char *Prompt;STATIC CHAR *Yanked;STATIC char *Screen;STATIC char NEWLINE[]= CRLF;STATIC HISTORY H;STATIC int Repeat;STATIC int End;STATIC int Mark;STATIC int OldPoint;STATIC int Point;STATIC int PushBack;STATIC int Pushed;STATIC int Signal;FORWARD KEYMAP Map[32];FORWARD KEYMAP MetaMap[16];STATIC SIZE_T Length;STATIC SIZE_T ScreenCount;STATIC SIZE_T ScreenSize;STATIC char *backspace;STATIC int TTYwidth;STATIC int TTYrows;/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */int rl_meta_chars = 0;/*** Declarations.*/STATIC CHAR *editinput();extern int read();extern int write();#if defined(USE_TERMCAP)extern char *getenv();extern char *tgetstr();extern int tgetent();#endif /* defined(USE_TERMCAP) *//*** TTY input/output functions.*/STATIC voidTTYflush(){ if (ScreenCount) { (void)write(1, Screen, ScreenCount); ScreenCount = 0; }}STATIC voidTTYput(c) CHAR c;{ Screen[ScreenCount] = c; if (++ScreenCount >= ScreenSize - 1) { ScreenSize += SCREEN_INC; RENEW(Screen, char, ScreenSize); }}STATIC voidTTYputs(p) CHAR *p;{ while (*p) TTYput(*p++);}STATIC voidTTYshow(c) CHAR c;{ if (c == DEL) { TTYput('^'); TTYput('?'); } else if (ISCTL(c)) { TTYput('^'); TTYput(UNCTL(c)); } else if (rl_meta_chars && ISMETA(c)) { TTYput('M'); TTYput('-'); TTYput(UNMETA(c)); } else TTYput(c);}STATIC voidTTYstring(p) CHAR *p;{ while (*p) TTYshow(*p++);}STATIC unsigned intTTYget(){ CHAR c; TTYflush(); if (Pushed) { Pushed = 0; return PushBack; } if (*Input) return *Input++; return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;}#define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))STATIC voidTTYbackn(n) int n;{ while (--n >= 0) TTYback();}STATIC voidTTYinfo(){ static int init;#if defined(USE_TERMCAP) char *term; char buff[2048]; char *bp, *p;#endif /* defined(USE_TERMCAP) */#if defined(TIOCGWINSZ) struct winsize W;#endif /* defined(TIOCGWINSZ) */ if (init) {#if defined(TIOCGWINSZ) /* Perhaps we got resized. */ if (ioctl(0, TIOCGWINSZ, &W) >= 0 && W.ws_col > 0 && W.ws_row > 0) { TTYwidth = (int)W.ws_col; TTYrows = (int)W.ws_row; }#endif /* defined(TIOCGWINSZ) */ return; } init++; TTYwidth = TTYrows = 0;#if defined(USE_TERMCAP) bp = &buff[0]; if ((term = getenv("TERM")) == NULL) term = "dumb"; if (tgetent(buff, term) < 0) { TTYwidth = SCREEN_WIDTH; TTYrows = SCREEN_ROWS; return; } p = tgetstr("le", &bp); backspace = p ? strdup(p) : NULL; TTYwidth = tgetnum("co"); TTYrows = tgetnum("li");#endif /* defined(USE_TERMCAP) */#if defined(TIOCGWINSZ) if (ioctl(0, TIOCGWINSZ, &W) >= 0) { TTYwidth = (int)W.ws_col; TTYrows = (int)W.ws_row; }#endif /* defined(TIOCGWINSZ) */ if (TTYwidth <= 0 || TTYrows <= 0) { TTYwidth = SCREEN_WIDTH; TTYrows = SCREEN_ROWS; }}STATIC voidreposition(){ int i; CHAR *p; TTYput('\r'); TTYputs((CONST CHAR *)Prompt); for (i = Point, p = Line; --i >= 0; p++) TTYshow(*p);}STATIC voidleft(Change) STATUS Change;{ TTYback(); if (Point) { if (ISCTL(Line[Point - 1])) TTYback(); else if (rl_meta_chars && ISMETA(Line[Point - 1])) { TTYback(); TTYback(); } } if (Change == CSmove) Point--;}STATIC voidright(Change) STATUS Change;{ TTYshow(Line[Point]); if (Change == CSmove) Point++;}STATIC STATUSring_bell(){ TTYput('\07'); TTYflush(); return CSstay;}STATIC STATUSdo_macro(c) unsigned int c;{ CHAR name[4]; name[0] = '_'; name[1] = c; name[2] = '_'; name[3] = '\0'; if ((Input = (CHAR *)getenv((char *)name)) == NULL) { Input = NIL; return ring_bell(); } return CSstay;}STATIC STATUSdo_forward(move) STATUS move;{ int i; CHAR *p; i = 0; do { p = &Line[Point]; for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++) if (move == CSmove) right(CSstay); for (; Point < End && isalnum(*p); Point++, p++) if (move == CSmove) right(CSstay); if (Point == End) break; } while (++i < Repeat); return CSstay;}STATIC STATUSdo_case(type) CASE type;{ int i; int end; int count; CHAR *p; (void)do_forward(CSstay); if (OldPoint != Point) { if ((count = Point - OldPoint) < 0) count = -count; Point = OldPoint; if ((end = Point + count) > End) end = End; for (i = Point, p = &Line[i]; i < end; i++, p++) { if (type == TOupper) { if (islower(*p)) *p = toupper(*p); } else if (isupper(*p)) *p = tolower(*p); right(CSmove); } } return CSstay;}STATIC STATUScase_down_word(){ return do_case(TOlower);}STATIC STATUScase_up_word(){ return do_case(TOupper);}STATIC voidceol(){ int extras; int i; CHAR *p; for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { TTYput(' '); if (ISCTL(*p)) { TTYput(' '); extras++; } else if (rl_meta_chars && ISMETA(*p)) { TTYput(' '); TTYput(' '); extras += 2; } } for (i += extras; i > Point; i--) TTYback();}STATIC voidclear_line(){ Point = -strlen(Prompt); TTYput('\r'); ceol(); Point = 0; End = 0; Line[0] = '\0';}STATIC STATUSinsert_string(p) CHAR *p;{ SIZE_T len; int i; CHAR *new; CHAR *q; len = strlen((char *)p); if (End + len >= Length) { if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL) return CSstay; if (Length) { COPYFROMTO(new, Line, Length); DISPOSE(Line); } Line = new; Length += len + MEM_INC; } for (q = &Line[Point], i = End - Point; --i >= 0; ) q[len + i] = q[i]; COPYFROMTO(&Line[Point], p, len); End += len; Line[End] = '\0'; TTYstring(&Line[Point]); Point += len; return Point == End ? CSstay : CSmove;}STATIC STATUSredisplay(){ TTYputs((CONST CHAR *)NEWLINE); TTYputs((CONST CHAR *)Prompt); TTYstring(Line); return CSmove;}STATIC STATUStoggle_meta_mode(){ rl_meta_chars = ! rl_meta_chars; return redisplay();}STATIC CHAR *next_hist(){ return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];}STATIC CHAR *prev_hist(){ return H.Pos == 0 ? NULL : H.Lines[--H.Pos];}STATIC STATUSdo_insert_hist(p) CHAR *p;{ if (p == NULL) return ring_bell(); Point = 0; reposition(); ceol(); End = 0; return insert_string(p);}STATIC STATUSdo_hist(move) CHAR *(*move)();{ CHAR *p; int i; i = 0; do { if ((p = (*move)()) == NULL) return ring_bell(); } while (++i < Repeat); return do_insert_hist(p);}STATIC STATUSh_next(){ return do_hist(next_hist);}STATIC STATUSh_prev(){ return do_hist(prev_hist);}STATIC STATUSh_first(){ return do_insert_hist(H.Lines[H.Pos = 0]);}STATIC STATUSh_last(){ return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);}/*** Return zero if pat appears as a substring in text.*/STATIC intsubstrcmp(text, pat, len) char *text; char *pat; int len;{ char c; if ((c = *pat) == '\0') return *text == '\0'; for ( ; *text; text++) if (*text == c && strncmp(text, pat, len) == 0) return 0; return 1;}STATIC CHAR *search_hist(search, move) CHAR *search; CHAR *(*move)();{ static CHAR *old_search; int len; int pos; int (*match)(); char *pat; /* Save or get remembered search pattern. */ if (search && *search) { if (old_search) DISPOSE(old_search); old_search = (CHAR *)strdup((char *)search); } else { if (old_search == NULL || *old_search == '\0') return NULL; search = old_search; } /* Set up pattern-finder. */ if (*search == '^') { match = strncmp; pat = (char *)(search + 1); } else { match = substrcmp; pat = (char *)search; } len = strlen(pat); for (pos = H.Pos; (*move)() != NULL; ) if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) return H.Lines[H.Pos]; H.Pos = pos; return NULL;}STATIC STATUSh_search(){ static int Searching; CONST char *old_prompt; CHAR *(*move)(); CHAR *p; if (Searching) return ring_bell(); Searching = 1; clear_line(); old_prompt = Prompt; Prompt = "Search: "; TTYputs((CONST CHAR *)Prompt); move = Repeat == NO_ARG ? prev_hist : next_hist; p = editinput(); Prompt = old_prompt; Searching = 0; TTYputs((CONST CHAR *)Prompt); if (p == NULL && Signal > 0) { Signal = 0; clear_line(); return redisplay(); } p = search_hist(p, move); clear_line(); if (p == NULL) { (void)ring_bell(); return redisplay(); } return do_insert_hist(p);}STATIC STATUSfd_char(){ int i; i = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -