|
|
1.1 root 1: /*********************************************************************
2: * COPYRIGHT NOTICE *
3: **********************************************************************
4: * This software is copyright (C) 1982 by Pavel Curtis *
5: * *
6: * Permission is granted to reproduce and distribute *
7: * this file by any means so long as no fee is charged *
8: * above a nominal handling fee and so long as this *
9: * notice is always included in the copies. *
10: * *
11: * Other rights are reserved except as explicitly granted *
12: * by written permission of the author. *
13: * Pavel Curtis *
14: * Computer Science Dept. *
15: * 405 Upson Hall *
16: * Cornell University *
17: * Ithaca, NY 14853 *
18: * *
19: * Ph- (607) 256-4934 *
20: * *
21: * Pavel.Cornell@Udel-Relay (ARPAnet) *
22: * decvax!cornell!pavel (UUCPnet) *
23: *********************************************************************/
24:
25: /*
26: **
27: ** lib_mvcur.c
28: **
29: ** mvcur() and its subroutines
30: **
31: ** $Log: lib_mvcur.c,v $
32: * Revision 1.8 93/04/12 14:13:47 bin
33: * Udo: third color update
34: *
35: * Revision 1.2 92/04/13 14:37:43 bin
36: * update by vlad
37: *
38: * Revision 2.2 91/04/20 19:25:30 munk
39: * Usage of register variables
40: *
41: * Revision 2.1 82/10/25 14:47:54 pavel
42: * Added Copyright Notice
43: *
44: * Revision 2.0 82/10/25 13:46:40 pavel
45: * Beta-one Test Release
46: *
47: **
48: ** Revisions needed:
49: ** implement c_save instead of multiple tputs() calls
50: ** routine revisions
51: */
52:
53: #ifdef RCSHDR
54: static char RCSid[] =
55: "$Header: /src386/usr/lib/ncurses/RCS/lib_mvcur.c,v 1.8 93/04/12 14:13:47 bin Exp Locker: bin $";
56: #endif
57:
58: #include "term.h"
59: #include "curses.h"
60: #include "curses.priv.h"
61:
62:
63: #define BUFSIZE 128 /* size of strategy buffer */
64:
65: struct Sequence
66: {
67: int vec[BUFSIZE], /* vector of operations */
68: *end, /* end of vector */
69: cost; /* cost of vector */
70: };
71:
72: /*
73: ** #define
74: ** Make_seq_best(s1, s2)
75: **
76: ** Make_seq_best() swaps the values
77: ** of the pointers if s1->cost > s2->cost.
78: */
79:
80: #define Make_seq_best(s1, s2) \
81: if (s1->cost > s2->cost) \
82: { \
83: struct Sequence *temp; \
84: \
85: temp = s1; \
86: s1 = s2; \
87: s2 = temp; \
88: }
89:
90:
91: FILE *out_file; /* pointer to output file */
92:
93: static int c_count; /* used for counting tputs output */
94:
95: /*rev c_save not yet used*/
96: /*static char *c_save;*/ /* used for saving tputs output */
97:
98: #define INFINITY 1000 /* biggest, impossible sequence cost */
99:
100: #define NUM_OPS 16 /* num. term. control sequences */
101: #define NUM_NPARM 9 /* num. ops wo/ parameters */
102:
103: /* operator indexes into op_info */
104:
105: #define CARRIAGE_RETURN 0 /* watch out for nl mapping */
106: #define CURS_DOWN 1
107: #define CURS_HOME 2
108: #define CURS_LEFT 3
109: #define CURS_RIGHT 4
110: #define CURS_TO_LL 5
111: #define CURS_UP 6
112: #define TAB 7
113: #define BACK_TAB 8
114: #define ROW_ADDR 9
115: #define COL_ADDR 10
116: #define P_DOWN_CURS 11
117: #define P_LEFT_CURS 12
118: #define P_RIGHT_CURS 13
119: #define P_UP_CURS 14
120: #define CURS_ADDR 15
121:
122: static bool loc_init = FALSE; /* set if op_info is init'ed */
123:
124: static bool rel_ok; /* set if we really know where we are */
125:
126: /*
127: * op_info[NUM_OPS]
128: *
129: * op_info[] contains for operations with no parameters
130: * the cost of the operation. These ops should be first in the array.
131: * For operations with parameters, op_info[] contains
132: * the negative of the number of parameters.
133: */
134:
135: static int op_info[NUM_OPS] =
136: {
137: 0, /* carriage_return */
138: 0, /* cursor_down */
139: 0, /* cursor_home */
140: 0, /* cursor_left */
141: 0, /* cursor_right */
142: 0, /* cursor_to_ll */
143: 0, /* cursor_up */
144: 0, /* tab */
145: 0, /* back_tab */
146: -1, /* row_address */
147: -1, /* column_address */
148: -1, /* parm_down_cursor */
149: -1, /* parm_left_cursor */
150: -1, /* parm_right_cursor */
151: -1, /* parm_up_cursor */
152: -2 /* cursor_address */
153: };
154:
155:
156: /*
157: **
158: ** mvcur(oldrow, oldcol, newrow, newcol)
159: **
160: ** mvcur() optimally moves the cursor from the position
161: ** specified by (oldrow, oldcol) to (newrow, newcol). If
162: ** (oldrow, oldcol) == (-1, -1), mvcur() does not use relative
163: ** cursor motions. If the coordinates are otherwise
164: ** out of bounds, it mods them into range.
165: **
166: ** Revisions needed:
167: ** eat_newline_glitch, auto_right_margin
168: */
169:
170: mvcur(oldrow, oldcol, newrow, newcol)
171: int oldrow, oldcol,
172: newrow, newcol;
173: {
174: struct Sequence seqA, seqB, /* allocate work structures */
175: col0seq, /* sequence to get from col0 to nc */
176: *best, /* best sequence so far */
177: *try; /* next try */
178:
179: #ifdef TRACE
180: if (_tracing)
181: _tracef("mvcur(%d,%d,%d,%d) called",
182: oldrow, oldcol, newrow, newcol);
183: #endif
184:
185: update_ops(); /* make sure op_info[] is current */
186:
187: if (oldrow < 0 || oldcol < 0)
188: rel_ok = FALSE; /* relative ops ok? */
189: else
190: {
191: rel_ok = TRUE;
192:
193: oldrow %= lines; /* mod values into range */
194: oldcol %= columns;
195: }
196: newrow %= lines;
197: newcol %= columns;
198:
199: best = &seqA;
200: try = &seqB;
201:
202: /* try out direct cursor addressing */
203:
204: zero_seq(best);
205: add_op(best, CURS_ADDR, newrow, newcol);
206:
207: /* try out independent row/column addressing */
208:
209: if (rel_ok)
210: {
211: zero_seq(try);
212: row(try, oldrow, newrow);
213: column(try, oldcol, newcol);
214: Make_seq_best(best, try);
215: }
216:
217: zero_seq(&col0seq); /* store seq. to get from c0 to nc */
218: column(&col0seq, 0, newcol);
219:
220: if(col0seq.cost < INFINITY) /* can get from col0 to newcol */
221: {
222: /* try out homing and then row/column */
223:
224: if (! rel_ok || newcol < oldcol || newrow < oldrow)
225: {
226: zero_seq(try);
227: add_op(try, CURS_HOME, 1);
228: row(try, 0, newrow);
229: add_seq(try, &col0seq);
230: Make_seq_best(best, try);
231: }
232:
233: /* try out homing to last line and then row/column */
234:
235: if (! rel_ok || newcol < oldcol || newrow > oldrow)
236: {
237: zero_seq(try);
238: add_op(try, CURS_TO_LL, 1);
239: row(try, lines - 1, newrow);
240: add_seq(try, &col0seq);
241: Make_seq_best(best, try);
242: }
243: }
244:
245: #ifdef TRACE
246: if (_tracing)
247: _tracef("\tmvcur: result follows");
248: #endif
249:
250: out_seq(best);
251:
252: #ifdef TRACE
253: if (_tracing)
254: _tracef("\tmvcur: end of result");
255: #endif
256: }
257:
258:
259: /*
260: ** row(outseq, oldrow, newrow)
261: **
262: ** row() adds the best sequence for moving
263: ** the cursor from oldrow to newrow to seq.
264: ** row() considers row_address, parm_up/down_cursor
265: ** and cursor_up/down.
266: */
267:
268: static
269: row(outseq, orow, nrow)
270: int orow, nrow; /* old, new cursor locations */
271: struct Sequence *outseq; /* where to put the output */
272: {
273: struct Sequence seqA, seqB,
274: *best, /* best sequence so far */
275: *try; /* next try */
276: int parm_cursor, one_step;
277:
278: best = &seqA;
279: try = &seqB;
280:
281: if (nrow == orow)
282: return;
283:
284: if (nrow < orow)
285: {
286: parm_cursor = P_UP_CURS;
287: one_step = CURS_UP;
288: }
289: else
290: {
291: parm_cursor = P_DOWN_CURS;
292: one_step = CURS_DOWN;
293: }
294:
295: /* try out direct row addressing */
296:
297: zero_seq(best);
298: add_op(best, ROW_ADDR, nrow);
299:
300: /* try out paramaterized up or down motion */
301:
302: if (rel_ok)
303: {
304: zero_seq(try);
305: add_op(try, parm_cursor, abs(orow - nrow));
306: Make_seq_best(best, try);
307: }
308: /* try getting there one step at a time... */
309:
310: if (rel_ok)
311: {
312: zero_seq(try);
313: add_op(try, one_step, abs(orow-nrow));
314: Make_seq_best(best, try);
315: }
316:
317: add_seq(outseq, best);
318: }
319:
320:
321: /*
322: ** column(outseq, oldcol, newcol)
323: **
324: ** column() adds the best sequence for moving
325: ** the cursor from oldcol to newcol to outseq.
326: ** column() considers column_address, parm_left/right_cursor,
327: ** simp_col(), and carriage_return followed by simp_col().
328: */
329:
330: static
331: column(outseq, ocol, ncol)
332: struct Sequence *outseq; /* where to put the output */
333: int ocol, ncol; /* old, new cursor column */
334: {
335: struct Sequence seqA, seqB,
336: *best, *try;
337: int parm_cursor; /* set to either parm_up/down_cursor */
338:
339: best = &seqA;
340: try = &seqB;
341:
342: if (ncol == ocol)
343: return;
344:
345: if (ncol < ocol)
346: parm_cursor = P_LEFT_CURS;
347: else
348: parm_cursor = P_RIGHT_CURS;
349:
350: /* try out direct column addressing */
351:
352: zero_seq(best);
353: add_op(best, COL_ADDR, ncol);
354:
355: /* try carriage_return then simp_col() */
356:
357: if (! rel_ok || (ncol < ocol))
358: {
359: zero_seq(try);
360: add_op(try, CARRIAGE_RETURN, 1);
361: simp_col(try, 0, ncol);
362: Make_seq_best(best, try);
363: }
364: if (rel_ok)
365: {
366: /* try out paramaterized left or right motion */
367:
368: zero_seq(try);
369: add_op(try, parm_cursor, abs(ocol - ncol));
370: Make_seq_best(best, try);
371:
372: /* try getting there with simp_col() */
373:
374: zero_seq(try);
375: simp_col(try, ocol, ncol);
376: Make_seq_best(best, try);
377: }
378:
379: add_seq(outseq, best);
380: }
381:
382:
383: /*
384: ** simp_col(outseq, oldcol, newcol)
385: **
386: ** simp_col() adds the best simple sequence for getting
387: ** from oldcol to newcol to outseq.
388: ** simp_col() considers (back_)tab and cursor_left/right.
389: **
390: ** Revisions needed:
391: ** Simp_col asssumes that the cost of a (back_)tab
392: ** is less then the cost of one-stepping to get to the same column.
393: ** Should sometimes use overprinting instead of cursor_right.
394: */
395:
396: static
397: simp_col(outseq, oc, nc)
398: struct Sequence *outseq; /* place to put sequence */
399: int oc, nc; /* old column, new column */
400: {
401: struct Sequence seqA, seqB, tabseq,
402: *best, *try;
403: int mytab, tabs, onepast,
404: one_step, opp_step;
405:
406: if (! rel_ok)
407: {
408: outseq->cost = INFINITY;
409: return;
410: }
411:
412: if (oc == nc)
413: return;
414:
415: best = &seqA;
416: try = &seqB;
417:
418: if (oc < nc)
419: {
420: mytab = TAB;
421: if (init_tabs > 0 && op_info[TAB] < INFINITY)
422: {
423: tabs = nc / init_tabs - oc / init_tabs;
424: onepast = ((nc / init_tabs) + 1) * init_tabs;
425: if (tabs)
426: oc = onepast - init_tabs; /* consider it done */
427: }
428: else
429: tabs = 0;
430:
431: one_step = CURS_RIGHT;
432: opp_step = CURS_LEFT;
433: }
434: else
435: {
436: mytab = BACK_TAB;
437: if (init_tabs > 0 && op_info[BACK_TAB] < INFINITY)
438: {
439: tabs = oc / init_tabs - nc / init_tabs;
440: onepast = ((nc - 1) / init_tabs) * init_tabs;
441: if (tabs)
442: oc = onepast + init_tabs; /* consider it done */
443: }
444: else
445: tabs = 0;
446:
447: one_step = CURS_LEFT;
448: opp_step = CURS_RIGHT;
449: }
450:
451: /* tab as close as possible to nc */
452:
453: zero_seq(&tabseq);
454: add_op(&tabseq, mytab, tabs);
455:
456: /* try extra tab and backing up */
457:
458: zero_seq(best);
459:
460: if (onepast >= 0 && onepast < columns)
461: {
462: add_op(best, mytab, 1);
463: add_op(best, opp_step, abs(onepast - nc));
464: }
465: else
466: best->cost = INFINITY; /* make sure of next swap */
467:
468: /* try stepping to nc */
469:
470: zero_seq(try);
471: add_op(try, one_step, abs(nc - oc));
472: Make_seq_best(best, try);
473:
474: if (tabseq.cost < INFINITY)
475: add_seq(outseq, &tabseq);
476: add_seq(outseq, best);
477: }
478:
479:
480: /*
481: ** zero_seq(seq)
482: ** add_seq(seq1, seq2)
483: ** out_seq(seq)
484: **
485: ** zero_seq() empties seq.
486: ** add_seq() adds seq1 to seq2.
487: ** out_seq() outputs a sequence.
488: */
489:
490: static
491: zero_seq(seq)
492: struct Sequence *seq;
493: {
494: seq->end = seq->vec;
495: seq->cost = 0;
496: }
497:
498:
499: static
500: add_seq(seq1, seq2)
501: register struct Sequence *seq1, *seq2;
502: {
503: int *vptr;
504:
505: if(seq1->cost >= INFINITY || seq2->cost >= INFINITY)
506: seq1->cost = INFINITY;
507: else
508: {
509: vptr = seq2->vec;
510: while (vptr != seq2->end)
511: *(seq1->end++) = *(vptr++);
512: seq1->cost += seq2->cost;
513: }
514: }
515:
516:
517: static
518: out_seq(seq)
519: register struct Sequence *seq;
520: {
521: char *tparm();
522: register int *opptr;
523: int prm[9], ps, p, op, outc();
524: int count;
525: char *sequence();
526:
527: if (seq->cost >= INFINITY)
528: return;
529:
530: for (opptr = seq->vec; opptr < seq->end; opptr++)
531: {
532: op = *opptr; /* grab operator */
533: ps = -op_info[op];
534: if(ps > 0) /* parameterized */
535: {
536: for (p = 0; p < ps; p++) /* fill in needed parms */
537: prm[p] = *(++opptr);
538:
539: tputs(tparm(sequence(op),
540: prm[0], prm[1], prm[2], prm[3], prm[4],
541: prm[5], prm[6], prm[7], prm[8]), 1, outc);
542: }
543: else
544: {
545: count = *(++opptr);
546: /*rev should save tputs output instead of mult calls */
547: while (count--) /* do count times */
548: tputs(sequence(op), 1, outc);
549: }
550: }
551: }
552:
553:
554: /*
555: ** update_ops()
556: **
557: ** update_ops() makes sure that
558: ** the op_info[] array is updated and initializes
559: ** the cost array for SP if needed.
560: */
561:
562: static
563: update_ops()
564: {
565: char *index();
566:
567: if (SP) /* SP structure exists */
568: {
569: register int op;
570:
571: out_file = SP->_ofp; /* set output file pointer */
572:
573: if (! SP->_costinit) /* this term not yet assigned costs */
574: {
575: loc_init = FALSE; /* if !SP in the future, new term */
576: init_costs(SP->_costs); /* fill term costs */
577: SP->_costinit = TRUE;
578: }
579:
580: for (op = 0; op < NUM_NPARM; op++)
581: op_info[op] = SP->_costs[op]; /* set up op_info */
582:
583: /* check for newline that might be mapped... */
584: if (SP->_nlmapping && (index(sequence(CURS_DOWN), '\n') != NULL))
585: op_info[CURS_DOWN] = INFINITY;
586: }
587: else
588: {
589: out_file = stdout;
590:
591: if (! loc_init) /* using local costs */
592: {
593: loc_init = TRUE;
594: init_costs(op_info); /* set up op_info */
595: }
596: /* check for newline that might be mapped... */
597: if (index(sequence(CURS_DOWN), '\n') != NULL)
598: op_info[CURS_DOWN] = INFINITY;
599: }
600: }
601:
602:
603: /*
604: ** init_costs(costs)
605: **
606: ** init_costs() fills the array costs[NUM_NPARM]
607: ** with costs calculated by doing tputs() calls.
608: */
609:
610: static
611: init_costs(costs)
612: int costs[];
613: {
614: register int i;
615: int countc();
616:
617: for (i = 0; i < NUM_NPARM; i++)
618: if(sequence(i) != (char *) 0)
619: {
620: #ifdef TRACE
621: if (_tracing)
622: _tracef("\tinit_costs: pricing %d: '%s'", i, sequence(i));
623: #endif
624:
625: c_count = 0;
626: tputs(sequence(i), 1, countc);
627: costs[i] = c_count;
628: }
629: else
630: costs[i] = INFINITY;
631: }
632:
633:
634: /*
635: ** countc()
636: ** outc(c)
637: ** savec(c)
638: **
639: ** countc() increments global var c_count.
640: ** outc() outputs a single character.
641: ** savec() saves c in *c_save and increments c_save and c_count.
642: */
643:
644: static
645: countc()
646: {
647: c_count++;
648: }
649:
650:
651: static
652: outc(c)
653: char c;
654: {
655: fputc(c, out_file);
656: }
657:
658:
659: /*rev not yet needed
660: static
661: savec(c)
662: char c;
663: {
664: *(c_save++) = c;
665: c_count++;
666: }
667: */
668:
669:
670: /*
671: ** add_op(seq, op, p0, p1, ... , p8)
672: **
673: ** add_op() adds the operator op and the appropriate
674: ** number of paramaters to seq. It also increases the
675: ** cost appropriately.
676: ** if op has no parameters, p0 is taken to be a count.
677: */
678:
679: static
680: add_op(seq, op, p0, p1, p2, p3, p4, p5, p6, p7, p8)
681: struct Sequence *seq;
682: int op, p0, p1, p2, p3, p4, p5, p6, p7, p8;
683: {
684: char *tparm();
685: int num_ps, p;
686:
687: #ifdef TRACE
688: if (_tracing)
689: _tracef("\tadd_op(%o,%d,%d,%d) called", seq, op, p0, p1);
690: #endif
691:
692: num_ps = - op_info[op]; /* get parms or -cost */
693: *(seq->end++) = op;
694:
695: if (num_ps == (- INFINITY) || sequence(op) == (char *) 0)
696: seq->cost = INFINITY;
697: else
698: if (num_ps <= 0) /* no parms, -cost */
699: {
700: seq->cost -= p0 * num_ps; /* ADD count * cost */
701: *(seq->end++) = p0;
702: }
703: else
704: {
705: int pms[9];
706:
707: pms[0] = p0; pms[1] = p1; pms[2] = p2;
708: pms[3] = p3; pms[4] = p4; pms[5] = p5;
709: pms[6] = p6; pms[7] = p7; pms[8] = p8;
710: for(p = 0; p < num_ps; p++)
711: *(seq->end++) = pms[p];
712: c_count = 0;
713: tputs(tparm(sequence(op), p0, p1, p2, p3, p4, p5, p6, p7, p8),
714: 1, countc);
715: seq->cost += c_count;
716: }
717: }
718:
719:
720: /*
721: ** char *
722: ** sequence(op)
723: **
724: ** sequence() returns a pointer to the op's
725: ** terminal control sequence.
726: */
727:
728: static char *
729: sequence(op)
730: register int op;
731: {
732:
733: switch(op)
734: {
735: case CARRIAGE_RETURN:
736: return (carriage_return);
737: case CURS_DOWN:
738: return (cursor_down);
739: case CURS_HOME:
740: return (cursor_home);
741: case CURS_LEFT:
742: return (cursor_left);
743: case CURS_RIGHT:
744: return (cursor_right);
745: case CURS_TO_LL:
746: return (cursor_to_ll);
747: case CURS_UP:
748: return (cursor_up);
749: case TAB:
750: return (tab);
751: case BACK_TAB:
752: return (back_tab);
753: case ROW_ADDR:
754: return (row_address);
755: case COL_ADDR:
756: return (column_address);
757: case P_DOWN_CURS:
758: return (parm_down_cursor);
759: case P_LEFT_CURS:
760: return (parm_left_cursor);
761: case P_RIGHT_CURS:
762: return (parm_right_cursor);
763: case P_UP_CURS:
764: return (parm_up_cursor);
765: case CURS_ADDR:
766: return (cursor_address);
767: default:
768: return ((char *) 0);
769: }
770: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.