GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
* Copyright (C) 1984-2012 Mark Nudelman |
||
3 |
* Modified for use with illumos by Garrett D'Amore. |
||
4 |
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
||
5 |
* |
||
6 |
* You may distribute under the terms of either the GNU General Public |
||
7 |
* License or the Less License, as specified in the README file. |
||
8 |
* |
||
9 |
* For more information, see the README file. |
||
10 |
*/ |
||
11 |
|||
12 |
/* |
||
13 |
* Routines to manipulate the "line buffer". |
||
14 |
* The line buffer holds a line of output as it is being built |
||
15 |
* in preparation for output to the screen. |
||
16 |
*/ |
||
17 |
|||
18 |
#include "charset.h" |
||
19 |
#include "less.h" |
||
20 |
|||
21 |
static char *linebuf = NULL; /* Buffer which holds the current output line */ |
||
22 |
static char *attr = NULL; /* Extension of linebuf to hold attributes */ |
||
23 |
int size_linebuf = 0; /* Size of line buffer (and attr buffer) */ |
||
24 |
|||
25 |
static int cshift; /* Current left-shift of output line buffer */ |
||
26 |
int hshift; /* Desired left-shift of output line buffer */ |
||
27 |
int tabstops[TABSTOP_MAX] = { 0 }; /* Custom tabstops */ |
||
28 |
int ntabstops = 1; /* Number of tabstops */ |
||
29 |
int tabdefault = 8; /* Default repeated tabstops */ |
||
30 |
off_t highest_hilite; /* Pos of last hilite in file found so far */ |
||
31 |
|||
32 |
static int curr; /* Index into linebuf */ |
||
33 |
static int column; /* Printable length, accounting for backspaces, etc. */ |
||
34 |
static int overstrike; /* Next char should overstrike previous char */ |
||
35 |
static int is_null_line; /* There is no current line */ |
||
36 |
static int lmargin; /* Left margin */ |
||
37 |
static char pendc; |
||
38 |
static off_t pendpos; |
||
39 |
static char *end_ansi_chars; |
||
40 |
static char *mid_ansi_chars; |
||
41 |
|||
42 |
static int attr_swidth(int); |
||
43 |
static int attr_ewidth(int); |
||
44 |
static int do_append(LWCHAR, char *, off_t); |
||
45 |
|||
46 |
extern volatile sig_atomic_t sigs; |
||
47 |
extern int bs_mode; |
||
48 |
extern int linenums; |
||
49 |
extern int ctldisp; |
||
50 |
extern int twiddle; |
||
51 |
extern int binattr; |
||
52 |
extern int status_col; |
||
53 |
extern int auto_wrap, ignaw; |
||
54 |
extern int bo_s_width, bo_e_width; |
||
55 |
extern int ul_s_width, ul_e_width; |
||
56 |
extern int bl_s_width, bl_e_width; |
||
57 |
extern int so_s_width, so_e_width; |
||
58 |
extern int sc_width, sc_height; |
||
59 |
extern int utf_mode; |
||
60 |
extern off_t start_attnpos; |
||
61 |
extern off_t end_attnpos; |
||
62 |
|||
63 |
static char mbc_buf[MAX_UTF_CHAR_LEN]; |
||
64 |
static int mbc_buf_len = 0; |
||
65 |
static int mbc_buf_index = 0; |
||
66 |
static off_t mbc_pos; |
||
67 |
|||
68 |
/* |
||
69 |
* Initialize from environment variables. |
||
70 |
*/ |
||
71 |
void |
||
72 |
init_line(void) |
||
73 |
{ |
||
74 |
78 |
end_ansi_chars = lgetenv("LESSANSIENDCHARS"); |
|
75 |
✗✓✗✗ |
39 |
if (end_ansi_chars == NULL || *end_ansi_chars == '\0') |
76 |
39 |
end_ansi_chars = "m"; |
|
77 |
|||
78 |
39 |
mid_ansi_chars = lgetenv("LESSANSIMIDCHARS"); |
|
79 |
✗✓✗✗ |
39 |
if (mid_ansi_chars == NULL || *mid_ansi_chars == '\0') |
80 |
39 |
mid_ansi_chars = "0123456789;[?!\"'#%()*+ "; |
|
81 |
|||
82 |
39 |
linebuf = ecalloc(LINEBUF_SIZE, sizeof (char)); |
|
83 |
39 |
attr = ecalloc(LINEBUF_SIZE, sizeof (char)); |
|
84 |
39 |
size_linebuf = LINEBUF_SIZE; |
|
85 |
39 |
} |
|
86 |
|||
87 |
/* |
||
88 |
* Expand the line buffer. |
||
89 |
*/ |
||
90 |
static int |
||
91 |
expand_linebuf(void) |
||
92 |
{ |
||
93 |
/* Double the size of the line buffer. */ |
||
94 |
6 |
int new_size = size_linebuf * 2; |
|
95 |
|||
96 |
/* Just realloc to expand the buffer, if we can. */ |
||
97 |
3 |
char *new_buf = recallocarray(linebuf, size_linebuf, new_size, 1); |
|
98 |
3 |
char *new_attr = recallocarray(attr, size_linebuf, new_size, 1); |
|
99 |
✗✓ | 3 |
if (new_buf == NULL || new_attr == NULL) { |
100 |
free(new_attr); |
||
101 |
free(new_buf); |
||
102 |
return (1); |
||
103 |
} |
||
104 |
3 |
linebuf = new_buf; |
|
105 |
3 |
attr = new_attr; |
|
106 |
3 |
size_linebuf = new_size; |
|
107 |
3 |
return (0); |
|
108 |
3 |
} |
|
109 |
|||
110 |
/* |
||
111 |
* Is a character ASCII? |
||
112 |
*/ |
||
113 |
int |
||
114 |
is_ascii_char(LWCHAR ch) |
||
115 |
{ |
||
116 |
return (ch <= 0x7F); |
||
117 |
} |
||
118 |
|||
119 |
/* |
||
120 |
* Rewind the line buffer. |
||
121 |
*/ |
||
122 |
void |
||
123 |
prewind(void) |
||
124 |
{ |
||
125 |
55564 |
curr = 0; |
|
126 |
27782 |
column = 0; |
|
127 |
27782 |
cshift = 0; |
|
128 |
27782 |
overstrike = 0; |
|
129 |
27782 |
mbc_buf_len = 0; |
|
130 |
27782 |
is_null_line = 0; |
|
131 |
27782 |
pendc = '\0'; |
|
132 |
27782 |
lmargin = 0; |
|
133 |
✗✓ | 27782 |
if (status_col) |
134 |
lmargin += 1; |
||
135 |
27782 |
} |
|
136 |
|||
137 |
/* |
||
138 |
* Insert the line number (of the given position) into the line buffer. |
||
139 |
*/ |
||
140 |
void |
||
141 |
plinenum(off_t pos) |
||
142 |
{ |
||
143 |
off_t linenum = 0; |
||
144 |
int i; |
||
145 |
|||
146 |
✗✓ | 55564 |
if (linenums == OPT_ONPLUS) { |
147 |
/* |
||
148 |
* Get the line number and put it in the current line. |
||
149 |
* {{ Note: since find_linenum calls forw_raw_line, |
||
150 |
* it may seek in the input file, requiring the caller |
||
151 |
* of plinenum to re-seek if necessary. }} |
||
152 |
* {{ Since forw_raw_line modifies linebuf, we must |
||
153 |
* do this first, before storing anything in linebuf. }} |
||
154 |
*/ |
||
155 |
linenum = find_linenum(pos); |
||
156 |
} |
||
157 |
|||
158 |
/* |
||
159 |
* Display a status column if the -J option is set. |
||
160 |
*/ |
||
161 |
✗✓ | 27782 |
if (status_col) { |
162 |
linebuf[curr] = ' '; |
||
163 |
if (start_attnpos != -1 && |
||
164 |
pos >= start_attnpos && pos < end_attnpos) |
||
165 |
attr[curr] = AT_NORMAL|AT_HILITE; |
||
166 |
else |
||
167 |
attr[curr] = AT_NORMAL; |
||
168 |
curr++; |
||
169 |
column++; |
||
170 |
} |
||
171 |
/* |
||
172 |
* Display the line number at the start of each line |
||
173 |
* if the -N option is set. |
||
174 |
*/ |
||
175 |
✗✓ | 27782 |
if (linenums == OPT_ONPLUS) { |
176 |
char buf[23]; |
||
177 |
int n; |
||
178 |
|||
179 |
postoa(linenum, buf, sizeof(buf)); |
||
180 |
n = strlen(buf); |
||
181 |
if (n < MIN_LINENUM_WIDTH) |
||
182 |
n = MIN_LINENUM_WIDTH; |
||
183 |
snprintf(linebuf+curr, size_linebuf-curr, "%*s ", n, buf); |
||
184 |
n++; /* One space after the line number. */ |
||
185 |
for (i = 0; i < n; i++) |
||
186 |
attr[curr+i] = AT_NORMAL; |
||
187 |
curr += n; |
||
188 |
column += n; |
||
189 |
lmargin += n; |
||
190 |
} |
||
191 |
|||
192 |
/* |
||
193 |
* Append enough spaces to bring us to the lmargin. |
||
194 |
*/ |
||
195 |
✗✓ | 27782 |
while (column < lmargin) { |
196 |
linebuf[curr] = ' '; |
||
197 |
attr[curr++] = AT_NORMAL; |
||
198 |
column++; |
||
199 |
} |
||
200 |
27782 |
} |
|
201 |
|||
202 |
/* |
||
203 |
* Shift the input line left. |
||
204 |
* This means discarding N printable chars at the start of the buffer. |
||
205 |
*/ |
||
206 |
static void |
||
207 |
pshift(int shift) |
||
208 |
{ |
||
209 |
LWCHAR prev_ch = 0; |
||
210 |
unsigned char c; |
||
211 |
int shifted = 0; |
||
212 |
int to; |
||
213 |
int from; |
||
214 |
int len; |
||
215 |
int width; |
||
216 |
int prev_attr; |
||
217 |
int next_attr; |
||
218 |
|||
219 |
✗✓ | 74634 |
if (shift > column - lmargin) |
220 |
shift = column - lmargin; |
||
221 |
✗✓ | 37317 |
if (shift > curr - lmargin) |
222 |
shift = curr - lmargin; |
||
223 |
|||
224 |
37317 |
to = from = lmargin; |
|
225 |
/* |
||
226 |
* We keep on going when shifted == shift |
||
227 |
* to get all combining chars. |
||
228 |
*/ |
||
229 |
✓✗✓✓ |
7219311 |
while (shifted <= shift && from < curr) { |
230 |
2369120 |
c = linebuf[from]; |
|
231 |
✗✓✗✗ ✗✗ |
2369120 |
if (ctldisp == OPT_ONPLUS && IS_CSI_START(c)) { |
232 |
/* Keep cumulative effect. */ |
||
233 |
linebuf[to] = c; |
||
234 |
attr[to++] = attr[from++]; |
||
235 |
while (from < curr && linebuf[from]) { |
||
236 |
linebuf[to] = linebuf[from]; |
||
237 |
attr[to++] = attr[from]; |
||
238 |
if (!is_ansi_middle(linebuf[from++])) |
||
239 |
break; |
||
240 |
} |
||
241 |
continue; |
||
242 |
} |
||
243 |
|||
244 |
width = 0; |
||
245 |
|||
246 |
✗✓ | 2369120 |
if (!IS_ASCII_OCTET(c) && utf_mode) { |
247 |
/* Assumes well-formedness validation already done. */ |
||
248 |
LWCHAR ch; |
||
249 |
|||
250 |
len = utf_len(c); |
||
251 |
if (from + len > curr) |
||
252 |
break; |
||
253 |
ch = get_wchar(linebuf + from); |
||
254 |
if (!is_composing_char(ch) && |
||
255 |
!is_combining_char(prev_ch, ch)) |
||
256 |
width = is_wide_char(ch) ? 2 : 1; |
||
257 |
prev_ch = ch; |
||
258 |
} else { |
||
259 |
len = 1; |
||
260 |
✗✓ | 2369120 |
if (c == '\b') |
261 |
/* XXX - Incorrect if several '\b' in a row. */ |
||
262 |
width = (utf_mode && is_wide_char(prev_ch)) ? |
||
263 |
-2 : -1; |
||
264 |
✓✗ | 2369120 |
else if (!control_char(c)) |
265 |
2369120 |
width = 1; |
|
266 |
prev_ch = 0; |
||
267 |
} |
||
268 |
|||
269 |
✗✓✗✗ |
2369120 |
if (width == 2 && shift - shifted == 1) { |
270 |
/* Should never happen when called by pshift_all(). */ |
||
271 |
attr[to] = attr[from]; |
||
272 |
/* |
||
273 |
* Assume a wide_char will never be the first half of a |
||
274 |
* combining_char pair, so reset prev_ch in case we're |
||
275 |
* followed by a '\b'. |
||
276 |
*/ |
||
277 |
prev_ch = linebuf[to++] = ' '; |
||
278 |
from += len; |
||
279 |
shifted++; |
||
280 |
continue; |
||
281 |
} |
||
282 |
|||
283 |
/* Adjust width for magic cookies. */ |
||
284 |
✗✓ | 4738240 |
prev_attr = (to > 0) ? attr[to-1] : AT_NORMAL; |
285 |
✓✓ | 7107360 |
next_attr = (from + len < curr) ? attr[from + len] : prev_attr; |
286 |
✗✓✗✗ |
2369120 |
if (!is_at_equiv(attr[from], prev_attr) && |
287 |
!is_at_equiv(attr[from], next_attr)) { |
||
288 |
width += attr_swidth(attr[from]); |
||
289 |
if (from + len < curr) |
||
290 |
width += attr_ewidth(attr[from]); |
||
291 |
if (is_at_equiv(prev_attr, next_attr)) { |
||
292 |
width += attr_ewidth(prev_attr); |
||
293 |
if (from + len < curr) |
||
294 |
width += attr_swidth(next_attr); |
||
295 |
} |
||
296 |
} |
||
297 |
|||
298 |
✓✗ | 2369120 |
if (shift - shifted < width) |
299 |
break; |
||
300 |
from += len; |
||
301 |
2369120 |
shifted += width; |
|
302 |
2369120 |
if (shifted < 0) |
|
303 |
shifted = 0; |
||
304 |
} |
||
305 |
✗✓ | 37317 |
while (from < curr) { |
306 |
linebuf[to] = linebuf[from]; |
||
307 |
attr[to++] = attr[from++]; |
||
308 |
} |
||
309 |
37317 |
curr = to; |
|
310 |
37317 |
column -= shifted; |
|
311 |
37317 |
cshift += shifted; |
|
312 |
37317 |
} |
|
313 |
|||
314 |
/* |
||
315 |
* |
||
316 |
*/ |
||
317 |
void |
||
318 |
pshift_all(void) |
||
319 |
{ |
||
320 |
74634 |
pshift(column); |
|
321 |
37317 |
} |
|
322 |
|||
323 |
/* |
||
324 |
* Return the printing width of the start (enter) sequence |
||
325 |
* for a given character attribute. |
||
326 |
*/ |
||
327 |
static int |
||
328 |
attr_swidth(int a) |
||
329 |
{ |
||
330 |
int w = 0; |
||
331 |
|||
332 |
4744 |
a = apply_at_specials(a); |
|
333 |
|||
334 |
✓✓ | 2372 |
if (a & AT_UNDERLINE) |
335 |
201 |
w += ul_s_width; |
|
336 |
✓✓ | 2372 |
if (a & AT_BOLD) |
337 |
376 |
w += bo_s_width; |
|
338 |
✗✓ | 2372 |
if (a & AT_BLINK) |
339 |
w += bl_s_width; |
||
340 |
✓✓ | 2372 |
if (a & AT_STANDOUT) |
341 |
1795 |
w += so_s_width; |
|
342 |
|||
343 |
2372 |
return (w); |
|
344 |
} |
||
345 |
|||
346 |
/* |
||
347 |
* Return the printing width of the end (exit) sequence |
||
348 |
* for a given character attribute. |
||
349 |
*/ |
||
350 |
static int |
||
351 |
attr_ewidth(int a) |
||
352 |
{ |
||
353 |
int w = 0; |
||
354 |
|||
355 |
8268652 |
a = apply_at_specials(a); |
|
356 |
|||
357 |
✓✓ | 4134326 |
if (a & AT_UNDERLINE) |
358 |
2970 |
w += ul_e_width; |
|
359 |
✓✓ | 4134326 |
if (a & AT_BOLD) |
360 |
3554 |
w += bo_e_width; |
|
361 |
✗✓ | 4134326 |
if (a & AT_BLINK) |
362 |
w += bl_e_width; |
||
363 |
✓✓ | 4134326 |
if (a & AT_STANDOUT) |
364 |
8927 |
w += so_e_width; |
|
365 |
|||
366 |
4134326 |
return (w); |
|
367 |
} |
||
368 |
|||
369 |
/* |
||
370 |
* Return the printing width of a given character and attribute, |
||
371 |
* if the character were added to the current position in the line buffer. |
||
372 |
* Adding a character with a given attribute may cause an enter or exit |
||
373 |
* attribute sequence to be inserted, so this must be taken into account. |
||
374 |
*/ |
||
375 |
static int |
||
376 |
pwidth(LWCHAR ch, int a, LWCHAR prev_ch) |
||
377 |
{ |
||
378 |
int w; |
||
379 |
|||
380 |
✗✓ | 8256978 |
if (ch == '\b') |
381 |
/* |
||
382 |
* Backspace moves backwards one or two positions. |
||
383 |
* XXX - Incorrect if several '\b' in a row. |
||
384 |
*/ |
||
385 |
return ((utf_mode && is_wide_char(prev_ch)) ? -2 : -1); |
||
386 |
|||
387 |
✗✓✗✗ |
4128489 |
if (!utf_mode || is_ascii_char(ch)) { |
388 |
✗✓ | 4128489 |
if (control_char((char)ch)) { |
389 |
/* |
||
390 |
* Control characters do unpredictable things, |
||
391 |
* so we don't even try to guess; say it doesn't move. |
||
392 |
* This can only happen if the -r flag is in effect. |
||
393 |
*/ |
||
394 |
return (0); |
||
395 |
} |
||
396 |
} else { |
||
397 |
if (is_composing_char(ch) || is_combining_char(prev_ch, ch)) { |
||
398 |
/* |
||
399 |
* Composing and combining chars take up no space. |
||
400 |
* |
||
401 |
* Some terminals, upon failure to compose a |
||
402 |
* composing character with the character(s) that |
||
403 |
* precede(s) it will actually take up one column |
||
404 |
* for the composing character; there isn't much |
||
405 |
* we could do short of testing the (complex) |
||
406 |
* composition process ourselves and printing |
||
407 |
* a binary representation when it fails. |
||
408 |
*/ |
||
409 |
return (0); |
||
410 |
} |
||
411 |
} |
||
412 |
|||
413 |
/* |
||
414 |
* Other characters take one or two columns, |
||
415 |
* plus the width of any attribute enter/exit sequence. |
||
416 |
*/ |
||
417 |
w = 1; |
||
418 |
✗✓ | 4128489 |
if (is_wide_char(ch)) |
419 |
w++; |
||
420 |
✓✓✓✓ |
8212194 |
if (curr > 0 && !is_at_equiv(attr[curr-1], a)) |
421 |
8232 |
w += attr_ewidth(attr[curr-1]); |
|
422 |
✓✓✓✓ |
4137954 |
if ((apply_at_specials(a) != AT_NORMAL) && |
423 |
✓✓ | 18993 |
(curr == 0 || !is_at_equiv(attr[curr-1], a))) |
424 |
2372 |
w += attr_swidth(a); |
|
425 |
4128489 |
return (w); |
|
426 |
4128489 |
} |
|
427 |
|||
428 |
/* |
||
429 |
* Delete to the previous base character in the line buffer. |
||
430 |
* Return 1 if one is found. |
||
431 |
*/ |
||
432 |
static int |
||
433 |
backc(void) |
||
434 |
{ |
||
435 |
LWCHAR prev_ch; |
||
436 |
4790 |
char *p = linebuf + curr; |
|
437 |
2395 |
LWCHAR ch = step_char(&p, -1, linebuf + lmargin); |
|
438 |
int width; |
||
439 |
|||
440 |
/* This assumes that there is no '\b' in linebuf. */ |
||
441 |
✓✗✓✗ ✓✗ |
9580 |
while (curr > lmargin && column > lmargin && |
442 |
2395 |
(!(attr[curr - 1] & (AT_ANSI|AT_BINARY)))) { |
|
443 |
2395 |
curr = p - linebuf; |
|
444 |
2395 |
prev_ch = step_char(&p, -1, linebuf + lmargin); |
|
445 |
2395 |
width = pwidth(ch, attr[curr], prev_ch); |
|
446 |
2395 |
column -= width; |
|
447 |
✓✗ | 2395 |
if (width > 0) |
448 |
2395 |
return (1); |
|
449 |
ch = prev_ch; |
||
450 |
} |
||
451 |
|||
452 |
return (0); |
||
453 |
2395 |
} |
|
454 |
|||
455 |
/* |
||
456 |
* Are we currently within a recognized ANSI escape sequence? |
||
457 |
*/ |
||
458 |
static int |
||
459 |
in_ansi_esc_seq(void) |
||
460 |
{ |
||
461 |
char *p; |
||
462 |
|||
463 |
/* |
||
464 |
* Search backwards for either an ESC (which means we ARE in a seq); |
||
465 |
* or an end char (which means we're NOT in a seq). |
||
466 |
*/ |
||
467 |
for (p = &linebuf[curr]; p > linebuf; ) { |
||
468 |
LWCHAR ch = step_char(&p, -1, linebuf); |
||
469 |
if (IS_CSI_START(ch)) |
||
470 |
return (1); |
||
471 |
if (!is_ansi_middle(ch)) |
||
472 |
return (0); |
||
473 |
} |
||
474 |
return (0); |
||
475 |
} |
||
476 |
|||
477 |
/* |
||
478 |
* Is a character the end of an ANSI escape sequence? |
||
479 |
*/ |
||
480 |
int |
||
481 |
is_ansi_end(LWCHAR ch) |
||
482 |
{ |
||
483 |
if (!is_ascii_char(ch)) |
||
484 |
return (0); |
||
485 |
return (strchr(end_ansi_chars, (char)ch) != NULL); |
||
486 |
} |
||
487 |
|||
488 |
/* |
||
489 |
* |
||
490 |
*/ |
||
491 |
int |
||
492 |
is_ansi_middle(LWCHAR ch) |
||
493 |
{ |
||
494 |
if (!is_ascii_char(ch)) |
||
495 |
return (0); |
||
496 |
if (is_ansi_end(ch)) |
||
497 |
return (0); |
||
498 |
return (strchr(mid_ansi_chars, (char)ch) != NULL); |
||
499 |
} |
||
500 |
|||
501 |
/* |
||
502 |
* Append a character and attribute to the line buffer. |
||
503 |
*/ |
||
504 |
#define STORE_CHAR(ch, a, rep, pos) \ |
||
505 |
if (store_char((ch), (a), (rep), (pos))) \ |
||
506 |
return (1) |
||
507 |
|||
508 |
static int |
||
509 |
store_char(LWCHAR ch, char a, char *rep, off_t pos) |
||
510 |
{ |
||
511 |
int w; |
||
512 |
int replen; |
||
513 |
8251148 |
char cs; |
|
514 |
4125574 |
int matches; |
|
515 |
|||
516 |
✓✓ | 4125574 |
if (is_hilited(pos, pos+1, 0, &matches)) { |
517 |
/* |
||
518 |
* This character should be highlighted. |
||
519 |
* Override the attribute passed in. |
||
520 |
*/ |
||
521 |
✓✗ | 7130 |
if (a != AT_ANSI) { |
522 |
✓✗✓✓ |
14260 |
if (highest_hilite != -1 && pos > highest_hilite) |
523 |
6874 |
highest_hilite = pos; |
|
524 |
7130 |
a |= AT_HILITE; |
|
525 |
7130 |
} |
|
526 |
} |
||
527 |
|||
528 |
✗✓✗✗ |
4125574 |
if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq()) { |
529 |
if (!is_ansi_end(ch) && !is_ansi_middle(ch)) { |
||
530 |
/* Remove whole unrecognized sequence. */ |
||
531 |
char *p = &linebuf[curr]; |
||
532 |
LWCHAR bch; |
||
533 |
do { |
||
534 |
bch = step_char(&p, -1, linebuf); |
||
535 |
} while (p > linebuf && !IS_CSI_START(bch)); |
||
536 |
curr = p - linebuf; |
||
537 |
return (0); |
||
538 |
} |
||
539 |
a = AT_ANSI; /* Will force re-AT_'ing around it. */ |
||
540 |
w = 0; |
||
541 |
✗✓✗✗ |
4125574 |
} else if (ctldisp == OPT_ONPLUS && IS_CSI_START(ch)) { |
542 |
a = AT_ANSI; /* Will force re-AT_'ing around it. */ |
||
543 |
w = 0; |
||
544 |
} else { |
||
545 |
4125574 |
char *p = &linebuf[curr]; |
|
546 |
4125574 |
LWCHAR prev_ch = step_char(&p, -1, linebuf); |
|
547 |
4125574 |
w = pwidth(ch, a, prev_ch); |
|
548 |
4125574 |
} |
|
549 |
|||
550 |
✓✗✓✓ |
8251148 |
if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width) |
551 |
/* |
||
552 |
* Won't fit on screen. |
||
553 |
*/ |
||
554 |
17421 |
return (1); |
|
555 |
|||
556 |
✓✓ | 4108153 |
if (rep == NULL) { |
557 |
4104496 |
cs = (char)ch; |
|
558 |
rep = &cs; |
||
559 |
replen = 1; |
||
560 |
4104496 |
} else { |
|
561 |
3657 |
replen = utf_len(rep[0]); |
|
562 |
} |
||
563 |
✗✓ | 4108153 |
if (curr + replen >= size_linebuf-6) { |
564 |
/* |
||
565 |
* Won't fit in line buffer. |
||
566 |
* Try to expand it. |
||
567 |
*/ |
||
568 |
if (expand_linebuf()) |
||
569 |
return (1); |
||
570 |
} |
||
571 |
|||
572 |
✓✓ | 12324459 |
while (replen-- > 0) { |
573 |
4108153 |
linebuf[curr] = *rep++; |
|
574 |
4108153 |
attr[curr] = a; |
|
575 |
4108153 |
curr++; |
|
576 |
} |
||
577 |
4108153 |
column += w; |
|
578 |
4108153 |
return (0); |
|
579 |
4125574 |
} |
|
580 |
|||
581 |
/* |
||
582 |
* Append a tab to the line buffer. |
||
583 |
* Store spaces to represent the tab. |
||
584 |
*/ |
||
585 |
#define STORE_TAB(a, pos) \ |
||
586 |
if (store_tab((a), (pos))) \ |
||
587 |
return (1) |
||
588 |
|||
589 |
static int |
||
590 |
store_tab(int attr, off_t pos) |
||
591 |
{ |
||
592 |
1038 |
int to_tab = column + cshift - lmargin; |
|
593 |
int i; |
||
594 |
|||
595 |
✗✓✗✗ |
519 |
if (ntabstops < 2 || to_tab >= tabstops[ntabstops-1]) |
596 |
1038 |
to_tab = tabdefault - |
|
597 |
519 |
((to_tab - tabstops[ntabstops-1]) % tabdefault); |
|
598 |
else { |
||
599 |
for (i = ntabstops - 2; i >= 0; i--) |
||
600 |
if (to_tab >= tabstops[i]) |
||
601 |
break; |
||
602 |
to_tab = tabstops[i+1] - to_tab; |
||
603 |
} |
||
604 |
|||
605 |
✗✓ | 1557 |
if (column + to_tab - 1 + pwidth(' ', attr, 0) + |
606 |
1038 |
attr_ewidth(attr) > sc_width) |
|
607 |
return (1); |
||
608 |
|||
609 |
do { |
||
610 |
✗✓ | 3657 |
STORE_CHAR(' ', attr, " ", pos); |
611 |
✓✓ | 3657 |
} while (--to_tab > 0); |
612 |
519 |
return (0); |
|
613 |
519 |
} |
|
614 |
|||
615 |
#define STORE_PRCHAR(c, pos) \ |
||
616 |
if (store_prchar((c), (pos))) \ |
||
617 |
return (1) |
||
618 |
|||
619 |
static int |
||
620 |
store_prchar(char c, off_t pos) |
||
621 |
{ |
||
622 |
char *s; |
||
623 |
|||
624 |
/* |
||
625 |
* Convert to printable representation. |
||
626 |
*/ |
||
627 |
2 |
s = prchar(c); |
|
628 |
|||
629 |
/* |
||
630 |
* Make sure we can get the entire representation |
||
631 |
* of the character on this line. |
||
632 |
*/ |
||
633 |
✗✓ | 3 |
if (column + (int)strlen(s) - 1 + |
634 |
2 |
pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width) |
|
635 |
return (1); |
||
636 |
|||
637 |
✓✓ | 5 |
for (; *s != 0; s++) { |
638 |
✗✓ | 2 |
STORE_CHAR(*s, AT_BINARY, NULL, pos); |
639 |
} |
||
640 |
1 |
return (0); |
|
641 |
1 |
} |
|
642 |
|||
643 |
static int |
||
644 |
flush_mbc_buf(off_t pos) |
||
645 |
{ |
||
646 |
int i; |
||
647 |
|||
648 |
for (i = 0; i < mbc_buf_index; i++) |
||
649 |
if (store_prchar(mbc_buf[i], pos)) |
||
650 |
return (mbc_buf_index - i); |
||
651 |
|||
652 |
return (0); |
||
653 |
} |
||
654 |
|||
655 |
/* |
||
656 |
* Append a character to the line buffer. |
||
657 |
* Expand tabs into spaces, handle underlining, boldfacing, etc. |
||
658 |
* Returns 0 if ok, 1 if couldn't fit in buffer. |
||
659 |
*/ |
||
660 |
int |
||
661 |
pappend(char c, off_t pos) |
||
662 |
{ |
||
663 |
int r; |
||
664 |
|||
665 |
✗✓ | 8249664 |
if (pendc) { |
666 |
if (do_append(pendc, NULL, pendpos)) |
||
667 |
/* |
||
668 |
* Oops. We've probably lost the char which |
||
669 |
* was in pendc, since caller won't back up. |
||
670 |
*/ |
||
671 |
return (1); |
||
672 |
pendc = '\0'; |
||
673 |
} |
||
674 |
|||
675 |
✓✓ | 4124832 |
if (c == '\r' && bs_mode == BS_SPECIAL) { |
676 |
✗✓ | 2 |
if (mbc_buf_len > 0) /* utf_mode must be on. */ { |
677 |
/* Flush incomplete (truncated) sequence. */ |
||
678 |
r = flush_mbc_buf(mbc_pos); |
||
679 |
mbc_buf_index = r + 1; |
||
680 |
mbc_buf_len = 0; |
||
681 |
if (r) |
||
682 |
return (mbc_buf_index); |
||
683 |
} |
||
684 |
|||
685 |
/* |
||
686 |
* Don't put the CR into the buffer until we see |
||
687 |
* the next char. If the next char is a newline, |
||
688 |
* discard the CR. |
||
689 |
*/ |
||
690 |
2 |
pendc = c; |
|
691 |
2 |
pendpos = pos; |
|
692 |
2 |
return (0); |
|
693 |
} |
||
694 |
|||
695 |
✓✗ | 4124830 |
if (!utf_mode) { |
696 |
4124830 |
r = do_append((LWCHAR) c, NULL, pos); |
|
697 |
4124830 |
} else { |
|
698 |
/* Perform strict validation in all possible cases. */ |
||
699 |
if (mbc_buf_len == 0) { |
||
700 |
retry: |
||
701 |
mbc_buf_index = 1; |
||
702 |
*mbc_buf = c; |
||
703 |
if (IS_ASCII_OCTET(c)) { |
||
704 |
r = do_append((LWCHAR) c, NULL, pos); |
||
705 |
} else if (IS_UTF8_LEAD(c)) { |
||
706 |
mbc_buf_len = utf_len(c); |
||
707 |
mbc_pos = pos; |
||
708 |
return (0); |
||
709 |
} else { |
||
710 |
/* UTF8_INVALID or stray UTF8_TRAIL */ |
||
711 |
r = flush_mbc_buf(pos); |
||
712 |
} |
||
713 |
} else if (IS_UTF8_TRAIL(c)) { |
||
714 |
mbc_buf[mbc_buf_index++] = c; |
||
715 |
if (mbc_buf_index < mbc_buf_len) |
||
716 |
return (0); |
||
717 |
if (is_utf8_well_formed(mbc_buf)) |
||
718 |
r = do_append(get_wchar(mbc_buf), mbc_buf, |
||
719 |
mbc_pos); |
||
720 |
else |
||
721 |
/* Complete, but not shortest form, sequence. */ |
||
722 |
mbc_buf_index = r = flush_mbc_buf(mbc_pos); |
||
723 |
mbc_buf_len = 0; |
||
724 |
} else { |
||
725 |
/* Flush incomplete (truncated) sequence. */ |
||
726 |
r = flush_mbc_buf(mbc_pos); |
||
727 |
mbc_buf_index = r + 1; |
||
728 |
mbc_buf_len = 0; |
||
729 |
/* Handle new char. */ |
||
730 |
if (!r) |
||
731 |
goto retry; |
||
732 |
} |
||
733 |
} |
||
734 |
|||
735 |
/* |
||
736 |
* If we need to shift the line, do it. |
||
737 |
* But wait until we get to at least the middle of the screen, |
||
738 |
* so shifting it doesn't affect the chars we're currently |
||
739 |
* pappending. (Bold & underline can get messed up otherwise.) |
||
740 |
*/ |
||
741 |
✗✓✗✗ |
4124830 |
if (cshift < hshift && column > sc_width / 2) { |
742 |
linebuf[curr] = '\0'; |
||
743 |
pshift(hshift - cshift); |
||
744 |
} |
||
745 |
✓✓ | 4124830 |
if (r) { |
746 |
/* How many chars should caller back up? */ |
||
747 |
17421 |
r = (!utf_mode) ? 1 : mbc_buf_index; |
|
748 |
17421 |
} |
|
749 |
4124830 |
return (r); |
|
750 |
4124832 |
} |
|
751 |
|||
752 |
static int |
||
753 |
do_append(LWCHAR ch, char *rep, off_t pos) |
||
754 |
{ |
||
755 |
int a; |
||
756 |
LWCHAR prev_ch; |
||
757 |
|||
758 |
a = AT_NORMAL; |
||
759 |
|||
760 |
✓✓ | 8249660 |
if (ch == '\b') { |
761 |
✓✗ | 2395 |
if (bs_mode == BS_CONTROL) |
762 |
goto do_control_char; |
||
763 |
|||
764 |
/* |
||
765 |
* A better test is needed here so we don't |
||
766 |
* backspace over part of the printed |
||
767 |
* representation of a binary character. |
||
768 |
*/ |
||
769 |
✓✗✗✓ |
4790 |
if (curr <= lmargin || |
770 |
✓✗ | 2395 |
column <= lmargin || |
771 |
2395 |
(attr[curr - 1] & (AT_ANSI|AT_BINARY))) { |
|
772 |
STORE_PRCHAR('\b', pos); |
||
773 |
✗✓ | 2395 |
} else if (bs_mode == BS_NORMAL) { |
774 |
STORE_CHAR(ch, AT_NORMAL, NULL, pos); |
||
775 |
✓✗ | 2395 |
} else if (bs_mode == BS_SPECIAL) { |
776 |
2395 |
overstrike = backc(); |
|
777 |
2395 |
} |
|
778 |
|||
779 |
2395 |
return (0); |
|
780 |
} |
||
781 |
|||
782 |
✓✓ | 4122435 |
if (overstrike > 0) { |
783 |
/* |
||
784 |
* Overstrike the character at the current position |
||
785 |
* in the line buffer. This will cause either |
||
786 |
* underline (if a "_" is overstruck), |
||
787 |
* bold (if an identical character is overstruck), |
||
788 |
* or just deletion of the character in the buffer. |
||
789 |
*/ |
||
790 |
2395 |
overstrike = utf_mode ? -1 : 0; |
|
791 |
/* To be correct, this must be a base character. */ |
||
792 |
2395 |
prev_ch = get_wchar(linebuf + curr); |
|
793 |
2395 |
a = attr[curr]; |
|
794 |
✓✓ | 2395 |
if (ch == prev_ch) { |
795 |
/* |
||
796 |
* Overstriking a char with itself means make it bold. |
||
797 |
* But overstriking an underscore with itself is |
||
798 |
* ambiguous. It could mean make it bold, or |
||
799 |
* it could mean make it underlined. |
||
800 |
* Use the previous overstrike to resolve it. |
||
801 |
*/ |
||
802 |
✓✓ | 1338 |
if (ch == '_') { |
803 |
✗✓ | 11 |
if ((a & (AT_BOLD|AT_UNDERLINE)) != AT_NORMAL) |
804 |
a |= (AT_BOLD|AT_UNDERLINE); |
||
805 |
✓✗✓✓ |
22 |
else if (curr > 0 && attr[curr - 1] & AT_UNDERLINE) |
806 |
9 |
a |= AT_UNDERLINE; |
|
807 |
✓✗✓✗ |
4 |
else if (curr > 0 && attr[curr - 1] & AT_BOLD) |
808 |
2 |
a |= AT_BOLD; |
|
809 |
else |
||
810 |
a |= AT_INDET; |
||
811 |
} else { |
||
812 |
1327 |
a |= AT_BOLD; |
|
813 |
} |
||
814 |
✗✓ | 1057 |
} else if (ch == '_') { |
815 |
a |= AT_UNDERLINE; |
||
816 |
ch = prev_ch; |
||
817 |
rep = linebuf + curr; |
||
818 |
✓✗ | 1057 |
} else if (prev_ch == '_') { |
819 |
1057 |
a |= AT_UNDERLINE; |
|
820 |
1057 |
} |
|
821 |
/* Else we replace prev_ch, but we keep its attributes. */ |
||
822 |
✗✓ | 4120040 |
} else if (overstrike < 0) { |
823 |
if (is_composing_char(ch) || |
||
824 |
is_combining_char(get_wchar(linebuf + curr), ch)) { |
||
825 |
/* Continuation of the same overstrike. */ |
||
826 |
if (curr > 0) |
||
827 |
a = attr[curr - 1] & (AT_UNDERLINE | AT_BOLD); |
||
828 |
else |
||
829 |
a = AT_NORMAL; |
||
830 |
} else |
||
831 |
overstrike = 0; |
||
832 |
} |
||
833 |
|||
834 |
✓✓ | 4122435 |
if (ch == '\t') { |
835 |
/* |
||
836 |
* Expand a tab into spaces. |
||
837 |
*/ |
||
838 |
✗✓✓✓ |
3618147 |
switch (bs_mode) { |
839 |
case BS_CONTROL: |
||
840 |
goto do_control_char; |
||
841 |
case BS_NORMAL: |
||
842 |
case BS_SPECIAL: |
||
843 |
✗✓ | 519 |
STORE_TAB(a, pos); |
844 |
break; |
||
845 |
} |
||
846 |
✗✓✗✗ ✓✓ |
8243832 |
} else if ((!utf_mode || is_ascii_char(ch)) && control_char((char)ch)) { |
847 |
do_control_char: |
||
848 |
✓✗ | 1 |
if (ctldisp == OPT_ON || |
849 |
✗✓✗✗ |
1 |
(ctldisp == OPT_ONPLUS && IS_CSI_START(ch))) { |
850 |
/* |
||
851 |
* Output as a normal character. |
||
852 |
*/ |
||
853 |
STORE_CHAR(ch, AT_NORMAL, rep, pos); |
||
854 |
} else { |
||
855 |
✗✓ | 1 |
STORE_PRCHAR((char)ch, pos); |
856 |
} |
||
857 |
✗✓✗✗ |
4121915 |
} else if (utf_mode && ctldisp != OPT_ON && is_ubin_char(ch)) { |
858 |
char *s; |
||
859 |
|||
860 |
s = prutfchar(ch); |
||
861 |
|||
862 |
if (column + (int)strlen(s) - 1 + |
||
863 |
pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width) |
||
864 |
return (1); |
||
865 |
|||
866 |
for (; *s != 0; s++) |
||
867 |
STORE_CHAR(*s, AT_BINARY, NULL, pos); |
||
868 |
} else { |
||
869 |
✓✓ | 4139336 |
STORE_CHAR(ch, a, rep, pos); |
870 |
} |
||
871 |
4105014 |
return (0); |
|
872 |
4124830 |
} |
|
873 |
|||
874 |
/* |
||
875 |
* |
||
876 |
*/ |
||
877 |
int |
||
878 |
pflushmbc(void) |
||
879 |
{ |
||
880 |
int r = 0; |
||
881 |
|||
882 |
✗✓ | 150796 |
if (mbc_buf_len > 0) { |
883 |
/* Flush incomplete (truncated) sequence. */ |
||
884 |
r = flush_mbc_buf(mbc_pos); |
||
885 |
mbc_buf_len = 0; |
||
886 |
} |
||
887 |
75398 |
return (r); |
|
888 |
} |
||
889 |
|||
890 |
/* |
||
891 |
* Terminate the line in the line buffer. |
||
892 |
*/ |
||
893 |
void |
||
894 |
pdone(int endline, int forw) |
||
895 |
{ |
||
896 |
int i; |
||
897 |
|||
898 |
55526 |
(void) pflushmbc(); |
|
899 |
|||
900 |
✓✓✗✓ |
27765 |
if (pendc && (pendc != '\r' || !endline)) |
901 |
/* |
||
902 |
* If we had a pending character, put it in the buffer. |
||
903 |
* But discard a pending CR if we are at end of line |
||
904 |
* (that is, discard the CR in a CR/LF sequence). |
||
905 |
*/ |
||
906 |
(void) do_append(pendc, NULL, pendpos); |
||
907 |
|||
908 |
✓✓ | 3528802 |
for (i = curr - 1; i >= 0; i--) { |
909 |
✗✓ | 1736638 |
if (attr[i] & AT_INDET) { |
910 |
attr[i] &= ~AT_INDET; |
||
911 |
if (i < curr - 1 && attr[i + 1] & AT_BOLD) |
||
912 |
attr[i] |= AT_BOLD; |
||
913 |
else |
||
914 |
attr[i] |= AT_UNDERLINE; |
||
915 |
} |
||
916 |
} |
||
917 |
|||
918 |
/* |
||
919 |
* Make sure we've shifted the line, if we need to. |
||
920 |
*/ |
||
921 |
✗✓ | 27763 |
if (cshift < hshift) |
922 |
pshift(hshift - cshift); |
||
923 |
|||
924 |
✗✓✗✗ |
27763 |
if (ctldisp == OPT_ONPLUS && is_ansi_end('m')) { |
925 |
/* Switch to normal attribute at end of line. */ |
||
926 |
char *p = "\033[m"; |
||
927 |
for (; *p != '\0'; p++) { |
||
928 |
linebuf[curr] = *p; |
||
929 |
attr[curr++] = AT_ANSI; |
||
930 |
} |
||
931 |
} |
||
932 |
|||
933 |
/* |
||
934 |
* Add a newline if necessary, |
||
935 |
* and append a '\0' to the end of the line. |
||
936 |
* We output a newline if we're not at the right edge of the screen, |
||
937 |
* or if the terminal doesn't auto wrap, |
||
938 |
* or if this is really the end of the line AND the terminal ignores |
||
939 |
* a newline at the right edge. |
||
940 |
* (In the last case we don't want to output a newline if the terminal |
||
941 |
* doesn't ignore it since that would produce an extra blank line. |
||
942 |
* But we do want to output a newline if the terminal ignores it in case |
||
943 |
* the next line is blank. In that case the single newline output for |
||
944 |
* that blank line would be ignored!) |
||
945 |
*/ |
||
946 |
✓✓✓✓ |
38065 |
if (column < sc_width || !auto_wrap || (endline && ignaw) || |
947 |
5151 |
ctldisp == OPT_ON) { |
|
948 |
22628 |
linebuf[curr] = '\n'; |
|
949 |
22628 |
attr[curr] = AT_NORMAL; |
|
950 |
22628 |
curr++; |
|
951 |
✓✗✓✓ |
32898 |
} else if (ignaw && column >= sc_width && forw) { |
952 |
/* |
||
953 |
* Terminals with "ignaw" don't wrap until they *really* need |
||
954 |
* to, i.e. when the character *after* the last one to fit on a |
||
955 |
* line is output. But they are too hard to deal with when they |
||
956 |
* get in the state where a full screen width of characters |
||
957 |
* have been output but the cursor is sitting on the right edge |
||
958 |
* instead of at the start of the next line. |
||
959 |
* So we nudge them into wrapping by outputting a space |
||
960 |
* character plus a backspace. But do this only if moving |
||
961 |
* forward; if we're moving backward and drawing this line at |
||
962 |
* the top of the screen, the space would overwrite the first |
||
963 |
* char on the next line. We don't need to do this "nudge" |
||
964 |
* at the top of the screen anyway. |
||
965 |
*/ |
||
966 |
5111 |
linebuf[curr] = ' '; |
|
967 |
5111 |
attr[curr++] = AT_NORMAL; |
|
968 |
5111 |
linebuf[curr] = '\b'; |
|
969 |
5111 |
attr[curr++] = AT_NORMAL; |
|
970 |
5111 |
} |
|
971 |
27763 |
linebuf[curr] = '\0'; |
|
972 |
27763 |
attr[curr] = AT_NORMAL; |
|
973 |
27763 |
} |
|
974 |
|||
975 |
/* |
||
976 |
* |
||
977 |
*/ |
||
978 |
void |
||
979 |
set_status_col(char c) |
||
980 |
{ |
||
981 |
linebuf[0] = c; |
||
982 |
attr[0] = AT_NORMAL|AT_HILITE; |
||
983 |
} |
||
984 |
|||
985 |
/* |
||
986 |
* Get a character from the current line. |
||
987 |
* Return the character as the function return value, |
||
988 |
* and the character attribute in *ap. |
||
989 |
*/ |
||
990 |
int |
||
991 |
gline(int i, int *ap) |
||
992 |
{ |
||
993 |
✓✓ | 3397202 |
if (is_null_line) { |
994 |
/* |
||
995 |
* If there is no current line, we pretend the line is |
||
996 |
* either "~" or "", depending on the "twiddle" flag. |
||
997 |
*/ |
||
998 |
✓✗ | 507 |
if (twiddle) { |
999 |
✓✓ | 507 |
if (i == 0) { |
1000 |
169 |
*ap = AT_BOLD; |
|
1001 |
169 |
return ('~'); |
|
1002 |
} |
||
1003 |
338 |
--i; |
|
1004 |
338 |
} |
|
1005 |
/* Make sure we're back to AT_NORMAL before the '\n'. */ |
||
1006 |
338 |
*ap = AT_NORMAL; |
|
1007 |
338 |
return (i ? '\0' : '\n'); |
|
1008 |
} |
||
1009 |
|||
1010 |
1698094 |
*ap = attr[i]; |
|
1011 |
1698094 |
return (linebuf[i] & 0xFF); |
|
1012 |
1698601 |
} |
|
1013 |
|||
1014 |
/* |
||
1015 |
* Indicate that there is no current line. |
||
1016 |
*/ |
||
1017 |
void |
||
1018 |
null_line(void) |
||
1019 |
{ |
||
1020 |
398 |
is_null_line = 1; |
|
1021 |
199 |
cshift = 0; |
|
1022 |
199 |
} |
|
1023 |
|||
1024 |
/* |
||
1025 |
* Analogous to forw_line(), but deals with "raw lines": |
||
1026 |
* lines which are not split for screen width. |
||
1027 |
* {{ This is supposed to be more efficient than forw_line(). }} |
||
1028 |
*/ |
||
1029 |
off_t |
||
1030 |
forw_raw_line(off_t curr_pos, char **linep, int *line_lenp) |
||
1031 |
{ |
||
1032 |
int n; |
||
1033 |
int c; |
||
1034 |
off_t new_pos; |
||
1035 |
|||
1036 |
✓✗✓✗ ✓✓ |
180124 |
if (curr_pos == -1 || ch_seek(curr_pos) || |
1037 |
45031 |
(c = ch_forw_get()) == EOI) |
|
1038 |
33 |
return (-1); |
|
1039 |
|||
1040 |
n = 0; |
||
1041 |
2883286 |
for (;;) { |
|
1042 |
✓✓✗✓ |
5721574 |
if (c == '\n' || c == EOI || ABORT_SIGS()) { |
1043 |
44998 |
new_pos = ch_tell(); |
|
1044 |
44998 |
break; |
|
1045 |
} |
||
1046 |
✓✓ | 2838288 |
if (n >= size_linebuf-1) { |
1047 |
✗✓ | 3 |
if (expand_linebuf()) { |
1048 |
/* |
||
1049 |
* Overflowed the input buffer. |
||
1050 |
* Pretend the line ended here. |
||
1051 |
*/ |
||
1052 |
new_pos = ch_tell() - 1; |
||
1053 |
break; |
||
1054 |
} |
||
1055 |
} |
||
1056 |
2838288 |
linebuf[n++] = (char)c; |
|
1057 |
2838288 |
c = ch_forw_get(); |
|
1058 |
} |
||
1059 |
44998 |
linebuf[n] = '\0'; |
|
1060 |
✓✓ | 44998 |
if (linep != NULL) |
1061 |
14576 |
*linep = linebuf; |
|
1062 |
✓✓ | 44998 |
if (line_lenp != NULL) |
1063 |
14576 |
*line_lenp = n; |
|
1064 |
44998 |
return (new_pos); |
|
1065 |
45031 |
} |
|
1066 |
|||
1067 |
/* |
||
1068 |
* Analogous to back_line(), but deals with "raw lines". |
||
1069 |
* {{ This is supposed to be more efficient than back_line(). }} |
||
1070 |
*/ |
||
1071 |
off_t |
||
1072 |
back_raw_line(off_t curr_pos, char **linep, int *line_lenp) |
||
1073 |
{ |
||
1074 |
int n; |
||
1075 |
int c; |
||
1076 |
off_t new_pos; |
||
1077 |
|||
1078 |
✓✗✗✓ |
20787 |
if (curr_pos == -1 || curr_pos <= ch_zero() || ch_seek(curr_pos - 1)) |
1079 |
return (-1); |
||
1080 |
|||
1081 |
6929 |
n = size_linebuf; |
|
1082 |
6929 |
linebuf[--n] = '\0'; |
|
1083 |
261399 |
for (;;) { |
|
1084 |
261399 |
c = ch_back_get(); |
|
1085 |
✓✓✗✓ |
515869 |
if (c == '\n' || ABORT_SIGS()) { |
1086 |
/* |
||
1087 |
* This is the newline ending the previous line. |
||
1088 |
* We have hit the beginning of the line. |
||
1089 |
*/ |
||
1090 |
6929 |
new_pos = ch_tell() + 1; |
|
1091 |
6929 |
break; |
|
1092 |
} |
||
1093 |
✗✓ | 254470 |
if (c == EOI) { |
1094 |
/* |
||
1095 |
* We have hit the beginning of the file. |
||
1096 |
* This must be the first line in the file. |
||
1097 |
* This must, of course, be the beginning of the line. |
||
1098 |
*/ |
||
1099 |
new_pos = ch_zero(); |
||
1100 |
break; |
||
1101 |
} |
||
1102 |
✗✓ | 254470 |
if (n <= 0) { |
1103 |
int old_size_linebuf = size_linebuf; |
||
1104 |
if (expand_linebuf()) { |
||
1105 |
/* |
||
1106 |
* Overflowed the input buffer. |
||
1107 |
* Pretend the line ended here. |
||
1108 |
*/ |
||
1109 |
new_pos = ch_tell() + 1; |
||
1110 |
break; |
||
1111 |
} |
||
1112 |
/* |
||
1113 |
* Shift the data to the end of the new linebuf. |
||
1114 |
*/ |
||
1115 |
n = size_linebuf - old_size_linebuf; |
||
1116 |
memmove(linebuf + n, linebuf, old_size_linebuf); |
||
1117 |
} |
||
1118 |
254470 |
linebuf[--n] = c; |
|
1119 |
} |
||
1120 |
✗✓ | 6929 |
if (linep != NULL) |
1121 |
*linep = &linebuf[n]; |
||
1122 |
✗✓ | 6929 |
if (line_lenp != NULL) |
1123 |
*line_lenp = size_linebuf - 1 - n; |
||
1124 |
6929 |
return (new_pos); |
|
1125 |
6929 |
} |
Generated by: GCOVR (Version 3.3) |