# 2.11BSD#431 - /usr/src/local/less/prim.c

##### Functions

    backward          X
    forward           X
    get_back_scroll   X
    gomark            X
    init_mark         X
    jump_back         X
    jump_forw         X
    jump_loc          X
    jump_percent      X
    lastmark          X
    repaint           X
    search            X
    setmark           X

##### Variables

    hit_eof           X
    public            X

##### Macros

    LASTMARK          X
    NMARKS            X

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

#### Defined functions

back defined in line 156; used 3 times

- in line 246, 293, 408

backward defined in line 229; used 4 times

- in /usr/src/local/less/command.c line 363, 390, 414
- in /usr/src/local/less/funcs.h line 9

badmark defined in line 458; used 2 times

- in line 477, 499

eof_bell defined in line 22; used 4 times

- in line 147, 199, 218, 243

eof_check defined in line 34; used 2 times

- in line 145, 197

forw defined in line 55; used 3 times

- in line 222, 257, 418

forward defined in line 208; used 4 times

- in /usr/src/local/less/command.c line 352, 377, 402
- in /usr/src/local/less/funcs.h line 8

get_back_scroll defined in line 516; used 4 times

- in line 166, 400
- in /usr/src/local/less/funcs.h line 19
- in /usr/src/local/less/option.c line 229

gomark defined in line 491; used 2 times

- in /usr/src/local/less/command.c line 635
- in /usr/src/local/less/funcs.h line 18

init_mark defined in line 446; used 2 times

- in /usr/src/local/less/funcs.h line 15
- in /usr/src/local/less/main.c line 175

jump_back defined in line 299; used 4 times

- in /usr/src/local/less/command.c line 160, 442, 468
- in /usr/src/local/less/funcs.h line 12

jump_forw defined in line 278; used 2 times

- in /usr/src/local/less/command.c line 466
- in /usr/src/local/less/funcs.h line 11

jump_loc defined in line 382; used 6 times

- in line 318, 339, 376, 507, 710
- in /usr/src/local/less/funcs.h line 14

jump_percent defined in line 347; used 2 times

- in /usr/src/local/less/command.c line 456
- in /usr/src/local/less/funcs.h line 13

lastmark defined in line 482; used 3 times

- in line 288, 431
- in /usr/src/local/less/funcs.h line 17

match defined in line 719; used 1 times

- in line 700

prepaint defined in line 252; used 2 times

- in line 270, 432

repaint defined in line 263; used 7 times

- in line 149, 201
- in /usr/src/local/less/command.c line 162, 431
- in /usr/src/local/less/funcs.h line 10
- in /usr/src/local/less/option.c line 236
- in /usr/src/local/less/output.c line 221

search defined in line 528; used 3 times

- in /usr/src/local/less/command.c line 278, 516
- in /usr/src/local/less/funcs.h line 20

setmark defined in line 473; used 2 times

- in /usr/src/local/less/command.c line 622
- in /usr/src/local/less/funcs.h line 16

#### Defined variables

hit_eof defined in line 8; used 9 times

- in line 46, 143, 167, 219, 256
- in /usr/src/local/less/command.c line 241
- in /usr/src/local/less/prompt.c line 168-172(2), 191

marks defined in line 441; used 5 times

- in line 452, 479, 485, 498-502(2)

public defined in line 528; never used

#### Defined macros

LASTMARK defined in line 440; used 2 times

- in line 485, 498

NMARKS defined in line 439; used 3 times

- in line 440-441(2), 451

Last modified: 1990-07-10 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1241 |