1 /* Copyright (c) 1985 Ceriel J.H. Jacobs */
4 static char rcsid
[] = "$Header$";
10 # include "commands.h"
31 # include <sys/file.h>
36 # include <sys/types.h>
41 char *strcpy(), *strcat();
43 static long lastcount
; /* Save last count for '.' command */
44 static int lastcomm
; /* Save last command for '.' command */
48 do_nocomm(cnt
) long cnt
; { /* Do nothing */
53 do_chkm(cnt
) long cnt
; { /* Change key map */
54 register struct keymap
*p
;
56 if (!(p
= othermap
)) {
57 error("No other keymap");
64 static int searchdir
; /* Direction of last search */
71 do_search(str
,cnt
,dir
) char *str
; long cnt
; int dir
; {
77 * We have to get a pattern, which we have to prompt for
78 * with the string "str".
80 if ((p
= readline(str
)) == 0) {
82 * User cancelled command
86 if ((p
= re_comp(p
))) {
88 * There was an error in the pattern
95 if (dir
< 0) lineno
= scr_info
.firstline
;
96 else lineno
= scr_info
.lastline
;
99 if ((lineno
+= dir
) > 0) p
= getline(lineno
, 0);
100 if (interrupt
) return;
101 if (!p
) { /* End of file reached */
102 error("pattern not found");
105 if (re_exec(p
) && --cnt
<= 0) {
107 * We found the pattern, and we found it often enough.
108 * Pity that we still don't know where the match is.
109 * We only know the linenumber. So, we just hope the
110 * following will at least bring it on the screen ...
112 (VOID
) display(lineno
,0,pagesize
,0);
122 do_fsearch(cnt
) long cnt
; { /* Forward search */
124 do_search("/", cnt
, 1);
128 do_bsearch(cnt
) long cnt
; { /* Backward search */
130 do_search("?", cnt
, -1);
134 * Repeat last search in direction "dir"
138 n_or_rn_search(cnt
,dir
) long cnt
; int dir
; {
144 else if (dir
== -1) {
148 error("No previous pattern");
151 if (!stupid
) clrbline();
154 do_search((char *) 0, cnt
, dir
);
158 do_nsearch(cnt
) long cnt
; { /* Repeat search in same direction */
160 n_or_rn_search(cnt
,searchdir
);
164 do_rnsearch(cnt
) long cnt
; { /* Repeat search in opposite direction */
166 n_or_rn_search(cnt
, -searchdir
);
169 STATIC
int shell(esc_ch
, cnt
) long cnt
;
175 if (p
= readline(buf
)) {
176 shellescape(p
, esc_ch
);
177 if (cnt
>= 0 && !hardcopy
) {
184 * Avoid double redraw.
185 * After a "startcomm", a redraw will
195 do_shell(cnt
) long cnt
; { /* Execute a shell escape */
200 do_pipe(cnt
) long cnt
; { /* Execute a shell escape */
206 do_writefile(cnt
) long cnt
; { /* Write input to a file */
210 if ((p
= readline("Filename: ")) == 0 || !*p
) {
216 # if USG_OPEN || BSD4_2_OPEN || POSIX_OPEN
217 if ((fd
= open(p
,O_CREAT
|O_EXCL
|O_WRONLY
,0644)) < 0) {
218 if (errno
== EEXIST
) {
219 error("File exists");
222 error("Could not open file");
227 error("File exists");
230 if ((fd
= creat(p
,0644)) < 0) {
231 error("Could not open file");
243 register char *p
= getline(l
,0), *pbuf
;
248 while (p
&& pbuf
< &buf
[1024]) {
253 else *pbuf
++ = *p
++ & 0177;
255 if (write(fd
, buf
, pbuf
- buf
) < 0) {
256 error("Write failed");
263 do_absolute(cnt
) long cnt
; { /* Go to linenumber "cnt" */
265 if (!getline(cnt
,0)) { /* Not there or interrupt */
268 * User did'nt give an interrupt, so the line number
269 * was too high. Go to the last line.
275 (VOID
) display(cnt
,0,pagesize
,1);
280 do_visit(cnt
) long cnt
; { /* Visit a file */
282 static char fn
[128]; /* Keep file name */
284 if ((p
= readline("Filename: ")) == 0) {
293 * User typed a return. Visit the current file
295 if (!(p
= filenames
[filecount
])) {
296 error("No current file");
301 (VOID
) display(1L, 0, pagesize
, 1);
306 do_error(cnt
) long cnt
; { /* Called when user types wrong key sequence */
308 error(currmap
->k_help
);
312 * Interface routine for displaying previous screen,
313 * depending on cflag.
317 prev_screen(sz
,really
) int sz
, really
; {
320 retval
= scrollb(sz
- 1, really
&& cflag
);
321 if (really
&& !cflag
) {
323 * The previous call did not display anything, but at least we
324 * know where to start
326 return display(scr_info
.firstline
, scr_info
.nf
, sz
, 1);
332 * Interface routine for displaying the next screen,
333 * dependent on cflag.
337 next_screen(sz
,really
) int sz
, really
; {
340 register struct scr_info
*p
= &scr_info
;
343 return scrollf(sz
-1,really
);
345 t
= p
->tail
->cnt
- 1;
346 if (p
->lastline
== p
->firstline
) {
349 return display(p
->lastline
, t
, sz
, really
);
354 do_redraw(cnt
) long cnt
; {
360 page_size(cnt
) unsigned cnt
; {
363 if (cnt
> maxpagesize
) return maxpagesize
;
364 if (cnt
< MINPAGESIZE
) return MINPAGESIZE
;
371 do_forward(cnt
) long cnt
; { /* Display next page */
374 i
= page_size((unsigned) cnt
);
375 if (status
& EOFILE
) {
377 * May seem strange, but actually a visit to the next file
378 * has already been done here
380 (VOID
) display(1L,0,i
,1);
383 (VOID
) next_screen(i
,1);
387 do_backward(cnt
) long cnt
; {
388 register int i
, temp
;
390 i
= page_size((unsigned) cnt
);
391 if (!(status
& START
)) {
392 (VOID
) prev_screen(i
,1);
396 (VOID
) display(1L,0,i
,1);
400 * The next part is a bit clumsy.
401 * We want to display the last page of the previous file (for which
402 * a visit has already been done), but the pagesize may temporarily
403 * be different because the command had a count
413 do_firstline(cnt
) long cnt
; { /* Go to start of input */
419 do_lline(cnt
) long cnt
; { /* Go to end of input */
421 register int j
= pagesize
- 1;
423 if ((cnt
= to_lastline()) < 0) {
425 * Interrupted by the user
430 * Display the page such that only the last line of the page is
431 * a "~", independant of the pagesize
433 while (!(display(cnt
,i
,j
,0) & EOFILE
)) {
435 * The last line could of course be very long ...
439 (VOID
) scrollb(j
- scr_info
.tail
->cnt
, 0);
444 do_lf(cnt
) long cnt
; { /* Display next line, or go to line */
446 if (cnt
) { /* Go to line */
454 do_upline(cnt
) long cnt
; { /* Display previous line, or go to line */
456 if (cnt
) { /* Go to line */
464 do_skiplines(cnt
) long cnt
; { /* Skip lines forwards */
466 /* Should be interruptable ... */
467 (VOID
) scrollf((int) (cnt
+ maxpagesize
- 1), 0);
472 do_bskiplines(cnt
) long cnt
; { /* Skip lines backwards */
474 /* Should be interruptable ... */
475 (VOID
) scrollb((int) (cnt
+ pagesize
- 1), 0);
480 do_fscreens(cnt
) long cnt
; { /* Skip screens forwards */
483 if ((next_screen(pagesize
,0) & EOFILE
) || interrupt
) break;
484 } while (--cnt
>= 0);
489 do_bscreens(cnt
) long cnt
; { /* Skip screens backwards */
492 if ((prev_screen(pagesize
,0) & START
) || interrupt
) break;
493 } while (--cnt
>= 0);
498 scro_size(cnt
) unsigned cnt
; {
500 if (cnt
>= maxpagesize
) return maxpagesize
;
501 if (cnt
) return (int) cnt
;
506 do_f_scroll(cnt
) long cnt
; { /* Scroll forwards */
508 (VOID
) scrollf(scro_size((unsigned) cnt
),1);
512 do_b_scroll(cnt
) long cnt
; { /* Scroll backwards */
514 (VOID
) scrollb(scro_size((unsigned) cnt
),1);
518 do_previousfile(cnt
) long cnt
; {/* Visit previous file */
520 if (nextfile(- (int) cnt
)) {
521 error("No (Nth) previous file");
528 do_nextfile(cnt
) long cnt
; { /* Visit next file */
530 if (nextfile((int) cnt
)) {
531 error("No (Nth) next file");
537 STATIC
int do_lcomm();
540 * The next array is initialized, sorted on the first element of the structs,
541 * so that we can perform binary search
543 struct commands commands
[] = {
544 {"", 0, do_error
, ""},
545 {"", 0, do_nocomm
, ""},
546 {"bf", STICKY
|NEEDS_COUNT
,
547 do_previousfile
,"Visit previous file"},
548 {"bl", NEEDS_SCREEN
|STICKY
,
549 do_upline
, "Scroll one line up, or go to line"},
551 do_lline
, "Go to last line of the input"},
552 {"bp", BACK
|NEEDS_SCREEN
|TOPREVFILE
|STICKY
,
553 do_backward
, "display previous page"},
554 {"bps", SCREENSIZE_ADAPT
|BACK
|NEEDS_SCREEN
|TOPREVFILE
|STICKY
,
555 do_backward
, "Display previous page, set pagesize"},
556 {"bs", BACK
|NEEDS_SCREEN
|STICKY
,
557 do_b_scroll
, "Scroll backwards"},
558 {"bse", 0, do_bsearch
, "Search backwards for pattern"},
559 {"bsl", BACK
|NEEDS_SCREEN
|STICKY
|NEEDS_COUNT
,
560 do_bskiplines
, "Skip lines backwards"},
561 {"bsp", BACK
|NEEDS_SCREEN
|STICKY
|NEEDS_COUNT
,
562 do_bscreens
, "Skip screens backwards"},
563 {"bss", SCROLLSIZE_ADAPT
|BACK
|NEEDS_SCREEN
|STICKY
,
564 do_b_scroll
, "Scroll backwards, set scrollsize"},
565 {"chm", 0, do_chkm
, "Switch to other keymap"},
566 {"exg", STICKY
, exgmark
, "Exchange current page with mark"},
567 {"ff", STICKY
|NEEDS_COUNT
,
568 do_nextfile
, "Visit next file"},
569 {"fl", NEEDS_SCREEN
|STICKY
,
570 do_lf
, "Scroll one line down, or go to line"},
571 {"fp", TONEXTFILE
|AHEAD
|STICKY
,
572 do_forward
, "Display next page"},
573 {"fps", SCREENSIZE_ADAPT
|TONEXTFILE
|AHEAD
|STICKY
,
574 do_forward
, "Display next page, set pagesize"},
575 {"fs", AHEAD
|NEEDS_SCREEN
|STICKY
,
576 do_f_scroll
, "Scroll forwards"},
577 {"fse", 0, do_fsearch
, "Search forwards for pattern"},
578 {"fsl", AHEAD
|NEEDS_SCREEN
|STICKY
|NEEDS_COUNT
,
579 do_skiplines
, "Skip lines forwards"},
580 {"fsp", AHEAD
|NEEDS_SCREEN
|STICKY
|NEEDS_COUNT
,
581 do_fscreens
, "Skip screens forwards"},
582 {"fss", SCROLLSIZE_ADAPT
|AHEAD
|NEEDS_SCREEN
|STICKY
,
583 do_f_scroll
, "Scroll forwards, set scrollsize"},
584 {"hlp", 0, do_help
, "Give description of all commands"},
585 {"mar", 0, setmark
, "Set a mark on the current page"},
586 {"nse", STICKY
, do_nsearch
, "Repeat the last search"},
587 {"nsr", STICKY
, do_rnsearch
, "Repeat last search in other direction"},
588 {"pip", ESC
, do_pipe
, "pipe input into shell command"},
589 {"qui", 0, quit
, "Exit from yap"},
590 {"red", 0, do_redraw
, "Redraw screen"},
591 {"rep", 0, do_lcomm
, "Repeat last command"},
592 {"shl", ESC
, do_shell
, "Execute a shell escape"},
593 {"tom", 0, tomark
, "Go to mark"},
594 {"top", STICKY
, do_firstline
, "Go to the first line of the input"},
595 {"vis", 0, do_visit
, "Visit a file"},
596 {"wrf", 0, do_writefile
, "Write input to a file"},
600 * Lookup string "s" in the commands array, and return index.
601 * return 0 if not found.
606 register struct commands
*l
, *u
, *m
;
609 u
= &commands
[sizeof(commands
) / sizeof(*u
) - 1];
612 * Perform binary search
615 if (strcmp(s
, m
->c_cmd
) > 0) l
= m
+ 1;
618 if (!strcmp(s
, u
->c_cmd
)) return u
- commands
;
624 do_lcomm(cnt
) long cnt
; { /* Repeat last command */
627 error("No previous command");
630 do_comm(lastcomm
, lastcount
);
634 * Execute a command, with optional count "count".
638 do_comm(comm
, count
) register int comm
; register long count
; {
640 register struct commands
*pcomm
;
644 pcomm
= &commands
[comm
];
645 flags
= pcomm
->c_flags
;
649 * If the last line of the file is displayed and the command goes
650 * forwards and does'nt have the ability to go to the next file, it
652 * If the first line of the file is displayed and the command goes
653 * backwards and does'nt have the ability to go to the previous file,
655 * Also check wether we need the next or previous file. If so, get it.
657 if ((status
& EOFILE
) && (flags
& AHEAD
)) {
658 if (qflag
|| !(flags
& TONEXTFILE
)) return;
659 if (nextfile(1)) quit();
661 if ((status
& START
) && (flags
& BACK
)) {
662 if (qflag
|| !(flags
& TOPREVFILE
)) return;
663 if (nextfile(-1)) quit();
666 * Does the command stick around for LASTCOMM?
668 if (flags
& STICKY
) {
673 if (flags
& NEEDS_COUNT
) count
= 1;
677 * Does the command adapt the screensize?
679 if (flags
& SCREENSIZE_ADAPT
) {
681 if ((unsigned) count
< temp
) {
684 if (temp
< MINPAGESIZE
) {
691 * Does the command adapt the scrollsize?
693 if (flags
& SCROLLSIZE_ADAPT
) {
694 temp
= maxpagesize
- 1;
695 if ((unsigned) count
< temp
) {
703 * Now execute the command.
705 (*(pcomm
->c_func
))(count
);