10Sduke/* 216032Sasmotrak * Copyright (C) 1984-2023 Mark Nudelman 30Sduke * 40Sduke * You may distribute under the terms of either the GNU General Public 50Sduke * License or the Less License, as specified in the README file. 60Sduke * 70Sduke * For more information, see the README file. 80Sduke */ 90Sduke 100Sduke 110Sduke/* 120Sduke * Routines dealing with the "position" table. 130Sduke * This is a table which tells the position (in the input file) of the 140Sduke * first char on each currently displayed line. 150Sduke * 160Sduke * {{ The position table is scrolled by moving all the entries. 170Sduke * Would be better to have a circular table 180Sduke * and just change a couple of pointers. }} 192362Sohair */ 202362Sohair 212362Sohair#include "less.h" 220Sduke#include "position.h" 230Sduke 240Sdukestatic POSITION *table = NULL; /* The position table */ 250Sdukestatic int table_size = 0; 260Sduke 270Sdukeextern int sc_width, sc_height; 280Sdukeextern int header_lines; 290Sduke 300Sduke/* 310Sduke * Return the starting file position of a line displayed on the screen. 320Sduke * The line may be specified as a line number relative to the top 330Sduke * of the screen, but is usually one of these special cases: 340Sduke * the top (first) line on the screen 350Sduke * the second line on the screen 360Sduke * the bottom line on the screen 370Sduke * the line after the bottom line on the screen 380Sduke */ 390Sdukepublic POSITION position(int sindex) 400Sduke{ 410Sduke switch (sindex) 420Sduke { 430Sduke case BOTTOM: 440Sduke sindex = sc_height - 2; 4511503Sweijun break; 4611503Sweijun case BOTTOM_PLUS_ONE: 470Sduke sindex = sc_height - 1; 480Sduke break; 490Sduke case MIDDLE: 500Sduke sindex = (sc_height - 1) / 2; 510Sduke break; 520Sduke } 530Sduke return (table[sindex]); 540Sduke} 550Sduke 560Sduke/* 570Sduke * Add a new file position to the bottom of the position table. 580Sduke */ 5911658Sweijunpublic void add_forw_pos(POSITION pos) 6011658Sweijun{ 610Sduke int i; 620Sduke 630Sduke /* 64903Sweijun * Scroll the position table up. 65903Sweijun */ 66903Sweijun for (i = 1; i < sc_height; i++) 67903Sweijun table[i-1] = table[i]; 68903Sweijun table[sc_height - 1] = pos; 690Sduke} 700Sduke 710Sduke/* 720Sduke * Add a new file position to the top of the position table. 730Sduke */ 740Sdukepublic void add_back_pos(POSITION pos) 750Sduke{ 760Sduke int i; 770Sduke 780Sduke /* 790Sduke * Scroll the position table down. 800Sduke */ 810Sduke for (i = sc_height - 1; i > 0; i--) 820Sduke table[i] = table[i-1]; 830Sduke table[0] = pos; 8411503Sweijun} 8515059Sweijun 8611503Sweijun/* 8715059Sweijun * Initialize the position table, done whenever we clear the screen. 880Sduke */ 8911503Sweijunpublic void pos_clear(void) 9011503Sweijun{ 9111503Sweijun int i; 9211503Sweijun 930Sduke for (i = 0; i < sc_height; i++) 9411503Sweijun table[i] = NULL_POSITION; 9515059Sweijun} 9611503Sweijun 970Sduke/* 9811503Sweijun * Allocate or reallocate the position table. 9911503Sweijun */ 10015059Sweijunpublic void pos_init(void) 10111503Sweijun{ 1020Sduke struct scrpos scrpos; 10311503Sweijun 10411503Sweijun if (sc_height <= table_size) 1050Sduke return; 1060Sduke /* 1070Sduke * If we already have a table, remember the first line in it 1080Sduke * before we free it, so we can copy that line to the new table. 1090Sduke */ 1100Sduke if (table != NULL) 1110Sduke { 1120Sduke get_scrpos(&scrpos, TOP); 1130Sduke free((char*)table); 1140Sduke } else 1150Sduke scrpos.pos = NULL_POSITION; 1160Sduke table = (POSITION *) ecalloc(sc_height, sizeof(POSITION)); 1170Sduke table_size = sc_height; 1180Sduke pos_clear(); 1190Sduke if (scrpos.pos != NULL_POSITION) 1200Sduke table[scrpos.ln-1] = scrpos.pos; 1210Sduke} 1220Sduke 1230Sduke/* 1240Sduke * See if the byte at a specified position is currently on the screen. 1250Sduke * Check the position table to see if the position falls within its range. 1260Sduke * Return the position table entry if found, -1 if not. 1270Sduke */ 1280Sdukepublic int onscreen(POSITION pos) 1290Sduke{ 1300Sduke int i; 1310Sduke 1320Sduke if (pos < table[0]) 1330Sduke return (-1); 1340Sduke for (i = 1; i < sc_height; i++) 1350Sduke if (pos < table[i]) 1360Sduke return (i-1); 1370Sduke return (-1); 138903Sweijun} 1390Sduke 1400Sduke/* 1410Sduke * See if the entire screen is empty. 1420Sduke */ 1430Sdukepublic int empty_screen(void) 1440Sduke{ 1450Sduke return (empty_lines(0, sc_height-1)); 1460Sduke} 1470Sduke 1480Sdukepublic int empty_lines(int s, int e) 1490Sduke{ 1500Sduke int i; 1510Sduke 1520Sduke for (i = s; i <= e; i++) 1530Sduke if (table[i] != NULL_POSITION && table[i] != 0) 1540Sduke return (0); 1550Sduke return (1); 1560Sduke} 1570Sduke 1580Sduke/* 1590Sduke * Get the current screen position. 1600Sduke * The screen position consists of both a file position and 1610Sduke * a screen line number where the file position is placed on the screen. 1620Sduke * Normally the screen line number is 0, but if we are positioned 1630Sduke * such that the top few lines are empty, we may have to set 1640Sduke * the screen line to a number > 0. 1650Sduke */ 1665976Ssflorespublic void get_scrpos(struct scrpos *scrpos, int where) 1675976Ssflores{ 1680Sduke int i; 1690Sduke int dir; 1705976Ssflores int last; 1710Sduke 1725976Ssflores switch (where) 1730Sduke { 1740Sduke case TOP: 1750Sduke i = 0; dir = +1; last = sc_height-2; 1760Sduke break; 1770Sduke case BOTTOM: case BOTTOM_PLUS_ONE: 1780Sduke i = sc_height-2; dir = -1; last = 0; 1790Sduke break; 1800Sduke default: 1810Sduke i = where; 1820Sduke if (table[i] == NULL_POSITION) { 1830Sduke scrpos->pos = NULL_POSITION; 1840Sduke return; 1850Sduke } 1860Sduke /* Values of dir and last don't matter after this. */ 1870Sduke break; 18810925Sweijun } 18910925Sweijun 19010925Sweijun /* 19110925Sweijun * Find the first line on the screen which has something on it, 19210925Sweijun * and return the screen line number and the file position. 19310925Sweijun */ 19410925Sweijun for (;; i += dir) 1950Sduke { 1960Sduke if (table[i] != NULL_POSITION) 1970Sduke { 1980Sduke scrpos->ln = i+1; 1990Sduke scrpos->pos = table[i]; 2000Sduke return; 2010Sduke } 2020Sduke if (i == last) break; 2030Sduke } 2040Sduke /* 2050Sduke * The screen is empty. 2060Sduke */ 2070Sduke scrpos->pos = NULL_POSITION; 2080Sduke} 2090Sduke 2100Sduke/* 2110Sduke * Adjust a screen line number to be a simple positive integer 2120Sduke * in the range { 0 .. sc_height-2 }. 2130Sduke * (The bottom line, sc_height-1, is reserved for prompts, etc.) 2140Sduke * The given "sline" may be in the range { 1 .. sc_height-1 } 2150Sduke * to refer to lines relative to the top of the screen (starting from 1), 2160Sduke * or it may be in { -1 .. -(sc_height-1) } to refer to lines 2170Sduke * relative to the bottom of the screen. 2180Sduke */ 2190Sdukepublic int sindex_from_sline(int sline) 2200Sduke{ 2210Sduke /* 2220Sduke * Negative screen line number means 2230Sduke * relative to the bottom of the screen. 2240Sduke */ 2250Sduke if (sline < 0) 2260Sduke sline += sc_height; 2270Sduke /* 2280Sduke * Can't be less than 1 or greater than sc_height. 2290Sduke */ 2300Sduke if (sline <= 0) 2310Sduke sline = 1; 2320Sduke if (sline > sc_height) 2330Sduke sline = sc_height; 2340Sduke /* 2350Sduke * Return zero-based line number, not one-based. 2360Sduke */ 2370Sduke return (sline-1); 2380Sduke} 2390Sduke