source: trunk/minix/commands/yap/commands.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 14.5 KB
Line 
1/* Copyright (c) 1985 Ceriel J.H. Jacobs */
2
3# ifndef lint
4static char rcsid[] = "$Header: /cvsup/minix/src/commands/yap/commands.c,v 1.1.1.1 2005/04/21 14:55:38 beng Exp $";
5# endif
6
7# define _COMMANDS_
8
9# include "in_all.h"
10# include "commands.h"
11# include "output.h"
12# include "process.h"
13# include "help.h"
14# include "term.h"
15# include "prompt.h"
16# include "getline.h"
17# include "getcomm.h"
18# include "pattern.h"
19# include "display.h"
20# include "options.h"
21# include "machine.h"
22# include "keys.h"
23# include "main.h"
24# include "assert.h"
25# if USG_OPEN
26# include <fcntl.h>
27# include <errno.h>
28extern int errno;
29# endif
30# if BSD4_2_OPEN
31# include <sys/file.h>
32# include <errno.h>
33extern int errno;
34# endif
35# if POSIX_OPEN
36# include <sys/types.h>
37# include <fcntl.h>
38# include <errno.h>
39# endif
40
41char *strcpy(), *strcat();
42
43static long lastcount; /* Save last count for '.' command */
44static int lastcomm; /* Save last command for '.' command */
45
46/*ARGSUSED*/
47STATIC int
48do_nocomm(cnt) long cnt; { /* Do nothing */
49}
50
51/*ARGSUSED*/
52int
53do_chkm(cnt) long cnt; { /* Change key map */
54 register struct keymap *p;
55
56 if (!(p = othermap)) {
57 error("No other keymap");
58 return;
59 }
60 othermap = currmap;
61 currmap = p;
62}
63
64static int searchdir; /* Direction of last search */
65
66/*
67 * Perform searches
68 */
69
70STATIC VOID
71do_search(str,cnt,dir) char *str; long cnt; int dir; {
72 register char *p;
73 register long lineno;
74
75 if (str) {
76 /*
77 * We have to get a pattern, which we have to prompt for
78 * with the string "str".
79 */
80 if ((p = readline(str)) == 0) {
81 /*
82 * User cancelled command
83 */
84 return;
85 }
86 if ((p = re_comp(p))) {
87 /*
88 * There was an error in the pattern
89 */
90 error(p);
91 return;
92 }
93 searchdir = dir;
94 }
95 if (dir < 0) lineno = scr_info.firstline;
96 else lineno = scr_info.lastline;
97 for (;;) {
98 p = 0;
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");
103 return;
104 }
105 if (re_exec(p) && --cnt <= 0) {
106 /*
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 ...
111 */
112 (VOID) display(lineno,0,pagesize,0);
113 (VOID) scrollb(2,0);
114 redraw(0);
115 return;
116 }
117 }
118 /* NOTREACHED */
119}
120
121STATIC int
122do_fsearch(cnt) long cnt; { /* Forward search */
123
124 do_search("/", cnt, 1);
125}
126
127STATIC int
128do_bsearch(cnt) long cnt; { /* Backward search */
129
130 do_search("?", cnt, -1);
131}
132
133/*
134 * Repeat last search in direction "dir"
135 */
136
137STATIC int
138n_or_rn_search(cnt,dir) long cnt; int dir; {
139 register char *p;
140
141 if (dir == 1) {
142 p = "/\r";
143 }
144 else if (dir == -1) {
145 p = "?\r";
146 }
147 else {
148 error("No previous pattern");
149 return;
150 }
151 if (!stupid) clrbline();
152 putline(p);
153 flush();
154 do_search((char *) 0, cnt, dir);
155}
156
157STATIC int
158do_nsearch(cnt) long cnt; { /* Repeat search in same direction */
159
160 n_or_rn_search(cnt,searchdir);
161}
162
163STATIC int
164do_rnsearch(cnt) long cnt; { /* Repeat search in opposite direction */
165
166 n_or_rn_search(cnt, -searchdir);
167}
168
169STATIC int shell(esc_ch, cnt) long cnt;
170{
171 register char *p;
172 static char buf[2];
173
174 buf[0] = esc_ch;
175 if (p = readline(buf)) {
176 shellescape(p, esc_ch);
177 if (cnt >= 0 && !hardcopy) {
178 p = startcomm;
179 startcomm = 0;
180 ret_to_continue();
181 putline(TI);
182 if (!p) {
183 /*
184 * Avoid double redraw.
185 * After a "startcomm", a redraw will
186 * take place anyway.
187 */
188 redraw(1);
189 }
190 }
191 }
192}
193
194STATIC int
195do_shell(cnt) long cnt; { /* Execute a shell escape */
196 shell('!', cnt);
197}
198
199STATIC int
200do_pipe(cnt) long cnt; { /* Execute a shell escape */
201 shell('|', cnt);
202}
203
204/*ARGSUSED*/
205STATIC int
206do_writefile(cnt) long cnt; { /* Write input to a file */
207 register char *p;
208 int fd;
209
210 if ((p = readline("Filename: ")) == 0 || !*p) {
211 /*
212 * No file name given
213 */
214 return;
215 }
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");
220 return;
221 }
222 error("Could not open file");
223 return;
224 }
225# else
226 if (!access(p,0)) {
227 error("File exists");
228 return;
229 }
230 if ((fd = creat(p,0644)) < 0) {
231 error("Could not open file");
232 return;
233 }
234# endif
235 wrt_fd(fd);
236 (VOID) close(fd);
237}
238
239VOID
240wrt_fd(fd)
241{
242 register long l = 1;
243 register char *p = getline(l,0), *pbuf;
244 char buf[1024];
245
246 while (p) {
247 pbuf = buf;
248 while (p && pbuf < &buf[1024]) {
249 if (!*p) {
250 *pbuf++ = '\n';
251 p = getline(++l,0);
252 }
253 else *pbuf++ = *p++ & 0177;
254 }
255 if (write(fd, buf, pbuf - buf) < 0) {
256 error("Write failed");
257 break;
258 }
259 }
260}
261
262STATIC int
263do_absolute(cnt) long cnt; { /* Go to linenumber "cnt" */
264
265 if (!getline(cnt,0)) { /* Not there or interrupt */
266 if (!interrupt) {
267 /*
268 * User did'nt give an interrupt, so the line number
269 * was too high. Go to the last line.
270 */
271 do_lline(cnt);
272 }
273 return;
274 }
275 (VOID) display(cnt,0,pagesize,1);
276}
277
278/*ARGSUSED*/
279STATIC int
280do_visit(cnt) long cnt; { /* Visit a file */
281 register char *p;
282 static char fn[128]; /* Keep file name */
283
284 if ((p = readline("Filename: ")) == 0) {
285 return;
286 }
287 if (*p) {
288 (VOID) strcpy(fn,p);
289 visitfile(fn);
290 }
291 else {
292 /*
293 * User typed a return. Visit the current file
294 */
295 if (!(p = filenames[filecount])) {
296 error("No current file");
297 return;
298 }
299 visitfile(p);
300 }
301 (VOID) display(1L, 0, pagesize, 1);
302}
303
304/*ARGSUSED*/
305STATIC int
306do_error(cnt) long cnt; { /* Called when user types wrong key sequence */
307
308 error(currmap->k_help);
309}
310
311/*
312 * Interface routine for displaying previous screen,
313 * depending on cflag.
314 */
315
316STATIC int
317prev_screen(sz,really) int sz, really; {
318 register int retval;
319
320 retval = scrollb(sz - 1, really && cflag);
321 if (really && !cflag) {
322 /*
323 * The previous call did not display anything, but at least we
324 * know where to start
325 */
326 return display(scr_info.firstline, scr_info.nf, sz, 1);
327 }
328 return retval;
329}
330
331/*
332 * Interface routine for displaying the next screen,
333 * dependent on cflag.
334 */
335
336STATIC int
337next_screen(sz,really) int sz, really; {
338
339 register int t;
340 register struct scr_info *p = &scr_info;
341
342 if (cflag) {
343 return scrollf(sz-1,really);
344 }
345 t = p->tail->cnt - 1;
346 if (p->lastline == p->firstline) {
347 t += p->nf;
348 }
349 return display(p->lastline, t, sz, really);
350}
351
352/*ARGSUSED*/
353STATIC int
354do_redraw(cnt) long cnt; {
355
356 redraw(1);
357}
358
359STATIC int
360page_size(cnt) unsigned cnt; {
361
362 if (cnt) {
363 if (cnt > maxpagesize) return maxpagesize;
364 if (cnt < MINPAGESIZE) return MINPAGESIZE;
365 return (int) cnt;
366 }
367 return pagesize;
368}
369
370STATIC int
371do_forward(cnt) long cnt; { /* Display next page */
372 register int i;
373
374 i = page_size((unsigned) cnt);
375 if (status & EOFILE) {
376 /*
377 * May seem strange, but actually a visit to the next file
378 * has already been done here
379 */
380 (VOID) display(1L,0,i,1);
381 return;
382 }
383 (VOID) next_screen(i,1);
384}
385
386STATIC int
387do_backward(cnt) long cnt; {
388 register int i, temp;
389
390 i = page_size((unsigned) cnt);
391 if (!(status & START)) {
392 (VOID) prev_screen(i,1);
393 return;
394 }
395 if (stdf < 0) {
396 (VOID) display(1L,0,i,1);
397 return;
398 }
399 /*
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
404 */
405 temp = pagesize;
406 pagesize = i;
407 do_lline(cnt);
408 pagesize = temp;
409}
410
411/*ARGSUSED*/
412STATIC int
413do_firstline(cnt) long cnt; { /* Go to start of input */
414
415 do_absolute(1L);
416}
417
418STATIC int
419do_lline(cnt) long cnt; { /* Go to end of input */
420 register int i = 0;
421 register int j = pagesize - 1;
422
423 if ((cnt = to_lastline()) < 0) {
424 /*
425 * Interrupted by the user
426 */
427 return;
428 }
429 /*
430 * Display the page such that only the last line of the page is
431 * a "~", independant of the pagesize
432 */
433 while (!(display(cnt,i,j,0) & EOFILE)) {
434 /*
435 * The last line could of course be very long ...
436 */
437 i+= j;
438 }
439 (VOID) scrollb(j - scr_info.tail->cnt, 0);
440 redraw(0);
441}
442
443STATIC int
444do_lf(cnt) long cnt; { /* Display next line, or go to line */
445
446 if (cnt) { /* Go to line */
447 do_absolute(cnt);
448 return;
449 }
450 (VOID) scrollf(1,1);
451}
452
453STATIC int
454do_upline(cnt) long cnt; { /* Display previous line, or go to line */
455
456 if (cnt) { /* Go to line */
457 do_absolute(cnt);
458 return;
459 }
460 (VOID) scrollb(1,1);
461}
462
463STATIC int
464do_skiplines(cnt) long cnt; { /* Skip lines forwards */
465
466 /* Should be interruptable ... */
467 (VOID) scrollf((int) (cnt + maxpagesize - 1), 0);
468 redraw(0);
469}
470
471STATIC int
472do_bskiplines(cnt) long cnt; { /* Skip lines backwards */
473
474 /* Should be interruptable ... */
475 (VOID) scrollb((int) (cnt + pagesize - 1), 0);
476 redraw(0);
477}
478
479STATIC int
480do_fscreens(cnt) long cnt; { /* Skip screens forwards */
481
482 do {
483 if ((next_screen(pagesize,0) & EOFILE) || interrupt) break;
484 } while (--cnt >= 0);
485 redraw(0);
486}
487
488STATIC int
489do_bscreens(cnt) long cnt; { /* Skip screens backwards */
490
491 do {
492 if ((prev_screen(pagesize,0) & START) || interrupt) break;
493 } while (--cnt >= 0);
494 redraw(0);
495}
496
497STATIC int
498scro_size(cnt) unsigned cnt; {
499
500 if (cnt >= maxpagesize) return maxpagesize;
501 if (cnt) return (int) cnt;
502 return scrollsize;
503}
504
505STATIC int
506do_f_scroll(cnt) long cnt; { /* Scroll forwards */
507
508 (VOID) scrollf(scro_size((unsigned) cnt),1);
509}
510
511STATIC int
512do_b_scroll(cnt) long cnt; { /* Scroll backwards */
513
514 (VOID) scrollb(scro_size((unsigned) cnt),1);
515}
516
517STATIC int
518do_previousfile(cnt) long cnt; {/* Visit previous file */
519
520 if (nextfile(- (int) cnt)) {
521 error("No (Nth) previous file");
522 return;
523 }
524 redraw(0);
525}
526
527STATIC int
528do_nextfile(cnt) long cnt; { /* Visit next file */
529
530 if (nextfile((int) cnt)) {
531 error("No (Nth) next file");
532 return;
533 }
534 redraw(0);
535}
536
537STATIC int do_lcomm();
538
539/*
540 * The next array is initialized, sorted on the first element of the structs,
541 * so that we can perform binary search
542 */
543struct 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"},
550{"bot", STICKY,
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"},
597};
598
599/*
600 * Lookup string "s" in the commands array, and return index.
601 * return 0 if not found.
602 */
603
604int
605lookup(s) char *s; {
606 register struct commands *l, *u, *m;
607
608 l = &commands[2];
609 u = &commands[sizeof(commands) / sizeof(*u) - 1];
610 do {
611 /*
612 * Perform binary search
613 */
614 m = l + (u - l) / 2;
615 if (strcmp(s, m->c_cmd) > 0) l = m + 1;
616 else u = m;
617 } while (l < u);
618 if (!strcmp(s, u->c_cmd)) return u - commands;
619 return 0;
620}
621
622/*ARGSUSED*/
623STATIC int
624do_lcomm(cnt) long cnt; { /* Repeat last command */
625
626 if (!lastcomm) {
627 error("No previous command");
628 return;
629 }
630 do_comm(lastcomm, lastcount);
631}
632
633/*
634 * Execute a command, with optional count "count".
635 */
636
637VOID
638do_comm(comm, count) register int comm; register long count; {
639
640 register struct commands *pcomm;
641 register int temp;
642 register int flags;
643
644 pcomm = &commands[comm];
645 flags = pcomm->c_flags;
646
647 /*
648 * Check the command.
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
651 * is an error.
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,
654 * it is an error.
655 * Also check wether we need the next or previous file. If so, get it.
656 */
657 if ((status & EOFILE) && (flags & AHEAD)) {
658 if (qflag || !(flags & TONEXTFILE)) return;
659 if (nextfile(1)) quit();
660 }
661 if ((status & START) && (flags & BACK)) {
662 if (qflag || !(flags & TOPREVFILE)) return;
663 if (nextfile(-1)) quit();
664 }
665 /*
666 * Does the command stick around for LASTCOMM?
667 */
668 if (flags & STICKY) {
669 lastcomm = comm;
670 lastcount = count;
671 }
672 if (!count) {
673 if (flags & NEEDS_COUNT) count = 1;
674 }
675 else {
676 /*
677 * Does the command adapt the screensize?
678 */
679 if (flags & SCREENSIZE_ADAPT) {
680 temp = maxpagesize;
681 if ((unsigned) count < temp) {
682 temp = count;
683 }
684 if (temp < MINPAGESIZE) {
685 temp = MINPAGESIZE;
686 }
687 count = 0;
688 pagesize = temp;
689 }
690 /*
691 * Does the command adapt the scrollsize?
692 */
693 if (flags & SCROLLSIZE_ADAPT) {
694 temp = maxpagesize - 1;
695 if ((unsigned) count < temp) {
696 temp = (int) count;
697 }
698 scrollsize = temp;
699 count = 0;
700 }
701 }
702 /*
703 * Now execute the command.
704 */
705 (*(pcomm->c_func))(count);
706}
Note: See TracBrowser for help on using the repository browser.