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 |
* User-level command processor. |
||
14 |
*/ |
||
15 |
|||
16 |
#include "cmd.h" |
||
17 |
#include "less.h" |
||
18 |
#include "option.h" |
||
19 |
#include "position.h" |
||
20 |
|||
21 |
extern int erase_char, erase2_char, kill_char; |
||
22 |
extern volatile sig_atomic_t sigs; |
||
23 |
extern int quit_if_one_screen; |
||
24 |
extern int less_is_more; |
||
25 |
extern int squished; |
||
26 |
extern int sc_width; |
||
27 |
extern int sc_height; |
||
28 |
extern int swindow; |
||
29 |
extern int jump_sline; |
||
30 |
extern int quitting; |
||
31 |
extern int wscroll; |
||
32 |
extern int top_scroll; |
||
33 |
extern int ignore_eoi; |
||
34 |
extern int secure; |
||
35 |
extern int hshift; |
||
36 |
extern int show_attn; |
||
37 |
extern off_t highest_hilite; |
||
38 |
extern char *every_first_cmd; |
||
39 |
extern char *curr_altfilename; |
||
40 |
extern char version[]; |
||
41 |
extern struct scrpos initial_scrpos; |
||
42 |
extern IFILE curr_ifile; |
||
43 |
extern void *ml_search; |
||
44 |
extern void *ml_examine; |
||
45 |
extern void *ml_shell; |
||
46 |
extern char *editor; |
||
47 |
extern char *editproto; |
||
48 |
extern int screen_trashed; /* The screen has been overwritten */ |
||
49 |
extern int shift_count; |
||
50 |
extern int oldbot; |
||
51 |
extern int forw_prompt; |
||
52 |
|||
53 |
static int mca; /* The multicharacter command (action) */ |
||
54 |
static int search_type; /* The previous type of search */ |
||
55 |
static off_t number; /* The number typed by the user */ |
||
56 |
static long fraction; /* The fractional part of the number */ |
||
57 |
static struct loption *curropt; |
||
58 |
static int opt_lower; |
||
59 |
static int optflag; |
||
60 |
static int optgetname; |
||
61 |
static off_t bottompos; |
||
62 |
static int save_hshift; |
||
63 |
static int pipec; |
||
64 |
|||
65 |
struct ungot { |
||
66 |
struct ungot *ug_next; |
||
67 |
int ug_char; |
||
68 |
}; |
||
69 |
static struct ungot *ungot = NULL; |
||
70 |
static int unget_end = 0; |
||
71 |
|||
72 |
static void multi_search(char *, int); |
||
73 |
|||
74 |
/* |
||
75 |
* Move the cursor to start of prompt line before executing a command. |
||
76 |
* This looks nicer if the command takes a long time before |
||
77 |
* updating the screen. |
||
78 |
*/ |
||
79 |
static void |
||
80 |
cmd_exec(void) |
||
81 |
{ |
||
82 |
72 |
clear_attn(); |
|
83 |
36 |
clear_bot(); |
|
84 |
36 |
flush(0); |
|
85 |
36 |
} |
|
86 |
|||
87 |
/* |
||
88 |
* Set up the display to start a new multi-character command. |
||
89 |
*/ |
||
90 |
static void |
||
91 |
start_mca(int action, const char *prompt, void *mlist, int cmdflags) |
||
92 |
{ |
||
93 |
64 |
mca = action; |
|
94 |
32 |
clear_bot(); |
|
95 |
32 |
clear_cmd(); |
|
96 |
32 |
cmd_putstr((char *)prompt); |
|
97 |
32 |
set_mlist(mlist, cmdflags); |
|
98 |
32 |
} |
|
99 |
|||
100 |
int |
||
101 |
in_mca(void) |
||
102 |
{ |
||
103 |
280 |
return (mca != 0 && mca != A_PREFIX); |
|
104 |
} |
||
105 |
|||
106 |
/* |
||
107 |
* Set up the display to start a new search command. |
||
108 |
*/ |
||
109 |
static void |
||
110 |
mca_search(void) |
||
111 |
{ |
||
112 |
✓✗ | 8 |
if (search_type & SRCH_FILTER) |
113 |
mca = A_FILTER; |
||
114 |
4 |
else if (search_type & SRCH_FORW) |
|
115 |
mca = A_F_SEARCH; |
||
116 |
else |
||
117 |
mca = A_B_SEARCH; |
||
118 |
|||
119 |
4 |
clear_bot(); |
|
120 |
4 |
clear_cmd(); |
|
121 |
|||
122 |
✗✓ | 4 |
if (search_type & SRCH_NO_MATCH) |
123 |
cmd_putstr("Non-match "); |
||
124 |
✗✓ | 4 |
if (search_type & SRCH_FIRST_FILE) |
125 |
cmd_putstr("First-file "); |
||
126 |
✗✓ | 4 |
if (search_type & SRCH_PAST_EOF) |
127 |
cmd_putstr("EOF-ignore "); |
||
128 |
✗✓ | 4 |
if (search_type & SRCH_NO_MOVE) |
129 |
cmd_putstr("Keep-pos "); |
||
130 |
✗✓ | 4 |
if (search_type & SRCH_NO_REGEX) |
131 |
cmd_putstr("Regex-off "); |
||
132 |
|||
133 |
✗✓ | 4 |
if (search_type & SRCH_FILTER) |
134 |
cmd_putstr("&/"); |
||
135 |
✓✗ | 4 |
else if (search_type & SRCH_FORW) |
136 |
4 |
cmd_putstr("/"); |
|
137 |
else |
||
138 |
cmd_putstr("?"); |
||
139 |
4 |
set_mlist(ml_search, 0); |
|
140 |
4 |
} |
|
141 |
|||
142 |
/* |
||
143 |
* Set up the display to start a new toggle-option command. |
||
144 |
*/ |
||
145 |
static void |
||
146 |
mca_opt_toggle(void) |
||
147 |
{ |
||
148 |
int no_prompt; |
||
149 |
int flag; |
||
150 |
char *dash; |
||
151 |
|||
152 |
no_prompt = (optflag & OPT_NO_PROMPT); |
||
153 |
flag = (optflag & ~OPT_NO_PROMPT); |
||
154 |
dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; |
||
155 |
|||
156 |
mca = A_OPT_TOGGLE; |
||
157 |
clear_bot(); |
||
158 |
clear_cmd(); |
||
159 |
cmd_putstr(dash); |
||
160 |
if (optgetname) |
||
161 |
cmd_putstr(dash); |
||
162 |
if (no_prompt) |
||
163 |
cmd_putstr("(P)"); |
||
164 |
switch (flag) { |
||
165 |
case OPT_UNSET: |
||
166 |
cmd_putstr("+"); |
||
167 |
break; |
||
168 |
case OPT_SET: |
||
169 |
cmd_putstr("!"); |
||
170 |
break; |
||
171 |
} |
||
172 |
set_mlist(NULL, 0); |
||
173 |
} |
||
174 |
|||
175 |
/* |
||
176 |
* Execute a multicharacter command. |
||
177 |
*/ |
||
178 |
static void |
||
179 |
exec_mca(void) |
||
180 |
{ |
||
181 |
char *cbuf; |
||
182 |
|||
183 |
9 |
cmd_exec(); |
|
184 |
6 |
cbuf = get_cmdbuf(); |
|
185 |
|||
186 |
✗✓✗✗ ✗✗✗✗ ✗✓ |
6 |
switch (mca) { |
187 |
case A_F_SEARCH: |
||
188 |
case A_B_SEARCH: |
||
189 |
3 |
multi_search(cbuf, (int)number); |
|
190 |
3 |
break; |
|
191 |
case A_FILTER: |
||
192 |
search_type ^= SRCH_NO_MATCH; |
||
193 |
set_filter_pattern(cbuf, search_type); |
||
194 |
break; |
||
195 |
case A_FIRSTCMD: |
||
196 |
/* |
||
197 |
* Skip leading spaces or + signs in the string. |
||
198 |
*/ |
||
199 |
while (*cbuf == '+' || *cbuf == ' ') |
||
200 |
cbuf++; |
||
201 |
free(every_first_cmd); |
||
202 |
if (*cbuf == '\0') |
||
203 |
every_first_cmd = NULL; |
||
204 |
else |
||
205 |
every_first_cmd = estrdup(cbuf); |
||
206 |
break; |
||
207 |
case A_OPT_TOGGLE: |
||
208 |
toggle_option(curropt, opt_lower, cbuf, optflag); |
||
209 |
curropt = NULL; |
||
210 |
break; |
||
211 |
case A_F_BRACKET: |
||
212 |
match_brac(cbuf[0], cbuf[1], 1, (int)number); |
||
213 |
break; |
||
214 |
case A_B_BRACKET: |
||
215 |
match_brac(cbuf[1], cbuf[0], 0, (int)number); |
||
216 |
break; |
||
217 |
case A_EXAMINE: |
||
218 |
if (secure) |
||
219 |
break; |
||
220 |
|||
221 |
/* POSIX behavior, but possibly generally useful */ |
||
222 |
if (strlen(cbuf) == 0) { |
||
223 |
reopen_curr_ifile(); |
||
224 |
jump_back(1); |
||
225 |
break; |
||
226 |
} |
||
227 |
/* POSIX behavior - probably not generally useful */ |
||
228 |
if (less_is_more && (strcmp(cbuf, "#") == 0)) { |
||
229 |
if (ntags()) { |
||
230 |
error("No previous file", NULL); |
||
231 |
break; |
||
232 |
} |
||
233 |
if (edit_prev(1)) { |
||
234 |
error("No previous file", NULL); |
||
235 |
} else { |
||
236 |
jump_back(1); |
||
237 |
} |
||
238 |
break; |
||
239 |
} |
||
240 |
edit_list(cbuf); |
||
241 |
/* If tag structure is loaded then clean it up. */ |
||
242 |
cleantags(); |
||
243 |
break; |
||
244 |
case A_PIPE: |
||
245 |
if (secure) |
||
246 |
break; |
||
247 |
(void) pipe_mark(pipec, cbuf); |
||
248 |
error("|done", NULL); |
||
249 |
break; |
||
250 |
} |
||
251 |
3 |
} |
|
252 |
|||
253 |
/* |
||
254 |
* Is a character an erase or kill char? |
||
255 |
*/ |
||
256 |
static int |
||
257 |
is_erase_char(int c) |
||
258 |
{ |
||
259 |
return (c == erase_char || c == erase2_char || c == kill_char); |
||
260 |
} |
||
261 |
|||
262 |
/* |
||
263 |
* Handle the first char of an option (after the initial dash). |
||
264 |
*/ |
||
265 |
static int |
||
266 |
mca_opt_first_char(int c) |
||
267 |
{ |
||
268 |
int flag = (optflag & ~OPT_NO_PROMPT); |
||
269 |
if (flag == OPT_NO_TOGGLE) { |
||
270 |
switch (c) { |
||
271 |
case '_': |
||
272 |
/* "__" = long option name. */ |
||
273 |
optgetname = TRUE; |
||
274 |
mca_opt_toggle(); |
||
275 |
return (MCA_MORE); |
||
276 |
} |
||
277 |
} else { |
||
278 |
switch (c) { |
||
279 |
case '+': |
||
280 |
/* "-+" = UNSET. */ |
||
281 |
optflag = (flag == OPT_UNSET) ? OPT_TOGGLE : OPT_UNSET; |
||
282 |
mca_opt_toggle(); |
||
283 |
return (MCA_MORE); |
||
284 |
case '!': |
||
285 |
/* "-!" = SET */ |
||
286 |
optflag = (flag == OPT_SET) ? OPT_TOGGLE : OPT_SET; |
||
287 |
mca_opt_toggle(); |
||
288 |
return (MCA_MORE); |
||
289 |
case CONTROL('P'): |
||
290 |
optflag ^= OPT_NO_PROMPT; |
||
291 |
mca_opt_toggle(); |
||
292 |
return (MCA_MORE); |
||
293 |
case '-': |
||
294 |
/* "--" = long option name. */ |
||
295 |
optgetname = TRUE; |
||
296 |
mca_opt_toggle(); |
||
297 |
return (MCA_MORE); |
||
298 |
} |
||
299 |
} |
||
300 |
/* Char was not handled here. */ |
||
301 |
return (NO_MCA); |
||
302 |
} |
||
303 |
|||
304 |
/* |
||
305 |
* Add a char to a long option name. |
||
306 |
* See if we've got a match for an option name yet. |
||
307 |
* If so, display the complete name and stop |
||
308 |
* accepting chars until user hits RETURN. |
||
309 |
*/ |
||
310 |
static int |
||
311 |
mca_opt_nonfirst_char(int c) |
||
312 |
{ |
||
313 |
char *p; |
||
314 |
char *oname; |
||
315 |
|||
316 |
if (curropt != NULL) { |
||
317 |
/* |
||
318 |
* Already have a match for the name. |
||
319 |
* Don't accept anything but erase/kill. |
||
320 |
*/ |
||
321 |
if (is_erase_char(c)) |
||
322 |
return (MCA_DONE); |
||
323 |
return (MCA_MORE); |
||
324 |
} |
||
325 |
/* |
||
326 |
* Add char to cmd buffer and try to match |
||
327 |
* the option name. |
||
328 |
*/ |
||
329 |
if (cmd_char(c) == CC_QUIT) |
||
330 |
return (MCA_DONE); |
||
331 |
p = get_cmdbuf(); |
||
332 |
opt_lower = islower(p[0]); |
||
333 |
curropt = findopt_name(&p, &oname, NULL); |
||
334 |
if (curropt != NULL) { |
||
335 |
/* |
||
336 |
* Got a match. |
||
337 |
* Remember the option and |
||
338 |
* display the full option name. |
||
339 |
*/ |
||
340 |
cmd_reset(); |
||
341 |
mca_opt_toggle(); |
||
342 |
for (p = oname; *p != '\0'; p++) { |
||
343 |
c = *p; |
||
344 |
if (!opt_lower && islower(c)) |
||
345 |
c = toupper(c); |
||
346 |
if (cmd_char(c) != CC_OK) |
||
347 |
return (MCA_DONE); |
||
348 |
} |
||
349 |
} |
||
350 |
return (MCA_MORE); |
||
351 |
} |
||
352 |
|||
353 |
/* |
||
354 |
* Handle a char of an option toggle command. |
||
355 |
*/ |
||
356 |
static int |
||
357 |
mca_opt_char(int c) |
||
358 |
{ |
||
359 |
PARG parg; |
||
360 |
|||
361 |
/* |
||
362 |
* This may be a short option (single char), |
||
363 |
* or one char of a long option name, |
||
364 |
* or one char of the option parameter. |
||
365 |
*/ |
||
366 |
if (curropt == NULL && len_cmdbuf() == 0) { |
||
367 |
int ret = mca_opt_first_char(c); |
||
368 |
if (ret != NO_MCA) |
||
369 |
return (ret); |
||
370 |
} |
||
371 |
if (optgetname) { |
||
372 |
/* We're getting a long option name. */ |
||
373 |
if (c != '\n' && c != '\r') |
||
374 |
return (mca_opt_nonfirst_char(c)); |
||
375 |
if (curropt == NULL) { |
||
376 |
parg.p_string = get_cmdbuf(); |
||
377 |
error("There is no --%s option", &parg); |
||
378 |
return (MCA_DONE); |
||
379 |
} |
||
380 |
optgetname = FALSE; |
||
381 |
cmd_reset(); |
||
382 |
} else { |
||
383 |
if (is_erase_char(c)) |
||
384 |
return (NO_MCA); |
||
385 |
if (curropt != NULL) |
||
386 |
/* We're getting the option parameter. */ |
||
387 |
return (NO_MCA); |
||
388 |
curropt = findopt(c); |
||
389 |
if (curropt == NULL) { |
||
390 |
parg.p_string = propt(c); |
||
391 |
error("There is no %s option", &parg); |
||
392 |
return (MCA_DONE); |
||
393 |
} |
||
394 |
} |
||
395 |
/* |
||
396 |
* If the option which was entered does not take a |
||
397 |
* parameter, toggle the option immediately, |
||
398 |
* so user doesn't have to hit RETURN. |
||
399 |
*/ |
||
400 |
if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE || |
||
401 |
!opt_has_param(curropt)) { |
||
402 |
toggle_option(curropt, islower(c), "", optflag); |
||
403 |
return (MCA_DONE); |
||
404 |
} |
||
405 |
/* |
||
406 |
* Display a prompt appropriate for the option parameter. |
||
407 |
*/ |
||
408 |
start_mca(A_OPT_TOGGLE, opt_prompt(curropt), NULL, 0); |
||
409 |
return (MCA_MORE); |
||
410 |
} |
||
411 |
|||
412 |
/* |
||
413 |
* Handle a char of a search command. |
||
414 |
*/ |
||
415 |
static int |
||
416 |
mca_search_char(int c) |
||
417 |
{ |
||
418 |
int flag = 0; |
||
419 |
|||
420 |
/* |
||
421 |
* Certain characters as the first char of |
||
422 |
* the pattern have special meaning: |
||
423 |
* ! Toggle the NO_MATCH flag |
||
424 |
* * Toggle the PAST_EOF flag |
||
425 |
* @ Toggle the FIRST_FILE flag |
||
426 |
*/ |
||
427 |
✓✓ | 30 |
if (len_cmdbuf() > 0) |
428 |
12 |
return (NO_MCA); |
|
429 |
|||
430 |
✗✗✗✗ ✗✗✗✗ ✓ |
3 |
switch (c) { |
431 |
case CONTROL('E'): /* ignore END of file */ |
||
432 |
case '*': |
||
433 |
if (mca != A_FILTER) |
||
434 |
flag = SRCH_PAST_EOF; |
||
435 |
break; |
||
436 |
case CONTROL('F'): /* FIRST file */ |
||
437 |
case '@': |
||
438 |
if (mca != A_FILTER) |
||
439 |
flag = SRCH_FIRST_FILE; |
||
440 |
break; |
||
441 |
case CONTROL('K'): /* KEEP position */ |
||
442 |
if (mca != A_FILTER) |
||
443 |
flag = SRCH_NO_MOVE; |
||
444 |
break; |
||
445 |
case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */ |
||
446 |
flag = SRCH_NO_REGEX; |
||
447 |
break; |
||
448 |
case CONTROL('N'): /* NOT match */ |
||
449 |
case '!': |
||
450 |
flag = SRCH_NO_MATCH; |
||
451 |
break; |
||
452 |
} |
||
453 |
|||
454 |
✗✓ | 3 |
if (flag != 0) { |
455 |
search_type ^= flag; |
||
456 |
mca_search(); |
||
457 |
return (MCA_MORE); |
||
458 |
} |
||
459 |
3 |
return (NO_MCA); |
|
460 |
15 |
} |
|
461 |
|||
462 |
/* |
||
463 |
* Handle a character of a multi-character command. |
||
464 |
*/ |
||
465 |
static int |
||
466 |
mca_char(int c) |
||
467 |
{ |
||
468 |
int ret; |
||
469 |
|||
470 |
✗✓✗✗ ✗✗✓✓ |
237 |
switch (mca) { |
471 |
case 0: |
||
472 |
/* |
||
473 |
* We're not in a multicharacter command. |
||
474 |
*/ |
||
475 |
return (NO_MCA); |
||
476 |
|||
477 |
case A_PREFIX: |
||
478 |
/* |
||
479 |
* In the prefix of a command. |
||
480 |
* This not considered a multichar command |
||
481 |
* (even tho it uses cmdbuf, etc.). |
||
482 |
* It is handled in the commands() switch. |
||
483 |
*/ |
||
484 |
96 |
return (NO_MCA); |
|
485 |
|||
486 |
case A_DIGIT: |
||
487 |
/* |
||
488 |
* Entering digits of a number. |
||
489 |
* Terminated by a non-digit. |
||
490 |
*/ |
||
491 |
if (!((c >= '0' && c <= '9') || c == '.') && editchar(c, |
||
492 |
EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == |
||
493 |
A_INVALID) { |
||
494 |
/* |
||
495 |
* Not part of the number. |
||
496 |
* End the number and treat this char |
||
497 |
* as a normal command character. |
||
498 |
*/ |
||
499 |
number = cmd_int(&fraction); |
||
500 |
mca = 0; |
||
501 |
cmd_accept(); |
||
502 |
return (NO_MCA); |
||
503 |
} |
||
504 |
break; |
||
505 |
|||
506 |
case A_OPT_TOGGLE: |
||
507 |
ret = mca_opt_char(c); |
||
508 |
if (ret != NO_MCA) |
||
509 |
return (ret); |
||
510 |
break; |
||
511 |
|||
512 |
case A_F_SEARCH: |
||
513 |
case A_B_SEARCH: |
||
514 |
case A_FILTER: |
||
515 |
15 |
ret = mca_search_char(c); |
|
516 |
✗✓ | 15 |
if (ret != NO_MCA) |
517 |
return (ret); |
||
518 |
break; |
||
519 |
|||
520 |
default: |
||
521 |
/* Other multicharacter command. */ |
||
522 |
break; |
||
523 |
} |
||
524 |
|||
525 |
/* |
||
526 |
* The multichar command is terminated by a newline. |
||
527 |
*/ |
||
528 |
✓✓ | 15 |
if (c == '\n' || c == '\r') { |
529 |
/* |
||
530 |
* Execute the command. |
||
531 |
*/ |
||
532 |
3 |
exec_mca(); |
|
533 |
3 |
return (MCA_DONE); |
|
534 |
} |
||
535 |
|||
536 |
/* |
||
537 |
* Append the char to the command buffer. |
||
538 |
*/ |
||
539 |
✗✓ | 12 |
if (cmd_char(c) == CC_QUIT) |
540 |
/* |
||
541 |
* Abort the multi-char command. |
||
542 |
*/ |
||
543 |
return (MCA_DONE); |
||
544 |
|||
545 |
✗✓✗✗ |
12 |
if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2) { |
546 |
/* |
||
547 |
* Special case for the bracket-matching commands. |
||
548 |
* Execute the command after getting exactly two |
||
549 |
* characters from the user. |
||
550 |
*/ |
||
551 |
exec_mca(); |
||
552 |
return (MCA_DONE); |
||
553 |
} |
||
554 |
|||
555 |
/* |
||
556 |
* Need another character. |
||
557 |
*/ |
||
558 |
12 |
return (MCA_MORE); |
|
559 |
111 |
} |
|
560 |
|||
561 |
/* |
||
562 |
* Discard any buffered file data. |
||
563 |
*/ |
||
564 |
static void |
||
565 |
clear_buffers(void) |
||
566 |
{ |
||
567 |
if (!(ch_getflags() & CH_CANSEEK)) |
||
568 |
return; |
||
569 |
ch_flush(); |
||
570 |
clr_linenum(); |
||
571 |
clr_hilite(); |
||
572 |
} |
||
573 |
|||
574 |
/* |
||
575 |
* Make sure the screen is displayed. |
||
576 |
*/ |
||
577 |
static void |
||
578 |
make_display(void) |
||
579 |
{ |
||
580 |
/* |
||
581 |
* If nothing is displayed yet, display starting from initial_scrpos. |
||
582 |
*/ |
||
583 |
✓✓ | 82 |
if (empty_screen()) { |
584 |
✓✗ | 8 |
if (initial_scrpos.pos == -1) |
585 |
/* |
||
586 |
* {{ Maybe this should be: |
||
587 |
* jump_loc(ch_zero(), jump_sline); |
||
588 |
* but this behavior seems rather unexpected |
||
589 |
* on the first screen. }} |
||
590 |
*/ |
||
591 |
8 |
jump_loc(ch_zero(), 1); |
|
592 |
else |
||
593 |
jump_loc(initial_scrpos.pos, initial_scrpos.ln); |
||
594 |
✗✓ | 33 |
} else if (screen_trashed) { |
595 |
int save_top_scroll = top_scroll; |
||
596 |
int save_ignore_eoi = ignore_eoi; |
||
597 |
top_scroll = 1; |
||
598 |
ignore_eoi = 0; |
||
599 |
if (screen_trashed == 2) { |
||
600 |
/* |
||
601 |
* Special case used by ignore_eoi: re-open the input |
||
602 |
* file and jump to the end of the file. |
||
603 |
*/ |
||
604 |
reopen_curr_ifile(); |
||
605 |
jump_forw(); |
||
606 |
} |
||
607 |
repaint(); |
||
608 |
top_scroll = save_top_scroll; |
||
609 |
ignore_eoi = save_ignore_eoi; |
||
610 |
} |
||
611 |
41 |
} |
|
612 |
|||
613 |
/* |
||
614 |
* Display the appropriate prompt. |
||
615 |
*/ |
||
616 |
static void |
||
617 |
prompt(void) |
||
618 |
{ |
||
619 |
const char *p; |
||
620 |
|||
621 |
✓✓ | 88 |
if (ungot != NULL) { |
622 |
/* |
||
623 |
* No prompt necessary if commands are from |
||
624 |
* ungotten chars rather than from the user. |
||
625 |
*/ |
||
626 |
3 |
return; |
|
627 |
} |
||
628 |
|||
629 |
/* |
||
630 |
* Make sure the screen is displayed. |
||
631 |
*/ |
||
632 |
41 |
make_display(); |
|
633 |
41 |
bottompos = position(BOTTOM_PLUS_ONE); |
|
634 |
|||
635 |
/* |
||
636 |
* If we've hit EOF on the last file and the -E flag is set, quit. |
||
637 |
*/ |
||
638 |
✗✓✗✗ |
41 |
if (get_quit_at_eof() == OPT_ONPLUS && |
639 |
eof_displayed() && !(ch_getflags() & CH_HELPFILE) && |
||
640 |
next_ifile(curr_ifile) == NULL) |
||
641 |
quit(QUIT_OK); |
||
642 |
|||
643 |
/* |
||
644 |
* If the entire file is displayed and the -F flag is set, quit. |
||
645 |
*/ |
||
646 |
✗✓✗✗ |
41 |
if (quit_if_one_screen && |
647 |
entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) && |
||
648 |
next_ifile(curr_ifile) == NULL) |
||
649 |
quit(QUIT_OK); |
||
650 |
|||
651 |
/* |
||
652 |
* Select the proper prompt and display it. |
||
653 |
*/ |
||
654 |
/* |
||
655 |
* If the previous action was a forward movement, |
||
656 |
* don't clear the bottom line of the display; |
||
657 |
* just print the prompt since the forward movement guarantees |
||
658 |
* that we're in the right position to display the prompt. |
||
659 |
* Clearing the line could cause a problem: for example, if the last |
||
660 |
* line displayed ended at the right screen edge without a newline, |
||
661 |
* then clearing would clear the last displayed line rather than |
||
662 |
* the prompt line. |
||
663 |
*/ |
||
664 |
✓✓ | 41 |
if (!forw_prompt) |
665 |
16 |
clear_bot(); |
|
666 |
41 |
clear_cmd(); |
|
667 |
41 |
forw_prompt = 0; |
|
668 |
41 |
p = prompt_string(); |
|
669 |
✗✓ | 41 |
if (is_filtering()) |
670 |
putstr("& "); |
||
671 |
✓✗✓✓ |
82 |
if (p == NULL || *p == '\0') { |
672 |
18 |
putchr(':'); |
|
673 |
18 |
} else { |
|
674 |
23 |
at_enter(AT_STANDOUT); |
|
675 |
23 |
putstr(p); |
|
676 |
23 |
at_exit(); |
|
677 |
} |
||
678 |
41 |
clear_eol(); |
|
679 |
85 |
} |
|
680 |
|||
681 |
/* |
||
682 |
* Display the less version message. |
||
683 |
*/ |
||
684 |
void |
||
685 |
dispversion(void) |
||
686 |
{ |
||
687 |
PARG parg; |
||
688 |
|||
689 |
parg.p_string = version; |
||
690 |
error("less %s", &parg); |
||
691 |
} |
||
692 |
|||
693 |
/* |
||
694 |
* Get command character. |
||
695 |
* The character normally comes from the keyboard, |
||
696 |
* but may come from ungotten characters |
||
697 |
* (characters previously given to ungetcc or ungetsc). |
||
698 |
*/ |
||
699 |
int |
||
700 |
getcc(void) |
||
701 |
{ |
||
702 |
✓✓ | 310 |
if (unget_end) { |
703 |
/* |
||
704 |
* We have just run out of ungotten chars. |
||
705 |
*/ |
||
706 |
3 |
unget_end = 0; |
|
707 |
✓✓✓✗ |
5 |
if (len_cmdbuf() == 0 || !empty_screen()) |
708 |
3 |
return (getchr()); |
|
709 |
/* |
||
710 |
* Command is incomplete, so try to complete it. |
||
711 |
*/ |
||
712 |
switch (mca) { |
||
713 |
case A_DIGIT: |
||
714 |
/* |
||
715 |
* We have a number but no command. Treat as #g. |
||
716 |
*/ |
||
717 |
return ('g'); |
||
718 |
|||
719 |
case A_F_SEARCH: |
||
720 |
case A_B_SEARCH: |
||
721 |
/* |
||
722 |
* We have "/string" but no newline. Add the \n. |
||
723 |
*/ |
||
724 |
return ('\n'); |
||
725 |
|||
726 |
default: |
||
727 |
/* |
||
728 |
* Some other incomplete command. Let user complete it. |
||
729 |
*/ |
||
730 |
return (getchr()); |
||
731 |
} |
||
732 |
} |
||
733 |
|||
734 |
✓✓ | 152 |
if (ungot == NULL) { |
735 |
/* |
||
736 |
* Normal case: no ungotten chars, so get one from the user. |
||
737 |
*/ |
||
738 |
149 |
return (getchr()); |
|
739 |
} |
||
740 |
|||
741 |
/* |
||
742 |
* Return the next ungotten char. |
||
743 |
*/ |
||
744 |
{ |
||
745 |
struct ungot *ug = ungot; |
||
746 |
3 |
int c = ug->ug_char; |
|
747 |
3 |
ungot = ug->ug_next; |
|
748 |
3 |
free(ug); |
|
749 |
3 |
unget_end = (ungot == NULL); |
|
750 |
return (c); |
||
751 |
} |
||
752 |
155 |
} |
|
753 |
|||
754 |
/* |
||
755 |
* "Unget" a command character. |
||
756 |
* The next getcc() will return this character. |
||
757 |
*/ |
||
758 |
void |
||
759 |
ungetcc(int c) |
||
760 |
{ |
||
761 |
6 |
struct ungot *ug = ecalloc(1, sizeof (struct ungot)); |
|
762 |
|||
763 |
3 |
ug->ug_char = c; |
|
764 |
3 |
ug->ug_next = ungot; |
|
765 |
3 |
ungot = ug; |
|
766 |
3 |
unget_end = 0; |
|
767 |
3 |
} |
|
768 |
|||
769 |
/* |
||
770 |
* Unget a whole string of command characters. |
||
771 |
* The next sequence of getcc()'s will return this string. |
||
772 |
*/ |
||
773 |
void |
||
774 |
ungetsc(char *s) |
||
775 |
{ |
||
776 |
char *p; |
||
777 |
|||
778 |
for (p = s + strlen(s) - 1; p >= s; p--) |
||
779 |
ungetcc(*p); |
||
780 |
} |
||
781 |
|||
782 |
/* |
||
783 |
* Search for a pattern, possibly in multiple files. |
||
784 |
* If SRCH_FIRST_FILE is set, begin searching at the first file. |
||
785 |
* If SRCH_PAST_EOF is set, continue the search thru multiple files. |
||
786 |
*/ |
||
787 |
static void |
||
788 |
multi_search(char *pattern, int n) |
||
789 |
{ |
||
790 |
int nomore; |
||
791 |
IFILE save_ifile; |
||
792 |
int changed_file; |
||
793 |
|||
794 |
changed_file = 0; |
||
795 |
8 |
save_ifile = save_curr_ifile(); |
|
796 |
|||
797 |
✗✓ | 4 |
if (search_type & SRCH_FIRST_FILE) { |
798 |
/* |
||
799 |
* Start at the first (or last) file |
||
800 |
* in the command line list. |
||
801 |
*/ |
||
802 |
if (search_type & SRCH_FORW) |
||
803 |
nomore = edit_first(); |
||
804 |
else |
||
805 |
nomore = edit_last(); |
||
806 |
if (nomore) { |
||
807 |
unsave_ifile(save_ifile); |
||
808 |
return; |
||
809 |
} |
||
810 |
changed_file = 1; |
||
811 |
search_type &= ~SRCH_FIRST_FILE; |
||
812 |
} |
||
813 |
|||
814 |
4 |
for (;;) { |
|
815 |
4 |
n = search(search_type, pattern, n); |
|
816 |
/* |
||
817 |
* The SRCH_NO_MOVE flag doesn't "stick": it gets cleared |
||
818 |
* after being used once. This allows "n" to work after |
||
819 |
* using a /@@ search. |
||
820 |
*/ |
||
821 |
4 |
search_type &= ~SRCH_NO_MOVE; |
|
822 |
✓✓ | 4 |
if (n == 0) { |
823 |
/* |
||
824 |
* Found it. |
||
825 |
*/ |
||
826 |
1 |
unsave_ifile(save_ifile); |
|
827 |
1 |
return; |
|
828 |
} |
||
829 |
|||
830 |
✓✓ | 3 |
if (n < 0) |
831 |
/* |
||
832 |
* Some kind of error in the search. |
||
833 |
* Error message has been printed by search(). |
||
834 |
*/ |
||
835 |
break; |
||
836 |
|||
837 |
✗✓ | 2 |
if ((search_type & SRCH_PAST_EOF) == 0) |
838 |
/* |
||
839 |
* We didn't find a match, but we're |
||
840 |
* supposed to search only one file. |
||
841 |
*/ |
||
842 |
break; |
||
843 |
/* |
||
844 |
* Move on to the next file. |
||
845 |
*/ |
||
846 |
if (search_type & SRCH_FORW) |
||
847 |
nomore = edit_next(1); |
||
848 |
else |
||
849 |
nomore = edit_prev(1); |
||
850 |
if (nomore) |
||
851 |
break; |
||
852 |
changed_file = 1; |
||
853 |
} |
||
854 |
|||
855 |
/* |
||
856 |
* Didn't find it. |
||
857 |
* Print an error message if we haven't already. |
||
858 |
*/ |
||
859 |
✓✓ | 3 |
if (n > 0) |
860 |
2 |
error("Pattern not found", NULL); |
|
861 |
|||
862 |
✗✓ | 3 |
if (changed_file) { |
863 |
/* |
||
864 |
* Restore the file we were originally viewing. |
||
865 |
*/ |
||
866 |
reedit_ifile(save_ifile); |
||
867 |
} else { |
||
868 |
3 |
unsave_ifile(save_ifile); |
|
869 |
} |
||
870 |
7 |
} |
|
871 |
|||
872 |
/* |
||
873 |
* Forward forever, or until a highlighted line appears. |
||
874 |
*/ |
||
875 |
static int |
||
876 |
forw_loop(int until_hilite) |
||
877 |
{ |
||
878 |
off_t curr_len; |
||
879 |
|||
880 |
if (ch_getflags() & CH_HELPFILE) |
||
881 |
return (A_NOACTION); |
||
882 |
|||
883 |
cmd_exec(); |
||
884 |
jump_forw(); |
||
885 |
curr_len = ch_length(); |
||
886 |
highest_hilite = until_hilite ? curr_len : -1; |
||
887 |
ignore_eoi = 1; |
||
888 |
while (!sigs) { |
||
889 |
if (until_hilite && highest_hilite > curr_len) { |
||
890 |
ring_bell(); |
||
891 |
break; |
||
892 |
} |
||
893 |
make_display(); |
||
894 |
forward(1, 0, 0); |
||
895 |
} |
||
896 |
ignore_eoi = 0; |
||
897 |
ch_set_eof(); |
||
898 |
|||
899 |
/* |
||
900 |
* This gets us back in "F mode" after processing |
||
901 |
* a non-abort signal (e.g. window-change). |
||
902 |
*/ |
||
903 |
if (sigs && !ABORT_SIGS()) |
||
904 |
return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER); |
||
905 |
|||
906 |
return (A_NOACTION); |
||
907 |
} |
||
908 |
|||
909 |
/* |
||
910 |
* Main command processor. |
||
911 |
* Accept and execute commands until a quit command. |
||
912 |
*/ |
||
913 |
void |
||
914 |
commands(void) |
||
915 |
{ |
||
916 |
int c = 0; |
||
917 |
int action; |
||
918 |
char *cbuf; |
||
919 |
int newaction; |
||
920 |
int save_search_type; |
||
921 |
16 |
char *extra; |
|
922 |
8 |
char tbuf[2]; |
|
923 |
8 |
PARG parg; |
|
924 |
IFILE old_ifile; |
||
925 |
IFILE new_ifile; |
||
926 |
char *tagfile; |
||
927 |
|||
928 |
8 |
search_type = SRCH_FORW; |
|
929 |
8 |
wscroll = (sc_height + 1) / 2; |
|
930 |
newaction = A_NOACTION; |
||
931 |
|||
932 |
41 |
for (;;) { |
|
933 |
44 |
mca = 0; |
|
934 |
44 |
cmd_accept(); |
|
935 |
44 |
number = 0; |
|
936 |
44 |
curropt = NULL; |
|
937 |
|||
938 |
/* |
||
939 |
* See if any signals need processing. |
||
940 |
*/ |
||
941 |
✗✓ | 44 |
if (sigs) { |
942 |
psignals(); |
||
943 |
if (quitting) |
||
944 |
quit(QUIT_SAVED_STATUS); |
||
945 |
} |
||
946 |
|||
947 |
/* |
||
948 |
* Display prompt and accept a character. |
||
949 |
*/ |
||
950 |
44 |
cmd_reset(); |
|
951 |
44 |
prompt(); |
|
952 |
✗✓ | 44 |
if (sigs) |
953 |
continue; |
||
954 |
✓✗ | 88 |
if (newaction == A_NOACTION) |
955 |
44 |
c = getcc(); |
|
956 |
|||
957 |
again: |
||
958 |
✗✓ | 155 |
if (sigs) |
959 |
continue; |
||
960 |
|||
961 |
✗✓ | 155 |
if (newaction != A_NOACTION) { |
962 |
action = newaction; |
||
963 |
newaction = A_NOACTION; |
||
964 |
} else { |
||
965 |
/* |
||
966 |
* If we are in a multicharacter command, call mca_char. |
||
967 |
* Otherwise we call fcmd_decode to determine the |
||
968 |
* action to be performed. |
||
969 |
*/ |
||
970 |
✓✓ | 155 |
if (mca) |
971 |
✓✓✓ | 114 |
switch (mca_char(c)) { |
972 |
case MCA_MORE: |
||
973 |
/* |
||
974 |
* Need another character. |
||
975 |
*/ |
||
976 |
12 |
c = getcc(); |
|
977 |
12 |
goto again; |
|
978 |
case MCA_DONE: |
||
979 |
/* |
||
980 |
* Command has been handled by mca_char. |
||
981 |
* Start clean with a prompt. |
||
982 |
*/ |
||
983 |
3 |
continue; |
|
984 |
case NO_MCA: |
||
985 |
/* |
||
986 |
* Not a multi-char command |
||
987 |
* (at least, not anymore). |
||
988 |
*/ |
||
989 |
break; |
||
990 |
} |
||
991 |
|||
992 |
/* |
||
993 |
* Decode the command character and decide what to do. |
||
994 |
*/ |
||
995 |
✓✓ | 140 |
if (mca) { |
996 |
/* |
||
997 |
* We're in a multichar command. |
||
998 |
* Add the character to the command buffer |
||
999 |
* and display it on the screen. |
||
1000 |
* If the user backspaces past the start |
||
1001 |
* of the line, abort the command. |
||
1002 |
*/ |
||
1003 |
✓✗✗✓ |
192 |
if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0) |
1004 |
continue; |
||
1005 |
96 |
cbuf = get_cmdbuf(); |
|
1006 |
96 |
} else { |
|
1007 |
/* |
||
1008 |
* Don't use cmd_char if we're starting fresh |
||
1009 |
* at the beginning of a command, because we |
||
1010 |
* don't want to echo the command until we know |
||
1011 |
* it is a multichar command. We also don't |
||
1012 |
* want erase_char/kill_char to be treated |
||
1013 |
* as line editing characters. |
||
1014 |
*/ |
||
1015 |
44 |
tbuf[0] = (char)c; |
|
1016 |
44 |
tbuf[1] = '\0'; |
|
1017 |
44 |
cbuf = tbuf; |
|
1018 |
} |
||
1019 |
140 |
extra = NULL; |
|
1020 |
140 |
action = fcmd_decode(cbuf, &extra); |
|
1021 |
/* |
||
1022 |
* If an "extra" string was returned, |
||
1023 |
* process it as a string of command characters. |
||
1024 |
*/ |
||
1025 |
✗✓ | 140 |
if (extra != NULL) |
1026 |
ungetsc(extra); |
||
1027 |
} |
||
1028 |
/* |
||
1029 |
* Clear the cmdbuf string. |
||
1030 |
* (But not if we're in the prefix of a command, |
||
1031 |
* because the partial command string is kept there.) |
||
1032 |
*/ |
||
1033 |
✓✓ | 140 |
if (action != A_PREFIX) |
1034 |
44 |
cmd_reset(); |
|
1035 |
|||
1036 |
✗✗✓✗ ✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✓✗✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✗✓ |
173 |
switch (action) { |
1037 |
case A_DIGIT: |
||
1038 |
/* |
||
1039 |
* First digit of a number. |
||
1040 |
*/ |
||
1041 |
start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE); |
||
1042 |
goto again; |
||
1043 |
|||
1044 |
case A_F_WINDOW: |
||
1045 |
/* |
||
1046 |
* Forward one window (and set the window size). |
||
1047 |
*/ |
||
1048 |
if (number > 0) |
||
1049 |
swindow = (int)number; |
||
1050 |
/* FALLTHRU */ |
||
1051 |
case A_F_SCREEN: |
||
1052 |
/* |
||
1053 |
* Forward one screen. |
||
1054 |
*/ |
||
1055 |
✓✗ | 22 |
if (number <= 0) |
1056 |
22 |
number = get_swindow(); |
|
1057 |
22 |
cmd_exec(); |
|
1058 |
✗✓ | 22 |
if (show_attn) |
1059 |
set_attnpos(bottompos); |
||
1060 |
22 |
forward((int)number, 0, 1); |
|
1061 |
22 |
break; |
|
1062 |
|||
1063 |
case A_B_WINDOW: |
||
1064 |
/* |
||
1065 |
* Backward one window (and set the window size). |
||
1066 |
*/ |
||
1067 |
if (number > 0) |
||
1068 |
swindow = (int)number; |
||
1069 |
/* FALLTHRU */ |
||
1070 |
case A_B_SCREEN: |
||
1071 |
/* |
||
1072 |
* Backward one screen. |
||
1073 |
*/ |
||
1074 |
✓✗ | 10 |
if (number <= 0) |
1075 |
10 |
number = get_swindow(); |
|
1076 |
10 |
cmd_exec(); |
|
1077 |
10 |
backward((int)number, 0, 1); |
|
1078 |
10 |
break; |
|
1079 |
|||
1080 |
case A_F_LINE: |
||
1081 |
/* |
||
1082 |
* Forward N (default 1) line. |
||
1083 |
*/ |
||
1084 |
if (number <= 0) |
||
1085 |
number = 1; |
||
1086 |
cmd_exec(); |
||
1087 |
if (show_attn == OPT_ONPLUS && number > 1) |
||
1088 |
set_attnpos(bottompos); |
||
1089 |
forward((int)number, 0, 0); |
||
1090 |
break; |
||
1091 |
|||
1092 |
case A_B_LINE: |
||
1093 |
/* |
||
1094 |
* Backward N (default 1) line. |
||
1095 |
*/ |
||
1096 |
if (number <= 0) |
||
1097 |
number = 1; |
||
1098 |
cmd_exec(); |
||
1099 |
backward((int)number, 0, 0); |
||
1100 |
break; |
||
1101 |
|||
1102 |
case A_F_SKIP: |
||
1103 |
/* |
||
1104 |
* Skip ahead one screen, and then number lines. |
||
1105 |
*/ |
||
1106 |
if (number <= 0) { |
||
1107 |
number = get_swindow(); |
||
1108 |
} else { |
||
1109 |
number += get_swindow(); |
||
1110 |
} |
||
1111 |
cmd_exec(); |
||
1112 |
if (show_attn == OPT_ONPLUS) |
||
1113 |
set_attnpos(bottompos); |
||
1114 |
forward((int)number, 0, 1); |
||
1115 |
break; |
||
1116 |
|||
1117 |
case A_FF_LINE: |
||
1118 |
/* |
||
1119 |
* Force forward N (default 1) line. |
||
1120 |
*/ |
||
1121 |
if (number <= 0) |
||
1122 |
number = 1; |
||
1123 |
cmd_exec(); |
||
1124 |
if (show_attn == OPT_ONPLUS && number > 1) |
||
1125 |
set_attnpos(bottompos); |
||
1126 |
forward((int)number, 1, 0); |
||
1127 |
break; |
||
1128 |
|||
1129 |
case A_BF_LINE: |
||
1130 |
/* |
||
1131 |
* Force backward N (default 1) line. |
||
1132 |
*/ |
||
1133 |
if (number <= 0) |
||
1134 |
number = 1; |
||
1135 |
cmd_exec(); |
||
1136 |
backward((int)number, 1, 0); |
||
1137 |
break; |
||
1138 |
|||
1139 |
case A_FF_SCREEN: |
||
1140 |
/* |
||
1141 |
* Force forward one screen. |
||
1142 |
*/ |
||
1143 |
if (number <= 0) |
||
1144 |
number = get_swindow(); |
||
1145 |
cmd_exec(); |
||
1146 |
if (show_attn == OPT_ONPLUS) |
||
1147 |
set_attnpos(bottompos); |
||
1148 |
forward((int)number, 1, 0); |
||
1149 |
break; |
||
1150 |
|||
1151 |
case A_F_FOREVER: |
||
1152 |
/* |
||
1153 |
* Forward forever, ignoring EOF. |
||
1154 |
*/ |
||
1155 |
newaction = forw_loop(0); |
||
1156 |
break; |
||
1157 |
|||
1158 |
case A_F_UNTIL_HILITE: |
||
1159 |
newaction = forw_loop(1); |
||
1160 |
break; |
||
1161 |
|||
1162 |
case A_F_SCROLL: |
||
1163 |
/* |
||
1164 |
* Forward N lines |
||
1165 |
* (default same as last 'd' or 'u' command). |
||
1166 |
*/ |
||
1167 |
if (number > 0) |
||
1168 |
wscroll = (int)number; |
||
1169 |
cmd_exec(); |
||
1170 |
if (show_attn == OPT_ONPLUS) |
||
1171 |
set_attnpos(bottompos); |
||
1172 |
forward(wscroll, 0, 0); |
||
1173 |
break; |
||
1174 |
|||
1175 |
case A_B_SCROLL: |
||
1176 |
/* |
||
1177 |
* Forward N lines |
||
1178 |
* (default same as last 'd' or 'u' command). |
||
1179 |
*/ |
||
1180 |
if (number > 0) |
||
1181 |
wscroll = (int)number; |
||
1182 |
cmd_exec(); |
||
1183 |
backward(wscroll, 0, 0); |
||
1184 |
break; |
||
1185 |
|||
1186 |
case A_FREPAINT: |
||
1187 |
/* |
||
1188 |
* Flush buffers, then repaint screen. |
||
1189 |
* Don't flush the buffers on a pipe! |
||
1190 |
*/ |
||
1191 |
clear_buffers(); |
||
1192 |
/* FALLTHRU */ |
||
1193 |
case A_REPAINT: |
||
1194 |
/* |
||
1195 |
* Repaint screen. |
||
1196 |
*/ |
||
1197 |
cmd_exec(); |
||
1198 |
repaint(); |
||
1199 |
break; |
||
1200 |
|||
1201 |
case A_GOLINE: |
||
1202 |
/* |
||
1203 |
* Go to line N, default beginning of file. |
||
1204 |
*/ |
||
1205 |
if (number <= 0) |
||
1206 |
number = 1; |
||
1207 |
cmd_exec(); |
||
1208 |
jump_back(number); |
||
1209 |
break; |
||
1210 |
|||
1211 |
case A_PERCENT: |
||
1212 |
/* |
||
1213 |
* Go to a specified percentage into the file. |
||
1214 |
*/ |
||
1215 |
if (number < 0) { |
||
1216 |
number = 0; |
||
1217 |
fraction = 0; |
||
1218 |
} |
||
1219 |
if (number > 100) { |
||
1220 |
number = 100; |
||
1221 |
fraction = 0; |
||
1222 |
} |
||
1223 |
cmd_exec(); |
||
1224 |
jump_percent((int)number, fraction); |
||
1225 |
break; |
||
1226 |
|||
1227 |
case A_GOEND: |
||
1228 |
/* |
||
1229 |
* Go to line N, default end of file. |
||
1230 |
*/ |
||
1231 |
cmd_exec(); |
||
1232 |
if (number <= 0) |
||
1233 |
jump_forw(); |
||
1234 |
else |
||
1235 |
jump_back(number); |
||
1236 |
break; |
||
1237 |
|||
1238 |
case A_GOPOS: |
||
1239 |
/* |
||
1240 |
* Go to a specified byte position in the file. |
||
1241 |
*/ |
||
1242 |
cmd_exec(); |
||
1243 |
if (number < 0) |
||
1244 |
number = 0; |
||
1245 |
jump_line_loc((off_t) number, jump_sline); |
||
1246 |
break; |
||
1247 |
|||
1248 |
case A_STAT: |
||
1249 |
/* |
||
1250 |
* Print file name, etc. |
||
1251 |
*/ |
||
1252 |
if (ch_getflags() & CH_HELPFILE) |
||
1253 |
break; |
||
1254 |
cmd_exec(); |
||
1255 |
parg.p_string = eq_message(); |
||
1256 |
error("%s", &parg); |
||
1257 |
break; |
||
1258 |
|||
1259 |
case A_VERSION: |
||
1260 |
/* |
||
1261 |
* Print version number, without the "@(#)". |
||
1262 |
*/ |
||
1263 |
cmd_exec(); |
||
1264 |
dispversion(); |
||
1265 |
break; |
||
1266 |
|||
1267 |
case A_QUIT: |
||
1268 |
/* |
||
1269 |
* Exit. |
||
1270 |
*/ |
||
1271 |
✓✗✗✓ |
16 |
if (curr_ifile != NULL && |
1272 |
8 |
ch_getflags() & CH_HELPFILE) { |
|
1273 |
/* |
||
1274 |
* Quit while viewing the help file |
||
1275 |
* just means return to viewing the |
||
1276 |
* previous file. |
||
1277 |
*/ |
||
1278 |
hshift = save_hshift; |
||
1279 |
if (edit_prev(1) == 0) |
||
1280 |
break; |
||
1281 |
} |
||
1282 |
✗✓ | 8 |
if (extra != NULL) |
1283 |
quit(*extra); |
||
1284 |
8 |
quit(QUIT_OK); |
|
1285 |
8 |
break; |
|
1286 |
|||
1287 |
/* |
||
1288 |
* Define abbreviation for a commonly used sequence below. |
||
1289 |
*/ |
||
1290 |
#define DO_SEARCH() \ |
||
1291 |
if (number <= 0) number = 1; \ |
||
1292 |
mca_search(); \ |
||
1293 |
cmd_exec(); \ |
||
1294 |
multi_search(NULL, (int)number); |
||
1295 |
|||
1296 |
|||
1297 |
case A_F_SEARCH: |
||
1298 |
/* |
||
1299 |
* Search forward for a pattern. |
||
1300 |
* Get the first char of the pattern. |
||
1301 |
*/ |
||
1302 |
3 |
search_type = SRCH_FORW; |
|
1303 |
✓✗ | 3 |
if (number <= 0) |
1304 |
3 |
number = 1; |
|
1305 |
3 |
mca_search(); |
|
1306 |
3 |
c = getcc(); |
|
1307 |
3 |
goto again; |
|
1308 |
|||
1309 |
case A_B_SEARCH: |
||
1310 |
/* |
||
1311 |
* Search backward for a pattern. |
||
1312 |
* Get the first char of the pattern. |
||
1313 |
*/ |
||
1314 |
search_type = SRCH_BACK; |
||
1315 |
if (number <= 0) |
||
1316 |
number = 1; |
||
1317 |
mca_search(); |
||
1318 |
c = getcc(); |
||
1319 |
goto again; |
||
1320 |
|||
1321 |
case A_FILTER: |
||
1322 |
search_type = SRCH_FORW | SRCH_FILTER; |
||
1323 |
mca_search(); |
||
1324 |
c = getcc(); |
||
1325 |
goto again; |
||
1326 |
|||
1327 |
case A_AGAIN_SEARCH: |
||
1328 |
/* |
||
1329 |
* Repeat previous search. |
||
1330 |
*/ |
||
1331 |
✓✗ | 3 |
DO_SEARCH(); |
1332 |
1 |
break; |
|
1333 |
|||
1334 |
case A_T_AGAIN_SEARCH: |
||
1335 |
/* |
||
1336 |
* Repeat previous search, multiple files. |
||
1337 |
*/ |
||
1338 |
search_type |= SRCH_PAST_EOF; |
||
1339 |
DO_SEARCH(); |
||
1340 |
break; |
||
1341 |
|||
1342 |
case A_REVERSE_SEARCH: |
||
1343 |
/* |
||
1344 |
* Repeat previous search, in reverse direction. |
||
1345 |
*/ |
||
1346 |
save_search_type = search_type; |
||
1347 |
search_type = SRCH_REVERSE(search_type); |
||
1348 |
DO_SEARCH(); |
||
1349 |
search_type = save_search_type; |
||
1350 |
break; |
||
1351 |
|||
1352 |
case A_T_REVERSE_SEARCH: |
||
1353 |
/* |
||
1354 |
* Repeat previous search, |
||
1355 |
* multiple files in reverse direction. |
||
1356 |
*/ |
||
1357 |
save_search_type = search_type; |
||
1358 |
search_type = SRCH_REVERSE(search_type); |
||
1359 |
search_type |= SRCH_PAST_EOF; |
||
1360 |
DO_SEARCH(); |
||
1361 |
search_type = save_search_type; |
||
1362 |
break; |
||
1363 |
|||
1364 |
case A_UNDO_SEARCH: |
||
1365 |
undo_search(); |
||
1366 |
break; |
||
1367 |
|||
1368 |
case A_HELP: |
||
1369 |
/* |
||
1370 |
* Help. |
||
1371 |
*/ |
||
1372 |
if (ch_getflags() & CH_HELPFILE) |
||
1373 |
break; |
||
1374 |
if (ungot != NULL || unget_end) { |
||
1375 |
error(less_is_more |
||
1376 |
? "Invalid option -p h" |
||
1377 |
: "Invalid option ++h", |
||
1378 |
NULL); |
||
1379 |
break; |
||
1380 |
} |
||
1381 |
cmd_exec(); |
||
1382 |
save_hshift = hshift; |
||
1383 |
hshift = 0; |
||
1384 |
(void) edit(helpfile()); |
||
1385 |
break; |
||
1386 |
|||
1387 |
case A_EXAMINE: |
||
1388 |
/* |
||
1389 |
* Edit a new file. Get the filename. |
||
1390 |
*/ |
||
1391 |
if (secure) { |
||
1392 |
error("Command not available", NULL); |
||
1393 |
break; |
||
1394 |
} |
||
1395 |
start_mca(A_EXAMINE, "Examine: ", ml_examine, 0); |
||
1396 |
c = getcc(); |
||
1397 |
goto again; |
||
1398 |
|||
1399 |
case A_VISUAL: |
||
1400 |
/* |
||
1401 |
* Invoke an editor on the input file. |
||
1402 |
*/ |
||
1403 |
if (secure) { |
||
1404 |
error("Command not available", NULL); |
||
1405 |
break; |
||
1406 |
} |
||
1407 |
if (ch_getflags() & CH_HELPFILE) |
||
1408 |
break; |
||
1409 |
if (strcmp(get_filename(curr_ifile), "-") == 0) { |
||
1410 |
error("Cannot edit standard input", NULL); |
||
1411 |
break; |
||
1412 |
} |
||
1413 |
if (curr_altfilename != NULL) { |
||
1414 |
error("WARNING: This file was viewed via " |
||
1415 |
"LESSOPEN", NULL); |
||
1416 |
} |
||
1417 |
/* |
||
1418 |
* Expand the editor prototype string |
||
1419 |
* and pass it to the system to execute. |
||
1420 |
* (Make sure the screen is displayed so the |
||
1421 |
* expansion of "+%lm" works.) |
||
1422 |
*/ |
||
1423 |
make_display(); |
||
1424 |
cmd_exec(); |
||
1425 |
lsystem(pr_expand(editproto, 0), NULL); |
||
1426 |
break; |
||
1427 |
|||
1428 |
case A_NEXT_FILE: |
||
1429 |
/* |
||
1430 |
* Examine next file. |
||
1431 |
*/ |
||
1432 |
if (ntags()) { |
||
1433 |
error("No next file", NULL); |
||
1434 |
break; |
||
1435 |
} |
||
1436 |
if (number <= 0) |
||
1437 |
number = 1; |
||
1438 |
if (edit_next((int)number)) { |
||
1439 |
if (get_quit_at_eof() && eof_displayed() && |
||
1440 |
!(ch_getflags() & CH_HELPFILE)) |
||
1441 |
quit(QUIT_OK); |
||
1442 |
parg.p_string = (number > 1) ? "(N-th) " : ""; |
||
1443 |
error("No %snext file", &parg); |
||
1444 |
} |
||
1445 |
break; |
||
1446 |
|||
1447 |
case A_PREV_FILE: |
||
1448 |
/* |
||
1449 |
* Examine previous file. |
||
1450 |
*/ |
||
1451 |
if (ntags()) { |
||
1452 |
error("No previous file", NULL); |
||
1453 |
break; |
||
1454 |
} |
||
1455 |
if (number <= 0) |
||
1456 |
number = 1; |
||
1457 |
if (edit_prev((int)number)) { |
||
1458 |
parg.p_string = (number > 1) ? "(N-th) " : ""; |
||
1459 |
error("No %sprevious file", &parg); |
||
1460 |
} |
||
1461 |
break; |
||
1462 |
|||
1463 |
case A_NEXT_TAG: |
||
1464 |
if (number <= 0) |
||
1465 |
number = 1; |
||
1466 |
cmd_exec(); |
||
1467 |
tagfile = nexttag((int)number); |
||
1468 |
if (tagfile == NULL) { |
||
1469 |
error("No next tag", NULL); |
||
1470 |
break; |
||
1471 |
} |
||
1472 |
if (edit(tagfile) == 0) { |
||
1473 |
off_t pos = tagsearch(); |
||
1474 |
if (pos != -1) |
||
1475 |
jump_loc(pos, jump_sline); |
||
1476 |
} |
||
1477 |
break; |
||
1478 |
|||
1479 |
case A_PREV_TAG: |
||
1480 |
if (number <= 0) |
||
1481 |
number = 1; |
||
1482 |
tagfile = prevtag((int)number); |
||
1483 |
if (tagfile == NULL) { |
||
1484 |
error("No previous tag", NULL); |
||
1485 |
break; |
||
1486 |
} |
||
1487 |
if (edit(tagfile) == 0) { |
||
1488 |
off_t pos = tagsearch(); |
||
1489 |
if (pos != -1) |
||
1490 |
jump_loc(pos, jump_sline); |
||
1491 |
} |
||
1492 |
break; |
||
1493 |
|||
1494 |
case A_INDEX_FILE: |
||
1495 |
/* |
||
1496 |
* Examine a particular file. |
||
1497 |
*/ |
||
1498 |
if (number <= 0) |
||
1499 |
number = 1; |
||
1500 |
if (edit_index((int)number)) |
||
1501 |
error("No such file", NULL); |
||
1502 |
break; |
||
1503 |
|||
1504 |
case A_REMOVE_FILE: |
||
1505 |
if (ch_getflags() & CH_HELPFILE) |
||
1506 |
break; |
||
1507 |
old_ifile = curr_ifile; |
||
1508 |
new_ifile = getoff_ifile(curr_ifile); |
||
1509 |
if (new_ifile == NULL) { |
||
1510 |
ring_bell(); |
||
1511 |
break; |
||
1512 |
} |
||
1513 |
if (edit_ifile(new_ifile) != 0) { |
||
1514 |
reedit_ifile(old_ifile); |
||
1515 |
break; |
||
1516 |
} |
||
1517 |
del_ifile(old_ifile); |
||
1518 |
break; |
||
1519 |
|||
1520 |
case A_OPT_TOGGLE: |
||
1521 |
optflag = OPT_TOGGLE; |
||
1522 |
optgetname = FALSE; |
||
1523 |
mca_opt_toggle(); |
||
1524 |
c = getcc(); |
||
1525 |
goto again; |
||
1526 |
|||
1527 |
case A_DISP_OPTION: |
||
1528 |
/* |
||
1529 |
* Report a flag setting. |
||
1530 |
*/ |
||
1531 |
optflag = OPT_NO_TOGGLE; |
||
1532 |
optgetname = FALSE; |
||
1533 |
mca_opt_toggle(); |
||
1534 |
c = getcc(); |
||
1535 |
goto again; |
||
1536 |
|||
1537 |
case A_FIRSTCMD: |
||
1538 |
/* |
||
1539 |
* Set an initial command for new files. |
||
1540 |
*/ |
||
1541 |
start_mca(A_FIRSTCMD, "+", NULL, 0); |
||
1542 |
c = getcc(); |
||
1543 |
goto again; |
||
1544 |
|||
1545 |
case A_SETMARK: |
||
1546 |
/* |
||
1547 |
* Set a mark. |
||
1548 |
*/ |
||
1549 |
if (ch_getflags() & CH_HELPFILE) |
||
1550 |
break; |
||
1551 |
start_mca(A_SETMARK, "mark: ", (void*)NULL, 0); |
||
1552 |
c = getcc(); |
||
1553 |
if (c == erase_char || c == erase2_char || |
||
1554 |
c == kill_char || c == '\n' || c == '\r') |
||
1555 |
break; |
||
1556 |
setmark(c); |
||
1557 |
break; |
||
1558 |
|||
1559 |
case A_GOMARK: |
||
1560 |
/* |
||
1561 |
* Go to a mark. |
||
1562 |
*/ |
||
1563 |
start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0); |
||
1564 |
c = getcc(); |
||
1565 |
if (c == erase_char || c == erase2_char || |
||
1566 |
c == kill_char || c == '\n' || c == '\r') |
||
1567 |
break; |
||
1568 |
cmd_exec(); |
||
1569 |
gomark(c); |
||
1570 |
break; |
||
1571 |
|||
1572 |
case A_PIPE: |
||
1573 |
if (secure) { |
||
1574 |
error("Command not available", NULL); |
||
1575 |
break; |
||
1576 |
} |
||
1577 |
start_mca(A_PIPE, "|mark: ", (void*)NULL, 0); |
||
1578 |
c = getcc(); |
||
1579 |
if (c == erase_char || c == erase2_char || |
||
1580 |
c == kill_char) |
||
1581 |
break; |
||
1582 |
if (c == '\n' || c == '\r') |
||
1583 |
c = '.'; |
||
1584 |
if (badmark(c)) |
||
1585 |
break; |
||
1586 |
pipec = c; |
||
1587 |
start_mca(A_PIPE, "!", ml_shell, 0); |
||
1588 |
c = getcc(); |
||
1589 |
goto again; |
||
1590 |
|||
1591 |
case A_B_BRACKET: |
||
1592 |
case A_F_BRACKET: |
||
1593 |
start_mca(action, "Brackets: ", (void*)NULL, 0); |
||
1594 |
c = getcc(); |
||
1595 |
goto again; |
||
1596 |
|||
1597 |
case A_LSHIFT: |
||
1598 |
if (number > 0) |
||
1599 |
shift_count = number; |
||
1600 |
else |
||
1601 |
number = (shift_count > 0) ? |
||
1602 |
shift_count : sc_width / 2; |
||
1603 |
if (number > hshift) |
||
1604 |
number = hshift; |
||
1605 |
hshift -= number; |
||
1606 |
screen_trashed = 1; |
||
1607 |
break; |
||
1608 |
|||
1609 |
case A_RSHIFT: |
||
1610 |
if (number > 0) |
||
1611 |
shift_count = number; |
||
1612 |
else |
||
1613 |
number = (shift_count > 0) ? |
||
1614 |
shift_count : sc_width / 2; |
||
1615 |
hshift += number; |
||
1616 |
screen_trashed = 1; |
||
1617 |
break; |
||
1618 |
|||
1619 |
case A_PREFIX: |
||
1620 |
/* |
||
1621 |
* The command is incomplete (more chars are needed). |
||
1622 |
* Display the current char, so the user knows |
||
1623 |
* what's going on, and get another character. |
||
1624 |
*/ |
||
1625 |
✓✓ | 96 |
if (mca != A_PREFIX) { |
1626 |
32 |
cmd_reset(); |
|
1627 |
32 |
start_mca(A_PREFIX, " ", (void*)NULL, |
|
1628 |
CF_QUIT_ON_ERASE); |
||
1629 |
32 |
(void) cmd_char(c); |
|
1630 |
32 |
} |
|
1631 |
96 |
c = getcc(); |
|
1632 |
96 |
goto again; |
|
1633 |
|||
1634 |
case A_NOACTION: |
||
1635 |
break; |
||
1636 |
|||
1637 |
default: |
||
1638 |
ring_bell(); |
||
1639 |
break; |
||
1640 |
} |
||
1641 |
} |
||
1642 |
} |
Generated by: GCOVR (Version 3.3) |