2 * Copyright (C) 1984-2024 Mark Nudelman
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
7 * For more information, see the README file.
12 * Routines dealing with the "position" table.
13 * This is a table which tells the position (in the input file) of the
14 * first char on each currently displayed line.
16 * {{ The position table is scrolled by moving all the entries.
17 * Would be better to have a circular table
18 * and just change a couple of pointers. }}
24 static POSITION
*table
= NULL
; /* The position table */
25 static int table_size
= 0;
27 extern int sc_width
, sc_height
;
31 * Return the starting file position of a line displayed on the screen.
32 * The line may be specified as a line number relative to the top
33 * of the screen, but is usually one of these special cases:
34 * the top (first) line on the screen
35 * the second line on the screen
36 * the bottom line on the screen
37 * the line after the bottom line on the screen
39 public POSITION
position(int sindex
)
44 sindex
= sc_height
- 2;
47 sindex
= sc_height
- 1;
50 sindex
= (sc_height
- 1) / 2;
53 return (table
[sindex
]);
57 * Add a new file position to the bottom of the position table.
59 public void add_forw_pos(POSITION pos
)
64 * Scroll the position table up.
66 for (i
= 1; i
< sc_height
; i
++)
67 table
[i
-1] = table
[i
];
68 table
[sc_height
- 1] = pos
;
72 * Add a new file position to the top of the position table.
74 public void add_back_pos(POSITION pos
)
79 * Scroll the position table down.
81 for (i
= sc_height
- 1; i
> 0; i
--)
82 table
[i
] = table
[i
-1];
87 * Initialize the position table, done whenever we clear the screen.
89 public void pos_clear(void)
93 for (i
= 0; i
< sc_height
; i
++)
94 table
[i
] = NULL_POSITION
;
98 * Allocate or reallocate the position table.
100 public void pos_init(void)
102 struct scrpos scrpos
;
104 if (sc_height
<= table_size
)
107 * If we already have a table, remember the first line in it
108 * before we free it, so we can copy that line to the new table.
112 get_scrpos(&scrpos
, TOP
);
115 scrpos
.pos
= NULL_POSITION
;
116 table
= (POSITION
*) ecalloc((size_t) sc_height
, sizeof(POSITION
)); /*{{type-issue}}*/
117 table_size
= sc_height
;
119 if (scrpos
.pos
!= NULL_POSITION
)
120 table
[scrpos
.ln
-1] = scrpos
.pos
;
124 * See if the byte at a specified position is currently on the screen.
125 * Check the position table to see if the position falls within its range.
126 * Return the position table entry if found, -1 if not.
128 public int onscreen(POSITION pos
)
134 for (i
= 1; i
< sc_height
; i
++)
141 * See if the entire screen is empty.
143 public int empty_screen(void)
145 return (empty_lines(0, sc_height
-1));
148 public int empty_lines(int s
, int e
)
152 for (i
= s
; i
<= e
; i
++)
153 if (table
[i
] != NULL_POSITION
&& table
[i
] != 0)
159 * Get the current screen position.
160 * The screen position consists of both a file position and
161 * a screen line number where the file position is placed on the screen.
162 * Normally the screen line number is 0, but if we are positioned
163 * such that the top few lines are empty, we may have to set
164 * the screen line to a number > 0.
166 public void get_scrpos(struct scrpos
*scrpos
, int where
)
175 i
= 0; dir
= +1; last
= sc_height
-2;
177 case BOTTOM
: case BOTTOM_PLUS_ONE
:
178 i
= sc_height
-2; dir
= -1; last
= 0;
182 if (table
[i
] == NULL_POSITION
) {
183 scrpos
->pos
= NULL_POSITION
;
186 /* Values of dir and last don't matter after this. */
191 * Find the first line on the screen which has something on it,
192 * and return the screen line number and the file position.
196 if (table
[i
] != NULL_POSITION
)
199 scrpos
->pos
= table
[i
];
202 if (i
== last
) break;
205 * The screen is empty.
207 scrpos
->pos
= NULL_POSITION
;
211 * Adjust a screen line number to be a simple positive integer
212 * in the range { 0 .. sc_height-2 }.
213 * (The bottom line, sc_height-1, is reserved for prompts, etc.)
214 * The given "sline" may be in the range { 1 .. sc_height-1 }
215 * to refer to lines relative to the top of the screen (starting from 1),
216 * or it may be in { -1 .. -(sc_height-1) } to refer to lines
217 * relative to the bottom of the screen.
219 public int sindex_from_sline(int sline
)
222 * Negative screen line number means
223 * relative to the bottom of the screen.
228 * Can't be less than 1 or greater than sc_height.
232 if (sline
> sc_height
)
235 * Return zero-based line number, not one-based.
241 * Given a line that starts at linepos,
242 * and the character at byte offset choff into that line,
243 * return the number of characters (not bytes) between the
244 * beginning of the line and the first byte of the choff character.
246 static int pos_shift(POSITION linepos
, size_t choff
)
254 pos
= forw_raw_line_len(linepos
, choff
, &line
, &line_len
);
255 if (pos
== NULL_POSITION
|| line_len
!= choff
)
257 cvt_ops
= get_cvt_ops(0); /* {{ Passing 0 ignores SRCH_NO_REGEX; does it matter? }} */
258 /* {{ It would be nice to be able to call cvt_text with dst=NULL, to avoid need to alloc a useless cline. }} */
259 cline
= (char *) ecalloc(1, line_len
+1);
260 cvt_text(cline
, line
, NULL
, &line_len
, cvt_ops
);
262 return (int) line_len
; /*{{type-issue}}*/
266 * Return the position of the first char of the line containing tpos.
267 * Thus if tpos is the first char of its line, just return tpos.
269 static POSITION
beginning_of_line(POSITION tpos
)
272 while (ch_tell() != ch_zero())
274 int ch
= ch_back_get();
277 (void) ch_forw_get();
285 * When viewing long lines, it may be that the first char in the top screen
286 * line is not the first char in its (file) line (the table is "beheaded").
287 * This function sets that entry to the position of the first char in the line,
288 * and sets hshift so that the first char in the first line is unchanged.
290 public void pos_rehead(void)
293 POSITION tpos
= table
[TOP
];
294 if (tpos
== NULL_POSITION
)
296 linepos
= beginning_of_line(tpos
);
299 table
[TOP
] = linepos
;
300 hshift
= pos_shift(linepos
, (size_t) (tpos
- linepos
));