|
|
1.1 root 1: /* Cursor motion subroutines for GNU Emacs.
2: Copyright (C) 1985 Richard M. Stallman.
3: based primarily on public domain code written by Chris Torek
4:
5: This file is part of GNU Emacs.
6:
7: GNU Emacs is distributed in the hope that it will be useful,
8: but WITHOUT ANY WARRANTY. No author or distributor
9: accepts responsibility to anyone for the consequences of using it
10: or for whether it serves any particular purpose or works at all,
11: unless he says so in writing. Refer to the GNU Emacs General Public
12: License for full details.
13:
14: Everyone is granted permission to copy, modify and redistribute
15: GNU Emacs, but only under the conditions described in the
16: GNU Emacs General Public License. A copy of this license is
17: supposed to have been given to you along with GNU Emacs so you
18: can know your rights and responsibilities. It should be in a
19: file named COPYING. Among other things, the copyright notice
20: and this notice must be preserved on all copies. */
21:
22:
23: #include "config.h"
24: #include <stdio.h>
25: #include "cm.h"
26: #include "termhooks.h"
27:
28: #define BIG 9999 /* 9999 good on VAXen. For 16 bit machines
29: use about 2000.... */
30:
31: char *malloc (), *tgoto (), *getenv ();
32:
33: extern char *BC, *UP;
34:
35: int cost; /* sums up costs */
36:
37: /* ARGSUSED */
38: evalcost (c)
39: char c;
40: {
41: cost++;
42: }
43:
44: void
45: cmputc (c)
46: char c;
47: {
48: if (termscript)
49: fputc (c & 0177, termscript);
50: putchar (c & 0177);
51: }
52:
53: /* NEXT TWO ARE DONE WITH MACROS */
54: #if 0
55: /*
56: * Assume the cursor is at row row, column col. Normally used only after
57: * clearing the screen, when the cursor is at (0, 0), but what the heck,
58: * let's let the guy put it anywhere.
59: */
60:
61: static
62: at (row, col) {
63: curY = row;
64: curX = col;
65: }
66:
67: /*
68: * Add n columns to the current cursor position.
69: */
70:
71: static
72: addcol (n) {
73: curX += n;
74:
75: /*
76: * If cursor hit edge of screen, what happened?
77: * N.B.: DO NOT!! write past edge of screen. If you do, you
78: * deserve what you get. Furthermore, on terminals with
79: * autowrap (but not magicwrap), don't write in the last column
80: * of the last line.
81: */
82:
83: if (curX == Wcm.cm_cols) {
84: /*
85: * Well, if magicwrap, still there, past the edge of the
86: * screen (!). If autowrap, on the col 0 of the next line.
87: * Otherwise on last column.
88: */
89:
90: if (Wcm.cm_magicwrap)
91: ; /* "limbo" */
92: else if (Wcm.cm_autowrap) {
93: curX = 0;
94: curY++; /* Beware end of screen! */
95: }
96: else
97: curX--;
98: }
99: }
100: #endif
101:
102: /*
103: * (Re)Initialize the cost factors, given the output speed of the terminal
104: * in the variable ospeed. (Note: this holds B300, B9600, etc -- ie stuff
105: * out of <sgtty.h>.)
106: */
107:
108: cmcostinit ()
109: {
110: char *p;
111:
112: #define COST(x,e) (x ? (cost = 0, tputs (x, 1, e), cost) : BIG)
113: #define CMCOST(x,e) ((x == 0) ? BIG : (p = tgoto(x, 0, 0), COST(p ,e)))
114:
115: Wcm.cc_up = COST (Wcm.cm_up, evalcost);
116: Wcm.cc_down = COST (Wcm.cm_down, evalcost);
117: Wcm.cc_left = COST (Wcm.cm_left, evalcost);
118: Wcm.cc_right = COST (Wcm.cm_right, evalcost);
119: Wcm.cc_home = COST (Wcm.cm_home, evalcost);
120: Wcm.cc_cr = COST (Wcm.cm_cr, evalcost);
121: Wcm.cc_ll = COST (Wcm.cm_ll, evalcost);
122: Wcm.cc_tab = Wcm.cm_tabwidth ? COST (Wcm.cm_tab, evalcost) : BIG;
123:
124: /*
125: * These last three are actually minimum costs. When (if) they are
126: * candidates for the least-cost motion, the real cost is computed.
127: * (Note that "0" is the assumed to generate the minimum cost.
128: * While this is not necessarily true, I have yet to see a terminal
129: * for which is not; all the terminals that have variable-cost
130: * cursor motion seem to take straight numeric values. --ACT)
131: */
132:
133: Wcm.cc_abs = CMCOST (Wcm.cm_abs, evalcost);
134: Wcm.cc_habs = CMCOST (Wcm.cm_habs, evalcost);
135: Wcm.cc_vabs = CMCOST (Wcm.cm_vabs, evalcost);
136:
137: #undef CMCOST
138: #undef COST
139: }
140:
141: /*
142: * Calculate the cost to move from (srcy, srcx) to (dsty, dstx) using
143: * up and down, and left and right, motions, and tabs. If doit is set
144: * actually perform the motion.
145: */
146:
147: static
148: calccost (srcy, srcx, dsty, dstx, doit)
149: {
150: register int deltay,
151: deltax,
152: c,
153: totalcost;
154: int ntabs,
155: n2tabs,
156: tabx,
157: tab2x,
158: tabcost;
159: register char *p;
160:
161: /* If have just wrapped on a terminal with xn,
162: don't believe the cursor position: give up here
163: and force use of absolute positioning. */
164:
165: if (curX == Wcm.cm_cols)
166: goto fail;
167:
168: totalcost = 0;
169: if ((deltay = dsty - srcy) == 0)
170: goto x;
171: if (deltay < 0)
172: p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay;
173: else
174: p = Wcm.cm_down, c = Wcm.cc_down;
175: if (c == BIG) { /* caint get thar from here */
176: if (doit)
177: printf ("OOPS");
178: return c;
179: }
180: totalcost = c * deltay;
181: if (doit)
182: while (--deltay >= 0)
183: tputs (p, 1, cmputc);
184: x:
185: if ((deltax = dstx - srcx) == 0)
186: goto done;
187: if (deltax < 0) {
188: p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
189: goto dodelta; /* skip all the tab junk */
190: }
191: /* Tabs (the toughie) */
192: if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs)
193: goto olddelta; /* forget it! */
194:
195: /*
196: * ntabs is # tabs towards but not past dstx; n2tabs is one more
197: * (ie past dstx), but this is only valid if that is not past the
198: * right edge of the screen. We can check that at the same time
199: * as we figure out where we would be if we use the tabs (which
200: * we will put into tabx (for ntabs) and tab2x (for n2tabs)).
201: */
202:
203: ntabs = deltax / Wcm.cm_tabwidth;
204: n2tabs = ntabs + 1;
205: tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth;
206: tab2x = tabx + Wcm.cm_tabwidth;
207:
208: if (tab2x >= Wcm.cm_cols) /* too far (past edge) */
209: n2tabs = 0;
210:
211: /*
212: * Now set tabcost to the cost for using ntabs, and c to the cost
213: * for using n2tabs, then pick the minimum.
214: */
215:
216: /* cost for ntabs + cost for right motion */
217: tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right
218: : BIG;
219:
220: /* cost for n2tabs + cost for left motion */
221: c = n2tabs ? n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left
222: : BIG;
223:
224: if (c < tabcost) /* then cheaper to overshoot & back up */
225: ntabs = n2tabs, tabcost = c, tabx = tab2x;
226:
227: if (tabcost >= BIG) /* caint use tabs */
228: goto newdelta;
229:
230: /*
231: * See if tabcost is less than just moving right
232: */
233:
234: if (tabcost < (deltax * Wcm.cc_right)) {
235: totalcost += tabcost; /* use the tabs */
236: if (doit)
237: while (--ntabs >= 0)
238: tputs (Wcm.cm_tab, 1, cmputc);
239: srcx = tabx;
240: }
241:
242: /*
243: * Now might as well just recompute the delta.
244: */
245:
246: newdelta:
247: if ((deltax = dstx - srcx) == 0)
248: goto done;
249: olddelta:
250: if (deltax > 0)
251: p = Wcm.cm_right, c = Wcm.cc_right;
252: else
253: p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax;
254:
255: dodelta:
256: if (c == BIG) { /* caint get thar from here */
257: fail:
258: if (doit)
259: printf ("OOPS");
260: return BIG;
261: }
262: totalcost += c * deltax;
263: if (doit)
264: while (--deltax >= 0)
265: tputs (p, 1, cmputc);
266: done:
267: return totalcost;
268: }
269:
270: losecursor ()
271: {
272: curY = -1;
273: }
274:
275: #define USEREL 0
276: #define USEHOME 1
277: #define USELL 2
278: #define USECR 3
279:
280: cmgoto (row, col)
281: {
282: int homecost,
283: crcost,
284: llcost,
285: relcost,
286: directcost;
287: int use;
288: char *p,
289: *dcm;
290:
291: /* First the degenerate case */
292: if (row == curY && col == curX) /* already there */
293: return;
294:
295: if (curY >= 0 && curX >= 0)
296: {
297: /*
298: * Pick least-cost motions
299: */
300:
301: relcost = calccost (curY, curX, row, col, 0);
302: use = USEREL;
303: if ((homecost = Wcm.cc_home) < BIG)
304: homecost += calccost (0, 0, row, col, 0);
305: if (homecost < relcost)
306: relcost = homecost, use = USEHOME;
307: if ((llcost = Wcm.cc_ll) < BIG)
308: llcost += calccost (Wcm.cm_rows - 1, 0, row, col, 0);
309: if (llcost < relcost)
310: relcost = llcost, use = USELL;
311: if ((crcost = Wcm.cc_cr) < BIG) {
312: if (Wcm.cm_autolf)
313: if (curY + 1 >= Wcm.cm_rows)
314: crcost = BIG;
315: else
316: crcost += calccost (curY + 1, 0, row, col, 0);
317: else
318: crcost += calccost (curY, 0, row, col, 0);
319: }
320: if (crcost < relcost)
321: relcost = crcost, use = USECR;
322: directcost = Wcm.cc_abs, dcm = Wcm.cm_abs;
323: if (row == curY && Wcm.cc_habs < BIG)
324: directcost = Wcm.cc_habs, dcm = Wcm.cm_habs;
325: else if (col == curX && Wcm.cc_vabs < BIG)
326: directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs;
327: }
328: else
329: {
330: directcost = 0, relcost = 100000;
331: dcm = Wcm.cm_abs;
332: }
333:
334: /*
335: * In the following comparison, the = in <= is because when the costs
336: * are the same, it looks nicer (I think) to move directly there.
337: */
338: if (directcost <= relcost)
339: {
340: /* compute REAL direct cost */
341: cost = 0;
342: p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) :
343: tgoto (dcm, col, row);
344: tputs (p, 1, evalcost);
345: if (cost <= relcost)
346: { /* really is cheaper */
347: tputs (p, 1, cmputc);
348: curY = row, curX = col;
349: return;
350: }
351: }
352:
353: switch (use)
354: {
355: case USEHOME:
356: tputs (Wcm.cm_home, 1, cmputc);
357: curY = 0, curX = 0;
358: break;
359:
360: case USELL:
361: tputs (Wcm.cm_ll, 1, cmputc);
362: curY = Wcm.cm_rows - 1, curX = 0;
363: break;
364:
365: case USECR:
366: tputs (Wcm.cm_cr, 1, cmputc);
367: if (Wcm.cm_autolf)
368: curY++;
369: curX = 0;
370: break;
371: }
372:
373: (void) calccost (curY, curX, row, col, 1);
374: curY = row, curX = col;
375: }
376:
377: /* Clear out all terminal info.
378: Used before copying into it the info on the actual terminal.
379: */
380:
381: Wcm_clear ()
382: {
383: bzero (&Wcm, sizeof Wcm);
384: UP = 0;
385: BC = 0;
386: }
387:
388: /*
389: * Initialized stuff
390: * Return 0 if can do CM.
391: */
392:
393: Wcm_init ()
394: {
395: /* Check that we know the size of the screen.... */
396: if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0)
397: return - 1;
398: if (Wcm.cm_abs && !Wcm.cm_ds)
399: return 0;
400: /* Require up and left, and, if no absolute, down and right */
401: if (!Wcm.cm_up || !Wcm.cm_left)
402: return - 1;
403: if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right))
404: return - 1;
405: return 0;
406: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.