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

Defined functions

back defined in line 152; used 3 times
badmark defined in line 438; used 2 times
eof_bell defined in line 22; used 4 times
eof_check defined in line 34; used 2 times
forw defined in line 55; used 3 times
jump_loc defined in line 362; used 4 times
match defined in line 673; used 1 times
prepaint defined in line 248; used 3 times

Defined variables

marks defined in line 421; used 3 times
public defined in line 294; never used
Last modified: 1986-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2390
Valid CSS Valid XHTML 1.0 Strict