Mercurial > emacs
annotate src/cm.c @ 23323:0800a4f84757
(underlying_strftime):
Set the buffer to a nonzero value before calling
strftime, and check to see whether strftime has set the buffer to zero.
This lets us distinguish between an empty buffer and an error.
I'm installing this patch by hand now; it will be superseded whenever
the glibc sources are propagated back to fsf.org.
| author | Paul Eggert <eggert@twinsun.com> |
|---|---|
| date | Fri, 25 Sep 1998 21:40:23 +0000 |
| parents | fa9ff387d260 |
| children | fa344b2d7041 |
| rev | line source |
|---|---|
| 484 | 1 /* Cursor motion subroutines for GNU Emacs. |
| 11235 | 2 Copyright (C) 1985, 1995 Free Software Foundation, Inc. |
| 484 | 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 free software; you can redistribute it and/or modify | |
| 8 it under the terms of the GNU General Public License as published by | |
| 7107 | 9 the Free Software Foundation; either version 2, or (at your option) |
| 484 | 10 any later version. |
| 11 | |
| 12 GNU Emacs is distributed in the hope that it will be useful, | |
| 13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 GNU General Public License for more details. | |
| 16 | |
| 17 You should have received a copy of the GNU General Public License | |
| 18 along with GNU Emacs; see the file COPYING. If not, write to | |
|
14186
ee40177f6c68
Update FSF's address in the preamble.
Erik Naggum <erik@naggum.no>
parents:
11235
diff
changeset
|
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
ee40177f6c68
Update FSF's address in the preamble.
Erik Naggum <erik@naggum.no>
parents:
11235
diff
changeset
|
20 Boston, MA 02111-1307, USA. */ |
| 484 | 21 |
| 22 | |
|
4696
1fc792473491
Include <config.h> instead of "config.h".
Roland McGrath <roland@gnu.org>
parents:
484
diff
changeset
|
23 #include <config.h> |
| 484 | 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 *tgoto (); | |
| 32 | |
| 33 extern char *BC, *UP; | |
| 34 | |
| 35 int cost; /* sums up costs */ | |
| 36 | |
| 37 /* ARGSUSED */ | |
| 21514 | 38 int |
| 484 | 39 evalcost (c) |
| 40 char c; | |
| 41 { | |
| 42 cost++; | |
|
8985
2825665b8352
(evalcost, cmputc): They now return their arguments.
Richard M. Stallman <rms@gnu.org>
parents:
7107
diff
changeset
|
43 return c; |
| 484 | 44 } |
| 45 | |
| 21514 | 46 int |
| 484 | 47 cmputc (c) |
| 48 char c; | |
| 49 { | |
| 50 if (termscript) | |
| 51 fputc (c & 0177, termscript); | |
| 52 putchar (c & 0177); | |
|
8985
2825665b8352
(evalcost, cmputc): They now return their arguments.
Richard M. Stallman <rms@gnu.org>
parents:
7107
diff
changeset
|
53 return c; |
| 484 | 54 } |
| 55 | |
| 56 /* NEXT TWO ARE DONE WITH MACROS */ | |
| 57 #if 0 | |
| 58 /* | |
| 59 * Assume the cursor is at row row, column col. Normally used only after | |
| 60 * clearing the screen, when the cursor is at (0, 0), but what the heck, | |
| 61 * let's let the guy put it anywhere. | |
| 62 */ | |
| 63 | |
| 64 static | |
| 65 at (row, col) { | |
| 66 curY = row; | |
| 67 curX = col; | |
| 68 } | |
| 69 | |
| 70 /* | |
| 71 * Add n columns to the current cursor position. | |
| 72 */ | |
| 73 | |
| 74 static | |
| 75 addcol (n) { | |
| 76 curX += n; | |
| 77 | |
| 78 /* | |
| 79 * If cursor hit edge of screen, what happened? | |
| 80 * N.B.: DO NOT!! write past edge of screen. If you do, you | |
| 81 * deserve what you get. Furthermore, on terminals with | |
| 82 * autowrap (but not magicwrap), don't write in the last column | |
| 83 * of the last line. | |
| 84 */ | |
| 85 | |
| 86 if (curX == Wcm.cm_cols) { | |
| 87 /* | |
| 88 * Well, if magicwrap, still there, past the edge of the | |
| 89 * screen (!). If autowrap, on the col 0 of the next line. | |
| 90 * Otherwise on last column. | |
| 91 */ | |
| 92 | |
| 93 if (Wcm.cm_magicwrap) | |
| 94 ; /* "limbo" */ | |
| 95 else if (Wcm.cm_autowrap) { | |
| 96 curX = 0; | |
| 97 curY++; /* Beware end of screen! */ | |
| 98 } | |
| 99 else | |
| 100 curX--; | |
| 101 } | |
| 102 } | |
| 103 #endif | |
| 104 | |
| 105 /* | |
| 10437 | 106 * Terminals with magicwrap (xn) don't all behave identically. |
| 107 * The VT100 leaves the cursor in the last column but will wrap before | |
| 108 * printing the next character. I hear that the Concept terminal does | |
| 109 * the wrap immediately but ignores the next newline it sees. And some | |
| 110 * terminals just have buggy firmware, and think that the cursor is still | |
| 111 * in limbo if we use direct cursor addressing from the phantom column. | |
| 112 * The only guaranteed safe thing to do is to emit a CRLF immediately | |
| 113 * after we reach the last column; this takes us to a known state. | |
| 114 */ | |
| 115 void | |
| 116 cmcheckmagic () | |
| 117 { | |
| 118 if (curX == FrameCols) | |
| 119 { | |
| 120 if (!MagicWrap || curY >= FrameRows - 1) | |
| 121 abort (); | |
| 122 if (termscript) | |
| 123 putc ('\r', termscript); | |
| 124 putchar ('\r'); | |
| 125 if (termscript) | |
| 126 putc ('\n', termscript); | |
| 127 putchar ('\n'); | |
| 128 curX = 0; | |
| 129 curY++; | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 | |
| 134 /* | |
| 484 | 135 * (Re)Initialize the cost factors, given the output speed of the terminal |
| 136 * in the variable ospeed. (Note: this holds B300, B9600, etc -- ie stuff | |
| 137 * out of <sgtty.h>.) | |
| 138 */ | |
| 139 | |
| 21514 | 140 void |
| 484 | 141 cmcostinit () |
| 142 { | |
| 143 char *p; | |
| 144 | |
| 145 #define COST(x,e) (x ? (cost = 0, tputs (x, 1, e), cost) : BIG) | |
| 146 #define CMCOST(x,e) ((x == 0) ? BIG : (p = tgoto(x, 0, 0), COST(p ,e))) | |
| 147 | |
| 148 Wcm.cc_up = COST (Wcm.cm_up, evalcost); | |
| 149 Wcm.cc_down = COST (Wcm.cm_down, evalcost); | |
| 150 Wcm.cc_left = COST (Wcm.cm_left, evalcost); | |
| 151 Wcm.cc_right = COST (Wcm.cm_right, evalcost); | |
| 152 Wcm.cc_home = COST (Wcm.cm_home, evalcost); | |
| 153 Wcm.cc_cr = COST (Wcm.cm_cr, evalcost); | |
| 154 Wcm.cc_ll = COST (Wcm.cm_ll, evalcost); | |
| 155 Wcm.cc_tab = Wcm.cm_tabwidth ? COST (Wcm.cm_tab, evalcost) : BIG; | |
| 156 | |
| 157 /* | |
| 158 * These last three are actually minimum costs. When (if) they are | |
| 159 * candidates for the least-cost motion, the real cost is computed. | |
| 160 * (Note that "0" is the assumed to generate the minimum cost. | |
| 161 * While this is not necessarily true, I have yet to see a terminal | |
| 162 * for which is not; all the terminals that have variable-cost | |
| 163 * cursor motion seem to take straight numeric values. --ACT) | |
| 164 */ | |
| 165 | |
| 166 Wcm.cc_abs = CMCOST (Wcm.cm_abs, evalcost); | |
| 167 Wcm.cc_habs = CMCOST (Wcm.cm_habs, evalcost); | |
| 168 Wcm.cc_vabs = CMCOST (Wcm.cm_vabs, evalcost); | |
| 169 | |
| 170 #undef CMCOST | |
| 171 #undef COST | |
| 172 } | |
| 173 | |
| 174 /* | |
| 175 * Calculate the cost to move from (srcy, srcx) to (dsty, dstx) using | |
| 176 * up and down, and left and right, motions, and tabs. If doit is set | |
| 177 * actually perform the motion. | |
| 178 */ | |
| 179 | |
| 21514 | 180 static int |
| 484 | 181 calccost (srcy, srcx, dsty, dstx, doit) |
| 182 { | |
| 183 register int deltay, | |
| 184 deltax, | |
| 185 c, | |
| 186 totalcost; | |
| 187 int ntabs, | |
| 188 n2tabs, | |
| 189 tabx, | |
| 190 tab2x, | |
| 191 tabcost; | |
| 192 register char *p; | |
| 193 | |
| 194 /* If have just wrapped on a terminal with xn, | |
| 195 don't believe the cursor position: give up here | |
| 196 and force use of absolute positioning. */ | |
| 197 | |
| 198 if (curX == Wcm.cm_cols) | |
| 199 goto fail; | |
| 200 | |
| 201 totalcost = 0; | |
| 202 if ((deltay = dsty - srcy) == 0) | |
| 203 goto x; | |
| 204 if (deltay < 0) | |
| 205 p = Wcm.cm_up, c = Wcm.cc_up, deltay = -deltay; | |
| 206 else | |
| 207 p = Wcm.cm_down, c = Wcm.cc_down; | |
| 208 if (c == BIG) { /* caint get thar from here */ | |
| 209 if (doit) | |
| 210 printf ("OOPS"); | |
| 211 return c; | |
| 212 } | |
| 213 totalcost = c * deltay; | |
| 214 if (doit) | |
| 215 while (--deltay >= 0) | |
| 216 tputs (p, 1, cmputc); | |
| 217 x: | |
| 218 if ((deltax = dstx - srcx) == 0) | |
| 219 goto done; | |
| 220 if (deltax < 0) { | |
| 221 p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax; | |
| 222 goto dodelta; /* skip all the tab junk */ | |
| 223 } | |
| 224 /* Tabs (the toughie) */ | |
| 225 if (Wcm.cc_tab >= BIG || !Wcm.cm_usetabs) | |
| 226 goto olddelta; /* forget it! */ | |
| 227 | |
| 228 /* | |
| 229 * ntabs is # tabs towards but not past dstx; n2tabs is one more | |
| 230 * (ie past dstx), but this is only valid if that is not past the | |
| 231 * right edge of the screen. We can check that at the same time | |
| 232 * as we figure out where we would be if we use the tabs (which | |
| 233 * we will put into tabx (for ntabs) and tab2x (for n2tabs)). | |
| 234 */ | |
| 235 | |
| 236 ntabs = (deltax + srcx % Wcm.cm_tabwidth) / Wcm.cm_tabwidth; | |
| 237 n2tabs = ntabs + 1; | |
| 238 tabx = (srcx / Wcm.cm_tabwidth + ntabs) * Wcm.cm_tabwidth; | |
| 239 tab2x = tabx + Wcm.cm_tabwidth; | |
| 240 | |
| 241 if (tab2x >= Wcm.cm_cols) /* too far (past edge) */ | |
| 242 n2tabs = 0; | |
| 243 | |
| 244 /* | |
| 245 * Now set tabcost to the cost for using ntabs, and c to the cost | |
| 246 * for using n2tabs, then pick the minimum. | |
| 247 */ | |
| 248 | |
| 249 /* cost for ntabs + cost for right motion */ | |
| 250 tabcost = ntabs ? ntabs * Wcm.cc_tab + (dstx - tabx) * Wcm.cc_right | |
| 251 : BIG; | |
| 252 | |
| 253 /* cost for n2tabs + cost for left motion */ | |
| 254 c = n2tabs ? n2tabs * Wcm.cc_tab + (tab2x - dstx) * Wcm.cc_left | |
| 255 : BIG; | |
| 256 | |
| 257 if (c < tabcost) /* then cheaper to overshoot & back up */ | |
| 258 ntabs = n2tabs, tabcost = c, tabx = tab2x; | |
| 259 | |
| 260 if (tabcost >= BIG) /* caint use tabs */ | |
| 261 goto newdelta; | |
| 262 | |
| 263 /* | |
| 264 * See if tabcost is less than just moving right | |
| 265 */ | |
| 266 | |
| 267 if (tabcost < (deltax * Wcm.cc_right)) { | |
| 268 totalcost += tabcost; /* use the tabs */ | |
| 269 if (doit) | |
| 270 while (--ntabs >= 0) | |
| 271 tputs (Wcm.cm_tab, 1, cmputc); | |
| 272 srcx = tabx; | |
| 273 } | |
| 274 | |
| 275 /* | |
| 276 * Now might as well just recompute the delta. | |
| 277 */ | |
| 278 | |
| 279 newdelta: | |
| 280 if ((deltax = dstx - srcx) == 0) | |
| 281 goto done; | |
| 282 olddelta: | |
| 283 if (deltax > 0) | |
| 284 p = Wcm.cm_right, c = Wcm.cc_right; | |
| 285 else | |
| 286 p = Wcm.cm_left, c = Wcm.cc_left, deltax = -deltax; | |
| 287 | |
| 288 dodelta: | |
| 289 if (c == BIG) { /* caint get thar from here */ | |
| 290 fail: | |
| 291 if (doit) | |
| 292 printf ("OOPS"); | |
| 293 return BIG; | |
| 294 } | |
| 295 totalcost += c * deltax; | |
| 296 if (doit) | |
| 297 while (--deltax >= 0) | |
| 298 tputs (p, 1, cmputc); | |
| 299 done: | |
| 300 return totalcost; | |
| 301 } | |
| 302 | |
| 303 #if 0 | |
| 304 losecursor () | |
| 305 { | |
| 306 curY = -1; | |
| 307 } | |
| 308 #endif | |
| 309 | |
| 310 #define USEREL 0 | |
| 311 #define USEHOME 1 | |
| 312 #define USELL 2 | |
| 313 #define USECR 3 | |
| 314 | |
| 21514 | 315 void |
| 484 | 316 cmgoto (row, col) |
| 317 { | |
| 318 int homecost, | |
| 319 crcost, | |
| 320 llcost, | |
| 321 relcost, | |
| 322 directcost; | |
| 323 int use; | |
| 324 char *p, | |
| 325 *dcm; | |
| 326 | |
| 327 /* First the degenerate case */ | |
| 328 if (row == curY && col == curX) /* already there */ | |
| 329 return; | |
| 330 | |
| 331 if (curY >= 0 && curX >= 0) | |
| 332 { | |
| 333 /* We may have quick ways to go to the upper-left, bottom-left, | |
| 334 * start-of-line, or start-of-next-line. Or it might be best to | |
| 335 * start where we are. Examine the options, and pick the cheapest. | |
| 336 */ | |
| 337 | |
| 338 relcost = calccost (curY, curX, row, col, 0); | |
| 339 use = USEREL; | |
| 340 if ((homecost = Wcm.cc_home) < BIG) | |
| 341 homecost += calccost (0, 0, row, col, 0); | |
| 342 if (homecost < relcost) | |
| 343 relcost = homecost, use = USEHOME; | |
| 344 if ((llcost = Wcm.cc_ll) < BIG) | |
| 345 llcost += calccost (Wcm.cm_rows - 1, 0, row, col, 0); | |
| 346 if (llcost < relcost) | |
| 347 relcost = llcost, use = USELL; | |
| 348 if ((crcost = Wcm.cc_cr) < BIG) { | |
| 349 if (Wcm.cm_autolf) | |
| 350 if (curY + 1 >= Wcm.cm_rows) | |
| 351 crcost = BIG; | |
| 352 else | |
| 353 crcost += calccost (curY + 1, 0, row, col, 0); | |
| 354 else | |
| 355 crcost += calccost (curY, 0, row, col, 0); | |
| 356 } | |
| 357 if (crcost < relcost) | |
| 358 relcost = crcost, use = USECR; | |
| 359 directcost = Wcm.cc_abs, dcm = Wcm.cm_abs; | |
| 360 if (row == curY && Wcm.cc_habs < BIG) | |
| 361 directcost = Wcm.cc_habs, dcm = Wcm.cm_habs; | |
| 362 else if (col == curX && Wcm.cc_vabs < BIG) | |
| 363 directcost = Wcm.cc_vabs, dcm = Wcm.cm_vabs; | |
| 364 } | |
| 365 else | |
| 366 { | |
| 367 directcost = 0, relcost = 100000; | |
| 368 dcm = Wcm.cm_abs; | |
| 369 } | |
| 370 | |
| 371 /* | |
| 372 * In the following comparison, the = in <= is because when the costs | |
| 373 * are the same, it looks nicer (I think) to move directly there. | |
| 374 */ | |
| 375 if (directcost <= relcost) | |
| 376 { | |
| 377 /* compute REAL direct cost */ | |
| 378 cost = 0; | |
| 379 p = dcm == Wcm.cm_habs ? tgoto (dcm, row, col) : | |
| 380 tgoto (dcm, col, row); | |
| 381 tputs (p, 1, evalcost); | |
| 382 if (cost <= relcost) | |
| 383 { /* really is cheaper */ | |
| 384 tputs (p, 1, cmputc); | |
| 385 curY = row, curX = col; | |
| 386 return; | |
| 387 } | |
| 388 } | |
| 389 | |
| 390 switch (use) | |
| 391 { | |
| 392 case USEHOME: | |
| 393 tputs (Wcm.cm_home, 1, cmputc); | |
| 394 curY = 0, curX = 0; | |
| 395 break; | |
| 396 | |
| 397 case USELL: | |
| 398 tputs (Wcm.cm_ll, 1, cmputc); | |
| 399 curY = Wcm.cm_rows - 1, curX = 0; | |
| 400 break; | |
| 401 | |
| 402 case USECR: | |
| 403 tputs (Wcm.cm_cr, 1, cmputc); | |
| 404 if (Wcm.cm_autolf) | |
| 405 curY++; | |
| 406 curX = 0; | |
| 407 break; | |
| 408 } | |
| 409 | |
| 410 (void) calccost (curY, curX, row, col, 1); | |
| 411 curY = row, curX = col; | |
| 412 } | |
| 413 | |
| 414 /* Clear out all terminal info. | |
| 415 Used before copying into it the info on the actual terminal. | |
| 416 */ | |
| 417 | |
| 21514 | 418 void |
| 484 | 419 Wcm_clear () |
| 420 { | |
| 421 bzero (&Wcm, sizeof Wcm); | |
| 422 UP = 0; | |
| 423 BC = 0; | |
| 424 } | |
| 425 | |
| 426 /* | |
| 427 * Initialized stuff | |
| 428 * Return 0 if can do CM. | |
| 429 * Return -1 if cannot. | |
| 430 * Return -2 if size not specified. | |
| 431 */ | |
| 432 | |
| 21514 | 433 int |
| 484 | 434 Wcm_init () |
| 435 { | |
| 436 #if 0 | |
| 437 if (Wcm.cm_abs && !Wcm.cm_ds) | |
| 438 return 0; | |
| 439 #endif | |
| 440 if (Wcm.cm_abs) | |
| 441 return 0; | |
| 442 /* Require up and left, and, if no absolute, down and right */ | |
| 443 if (!Wcm.cm_up || !Wcm.cm_left) | |
| 444 return - 1; | |
| 445 if (!Wcm.cm_abs && (!Wcm.cm_down || !Wcm.cm_right)) | |
| 446 return - 1; | |
| 447 /* Check that we know the size of the screen.... */ | |
| 448 if (Wcm.cm_rows <= 0 || Wcm.cm_cols <= 0) | |
| 449 return - 2; | |
| 450 return 0; | |
| 451 } |
