/* keep track of enough state to give us a hint as to whether we need to redo the visual matches */ static int need_to_rehilite(void) { /* save static copies of state that affects the search */ if ((curbp->b_highlight & (HILITE_ON | HILITE_DIRTY)) == (HILITE_ON | HILITE_DIRTY) || tb_length(searchpat) != tb_length(savepat) || (tb_length(searchpat) != 0 && tb_length(savepat) != 0 && memcmp(tb_values(searchpat), tb_values(savepat), tb_length(savepat))) || save_igncase != ignorecase || save_vattr != b_val(curbp, VAL_HILITEMATCH) || save_magic != b_val(curbp, MDMAGIC) || (!hilite_suppressed && save_curbp != curbp)) { tb_copy(&savepat, searchpat); save_igncase = ignorecase; save_vattr = (VIDEO_ATTR) b_val(curbp, VAL_HILITEMATCH); save_magic = b_val(curbp, MDMAGIC); save_curbp = curbp; return TRUE; } return FALSE; }
static void promptpattern(const char *prompt) { /* check to see if we are executing a command line */ if (!clexec) { TBUFF *temp = tb_visbuf(tb_values(searchpat), tb_length(searchpat)); mlforce("%s[%s]: ", prompt, temp ? tb_values(temp) : ""); tb_free(&temp); } }
/* ARGSUSED */ int scrsearchpat(int f GCC_UNUSED, int n GCC_UNUSED) { int status; TBUFF *temp = 0; status = readpattern("", &searchpat, &gregexp, EOS, TRUE); temp = tb_visbuf(tb_values(searchpat), tb_length(searchpat)); mlwrite("Search pattern is now %s", temp ? tb_values(temp) : "null"); tb_free(&temp); last_srch_direc = FORWARD; return status; }
/* * Common function for prompting for shell/pipe command, and for recording the * last shell/pipe command so that we can support "!!" convention. * * Note that for 'pipecmd()', we must retain a leading "!". */ static int ShellPrompt( TBUFF **holds, char *result, int rerun) /* TRUE/FALSE: spawn, -TRUE: pipecmd */ { register int s; register SIZE_T len; static const char bang[] = SHPIPE_LEFT; BUFFER *bp; int cb = any_changed_buf(&bp), fix = (rerun != -TRUE); char save[NLINE], temp[NLINE], line[NLINE+1]; if ((len = tb_length(*holds)) != 0) { (void)strncpy(save, tb_values(*holds), len); } save[len] = EOS; /* if it doesn't start with '!', or if that's all it is */ if (!isShellOrPipe(save) || save[1] == EOS) (void)strcpy(save, bang); (void)strcpy(line, save); if (rerun != TRUE) { if (cb != 0) { if (cb > 1) { (void)lsprintf(temp, "Warning: %d modified buffers: %s", cb, bang); } else { (void)lsprintf(temp, "Warning: buffer \"%s\" is modified: %s", bp->b_bname, bang); } } else { (void)lsprintf(temp, "%s%s", rerun == -TRUE ? "" : ": ", bang); } if ((s = mlreply_no_bs(temp, line+1, NLINE)) != TRUE) return s; } if (line[1] == EOS) return FALSE; *holds = tb_scopy(holds, line); (void)strcpy(result, line+fix); return TRUE; }
/* * This hack will search for the next occurrence of <searchpat> in the buffer, * either forward or backward. It is called with the status of the prior * search attempt, so that it knows not to bother if it didn't work last * time. If we can't find any more matches, "point" is left where it was * before. If we do find a match, "point" will be at the end of the matched * string for forward searches and at the beginning of the matched string for * reverse searches. */ static int scanmore( /* search forward or back for a pattern */ TBUFF *patrn, /* string to scan for */ int dir) /* direction to search */ { int sts = FALSE; /* current search status */ FreeIfNeeded(gregexp); gregexp = regcomp(tb_values(patrn), tb_length(patrn), b_val(curbp, MDMAGIC)); if (gregexp != 0) { ignorecase = window_b_val(curwp, MDIGNCASE); sts = scanner(gregexp, (dir < 0) ? REVERSE : FORWARD, FALSE, (int *) 0); if (!sts) { kbd_alarm(); /* beep the terminal if we fail */ } #if OPT_EXTRA_COLOR else { MARK save_MK; int *attrp = lookup_extra_color(XCOLOR_ISEARCH); if (!isEmpty(attrp)) { /* clear any existing search-match */ clear_match_attrs(TRUE, 1); /* draw the new search-match */ regionshape = rgn_EXACT; save_MK = MK; MK.l = DOT.l; MK.o = DOT.o + (C_NUM) tb_length(patrn); videoattribute = (VIDEO_ATTR) * attrp; videoattribute |= VOWN_MATCHES; (void) attributeregion(); /* fix for clear_match_attrs */ curbp->b_highlight |= HILITE_ON; MK = save_MK; } } #endif } return (sts); /* else, don't even try */ }
/* * readpattern -- read a pattern. if it is the * search string, recompile it. * pattern not updated if the user types in an empty line. */ int readpattern(const char *prompt, TBUFF **apat, regexp ** srchexpp, int c, int fromscreen) { char temp[NPAT]; int status; TRACE((T_CALLED "readpattern(%s, %s, %p, %d, %d)\n", prompt ? prompt : "", tb_visible(*apat), (void *) srchexpp, c, fromscreen)); if (fromscreen) { if ((status = screen_to_ident(temp, sizeof(temp))) == TRUE) { if (tb_init(apat, EOS) == 0 || tb_bappend(apat, temp, strlen(temp)) == 0) { status = FALSE; } } if (status != TRUE) returnCode(status); } else { /* don't expand #, %, :, and never process backslashes since they're handled by regexp directly for the search pattern, and in delins() for the replacement pattern */ hst_glue(c); /* * kbd_reply() expects a trailing null, to simplify calls from * kbd_string(). */ if (tb_values(*apat) != 0) tb_append(apat, EOS); status = kbd_reply(prompt, apat, eol_history, c, KBD_EXPPAT | KBD_0CHAR, no_completion); if (tb_length(*apat) != 0) tb_unput(*apat); /* trim the trailing null */ } if (status == TRUE) { if (srchexpp) { /* compile it */ beginDisplay(); FreeIfNeeded(*srchexpp); endofDisplay(); *srchexpp = regcomp(tb_values(*apat), tb_length(*apat), b_val(curbp, MDMAGIC)); if (!*srchexpp) returnCode(FALSE); } } else if (status == FALSE && tb_length(*apat) != 0) { /* Old one */ status = TRUE; } returnCode(status); }
/* For the "operator" commands -- the following command is a motion, or * the operator itself is repeated. All operate on regions. */ int vile_op(int f, int n, OpsFunc fn, const char *str) { int c = 0; int thiskey; int status; const CMDFUNC *cfp; /* function to execute */ const CMDFUNC *save_cmd_motion = cmd_motion; BUFFER *ourbp; #if OPT_MOUSE WINDOW *wp0 = curwp; #endif TRACE((T_CALLED "vile_op(%s)\n", str)); doingopcmd = TRUE; pre_op_dot = DOT; ourbp = curbp; if (havemotion != NULL) { cfp = havemotion; havemotion = NULL; } else { TBUFF *tok = 0; mlwrite("%s operation pending...", str); (void) update(FALSE); /* get the next command from the keyboard */ /* or a command line, as approp. */ if (clexec) { char *value = mac_unquotedarg(&tok); /* get the next token */ if (value != 0 && strcmp(value, "lines")) cfp = engl2fnc(value); else cfp = &f_godotplus; } else { thiskey = lastkey; c = kbd_seq(); #if OPT_MOUSE if (curwp != wp0) { unkeystroke(c); doingopcmd = FALSE; returnCode(FALSE); } #endif /* allow second chance for entering counts */ do_repeats(&c, &f, &n); if (thiskey == lastkey) cfp = &f_godotplus; else cfp = DefaultKeyBinding(c); } if (cfp != 0) { mlerase(); } else { if (!clexec) { char temp[NSTRING]; lsprintf(temp, "(%d)", c); tb_scopy(&tok, temp); } (void) no_such_function(tb_values(tok)); } tb_free(&tok); } if (!cfp) { status = FALSE; } else if ((cfp->c_flags & MOTION) == 0) { kbd_alarm(); status = ABORT; } else { /* motion is interpreted as affecting full lines */ if (regionshape == rgn_EXACT) { if (cfp->c_flags & FL) regionshape = rgn_FULLLINE; if (cfp->c_flags & VL_RECT) regionshape = rgn_RECTANGLE; } /* and execute the motion */ if ((status = execute(cfp, f, n)) == TRUE) { post_op_dot = DOT; } else { mlforce("[Motion failed]"); status = FALSE; } } if (status == TRUE) { opcmd = 0; MK = pre_op_dot; /* we've successfully set up a region */ if (!fn) { /* be defensive */ mlforce("BUG -- null func pointer in operator"); status = FALSE; } else if (fn == user_operator) { swapmark(); cmd_motion = cfp; status = dobuf(find_b_name(str), 1, f ? n : 1); } else { status = (fn) (); } if (ourbp == curbp) /* in case the func switched buffers on us */ swapmark(); if (regionshape == rgn_FULLLINE) (void) firstnonwhite(FALSE, 1); } regionshape = rgn_EXACT; doingopcmd = FALSE; haveregion = FALSE; cmd_motion = save_cmd_motion; returnCode(status); }
/* * This is invoked as a wrapper for 'kbd_putc()'. It writes to the Messages * scratch buffer, and also to the message line. If the Messages buffer isn't * visible, it is automatically popped up when a new message line is begun. * Since it's a scratch buffer, popping it down destroys it. */ int msg_putc(int c) { BUFFER *savebp = curbp; WINDOW *savewp = curwp; MARK savemk; int saverow = ttrow; int savecol = ttcol; register BUFFER *bp; register WINDOW *wp; if ((bp = create_msgs()) == 0) return TRUE; savemk = DOT; beginDisplay(); /* * Modify the current-buffer state as unobtrusively as possible (i.e., * don't modify the buffer order, and don't make the buffer visible if * it isn't already!). To use the 'bputc()' logic, though, we've got * to have a window, even if it's not real. */ curbp = bp; if ((wp = bp2any_wp(bp)) == NULL) { static WINDOW dummy; wp = &dummy; wp->w_bufp = bp; } curwp = wp; DOT.l = lback(buf_head(bp)); DOT.o = llength(DOT.l); /* * Write into the [Messages]-buffer */ #if OPT_TRACE if (c == '\n') { static TBUFF *ss; int len = (DOT.o > 0) ? DOT.o : 1; if (tb_init(&ss, EOS) != 0 && tb_bappend(&ss, (DOT.o > 0) ? lvalue(DOT.l) : "?", (size_t) len) != 0 && tb_append(&ss, EOS) != 0) { TRACE(("msg:%s\n", visible_buff(tb_values(ss), (int) tb_length(ss) - 1, TRUE))); } } #endif if ((c != '\n') || (DOT.o > 0)) { bputc(c); b_clr_changed(bp); } /* Finally, restore the original current-buffer and write the character * to the message line. */ curbp = savebp; curwp = savewp; if (savewp) DOT = savemk; movecursor(saverow, savecol); if (c != '\n') { if (sgarbf) { mlsavec(c); } else { kbd_putc(c); } } endofDisplay(); return TRUE; }
int attributeregion(void) { BUFFER *bp = curbp; int status; REGION region; AREGION *arp; if ((status = getregion(bp, ®ion)) == TRUE) { if (apply_attribute()) { if (add_line_attrib(bp, ®ion, regionshape, videoattribute, #if OPT_HYPERTEXT hypercmd #else 0 #endif )) { return TRUE; } /* add new attribute-region */ if ((arp = alloc_AREGION()) == NULL) { return FALSE; } arp->ar_region = region; arp->ar_vattr = videoattribute; /* include ownership */ arp->ar_shape = regionshape; #if OPT_HYPERTEXT arp->ar_hypercmd = 0; if (tb_length(hypercmd) && *tb_values(hypercmd)) { #if OPT_EXTRA_COLOR if (tb_length(hypercmd) > 4 && !memcmp(tb_values(hypercmd), "view ", (size_t) 4)) { int *newVideo = lookup_extra_color(XCOLOR_HYPERTEXT); if (!isEmpty(newVideo)) { arp->ar_vattr = (VIDEO_ATTR) * newVideo; } } #endif arp->ar_hypercmd = strmalloc(tb_values(hypercmd)); tb_init(&hypercmd, 0); } #endif attach_attrib(bp, arp); } else { /* purge attributes in this region */ L_NUM rls = line_no(bp, region.r_orig.l); L_NUM rle = line_no(bp, region.r_end.l); C_NUM ros = region.r_orig.o; C_NUM roe = region.r_end.o; AREGION **pp; AREGION **qq; AREGION *p, *n; int owner; owner = VOWNER(videoattribute); purge_line_attribs(bp, ®ion, regionshape, owner); pp = &(bp->b_attribs); for (p = *pp; p != 0; pp = qq, p = *pp) { L_NUM pls, ple; C_NUM pos, poe; if (interrupted()) return FALSE; qq = &(p->ar_next); if (owner != 0 && owner != VOWNER(p->ar_vattr)) continue; pls = line_no(bp, p->ar_region.r_orig.l); ple = line_no(bp, p->ar_region.r_end.l); pos = p->ar_region.r_orig.o; poe = p->ar_region.r_end.o; /* Earlier the overlapping region check was made based only * on line numbers and so was right only for FULLINES shape * changed it to be correct for rgn_EXACT and rgn_RECTANGLE also * -kuntal 9/13/98 */ /* * check for overlap: * for any shape of region 'p' things are fine as long as * 'region' is above or below it */ if (ple < rls || pls > rle) continue; /* * for rgn_EXACT 'p' region */ if (p->ar_shape == rgn_EXACT) { if (ple == rls && poe - 1 < ros) continue; if (pls == rle && pos > roe) continue; } /* * for rgn_RECTANGLE 'p' region */ if (p->ar_shape == rgn_RECTANGLE) if (poe < ros || pos > roe) continue; /* * FIXME: this removes the whole of an overlapping region; * we really only want to remove the overlapping portion... */ /* * we take care of this fix easily as long as neither of * 'p' or 'region' are rgn_RECTANGLE. we will need to create * at the most one new region in case 'region' is * completely contained within 'p' */ if (p->ar_shape != rgn_RECTANGLE && regionshape != rgn_RECTANGLE) { if ((rls > pls) || (rls == pls && ros > pos)) { p->ar_shape = rgn_EXACT; if ((rle < ple) || (rle == ple && roe < poe)) { /* open a new region */ if ((n = alloc_AREGION()) == NULL) { return FALSE; } n->ar_region = p->ar_region; n->ar_vattr = p->ar_vattr; n->ar_shape = p->ar_shape; #if OPT_HYPERTEXT n->ar_hypercmd = p->ar_hypercmd; #endif n->ar_region.r_orig.l = (region.r_end.l); n->ar_region.r_orig.o = (region.r_end.o); attach_attrib(bp, n); } p->ar_region.r_end.l = (region.r_orig.l); p->ar_region.r_end.o = (region.r_orig.o); curwp->w_flag |= WFHARD; continue; } else if ((rle < ple) || (rle == ple && roe < poe)) { p->ar_region.r_orig.l = (region.r_end.l); p->ar_region.r_orig.o = (region.r_end.o); curwp->w_flag |= WFHARD; continue; } } free_attrib2(bp, pp); qq = pp; } } } return status; }
/* Return comma-delimited list of "interesting" options. */ static char * cfgopts(void) { static const char *opts[] = { #if !OPT_SHELL "noshell", #endif #if SYS_WINNT && defined(VILE_OLE) "oleauto", #endif #if OPT_HYPERTEXT "hypertext", #endif #if OPT_LOCALE "locale", #endif #if OPT_ICONV_FUNCS "iconv", #endif #if OPT_MULTIBYTE "multibyte", #endif #if OPT_PERL "perl", #endif #if DISP_ANSI "ansi", #endif #if DISP_BORLAND "borland", #endif #if DISP_CURSES "curses", #endif #if DISP_NTCONS "ntcons", #endif #if DISP_NTWIN "ntwin", #endif #if DISP_TERMCAP # if USE_TERMINFO "terminfo", # else "termcap", # endif #endif #if DISP_VIO "os2vio", #endif #if DISP_VMSVT "vmsvt", #endif #if DISP_X11 # if MOTIF_WIDGETS "motif", # endif # if ATHENA_WIDGETS "athena", # ifdef HAVE_LIB_XAW "xaw", # endif # ifdef HAVE_LIB_XAW3D "xaw3d", # endif # ifdef HAVE_LIB_NEXTAW "nextaw", # endif # endif #endif NULL /* End of list marker */ }; static TBUFF *optstring; if (optstring == 0) { const char **lclopt; optstring = tb_init(&optstring, EOS); for (lclopt = opts; *lclopt; lclopt++) { if (tb_length(optstring)) optstring = tb_append(&optstring, ','); optstring = tb_sappend(&optstring, *lclopt); } optstring = tb_append(&optstring, EOS); } return tb_values(optstring); }
/* ARGSUSED */ static int isearch(int f GCC_UNUSED, int n) { static TBUFF *pat_save = 0; /* Saved copy of the old pattern str */ int status; /* Search status */ register int cpos; /* character number in search string */ register int c; /* current input character */ MARK curpos, curp; /* Current point on entry */ int init_direction; /* The initial search direction */ /* Initialize starting conditions */ cmd_reexecute = -1; /* We're not re-executing (yet?) */ itb_init(&cmd_buff, EOS); /* Init the command buffer */ /* Save the old pattern string */ (void) tb_copy(&pat_save, searchpat); curpos = DOT; /* Save the current pointer */ init_direction = n; /* Save the initial search direction */ ignorecase = window_b_val(curwp, MDIGNCASE); scanboundry(FALSE, DOT, FORWARD); /* keep scanner() finite */ /* This is a good place to start a re-execution: */ start_over: /* ask the user for the text of a pattern */ promptpattern("ISearch: "); status = TRUE; /* Assume everything's cool */ /* * Get the first character in the pattern. If we get an initial * Control-S or Control-R, re-use the old search string and find the * first occurrence */ c = kcod2key(get_char()); /* Get the first character */ if ((c == IS_FORWARD) || (c == IS_REVERSE)) { /* Reuse old search string? */ for (cpos = 0; cpos < (int) tb_length(searchpat); ++cpos) echochar(tb_values(searchpat)[cpos]); /* and re-echo the string */ curp = DOT; if (c == IS_REVERSE) { /* forward search? */ n = -1; /* No, search in reverse */ last_srch_direc = REVERSE; backchar(TRUE, 1); /* Be defensive about EOB */ } else { n = 1; /* Yes, search forward */ last_srch_direc = FORWARD; forwchar(TRUE, 1); } unget_char(); status = scanmore(searchpat, n); /* Do the search */ if (status != TRUE) DOT = curp; c = kcod2key(get_char()); /* Get another character */ } else { tb_init(&searchpat, EOS); } /* Top of the per character loop */ for_ever { /* ISearch per character loop */ /* Check for special characters, since they might change the * search to be done */ if (ABORTED(c) || c == '\r') /* search aborted? */ return (TRUE); /* end the search */ if (isbackspace(c)) c = '\b'; if (c == quotec) /* quote character? */ c = kcod2key(get_char()); /* Get the next char */ switch (c) { /* dispatch on the input char */ case IS_REVERSE: /* If backward search */ case IS_FORWARD: /* If forward search */ curp = DOT; if (c == IS_REVERSE) { /* forward search? */ last_srch_direc = REVERSE; n = -1; /* No, search in reverse */ backchar(TRUE, 1); /* Be defensive about * EOB */ } else { n = 1; /* Yes, search forward */ last_srch_direc = FORWARD; forwchar(TRUE, 1); } status = scanmore(searchpat, n); /* Do the search */ if (status != TRUE) DOT = curp; c = kcod2key(get_char()); /* Get the next char */ continue; /* Go continue with the search */ case '\t': /* Generically allowed */ case '\n': /* controlled characters */ break; /* Make sure we use it */ case '\b': /* or if a Rubout: */ if (itb_length(cmd_buff) <= 1) /* Anything to delete? */ return (TRUE); /* No, just exit */ unget_char(); DOT = curpos; /* Reset the pointer */ n = init_direction; /* Reset the search direction */ (void) tb_copy(&searchpat, pat_save); /* Restore the old search str */ cmd_reexecute = 0; /* Start the whole mess over */ goto start_over; /* Let it take care of itself */ /* Presumably a quasi-normal character comes here */ default: /* All other chars */ if (!isPrint(c)) { /* Is it printable? */ /* Nope. */ unkeystroke(c); /* Re-eat the char */ return (TRUE); /* And return the last status */ } } /* Switch */ /* I guess we got something to search for, so search for it */ tb_append(&searchpat, c); /* put the char in the buffer */ echochar(c); /* Echo the character */ if (!status) { /* If we lost last time */ kbd_alarm(); /* Feep again */ } else /* Otherwise, we must have won */ status = scanmore(searchpat, n); /* or find the next * match */ c = kcod2key(get_char()); /* Get the next char */ } /* for_ever */ }