|
|
1.1 ! root 1: /* ! 2: * Primitives for displaying the file on the screen. ! 3: */ ! 4: ! 5: #include "less.h" ! 6: #include "position.h" ! 7: ! 8: public int hit_eof; /* Keeps track of how many times we hit end of file */ ! 9: ! 10: extern int quiet; ! 11: extern int top_search; ! 12: extern int top_scroll; ! 13: extern int back_scroll; ! 14: extern int sc_width, sc_height; ! 15: extern int sigs; ! 16: extern char *line; ! 17: extern char *first_cmd; ! 18: ! 19: /* ! 20: * Sound the bell to indicate he is trying to move past end of file. ! 21: */ ! 22: static void ! 23: eof_bell() ! 24: { ! 25: if (quiet == NOT_QUIET) ! 26: bell(); ! 27: else ! 28: vbell(); ! 29: } ! 30: ! 31: /* ! 32: * Check to see if the end of file is currently "displayed". ! 33: */ ! 34: static void ! 35: eof_check() ! 36: { ! 37: POSITION pos; ! 38: ! 39: /* ! 40: * If the bottom line is empty, we are at EOF. ! 41: * If the bottom line ends at the file length, ! 42: * we must be just at EOF. ! 43: */ ! 44: pos = position(BOTTOM_PLUS_ONE); ! 45: if (pos == NULL_POSITION || pos == ch_length()) ! 46: hit_eof++; ! 47: } ! 48: ! 49: /* ! 50: * Display n lines, scrolling forward, ! 51: * starting at position pos in the input file. ! 52: * "force" means display the n lines even if we hit end of file. ! 53: * "only_last" means display only the last screenful if n > screen size. ! 54: */ ! 55: static void ! 56: forw(n, pos, force, only_last) ! 57: register int n; ! 58: POSITION pos; ! 59: int force; ! 60: int only_last; ! 61: { ! 62: int eof = 0; ! 63: int nlines = 0; ! 64: int repaint_flag; ! 65: ! 66: /* ! 67: * repaint_flag tells us not to display anything till the end, ! 68: * then just repaint the entire screen. ! 69: */ ! 70: repaint_flag = (only_last && n > sc_height-1); ! 71: ! 72: if (!repaint_flag) ! 73: { ! 74: if (top_scroll && n >= sc_height - 1) ! 75: { ! 76: /* ! 77: * Start a new screen. ! 78: * {{ This is not really desirable if we happen ! 79: * to hit eof in the middle of this screen, ! 80: * but we don't know if that will happen now. }} ! 81: */ ! 82: clear(); ! 83: home(); ! 84: force = 1; ! 85: } else ! 86: { ! 87: lower_left(); ! 88: clear_eol(); ! 89: } ! 90: ! 91: if (pos != position(BOTTOM_PLUS_ONE)) ! 92: { ! 93: /* ! 94: * This is not contiguous with what is ! 95: * currently displayed. Clear the screen image ! 96: * (position table) and start a new screen. ! 97: */ ! 98: pos_clear(); ! 99: add_forw_pos(pos); ! 100: force = 1; ! 101: if (top_scroll) ! 102: { ! 103: clear(); ! 104: home(); ! 105: } else ! 106: { ! 107: puts("...skipping...\n"); ! 108: } ! 109: } ! 110: } ! 111: ! 112: while (--n >= 0) ! 113: { ! 114: /* ! 115: * Read the next line of input. ! 116: */ ! 117: pos = forw_line(pos); ! 118: if (pos == NULL_POSITION) ! 119: { ! 120: /* ! 121: * End of file: stop here unless the top line ! 122: * is still empty, or "force" is true. ! 123: */ ! 124: eof = 1; ! 125: if (!force && position(TOP) != NULL_POSITION) ! 126: break; ! 127: line = NULL; ! 128: } ! 129: /* ! 130: * Add the position of the next line to the position table. ! 131: * Display the current line on the screen. ! 132: */ ! 133: add_forw_pos(pos); ! 134: nlines++; ! 135: if (!repaint_flag) ! 136: put_line(); ! 137: } ! 138: ! 139: if (eof) ! 140: hit_eof++; ! 141: else ! 142: eof_check(); ! 143: if (nlines == 0) ! 144: eof_bell(); ! 145: else if (repaint_flag) ! 146: repaint(); ! 147: } ! 148: ! 149: /* ! 150: * Display n lines, scrolling backward. ! 151: */ ! 152: static void ! 153: back(n, pos, force, only_last) ! 154: register int n; ! 155: POSITION pos; ! 156: int force; ! 157: int only_last; ! 158: { ! 159: int nlines = 0; ! 160: int repaint_flag; ! 161: ! 162: repaint_flag = (n > back_scroll || (only_last && n > sc_height-1)); ! 163: hit_eof = 0; ! 164: while (--n >= 0) ! 165: { ! 166: /* ! 167: * Get the previous line of input. ! 168: */ ! 169: pos = back_line(pos); ! 170: if (pos == NULL_POSITION) ! 171: { ! 172: /* ! 173: * Beginning of file: stop here unless "force" is true. ! 174: */ ! 175: if (!force) ! 176: break; ! 177: line = NULL; ! 178: } ! 179: /* ! 180: * Add the position of the previous line to the position table. ! 181: * Display the line on the screen. ! 182: */ ! 183: add_back_pos(pos); ! 184: nlines++; ! 185: if (!repaint_flag) ! 186: { ! 187: home(); ! 188: add_line(); ! 189: put_line(); ! 190: } ! 191: } ! 192: ! 193: eof_check(); ! 194: if (nlines == 0) ! 195: eof_bell(); ! 196: else if (repaint_flag) ! 197: repaint(); ! 198: } ! 199: ! 200: /* ! 201: * Display n more lines, forward. ! 202: * Start just after the line currently displayed at the bottom of the screen. ! 203: */ ! 204: public void ! 205: forward(n, only_last) ! 206: int n; ! 207: int only_last; ! 208: { ! 209: POSITION pos; ! 210: ! 211: pos = position(BOTTOM_PLUS_ONE); ! 212: if (pos == NULL_POSITION) ! 213: { ! 214: eof_bell(); ! 215: hit_eof++; ! 216: return; ! 217: } ! 218: forw(n, pos, 0, only_last); ! 219: } ! 220: ! 221: /* ! 222: * Display n more lines, backward. ! 223: * Start just before the line currently displayed at the top of the screen. ! 224: */ ! 225: public void ! 226: backward(n, only_last) ! 227: int n; ! 228: int only_last; ! 229: { ! 230: POSITION pos; ! 231: ! 232: pos = position(TOP); ! 233: if (pos == NULL_POSITION) ! 234: { ! 235: /* ! 236: * This will almost never happen, ! 237: * because the top line is almost never empty. ! 238: */ ! 239: eof_bell(); ! 240: return; ! 241: } ! 242: back(n, pos, 0, only_last); ! 243: } ! 244: ! 245: /* ! 246: * Repaint the screen, starting from a specified position. ! 247: */ ! 248: static void ! 249: prepaint(pos) ! 250: POSITION pos; ! 251: { ! 252: hit_eof = 0; ! 253: forw(sc_height-1, pos, 0, 0); ! 254: } ! 255: ! 256: /* ! 257: * Repaint the screen. ! 258: */ ! 259: public void ! 260: repaint() ! 261: { ! 262: /* ! 263: * Start at the line currently at the top of the screen ! 264: * and redisplay the screen. ! 265: */ ! 266: prepaint(position(TOP)); ! 267: } ! 268: ! 269: /* ! 270: * Jump to the end of the file. ! 271: * It is more convenient to paint the screen backward, ! 272: * from the end of the file toward the beginning. ! 273: */ ! 274: public void ! 275: jump_forw() ! 276: { ! 277: POSITION pos; ! 278: ! 279: if (ch_end_seek()) ! 280: { ! 281: error("Cannot seek to end of file"); ! 282: return; ! 283: } ! 284: pos = ch_tell(); ! 285: clear(); ! 286: pos_clear(); ! 287: add_back_pos(pos); ! 288: back(sc_height - 1, pos, 0, 0); ! 289: } ! 290: ! 291: /* ! 292: * Jump to line n in the file. ! 293: */ ! 294: public void ! 295: jump_back(n) ! 296: register int n; ! 297: { ! 298: register int c; ! 299: ! 300: /* ! 301: * This is done the slow way, by starting at the beginning ! 302: * of the file and counting newlines. ! 303: */ ! 304: if (ch_seek((POSITION)0)) ! 305: { ! 306: /* ! 307: * Probably a pipe with beginning of file no longer buffered. ! 308: */ ! 309: error("Cannot get to beginning of file"); ! 310: return; ! 311: } ! 312: ! 313: /* ! 314: * Start counting lines. ! 315: */ ! 316: while (--n > 0) ! 317: { ! 318: while ((c = ch_forw_get()) != '\n') ! 319: if (c == EOF) ! 320: { ! 321: error("File is not that long"); ! 322: /* {{ Maybe tell him how long it is? }} */ ! 323: return; ! 324: } ! 325: } ! 326: ! 327: /* ! 328: * Finally found the place to start. ! 329: * Clear and redisplay the screen from there. ! 330: * ! 331: * {{ We *could* figure out if the new position is ! 332: * close enough to just scroll there without clearing ! 333: * the screen, but it's not worth it. }} ! 334: */ ! 335: prepaint(ch_tell()); ! 336: } ! 337: ! 338: /* ! 339: * Jump to a specified percentage into the file. ! 340: * This is a poor compensation for not being able to ! 341: * quickly jump to a specific line number. ! 342: */ ! 343: public void ! 344: jump_percent(percent) ! 345: int percent; ! 346: { ! 347: POSITION pos, len; ! 348: ! 349: /* ! 350: * Determine the position in the file ! 351: * (the specified percentage of the file's length). ! 352: */ ! 353: if ((len = ch_length()) == NULL_POSITION) ! 354: { ! 355: error("Don't know length of file"); ! 356: return; ! 357: } ! 358: pos = (percent * len) / 100; ! 359: jump_loc(pos); ! 360: } ! 361: ! 362: public void ! 363: jump_loc(pos) ! 364: POSITION pos; ! 365: { ! 366: register int c; ! 367: register int nline; ! 368: POSITION tpos; ! 369: ! 370: /* ! 371: * See if the desired line is BEFORE the currently ! 372: * displayed screen. If so, see if it is close enough ! 373: * to scroll backwards to it. ! 374: */ ! 375: tpos = position(TOP); ! 376: if (pos < tpos) ! 377: { ! 378: for (nline = 1; nline <= back_scroll; nline++) ! 379: { ! 380: tpos = back_line(tpos); ! 381: if (tpos == NULL_POSITION || tpos <= pos) ! 382: { ! 383: back(nline, position(TOP), 1, 0); ! 384: return; ! 385: } ! 386: } ! 387: } else if ((nline = onscreen(pos)) >= 0) ! 388: { ! 389: /* ! 390: * The line is currently displayed. ! 391: * Just scroll there. ! 392: */ ! 393: forw(nline, position(BOTTOM_PLUS_ONE), 1, 0); ! 394: return; ! 395: } ! 396: ! 397: /* ! 398: * Line is not on screen. ! 399: * Back up to the beginning of the current line. ! 400: */ ! 401: if (ch_seek(pos)) ! 402: { ! 403: error("Cannot seek to that position"); ! 404: return; ! 405: } ! 406: while ((c = ch_back_get()) != '\n' && c != EOF) ! 407: ; ! 408: if (c == '\n') ! 409: (void) ch_forw_get(); ! 410: ! 411: /* ! 412: * Clear and paint the screen. ! 413: */ ! 414: prepaint(ch_tell()); ! 415: } ! 416: ! 417: /* ! 418: * The table of marks. ! 419: * A mark is simply a position in the file. ! 420: */ ! 421: static POSITION marks[26]; ! 422: ! 423: /* ! 424: * Initialize the mark table to show no marks are set. ! 425: */ ! 426: public void ! 427: init_mark() ! 428: { ! 429: int i; ! 430: ! 431: for (i = 0; i < 26; i++) ! 432: marks[i] = NULL_POSITION; ! 433: } ! 434: ! 435: /* ! 436: * See if a mark letter is valid (between a and z). ! 437: */ ! 438: static int ! 439: badmark(c) ! 440: int c; ! 441: { ! 442: if (c < 'a' || c > 'z') ! 443: { ! 444: error("Choose a letter between 'a' and 'z'"); ! 445: return (1); ! 446: } ! 447: return (0); ! 448: } ! 449: ! 450: /* ! 451: * Set a mark. ! 452: */ ! 453: public void ! 454: setmark(c) ! 455: int c; ! 456: { ! 457: if (badmark(c)) ! 458: return; ! 459: marks[c-'a'] = position(TOP); ! 460: } ! 461: ! 462: /* ! 463: * Go to a previously set mark. ! 464: */ ! 465: public void ! 466: gomark(c) ! 467: int c; ! 468: { ! 469: POSITION pos; ! 470: ! 471: if (badmark(c)) ! 472: return; ! 473: if ((pos = marks[c-'a']) == NULL_POSITION) ! 474: error("mark not set"); ! 475: else ! 476: jump_loc(pos); ! 477: } ! 478: ! 479: /* ! 480: * Search for the n-th occurence of a specified pattern, ! 481: * either forward (direction == '/'), or backwards (direction == '?'). ! 482: */ ! 483: public void ! 484: search(direction, pattern, n) ! 485: int direction; ! 486: char *pattern; ! 487: register int n; ! 488: { ! 489: register int search_forward = (direction == '/'); ! 490: POSITION pos, linepos; ! 491: ! 492: #if RECOMP ! 493: char *re_comp(); ! 494: char *errmsg; ! 495: ! 496: /* ! 497: * (re_comp handles a null pattern internally, ! 498: * so there is no need to check for a null pattern here.) ! 499: */ ! 500: if ((errmsg = re_comp(pattern)) != NULL) ! 501: { ! 502: error(errmsg); ! 503: return; ! 504: } ! 505: #else ! 506: #if REGCMP ! 507: char *regcmp(); ! 508: static char *cpattern = NULL; ! 509: ! 510: if (pattern == NULL || *pattern == '\0') ! 511: { ! 512: /* ! 513: * A null pattern means use the previous pattern. ! 514: * The compiled previous pattern is in cpattern, so just use it. ! 515: */ ! 516: if (cpattern == NULL) ! 517: { ! 518: error("No previous regular expression"); ! 519: return; ! 520: } ! 521: } else ! 522: { ! 523: /* ! 524: * Otherwise compile the given pattern. ! 525: */ ! 526: char *s; ! 527: if ((s = regcmp(pattern, 0)) == NULL) ! 528: { ! 529: error("Invalid pattern"); ! 530: return; ! 531: } ! 532: if (cpattern != NULL) ! 533: free(cpattern); ! 534: cpattern = s; ! 535: } ! 536: #else ! 537: static char lpbuf[100]; ! 538: static char *last_pattern = NULL; ! 539: ! 540: if (pattern == NULL || *pattern == '\0') ! 541: { ! 542: /* ! 543: * Null pattern means use the previous pattern. ! 544: */ ! 545: if (last_pattern == NULL) ! 546: { ! 547: error("No previous regular expression"); ! 548: return; ! 549: } ! 550: pattern = last_pattern; ! 551: } else ! 552: { ! 553: strcpy(lpbuf, pattern); ! 554: last_pattern = lpbuf; ! 555: } ! 556: #endif ! 557: #endif ! 558: ! 559: /* ! 560: * Figure out where to start the search. ! 561: */ ! 562: ! 563: if (position(TOP) == NULL_POSITION) ! 564: { ! 565: /* ! 566: * Nothing is currently displayed. ! 567: * Start at the beginning of the file. ! 568: * (This case is mainly for first_cmd searches, ! 569: * for example, "+/xyz" on the command line.) ! 570: */ ! 571: pos = (POSITION)0; ! 572: } else if (!search_forward) ! 573: { ! 574: /* ! 575: * Backward search: start just before the top line ! 576: * displayed on the screen. ! 577: */ ! 578: pos = position(TOP); ! 579: } else if (top_search) ! 580: { ! 581: /* ! 582: * Forward search and "start from top". ! 583: * Start at the second line displayed on the screen. ! 584: */ ! 585: pos = position(TOP_PLUS_ONE); ! 586: } else ! 587: { ! 588: /* ! 589: * Forward search but don't "start from top". ! 590: * Start just after the bottom line displayed on the screen. ! 591: */ ! 592: pos = position(BOTTOM_PLUS_ONE); ! 593: } ! 594: ! 595: if (pos == NULL_POSITION) ! 596: { ! 597: /* ! 598: * Can't find anyplace to start searching from. ! 599: */ ! 600: error("Nothing to search"); ! 601: return; ! 602: } ! 603: ! 604: for (;;) ! 605: { ! 606: /* ! 607: * Get lines until we find a matching one or ! 608: * until we hit end-of-file (or beginning-of-file ! 609: * if we're going backwards). ! 610: */ ! 611: if (sigs) ! 612: /* ! 613: * A signal aborts the search. ! 614: */ ! 615: return; ! 616: ! 617: if (search_forward) ! 618: { ! 619: /* ! 620: * Read the next line, and save the ! 621: * starting position of that line in linepos. ! 622: */ ! 623: linepos = pos; ! 624: pos = forw_raw_line(pos); ! 625: } else ! 626: { ! 627: /* ! 628: * Read the previous line and save the ! 629: * starting position of that line in linepos. ! 630: */ ! 631: pos = back_raw_line(pos); ! 632: linepos = pos; ! 633: } ! 634: ! 635: if (pos == NULL_POSITION) ! 636: { ! 637: /* ! 638: * We hit EOF/BOF without a match. ! 639: */ ! 640: error("Pattern not found"); ! 641: return; ! 642: } ! 643: ! 644: /* ! 645: * Test the next line to see if we have a match. ! 646: * This is done in a variety of ways, depending ! 647: * on what pattern matching functions are available. ! 648: */ ! 649: #if REGCMP ! 650: if ( (regex(cpattern, line) != NULL) ! 651: #else ! 652: #if RECOMP ! 653: if ( (re_exec(line) == 1) ! 654: #else ! 655: if ( (match(pattern, line)) ! 656: #endif ! 657: #endif ! 658: && (--n <= 0) ) ! 659: /* ! 660: * Found the matching line. ! 661: */ ! 662: break; ! 663: } ! 664: jump_loc(linepos); ! 665: } ! 666: ! 667: #if (!REGCMP) && (!RECOMP) ! 668: /* ! 669: * We have neither regcmp() nor re_comp(). ! 670: * We use this function to do simple pattern matching. ! 671: * It supports no metacharacters like *, etc. ! 672: */ ! 673: static int ! 674: match(pattern, buf) ! 675: char *pattern, *buf; ! 676: { ! 677: register char *pp, *lp; ! 678: ! 679: for ( ; *buf != '\0'; buf++) ! 680: { ! 681: for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) ! 682: if (*pp == '\0' || *lp == '\0') ! 683: break; ! 684: if (*pp == '\0') ! 685: return (1); ! 686: } ! 687: return (0); ! 688: } ! 689: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.