aboutsummaryrefslogtreecommitdiff
path: root/contrib/nvi/vi/v_ch.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/nvi/vi/v_ch.c')
-rw-r--r--contrib/nvi/vi/v_ch.c295
1 files changed, 295 insertions, 0 deletions
diff --git a/contrib/nvi/vi/v_ch.c b/contrib/nvi/vi/v_ch.c
new file mode 100644
index 000000000000..6a1b61182680
--- /dev/null
+++ b/contrib/nvi/vi/v_ch.c
@@ -0,0 +1,295 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1992, 1993, 1994, 1995, 1996
+ * Keith Bostic. All rights reserved.
+ *
+ * See the LICENSE file for redistribution information.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)v_ch.c 10.8 (Berkeley) 3/6/96";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#include <bitstring.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../common/common.h"
+#include "vi.h"
+
+static void notfound __P((SCR *, ARG_CHAR_T));
+static void noprev __P((SCR *));
+
+/*
+ * v_chrepeat -- [count];
+ * Repeat the last F, f, T or t search.
+ *
+ * PUBLIC: int v_chrepeat __P((SCR *, VICMD *));
+ */
+int
+v_chrepeat(sp, vp)
+ SCR *sp;
+ VICMD *vp;
+{
+ vp->character = VIP(sp)->lastckey;
+
+ switch (VIP(sp)->csearchdir) {
+ case CNOTSET:
+ noprev(sp);
+ return (1);
+ case FSEARCH:
+ return (v_chF(sp, vp));
+ case fSEARCH:
+ return (v_chf(sp, vp));
+ case TSEARCH:
+ return (v_chT(sp, vp));
+ case tSEARCH:
+ return (v_cht(sp, vp));
+ default:
+ abort();
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * v_chrrepeat -- [count],
+ * Repeat the last F, f, T or t search in the reverse direction.
+ *
+ * PUBLIC: int v_chrrepeat __P((SCR *, VICMD *));
+ */
+int
+v_chrrepeat(sp, vp)
+ SCR *sp;
+ VICMD *vp;
+{
+ cdir_t savedir;
+ int rval;
+
+ vp->character = VIP(sp)->lastckey;
+ savedir = VIP(sp)->csearchdir;
+
+ switch (VIP(sp)->csearchdir) {
+ case CNOTSET:
+ noprev(sp);
+ return (1);
+ case FSEARCH:
+ rval = v_chf(sp, vp);
+ break;
+ case fSEARCH:
+ rval = v_chF(sp, vp);
+ break;
+ case TSEARCH:
+ rval = v_cht(sp, vp);
+ break;
+ case tSEARCH:
+ rval = v_chT(sp, vp);
+ break;
+ default:
+ abort();
+ }
+ VIP(sp)->csearchdir = savedir;
+ return (rval);
+}
+
+/*
+ * v_cht -- [count]tc
+ * Search forward in the line for the character before the next
+ * occurrence of the specified character.
+ *
+ * PUBLIC: int v_cht __P((SCR *, VICMD *));
+ */
+int
+v_cht(sp, vp)
+ SCR *sp;
+ VICMD *vp;
+{
+ if (v_chf(sp, vp))
+ return (1);
+
+ /*
+ * v_chf places the cursor on the character, where the 't'
+ * command wants it to its left. We know this is safe since
+ * we had to move right for v_chf() to have succeeded.
+ */
+ --vp->m_stop.cno;
+
+ /*
+ * Make any necessary correction to the motion decision made
+ * by the v_chf routine.
+ */
+ if (!ISMOTION(vp))
+ vp->m_final = vp->m_stop;
+
+ VIP(sp)->csearchdir = tSEARCH;
+ return (0);
+}
+
+/*
+ * v_chf -- [count]fc
+ * Search forward in the line for the next occurrence of the
+ * specified character.
+ *
+ * PUBLIC: int v_chf __P((SCR *, VICMD *));
+ */
+int
+v_chf(sp, vp)
+ SCR *sp;
+ VICMD *vp;
+{
+ size_t len;
+ u_long cnt;
+ int isempty, key;
+ char *endp, *p, *startp;
+
+ /*
+ * !!!
+ * If it's a dot command, it doesn't reset the key for which we're
+ * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'.
+ */
+ key = vp->character;
+ if (!F_ISSET(vp, VC_ISDOT))
+ VIP(sp)->lastckey = key;
+ VIP(sp)->csearchdir = fSEARCH;
+
+ if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
+ if (isempty)
+ goto empty;
+ return (1);
+ }
+
+ if (len == 0) {
+empty: notfound(sp, key);
+ return (1);
+ }
+
+ endp = (startp = p) + len;
+ p += vp->m_start.cno;
+ for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ while (++p < endp && *p != key);
+ if (p == endp) {
+ notfound(sp, key);
+ return (1);
+ }
+ }
+
+ vp->m_stop.cno = p - startp;
+
+ /*
+ * Non-motion commands move to the end of the range.
+ * Delete and yank stay at the start, ignore others.
+ */
+ vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
+ return (0);
+}
+
+/*
+ * v_chT -- [count]Tc
+ * Search backward in the line for the character after the next
+ * occurrence of the specified character.
+ *
+ * PUBLIC: int v_chT __P((SCR *, VICMD *));
+ */
+int
+v_chT(sp, vp)
+ SCR *sp;
+ VICMD *vp;
+{
+ if (v_chF(sp, vp))
+ return (1);
+
+ /*
+ * v_chF places the cursor on the character, where the 'T'
+ * command wants it to its right. We know this is safe since
+ * we had to move left for v_chF() to have succeeded.
+ */
+ ++vp->m_stop.cno;
+ vp->m_final = vp->m_stop;
+
+ VIP(sp)->csearchdir = TSEARCH;
+ return (0);
+}
+
+/*
+ * v_chF -- [count]Fc
+ * Search backward in the line for the next occurrence of the
+ * specified character.
+ *
+ * PUBLIC: int v_chF __P((SCR *, VICMD *));
+ */
+int
+v_chF(sp, vp)
+ SCR *sp;
+ VICMD *vp;
+{
+ size_t len;
+ u_long cnt;
+ int isempty, key;
+ char *endp, *p;
+
+ /*
+ * !!!
+ * If it's a dot command, it doesn't reset the key for which
+ * we're searching, e.g. in "df1|f2|.|;", the ';' searches
+ * for a '2'.
+ */
+ key = vp->character;
+ if (!F_ISSET(vp, VC_ISDOT))
+ VIP(sp)->lastckey = key;
+ VIP(sp)->csearchdir = FSEARCH;
+
+ if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
+ if (isempty)
+ goto empty;
+ return (1);
+ }
+
+ if (len == 0) {
+empty: notfound(sp, key);
+ return (1);
+ }
+
+ endp = p - 1;
+ p += vp->m_start.cno;
+ for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
+ while (--p > endp && *p != key);
+ if (p == endp) {
+ notfound(sp, key);
+ return (1);
+ }
+ }
+
+ vp->m_stop.cno = (p - endp) - 1;
+
+ /*
+ * All commands move to the end of the range. Motion commands
+ * adjust the starting point to the character before the current
+ * one.
+ */
+ vp->m_final = vp->m_stop;
+ if (ISMOTION(vp))
+ --vp->m_start.cno;
+ return (0);
+}
+
+static void
+noprev(sp)
+ SCR *sp;
+{
+ msgq(sp, M_BERR, "178|No previous F, f, T or t search");
+}
+
+static void
+notfound(sp, ch)
+ SCR *sp;
+ ARG_CHAR_T ch;
+{
+ msgq(sp, M_BERR, "179|%s not found", KEY_NAME(sp, ch));
+}