📄 search.c
字号:
* The command character (as well as the trailing slash) is optional, and
* is assumed to be 'p' if missing.
*/
void
doglob(lp, up, cmd)
LPTR *lp, *up;
char *cmd;
{
LINE *cp;
char *pat;
regexp *prog;
int ndone;
char cmdchar = NUL; /* what to do with matching lines */
/*
* If no range was given, do every line. If only one line
* was given, just do that one.
*/
if (lp->linep == NULL) {
*lp = *Filemem;
*up = *Fileend;
} else {
if (up->linep == NULL)
*up = *lp;
}
pat = ++cmd; /* skip the initial '/' */
while (*cmd) {
if (*cmd == '\\') /* next char is quoted */
cmd += 2;
else if (*cmd == '/') { /* delimiter */
cmdchar = cmd[1];
*cmd++ = NUL;
break;
} else
cmd++; /* regular character */
}
if (cmdchar == NUL)
cmdchar = 'p';
reg_ic = P(P_IC); /* set "ignore case" flag appropriately */
if (cmdchar != 'd' && cmdchar != 'p') {
emsg("Invalid command character");
return;
}
if ((prog = regcomp(pat)) == NULL) {
emsg("Invalid search string");
return;
}
msg("");
ndone = 0;
got_int = FALSE;
for (cp = lp->linep; cp != NULL && !got_int ;cp = cp->next) {
if (regexec(prog, cp->s, TRUE)) { /* a match on this line */
switch (cmdchar) {
case 'd': /* delete the line */
if (Curschar->linep != cp) {
LPTR savep;
savep = *Curschar;
Curschar->linep = cp;
Curschar->index = 0;
delline(1, FALSE);
*Curschar = savep;
} else
delline(1, FALSE);
break;
case 'p': /* print the line */
prt_line(cp->s);
outstr("\r\n");
break;
}
ndone++;
}
if (cp == up->linep)
break;
}
if (ndone) {
switch (cmdchar) {
case 'd':
updatescreen();
if (ndone >= P(P_RP) || got_int)
smsg("%s%d fewer line%c",
got_int ? "Interrupt: " : "",
ndone,
(ndone > 1) ? 's' : ' ');
break;
case 'p':
wait_return();
break;
}
} else {
if (got_int)
msg("Interrupt");
else
msg("No match");
}
got_int = FALSE;
free((char *)prog);
}
/*
* Character Searches
*/
static char lastc = NUL; /* last character searched for */
static int lastcdir; /* last direction of character search */
static int lastctype; /* last type of search ("find" or "to") */
/*
* searchc(c, dir, type)
*
* Search for character 'c', in direction 'dir'. If type is 0, move to
* the position of the character, otherwise move to just before the char.
*/
bool_t
searchc(c, dir, type)
char c;
int dir;
int type;
{
LPTR save;
save = *Curschar; /* save position in case we fail */
lastc = c;
lastcdir = dir;
lastctype = type;
/*
* On 'to' searches, skip one to start with so we can repeat
* searches in the same direction and have it work right.
*/
if (type)
(dir == FORWARD) ? oneright() : oneleft();
while ( (dir == FORWARD) ? oneright() : oneleft() ) {
if (gchar(Curschar) == c) {
if (type)
(dir == FORWARD) ? oneleft() : oneright();
return TRUE;
}
}
*Curschar = save;
return FALSE;
}
bool_t
crepsearch(flag)
int flag;
{
int dir = lastcdir;
int rval;
if (lastc == NUL)
return FALSE;
rval = searchc(lastc, flag ? OTHERDIR(lastcdir) : lastcdir, lastctype);
lastcdir = dir; /* restore dir., since it may have changed */
return rval;
}
/*
* "Other" Searches
*/
/*
* showmatch - move the cursor to the matching paren or brace
*/
LPTR *
showmatch()
{
static LPTR pos;
int (*move)(), inc(), dec();
char initc = gchar(Curschar); /* initial char */
char findc; /* terminating char */
char c;
int count = 0;
pos = *Curschar; /* set starting point */
switch (initc) {
case '(':
findc = ')';
move = inc;
break;
case ')':
findc = '(';
move = dec;
break;
case '{':
findc = '}';
move = inc;
break;
case '}':
findc = '{';
move = dec;
break;
case '[':
findc = ']';
move = inc;
break;
case ']':
findc = '[';
move = dec;
break;
default:
return (LPTR *) NULL;
}
while ((*move)(&pos) != -1) { /* until end of file */
c = gchar(&pos);
if (c == initc)
count++;
else if (c == findc) {
if (count == 0)
return &pos;
count--;
}
}
return (LPTR *) NULL; /* never found it */
}
/*
* findfunc(dir) - Find the next function in direction 'dir'
*
* Return TRUE if a function was found.
*/
bool_t
findfunc(dir)
int dir;
{
LPTR *curr;
curr = Curschar;
do {
curr = (dir == FORWARD) ? nextline(curr) : prevline(curr);
if (curr != NULL && curr->linep->s[0] == '{') {
setpcmark();
*Curschar = *curr;
return TRUE;
}
} while (curr != NULL);
return FALSE;
}
/*
* The following routines do the word searches performed by the
* 'w', 'W', 'b', 'B', 'e', and 'E' commands.
*/
/*
* To perform these searches, characters are placed into one of three
* classes, and transitions between classes determine word boundaries.
*
* The classes are:
*
* 0 - white space
* 1 - letters, digits, and underscore
* 2 - everything else
*/
static int stype; /* type of the word motion being performed */
#define C0(c) (((c) == ' ') || ((c) == '\t') || ((c) == NUL))
#define C1(c) (isalpha(c) || isdigit(c) || ((c) == '_'))
/*
* cls(c) - returns the class of character 'c'
*
* The 'type' of the current search modifies the classes of characters
* if a 'W', 'B', or 'E' motion is being done. In this case, chars. from
* class 2 are reported as class 1 since only white space boundaries are
* of interest.
*/
static int
cls(c)
char c;
{
if (C0(c))
return 0;
if (C1(c))
return 1;
/*
* If stype is non-zero, report these as class 1.
*/
return (stype == 0) ? 2 : 1;
}
/*
* fwd_word(pos, type) - move forward one word
*
* Returns the resulting position, or NULL if EOF was reached.
*/
LPTR *
fwd_word(p, type)
LPTR *p;
int type;
{
static LPTR pos;
int sclass = cls(gchar(p)); /* starting class */
pos = *p;
stype = type;
/*
* We always move at least one character.
*/
if (inc(&pos) == -1)
return NULL;
if (sclass != 0) {
while (cls(gchar(&pos)) == sclass) {
if (inc(&pos) == -1)
return NULL;
}
/*
* If we went from 1 -> 2 or 2 -> 1, return here.
*/
if (cls(gchar(&pos)) != 0)
return &pos;
}
/* We're in white space; go to next non-white */
while (cls(gchar(&pos)) == 0) {
/*
* We'll stop if we land on a blank line
*/
if (pos.index == 0 && pos.linep->s[0] == NUL)
break;
if (inc(&pos) == -1)
return NULL;
}
return &pos;
}
/*
* bck_word(pos, type) - move backward one word
*
* Returns the resulting position, or NULL if EOF was reached.
*/
LPTR *
bck_word(p, type)
LPTR *p;
int type;
{
static LPTR pos;
int sclass = cls(gchar(p)); /* starting class */
pos = *p;
stype = type;
if (dec(&pos) == -1)
return NULL;
/*
* If we're in the middle of a word, we just have to
* back up to the start of it.
*/
if (cls(gchar(&pos)) == sclass && sclass != 0) {
/*
* Move backward to start of the current word
*/
while (cls(gchar(&pos)) == sclass) {
if (dec(&pos) == -1)
return NULL;
}
inc(&pos); /* overshot - forward one */
return &pos;
}
/*
* We were at the start of a word. Go back to the start
* of the prior word.
*/
while (cls(gchar(&pos)) == 0) { /* skip any white space */
/*
* We'll stop if we land on a blank line
*/
if (pos.index == 0 && pos.linep->s[0] == NUL)
return &pos;
if (dec(&pos) == -1)
return NULL;
}
sclass = cls(gchar(&pos));
/*
* Move backward to start of this word.
*/
while (cls(gchar(&pos)) == sclass) {
if (dec(&pos) == -1)
return NULL;
}
inc(&pos); /* overshot - forward one */
return &pos;
}
/*
* end_word(pos, type, in_change) - move to the end of the word
*
* There is an apparent bug in the 'e' motion of the real vi. At least
* on the System V Release 3 version for the 80386. Unlike 'b' and 'w',
* the 'e' motion crosses blank lines. When the real vi crosses a blank
* line in an 'e' motion, the cursor is placed on the FIRST character
* of the next non-blank line. The 'E' command, however, works correctly.
* Since this appears to be a bug, I have not duplicated it here.
*
* There's a strange special case here that the 'in_change' parameter
* helps us deal with. Vi effectively turns 'cw' into 'ce'. If we're on
* a word with only one character, we need to stick at the current
* position so we don't change two words.
*
* Returns the resulting position, or NULL if EOF was reached.
*/
LPTR *
end_word(p, type, in_change)
LPTR *p;
int type;
bool_t in_change;
{
static LPTR pos;
int sclass = cls(gchar(p)); /* starting class */
pos = *p;
stype = type;
if (inc(&pos) == -1)
return NULL;
/*
* If we're in the middle of a word, we just have to
* move to the end of it.
*/
if (cls(gchar(&pos)) == sclass && sclass != 0) {
/*
* Move forward to end of the current word
*/
while (cls(gchar(&pos)) == sclass) {
if (inc(&pos) == -1)
return NULL;
}
dec(&pos); /* overshot - forward one */
return &pos;
}
/*
* We were at the end of a word. Go to the end of the next
* word, unless we're doing a change. In that case we stick
* at the end of the current word.
*/
if (in_change)
return p;
while (cls(gchar(&pos)) == 0) { /* skip any white space */
if (inc(&pos) == -1)
return NULL;
}
sclass = cls(gchar(&pos));
/*
* Move forward to end of this word.
*/
while (cls(gchar(&pos)) == sclass) {
if (inc(&pos) == -1)
return NULL;
}
dec(&pos); /* overshot - forward one */
return &pos;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -