summaryrefslogtreecommitdiffstats
path: root/lib/libncurses/lib_mvcur.c
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>1994-10-07 08:58:58 +0000
committerache <ache@FreeBSD.org>1994-10-07 08:58:58 +0000
commita80c0624fbd8bd1c784b0b5b7a0fd20b09d317b9 (patch)
tree4a94ca97fb2fc2fdc1fcdd522a66e39c6e763138 /lib/libncurses/lib_mvcur.c
downloadFreeBSD-src-a80c0624fbd8bd1c784b0b5b7a0fd20b09d317b9.zip
FreeBSD-src-a80c0624fbd8bd1c784b0b5b7a0fd20b09d317b9.tar.gz
Moved from ports with several enhancements
Diffstat (limited to 'lib/libncurses/lib_mvcur.c')
-rw-r--r--lib/libncurses/lib_mvcur.c719
1 files changed, 719 insertions, 0 deletions
diff --git a/lib/libncurses/lib_mvcur.c b/lib/libncurses/lib_mvcur.c
new file mode 100644
index 0000000..1a6ba65
--- /dev/null
+++ b/lib/libncurses/lib_mvcur.c
@@ -0,0 +1,719 @@
+/*---------------------------------------------------------------------------
+ *
+ * lib_mvcur.c
+ *
+ * The routine mvcur() etc.
+ *
+ * last edit-date: [Wed Jun 16 14:13:22 1993]
+ *
+ * -hm conversion from termcap -> terminfo
+ * -hm optimization debugging
+ * -hm zeyd's ncurses 0.7 update
+ * -hm eat_newline_glitch bugfix
+ * -hm hpux lint'ing ..
+ *
+ *---------------------------------------------------------------------------*/
+
+/* This work is copyrighted. See COPYRIGHT.OLD & COPYRIGHT.NEW for *
+* details. If they are missing then this copy is in violation of *
+* the copyright conditions. */
+
+#include <string.h>
+#include <stdlib.h>
+#include <nterm.h>
+#include "curses.priv.h"
+
+#ifndef OPT_MVCUR
+/*
+**
+** mvcur(oldrow, oldcol, newrow, newcol)
+** A hack for terminals that are smart enough
+** to know how to move cursor.
+** There is still a bug in the alternative long-
+** winded code.
+**
+*/
+
+int mvcur(int oldrow, int oldcol, int newrow, int newcol)
+{
+ T(("mvcur(%d,%d,%d,%d) called", oldrow, oldcol, newrow, newcol));
+
+ if(!cursor_address)
+ return ERR;
+
+ newrow %= lines;
+ newcol %= columns;
+
+ if (cursor_address)
+ putp(tparm(cursor_address, newrow, newcol));
+ return OK;
+
+}
+
+#else
+
+#define BUFSIZE 128 /* size of strategy buffer */
+
+struct Sequence
+{
+ int vec[BUFSIZE]; /* vector of operations */
+ int *end; /* end of vector */
+ int cost; /* cost of vector */
+};
+
+static void row(struct Sequence *outseq, int orow, int nrow);
+static void column(struct Sequence *outseq, int ocol, int ncol);
+static void simp_col(struct Sequence *outseq, int oc, int nc);
+static void zero_seq(struct Sequence *seq);
+static void add_seq(struct Sequence *seq1, struct Sequence *seq2);
+static void out_seq(struct Sequence *seq);
+static void update_ops(void);
+static void init_costs(int costs[]);
+static int countc(char ch);
+static void add_op(struct Sequence *seq, int op, ...);
+static char *sequence(int op);
+
+static int c_count; /* used for counting tputs output */
+
+#define INFINITY 1000 /* biggest, impossible sequence cost */
+#define NUM_OPS 16 /* num. term. control sequences */
+#define NUM_NPARM 9 /* num. ops wo/ parameters */
+
+ /* operator indexes into op_info */
+
+#define CARRIAGE_RETURN 0 /* watch out for nl mapping */
+#define CURS_DOWN 1
+#define CURS_HOME 2
+#define CURS_LEFT 3
+#define CURS_RIGHT 4
+#define CURS_TO_LL 5
+#define CURS_UP 6
+#define TAB 7
+#define BACK_TAB 8
+#define ROW_ADDR 9
+#define COL_ADDR 10
+#define P_DOWN_CURS 11
+#define P_LEFT_CURS 12
+#define P_RIGHT_CURS 13
+#define P_UP_CURS 14
+#define CURS_ADDR 15
+
+static bool loc_init = FALSE; /* set if op_info is init'ed */
+
+static bool rel_ok; /* set if we really know where we are */
+
+/*
+ * op_info[NUM_OPS]
+ *
+ * op_info[] contains for operations with no parameters
+ * the cost of the operation. These ops should be first in the array.
+ * For operations with parameters, op_info[] contains
+ * the negative of the number of parameters.
+ */
+
+static int op_info[NUM_OPS] = {
+ 0, /* carriage_return */
+ 0, /* cursor_down */
+ 0, /* cursor_home */
+ 0, /* cursor_left */
+ 0, /* cursor_right */
+ 0, /* cursor_to_ll */
+ 0, /* cursor_up */
+ 0, /* tab */
+ 0, /* back_tab */
+ -1, /* row_address */
+ -1, /* column_address */
+ -1, /* parm_down_cursor */
+ -1, /* parm_left_cursor */
+ -1, /* parm_right_cursor */
+ -1, /* parm_up_cursor */
+ -2 /* cursor_address */
+};
+
+/*
+** Make_seq_best(best, try)
+**
+** Make_seq_best() copies try to best if try->cost < best->cost
+**
+** fixed the old version, now it really runs .. (-hm/08.04.93)
+**
+*/
+
+inline void Make_seq_best(struct Sequence *best, struct Sequence *try)
+{
+ if (best->cost > try->cost) {
+ register int *sptr;
+
+ sptr = try->vec; /* src ptr */
+ best->end = best->vec; /* dst ptr */
+ while(sptr != try->end) /* copy src -> dst */
+ *(best->end++) = *(sptr++);
+ best->cost = try->cost; /* copy cost */
+ }
+}
+
+
+/*
+**
+** mvcur(oldrow, oldcol, newrow, newcol)
+**
+** mvcur() optimally moves the cursor from the position
+** specified by (oldrow, oldcol) to (newrow, newcol). If
+** (oldrow, oldcol) == (-1, -1), mvcur() does not use relative
+** cursor motions. If the coordinates are otherwise
+** out of bounds, it mods them into range.
+**
+** Revisions needed:
+** eat_newline_glitch, auto_right_margin
+*/
+
+int mvcur(int oldrow, int oldcol, int newrow, int newcol)
+{
+struct Sequence seqA, seqB, /* allocate work structures */
+ col0seq, /* sequence to get from col0 to nc */
+ *best, /* best sequence so far */
+ *try; /* next try */
+bool nlstat = SP->_nl; /* nl-output-mapping in effect ?*/
+
+#ifdef TRACE
+ if (_tracing)
+ _tracef("=============================\nmvcur(%d,%d,%d,%d) called",
+ oldrow, oldcol, newrow, newcol);
+#endif
+
+ if ((oldrow == newrow) && (oldcol == newcol))
+ return OK;
+
+ if (oldcol == columns-1 && eat_newline_glitch && auto_right_margin) {
+ tputs(tparm(cursor_address, newrow, newcol), 1, _outc);
+ return OK;
+ }
+
+#if 0
+ if (nlstat)
+ nonl();
+#endif
+ update_ops(); /* make sure op_info[] is current */
+
+ if (oldrow < 0 || oldcol < 0 || (eat_newline_glitch && oldcol == 0 )) {
+ rel_ok = FALSE; /* relative ops ok? */
+ } else {
+ rel_ok = TRUE;
+ oldrow %= lines; /* mod values into range */
+ oldcol %= columns;
+ }
+
+ newrow %= lines;
+ newcol %= columns;
+
+ best = &seqA;
+ try = &seqB;
+
+ /* try out direct cursor addressing */
+
+ zero_seq(best);
+ add_op(best, CURS_ADDR, newrow, newcol);
+
+ /* try out independent row/column addressing */
+
+ if(rel_ok) {
+ zero_seq(try);
+ row(try, oldrow, newrow);
+ column(try, oldcol, newcol);
+ Make_seq_best(best, try);
+ }
+
+ zero_seq(&col0seq); /* store seq. to get from c0 to nc */
+ column(&col0seq, 0, newcol);
+
+ if(col0seq.cost < INFINITY) { /* can get from col0 to newcol */
+
+ /* try out homing and then row/column */
+
+ if (! rel_ok || newcol < oldcol || newrow < oldrow) {
+ zero_seq(try);
+ add_op(try, CURS_HOME, 1);
+ row(try, 0, newrow);
+ add_seq(try, &col0seq);
+ Make_seq_best(best, try);
+ }
+
+ /* try out homing to last line and then row/column */
+
+ if (! rel_ok || newcol < oldcol || newrow > oldrow) {
+ zero_seq(try);
+ add_op(try, CURS_TO_LL, 1);
+ row(try, lines - 1, newrow);
+ add_seq(try, &col0seq);
+ Make_seq_best(best, try);
+ }
+ }
+
+ out_seq(best);
+#if 0
+ if(nlstat)
+ nl();
+#endif
+
+#ifdef TRACE
+ if (_tracing)
+ _tracef("===================================");
+#endif
+
+ return OK;
+}
+
+/*
+** row(outseq, oldrow, newrow)
+**
+** row() adds the best sequence for moving
+** the cursor from oldrow to newrow to seq.
+** row() considers row_address, parm_up/down_cursor
+** and cursor_up/down.
+*/
+
+static void
+row(struct Sequence *outseq, /* where to put the output */
+int orow, int nrow) /* old, new cursor locations */
+{
+struct Sequence seqA, seqB,
+ *best, /* best sequence so far */
+ *try; /* next try */
+
+int parm_cursor, one_step;
+
+ best = &seqA;
+ try = &seqB;
+
+ if (nrow == orow)
+ return;
+
+ if (nrow < orow) {
+ parm_cursor = P_UP_CURS;
+ one_step = CURS_UP;
+ } else {
+ parm_cursor = P_DOWN_CURS;
+ one_step = CURS_DOWN;
+ }
+
+ /* try out direct row addressing */
+
+ zero_seq(best);
+ add_op(best, ROW_ADDR, nrow);
+
+ /* try out paramaterized up or down motion */
+
+ if (rel_ok) {
+ zero_seq(try);
+ add_op(try, parm_cursor, abs(orow - nrow));
+ Make_seq_best(best, try);
+ }
+
+ /* try getting there one step at a time... */
+
+ if (rel_ok) {
+ zero_seq(try);
+ add_op(try, one_step, abs(orow-nrow));
+ Make_seq_best(best, try);
+ }
+
+ add_seq(outseq, best);
+}
+
+
+/*
+** column(outseq, oldcol, newcol)
+**
+** column() adds the best sequence for moving
+** the cursor from oldcol to newcol to outseq.
+** column() considers column_address, parm_left/right_cursor,
+** simp_col(), and carriage_return followed by simp_col().
+*/
+
+static void column(struct Sequence *outseq, /* where to put the output */
+int ocol, int ncol) /* old, new cursor column */
+{
+struct Sequence seqA, seqB,
+ *best, *try;
+int parm_cursor; /* set to either parm_up/down_cursor */
+
+ best = &seqA;
+ try = &seqB;
+
+ if (ncol == ocol)
+ return;
+
+ if (ncol < ocol)
+ parm_cursor = P_LEFT_CURS;
+ else
+ parm_cursor = P_RIGHT_CURS;
+
+ /* try out direct column addressing */
+
+ zero_seq(best);
+ add_op(best, COL_ADDR, ncol);
+
+ /* try carriage_return then simp_col() */
+
+ if(! rel_ok || (ncol < ocol)) {
+ zero_seq(try);
+ add_op(try, CARRIAGE_RETURN, 1);
+ simp_col(try, 0, ncol);
+ Make_seq_best(best, try);
+ }
+ if(rel_ok) {
+ /* try out paramaterized left or right motion */
+
+ zero_seq(try);
+ add_op(try, parm_cursor, abs(ocol - ncol));
+ Make_seq_best(best, try);
+
+ /* try getting there with simp_col() */
+
+ zero_seq(try);
+ simp_col(try, ocol, ncol);
+ Make_seq_best(best, try);
+ }
+
+ add_seq(outseq, best);
+}
+
+
+/*
+** simp_col(outseq, oldcol, newcol)
+**
+** simp_col() adds the best simple sequence for getting
+** from oldcol to newcol to outseq.
+** simp_col() considers (back_)tab and cursor_left/right.
+**
+** Revisions needed:
+** Simp_col asssumes that the cost of a (back_)tab
+** is less then the cost of one-stepping to get to the same column.
+** Should sometimes use overprinting instead of cursor_right.
+*/
+
+static void
+simp_col( struct Sequence *outseq, /* place to put sequence */
+int oc, int nc) /* old column, new column */
+{
+struct Sequence seqA, seqB, tabseq,
+ *best, *try;
+int mytab, tabs, onepast,
+ one_step, opp_step;
+
+ onepast = -1;
+
+ if (oc == nc)
+ return;
+
+ if(! rel_ok) {
+ outseq->cost = INFINITY;
+ return;
+ }
+
+ best = &seqA;
+ try = &seqB;
+
+ if(oc < nc) {
+ mytab = TAB;
+
+ if (init_tabs > 0 && op_info[TAB] < INFINITY) {
+ tabs = (nc / init_tabs) - (oc / init_tabs);
+ onepast = ((nc / init_tabs) + 1) * init_tabs;
+ if (tabs)
+ oc = onepast - init_tabs; /* consider it done */
+ } else {
+ tabs = 0;
+ }
+ one_step = CURS_RIGHT;
+ opp_step = CURS_LEFT;
+ } else {
+ mytab = BACK_TAB;
+ if (init_tabs > 0 && op_info[BACK_TAB] < INFINITY) {
+ tabs = (oc / init_tabs) - (nc / init_tabs);
+ onepast = ((nc - 1) / init_tabs) * init_tabs;
+ if (tabs)
+ oc = onepast + init_tabs; /* consider it done */
+ } else {
+ tabs = 0;
+ }
+ one_step = CURS_LEFT;
+ opp_step = CURS_RIGHT;
+ }
+
+ /* tab as close as possible to nc */
+
+ zero_seq(&tabseq);
+ add_op(&tabseq, mytab, tabs);
+
+ /* try extra tab and backing up */
+
+ zero_seq(best);
+
+ if (onepast >= 0 && onepast < columns) {
+ add_op(best, mytab, 1);
+ add_op(best, opp_step, abs(onepast - nc));
+ } else {
+ best->cost = INFINITY; /* make sure of next swap */
+ }
+
+ /* try stepping to nc */
+
+ zero_seq(try);
+ add_op(try, one_step, abs(nc - oc));
+ Make_seq_best(best, try);
+
+ if (tabseq.cost < INFINITY)
+ add_seq(outseq, &tabseq);
+ add_seq(outseq, best);
+}
+
+
+/*
+** zero_seq(seq) empties seq.
+** add_seq(seq1, seq2) adds seq1 to seq2.
+** out_seq(seq) outputs a sequence.
+*/
+
+static void
+zero_seq(seq)
+struct Sequence *seq;
+{
+ seq->end = seq->vec;
+ seq->cost = 0;
+}
+
+static void
+add_seq(struct Sequence *seq1, struct Sequence *seq2)
+{
+int *vptr;
+
+#ifdef TRACE
+ if (_tracing)
+ _tracef("add_seq(%x, %x)", seq1, seq2);
+#endif
+
+ if(seq1->cost >= INFINITY || seq2->cost >= INFINITY)
+ seq1->cost = INFINITY;
+ else {
+ vptr = seq2->vec;
+ while (vptr != seq2->end)
+ *(seq1->end++) = *(vptr++);
+ seq1->cost += seq2->cost;
+ }
+}
+
+
+static void
+out_seq(struct Sequence *seq)
+{
+int *opptr, prm[9], ps, p, op;
+int count;
+char *sequence();
+
+#ifdef TRACE
+ if (_tracing)
+ _tracef("out_seq(%x)", seq);
+#endif
+
+ if (seq->cost >= INFINITY)
+ return;
+
+ for (opptr = seq->vec; opptr < seq->end; opptr++) {
+ op = *opptr; /* grab operator */
+ ps = -op_info[op];
+ if(ps > 0) { /* parameterized */
+ for (p = 0; p < ps; p++) /* fill in needed parms */
+ prm[p] = *(++opptr);
+
+ tputs(tparm(sequence(op),
+ prm[0], prm[1], prm[2], prm[3], prm[4],
+ prm[5], prm[6], prm[7], prm[8]), 1, _outc);
+ } else {
+ count = *(++opptr);
+ /*rev should save tputs output instead of mult calls */
+ while (count--) /* do count times */
+ tputs(sequence(op), 1, _outc);
+ }
+ }
+}
+
+
+/*
+** update_ops()
+**
+** update_ops() makes sure that
+** the op_info[] array is updated and initializes
+** the cost array for SP if needed.
+*/
+
+static void
+update_ops()
+{
+#ifdef TRACE
+ if (_tracing)
+ _tracef("update_ops()");
+#endif
+
+ if (SP) { /* SP structure exists */
+ int op;
+
+ if (! SP->_costinit) { /* this term not yet assigned costs */
+ loc_init = FALSE; /* if !SP in the future, new term */
+ init_costs(SP->_costs); /* fill term costs */
+ SP->_costinit = TRUE;
+ }
+
+ for (op = 0; op < NUM_NPARM; op++)
+ op_info[op] = SP->_costs[op]; /* set up op_info */
+
+ /* check for newline that might be mapped... */
+
+ if (SP->_nlmapping && index(sequence(CURS_DOWN), '\n'))
+ op_info[CURS_DOWN] = INFINITY;
+ } else {
+ if (! loc_init) { /* using local costs */
+ loc_init = TRUE;
+ init_costs(op_info); /* set up op_info */
+ }
+
+ /* check for newline that might be mapped... */
+
+ if (index(sequence(CURS_DOWN), '\n'))
+ op_info[CURS_DOWN] = INFINITY;
+ }
+}
+
+
+/*
+** init_costs(costs)
+**
+** init_costs() fills the array costs[NUM_NPARM]
+** with costs calculated by doing tputs() calls.
+*/
+
+static void
+init_costs(int costs[])
+{
+int i;
+
+ for (i = 0; i < NUM_NPARM; i++) {
+ if (sequence(i) != (char *) 0) {
+ c_count = 0;
+ tputs(sequence(i), 1, countc);
+ costs[i] = c_count;
+ } else
+ costs[i] = INFINITY;
+ }
+}
+
+
+/*
+** countc() increments global var c_count.
+*/
+
+static int countc(char ch)
+{
+ return(c_count++);
+}
+
+/*
+** add_op(seq, op, p0, p1, ... , p8)
+**
+** add_op() adds the operator op and the appropriate
+** number of paramaters to seq. It also increases the
+** cost appropriately.
+** if op has no parameters, p0 is taken to be a count.
+*/
+
+static void add_op(struct Sequence *seq, int op, ...)
+{
+va_list argp;
+int num_ps, p;
+
+#ifdef TRACE
+ if (_tracing)
+ _tracef("adding op %d to sequence", op);
+#endif
+ va_start(argp, op);
+
+ num_ps = - op_info[op]; /* get parms or -cost */
+
+ *(seq->end++) = op;
+
+ if (num_ps == (- INFINITY) || sequence(op) == (char *) 0) {
+ seq->cost = INFINITY;
+ } else if (num_ps <= 0) { /* no parms, -cost */
+ int i = va_arg(argp, int);
+ seq->cost -= i * num_ps; /* ADD count * cost */
+ *(seq->end++) = i;
+ } else {
+ int prm[9];
+
+ for (p = 0; p < num_ps; p++)
+ *(seq->end++) = prm[p] = va_arg(argp, int);
+
+ c_count = 0;
+
+ tputs(tparm(sequence(op), prm[0], prm[1], prm[2], prm[3], prm[4],
+ prm[5], prm[6], prm[7], prm[8]), 1, countc);
+
+ seq->cost += c_count;
+ }
+ va_end(argp);
+}
+
+
+/*
+** char *sequence(op)
+**
+** sequence() returns a pointer to the op's
+** terminal control sequence.
+*/
+
+static char *sequence(int op)
+{
+#ifdef TRACE
+ if (_tracing)
+ _tracef("sequence(%d)", op);
+#endif
+ switch(op) {
+ case CARRIAGE_RETURN:
+ return (carriage_return);
+ case CURS_DOWN:
+ return (cursor_down);
+ case CURS_HOME:
+ return (cursor_home);
+ case CURS_LEFT:
+ return (cursor_left);
+ case CURS_RIGHT:
+ return (cursor_right);
+ case CURS_TO_LL:
+ return (cursor_to_ll);
+ case CURS_UP:
+ return (cursor_up);
+ case TAB:
+ return (tab);
+ case BACK_TAB:
+ return (back_tab);
+ case ROW_ADDR:
+ return (row_address);
+ case COL_ADDR:
+ return (column_address);
+ case P_DOWN_CURS:
+ return (parm_down_cursor);
+ case P_LEFT_CURS:
+ return (parm_left_cursor);
+ case P_RIGHT_CURS:
+ return (parm_right_cursor);
+ case P_UP_CURS:
+ return (parm_up_cursor);
+ case CURS_ADDR:
+ return (cursor_address);
+ default:
+ return ((char *) 0);
+ }
+}
+
+#endif
+
OpenPOWER on IntegriCloud