commands.c

Go to the documentation of this file.
00001 /* Copyright (c) 1985 Ceriel J.H. Jacobs */
00002 
00003 # ifndef lint
00004 static char rcsid[] = "$Header: /opt/proj/minix/cvsroot/src/commands/yap/commands.c,v 1.1.1.1 2005/04/21 14:55:38 beng Exp $";
00005 # endif
00006 
00007 # define _COMMANDS_
00008 
00009 # include "in_all.h"
00010 # include "commands.h"
00011 # include "output.h"
00012 # include "process.h"
00013 # include "help.h"
00014 # include "term.h"
00015 # include "prompt.h"
00016 # include "getline.h"
00017 # include "getcomm.h"
00018 # include "pattern.h"
00019 # include "display.h"
00020 # include "options.h"
00021 # include "machine.h"
00022 # include "keys.h"
00023 # include "main.h"
00024 # include "assert.h"
00025 # if USG_OPEN
00026 # include <fcntl.h>
00027 # include <errno.h>
00028 extern int errno;
00029 # endif
00030 # if BSD4_2_OPEN
00031 # include <sys/file.h>
00032 # include <errno.h>
00033 extern int errno;
00034 # endif
00035 # if POSIX_OPEN
00036 # include <sys/types.h>
00037 # include <fcntl.h>
00038 # include <errno.h>
00039 # endif
00040 
00041 char    *strcpy(), *strcat();
00042 
00043 static long lastcount;          /* Save last count for '.' command */
00044 static int lastcomm;            /* Save last command for '.' command */
00045 
00046 /*ARGSUSED*/
00047 STATIC int
00048 do_nocomm(cnt) long cnt; {      /* Do nothing */
00049 }
00050 
00051 /*ARGSUSED*/
00052 int
00053 do_chkm(cnt) long cnt; {        /* Change key map */
00054         register struct keymap *p;
00055 
00056         if (!(p = othermap)) {
00057                 error("No other keymap");
00058                 return;
00059         }
00060         othermap = currmap;
00061         currmap = p;
00062 }
00063 
00064 static int searchdir;           /* Direction of last search */
00065 
00066 /*
00067  * Perform searches
00068  */
00069 
00070 STATIC VOID
00071 do_search(str,cnt,dir) char *str; long cnt; int dir; {
00072         register char *p;
00073         register long lineno;
00074 
00075         if (str) {
00076                 /*
00077                  * We have to get a pattern, which we have to prompt for
00078                  * with the string "str".
00079                  */
00080                 if ((p = readline(str)) == 0) {
00081                         /*
00082                          * User cancelled command
00083                          */
00084                         return;
00085                 }
00086                 if ((p = re_comp(p))) {
00087                         /*
00088                          * There was an error in the pattern
00089                          */
00090                         error(p);
00091                         return;
00092                 }
00093                 searchdir = dir;
00094         }
00095         if (dir < 0) lineno = scr_info.firstline;
00096         else lineno = scr_info.lastline;
00097         for (;;) {
00098                 p = 0;
00099                 if ((lineno += dir) > 0) p = getline(lineno, 0);
00100                 if (interrupt) return;
00101                 if (!p) {       /* End of file reached */
00102                         error("pattern not found");
00103                         return;
00104                 }
00105                 if (re_exec(p) && --cnt <= 0) {
00106                         /*
00107                          * We found the pattern, and we found it often enough.
00108                          * Pity that we still don't know where the match is.
00109                          * We only know the linenumber. So, we just hope the
00110                          * following will at least bring it on the screen ...
00111                          */
00112                         (VOID) display(lineno,0,pagesize,0);
00113                         (VOID) scrollb(2,0);
00114                         redraw(0);
00115                         return;
00116                 }
00117         }
00118         /* NOTREACHED */
00119 }
00120 
00121 STATIC int
00122 do_fsearch(cnt) long cnt; {     /* Forward search */
00123 
00124         do_search("/", cnt, 1);
00125 }
00126 
00127 STATIC int
00128 do_bsearch(cnt) long cnt; {     /* Backward search */
00129 
00130         do_search("?", cnt, -1);
00131 }
00132 
00133 /*
00134  * Repeat last search in direction "dir"
00135  */
00136 
00137 STATIC int
00138 n_or_rn_search(cnt,dir) long cnt; int dir; {
00139         register char *p;
00140 
00141         if (dir == 1) {
00142                 p = "/\r";
00143         }
00144         else if (dir == -1) {
00145                 p = "?\r";
00146         }
00147         else {
00148                 error("No previous pattern");
00149                 return;
00150         }
00151         if (!stupid) clrbline();
00152         putline(p);
00153         flush();
00154         do_search((char *) 0, cnt, dir);
00155 }
00156 
00157 STATIC int
00158 do_nsearch(cnt) long cnt; {     /* Repeat search in same direction */
00159         
00160         n_or_rn_search(cnt,searchdir);
00161 }
00162 
00163 STATIC int
00164 do_rnsearch(cnt) long cnt; {    /* Repeat search in opposite direction */
00165 
00166         n_or_rn_search(cnt, -searchdir);
00167 }
00168 
00169 STATIC int shell(esc_ch, cnt) long cnt;
00170 {
00171         register char *p;
00172         static char buf[2];
00173 
00174         buf[0] = esc_ch;
00175         if (p = readline(buf)) {
00176                 shellescape(p, esc_ch);
00177                 if (cnt >= 0 && !hardcopy) {
00178                         p = startcomm;
00179                         startcomm = 0;
00180                         ret_to_continue();
00181                         putline(TI);
00182                         if (!p) {
00183                                 /*
00184                                  * Avoid double redraw.
00185                                  * After a "startcomm", a redraw will
00186                                  * take place anyway.
00187                                  */
00188                                 redraw(1);
00189                         }
00190                 }
00191         }
00192 }
00193 
00194 STATIC int
00195 do_shell(cnt) long cnt; {       /* Execute a shell escape */
00196         shell('!', cnt);
00197 }
00198 
00199 STATIC int
00200 do_pipe(cnt) long cnt; {        /* Execute a shell escape */
00201         shell('|', cnt);
00202 }
00203 
00204 /*ARGSUSED*/
00205 STATIC int
00206 do_writefile(cnt) long cnt; {   /* Write input to a file */
00207         register char *p;
00208         int fd;
00209 
00210         if ((p = readline("Filename: ")) == 0 || !*p) {
00211                 /*
00212                  * No file name given
00213                  */
00214                 return;
00215         }
00216 # if USG_OPEN || BSD4_2_OPEN || POSIX_OPEN
00217         if ((fd = open(p,O_CREAT|O_EXCL|O_WRONLY,0644)) < 0) {
00218                 if (errno == EEXIST) {
00219                         error("File exists");
00220                         return;
00221                 }
00222                 error("Could not open file");
00223                 return;
00224         }
00225 # else
00226         if (!access(p,0)) {
00227                 error("File exists");
00228                 return;
00229         }
00230         if ((fd = creat(p,0644)) < 0) {
00231                 error("Could not open file");
00232                 return;
00233         }
00234 # endif
00235         wrt_fd(fd);
00236         (VOID) close(fd);
00237 }
00238 
00239 VOID
00240 wrt_fd(fd)
00241 {
00242         register long l = 1;
00243         register char *p = getline(l,0), *pbuf;
00244         char buf[1024];
00245 
00246         while (p) {
00247                 pbuf = buf;
00248                 while (p && pbuf < &buf[1024]) {
00249                         if (!*p) {
00250                                 *pbuf++ = '\n';
00251                                 p = getline(++l,0);
00252                         }
00253                         else *pbuf++ = *p++ & 0177;
00254                 }
00255                 if (write(fd, buf, pbuf - buf) < 0) {
00256                         error("Write failed");
00257                         break;
00258                 }
00259         }
00260 }
00261 
00262 STATIC int
00263 do_absolute(cnt) long cnt; {    /* Go to linenumber "cnt" */
00264 
00265         if (!getline(cnt,0)) {  /* Not there or interrupt */
00266                 if (!interrupt) {
00267                         /*
00268                          * User did'nt give an interrupt, so the line number
00269                          * was too high. Go to the last line.
00270                          */
00271                         do_lline(cnt);
00272                 }
00273                 return;
00274         }
00275         (VOID) display(cnt,0,pagesize,1);
00276 }
00277 
00278 /*ARGSUSED*/
00279 STATIC int
00280 do_visit(cnt) long cnt; {       /* Visit a file */
00281         register char *p;
00282         static char fn[128];    /* Keep file name */
00283 
00284         if ((p = readline("Filename: ")) == 0) {
00285                 return;
00286         }
00287         if (*p) {
00288                 (VOID) strcpy(fn,p);
00289                 visitfile(fn);
00290         }
00291         else {
00292                 /*
00293                  * User typed a return. Visit the current file
00294                  */
00295                 if (!(p = filenames[filecount])) {
00296                         error("No current file");
00297                         return;
00298                 }
00299                 visitfile(p);
00300         }
00301         (VOID) display(1L, 0, pagesize, 1);
00302 }
00303 
00304 /*ARGSUSED*/
00305 STATIC int
00306 do_error(cnt) long cnt; {       /* Called when user types wrong key sequence */
00307 
00308         error(currmap->k_help);
00309 }
00310 
00311 /*
00312  * Interface routine for displaying previous screen,
00313  * depending on cflag.
00314  */
00315 
00316 STATIC int
00317 prev_screen(sz,really) int sz, really; {
00318         register int retval;
00319 
00320         retval = scrollb(sz - 1, really && cflag);
00321         if (really && !cflag) {
00322                 /*
00323                  * The previous call did not display anything, but at least we
00324                  * know where to start
00325                  */
00326                 return display(scr_info.firstline, scr_info.nf, sz, 1);
00327         }
00328         return retval;
00329 }
00330 
00331 /*
00332  * Interface routine for displaying the next screen,
00333  * dependent on cflag.
00334  */
00335 
00336 STATIC int
00337 next_screen(sz,really) int sz, really; {
00338 
00339         register int t;
00340         register struct scr_info *p = &scr_info;
00341 
00342         if (cflag) {
00343                 return scrollf(sz-1,really);
00344         }
00345         t = p->tail->cnt - 1;
00346         if (p->lastline == p->firstline) {
00347                 t += p->nf;
00348         }
00349         return display(p->lastline, t, sz, really);
00350 }
00351 
00352 /*ARGSUSED*/
00353 STATIC int
00354 do_redraw(cnt) long cnt; {
00355 
00356         redraw(1);
00357 }
00358 
00359 STATIC int
00360 page_size(cnt) unsigned cnt; {
00361 
00362         if (cnt) {
00363                 if (cnt > maxpagesize) return maxpagesize;
00364                 if (cnt < MINPAGESIZE) return MINPAGESIZE;
00365                 return (int) cnt;
00366         }
00367         return pagesize;
00368 }
00369 
00370 STATIC int
00371 do_forward(cnt) long cnt; {     /* Display next page */
00372         register int i;
00373 
00374         i = page_size((unsigned) cnt);
00375         if (status & EOFILE) {
00376                 /*
00377                  * May seem strange, but actually a visit to the next file
00378                  * has already been done here
00379                  */
00380                 (VOID) display(1L,0,i,1);
00381                 return;
00382         }
00383         (VOID) next_screen(i,1);
00384 }
00385 
00386 STATIC int
00387 do_backward(cnt) long cnt; {
00388         register int i, temp;
00389 
00390         i = page_size((unsigned) cnt);
00391         if (!(status & START)) {
00392                 (VOID) prev_screen(i,1);
00393                 return;
00394         }
00395         if (stdf < 0) {
00396                 (VOID) display(1L,0,i,1);
00397                 return;
00398         }
00399         /*
00400          * The next part is a bit clumsy.
00401          * We want to display the last page of the previous file (for which
00402          * a visit has already been done), but the pagesize may temporarily
00403          * be different because the command had a count
00404          */
00405         temp = pagesize;
00406         pagesize = i;
00407         do_lline(cnt);
00408         pagesize = temp;
00409 }
00410 
00411 /*ARGSUSED*/
00412 STATIC int
00413 do_firstline(cnt) long cnt; {   /* Go to start of input */
00414 
00415         do_absolute(1L);
00416 }
00417 
00418 STATIC int
00419 do_lline(cnt) long cnt; {       /* Go to end of input */
00420         register int i = 0;
00421         register int j = pagesize - 1;
00422 
00423         if ((cnt = to_lastline()) < 0) {
00424                 /*
00425                  * Interrupted by the user
00426                  */
00427                 return;
00428         }
00429         /*
00430          * Display the page such that only the last line of the page is
00431          * a "~", independant of the pagesize
00432          */
00433         while (!(display(cnt,i,j,0) & EOFILE)) {
00434                 /*
00435                  * The last line could of course be very long ...
00436                  */
00437                 i+= j;
00438         }
00439         (VOID) scrollb(j - scr_info.tail->cnt, 0);
00440         redraw(0);
00441 }
00442 
00443 STATIC int
00444 do_lf(cnt) long cnt; {          /* Display next line, or go to line */
00445 
00446         if (cnt) {              /* Go to line */
00447                 do_absolute(cnt);
00448                 return;
00449         }
00450         (VOID) scrollf(1,1);
00451 }
00452 
00453 STATIC int
00454 do_upline(cnt) long cnt; {      /* Display previous line, or go to line */
00455 
00456         if (cnt) {              /* Go to line */
00457                 do_absolute(cnt);
00458                 return;
00459         }
00460         (VOID) scrollb(1,1);
00461 }
00462 
00463 STATIC int
00464 do_skiplines(cnt) long cnt; {   /* Skip lines forwards */
00465 
00466         /* Should be interruptable ... */
00467         (VOID) scrollf((int) (cnt + maxpagesize - 1), 0);
00468         redraw(0);
00469 }
00470 
00471 STATIC int
00472 do_bskiplines(cnt) long cnt; {  /* Skip lines backwards */
00473 
00474         /* Should be interruptable ... */
00475         (VOID) scrollb((int) (cnt + pagesize - 1), 0);
00476         redraw(0);
00477 }
00478 
00479 STATIC int
00480 do_fscreens(cnt) long cnt; {    /* Skip screens forwards */
00481 
00482         do {
00483                 if ((next_screen(pagesize,0) & EOFILE) || interrupt) break;
00484         } while (--cnt >= 0);
00485         redraw(0);
00486 }
00487 
00488 STATIC int
00489 do_bscreens(cnt) long cnt; {    /* Skip screens backwards */
00490 
00491         do {
00492                 if ((prev_screen(pagesize,0) & START) || interrupt) break;
00493         } while (--cnt >= 0);
00494         redraw(0);
00495 }
00496 
00497 STATIC int
00498 scro_size(cnt) unsigned cnt; {
00499 
00500         if (cnt >= maxpagesize) return maxpagesize;
00501         if (cnt) return (int) cnt;
00502         return scrollsize;
00503 }
00504 
00505 STATIC int
00506 do_f_scroll(cnt) long cnt; {    /* Scroll forwards */
00507 
00508         (VOID) scrollf(scro_size((unsigned) cnt),1);
00509 }
00510 
00511 STATIC int
00512 do_b_scroll(cnt) long cnt; {    /* Scroll backwards */
00513 
00514         (VOID) scrollb(scro_size((unsigned) cnt),1);
00515 }
00516 
00517 STATIC int
00518 do_previousfile(cnt) long cnt; {/* Visit previous file */
00519 
00520         if (nextfile(- (int) cnt)) {
00521                 error("No (Nth) previous file");
00522                 return;
00523         }
00524         redraw(0);
00525 }
00526 
00527 STATIC int
00528 do_nextfile(cnt) long cnt; {    /* Visit next file */
00529 
00530         if (nextfile((int) cnt)) {
00531                 error("No (Nth) next file");
00532                 return;
00533         }
00534         redraw(0);
00535 }
00536 
00537 STATIC int do_lcomm();
00538 
00539 /*
00540  * The next array is initialized, sorted on the first element of the structs,
00541  * so that we can perform binary search
00542  */
00543 struct commands commands[] = {
00544 {"",        0,      do_error,       ""},
00545 {"",        0,      do_nocomm,      ""},
00546 {"bf",      STICKY|NEEDS_COUNT,
00547                     do_previousfile,"Visit previous file"},
00548 {"bl",      NEEDS_SCREEN|STICKY,
00549                     do_upline,      "Scroll one line up, or go to line"},
00550 {"bot",     STICKY,
00551                     do_lline,       "Go to last line of the input"},
00552 {"bp",      BACK|NEEDS_SCREEN|TOPREVFILE|STICKY,
00553                     do_backward,    "display previous page"},
00554 {"bps",     SCREENSIZE_ADAPT|BACK|NEEDS_SCREEN|TOPREVFILE|STICKY,
00555                     do_backward,    "Display previous page, set pagesize"},
00556 {"bs",      BACK|NEEDS_SCREEN|STICKY,
00557                     do_b_scroll,    "Scroll backwards"},
00558 {"bse",     0,      do_bsearch,     "Search backwards for pattern"},
00559 {"bsl",     BACK|NEEDS_SCREEN|STICKY|NEEDS_COUNT,
00560                     do_bskiplines,  "Skip lines backwards"},
00561 {"bsp",     BACK|NEEDS_SCREEN|STICKY|NEEDS_COUNT,
00562                     do_bscreens,    "Skip screens backwards"},
00563 {"bss",     SCROLLSIZE_ADAPT|BACK|NEEDS_SCREEN|STICKY,
00564                     do_b_scroll,    "Scroll backwards, set scrollsize"},
00565 {"chm",     0,      do_chkm,        "Switch to other keymap"},
00566 {"exg",     STICKY, exgmark,        "Exchange current page with mark"},
00567 {"ff",      STICKY|NEEDS_COUNT,
00568                     do_nextfile,    "Visit next file"},
00569 {"fl",      NEEDS_SCREEN|STICKY,
00570                     do_lf,          "Scroll one line down, or go to line"},
00571 {"fp",      TONEXTFILE|AHEAD|STICKY,
00572                     do_forward,     "Display next page"},
00573 {"fps",     SCREENSIZE_ADAPT|TONEXTFILE|AHEAD|STICKY,
00574                     do_forward,     "Display next page, set pagesize"},
00575 {"fs",      AHEAD|NEEDS_SCREEN|STICKY,
00576                     do_f_scroll,    "Scroll forwards"},
00577 {"fse",     0,      do_fsearch,     "Search forwards for pattern"},
00578 {"fsl",     AHEAD|NEEDS_SCREEN|STICKY|NEEDS_COUNT,
00579                     do_skiplines,   "Skip lines forwards"},
00580 {"fsp",     AHEAD|NEEDS_SCREEN|STICKY|NEEDS_COUNT,
00581                     do_fscreens,    "Skip screens forwards"},
00582 {"fss",     SCROLLSIZE_ADAPT|AHEAD|NEEDS_SCREEN|STICKY,
00583                     do_f_scroll,    "Scroll forwards, set scrollsize"},
00584 {"hlp",     0,      do_help,        "Give description of all commands"},
00585 {"mar",     0,      setmark,        "Set a mark on the current page"},
00586 {"nse",     STICKY, do_nsearch,     "Repeat the last search"},
00587 {"nsr",     STICKY, do_rnsearch, "Repeat last search in other direction"},
00588 {"pip",     ESC,    do_pipe,        "pipe input into shell command"},
00589 {"qui",     0,      quit,           "Exit from yap"},
00590 {"red",     0,      do_redraw,      "Redraw screen"},
00591 {"rep",     0,      do_lcomm,       "Repeat last command"},
00592 {"shl",     ESC,    do_shell,       "Execute a shell escape"},
00593 {"tom",     0,      tomark,         "Go to mark"},
00594 {"top",     STICKY, do_firstline,   "Go to the first line of the input"},
00595 {"vis",     0,      do_visit,       "Visit a file"},
00596 {"wrf",     0,      do_writefile,   "Write input to a file"},
00597 };
00598 
00599 /*
00600  * Lookup string "s" in the commands array, and return index.
00601  * return 0 if not found.
00602  */
00603 
00604 int
00605 lookup(s) char *s; {
00606         register struct commands *l, *u, *m;
00607 
00608         l = &commands[2];
00609         u = &commands[sizeof(commands) / sizeof(*u) - 1];
00610         do {
00611                 /*
00612                  * Perform binary search
00613                  */
00614                 m = l + (u - l) / 2;
00615                 if (strcmp(s, m->c_cmd) > 0) l = m + 1;
00616                 else u = m;
00617         } while (l < u);
00618         if (!strcmp(s, u->c_cmd)) return u - commands;
00619         return 0;
00620 }
00621 
00622 /*ARGSUSED*/
00623 STATIC int
00624 do_lcomm(cnt) long cnt; {       /* Repeat last command */
00625 
00626         if (!lastcomm) {
00627                 error("No previous command");
00628                 return;
00629         }
00630         do_comm(lastcomm, lastcount);
00631 }
00632 
00633 /*
00634  * Execute a command, with optional count "count".
00635  */
00636 
00637 VOID
00638 do_comm(comm, count) register int comm; register long count; {
00639 
00640         register struct commands *pcomm;
00641         register int temp;
00642         register int flags;
00643 
00644         pcomm = &commands[comm];
00645         flags = pcomm->c_flags;
00646 
00647         /*
00648          * Check the command.
00649          * If the last line of the file is displayed and the command goes
00650          * forwards and does'nt have the ability to go to the next file, it
00651          * is an error.
00652          * If the first line of the file is displayed and the command goes
00653          * backwards and does'nt have the ability to go to the previous file,
00654          * it is an error.
00655          * Also check wether we need the next or previous file. If so, get it.
00656          */
00657         if ((status & EOFILE) && (flags & AHEAD)) {
00658                 if (qflag || !(flags & TONEXTFILE)) return;
00659                 if (nextfile(1)) quit();
00660         }
00661         if ((status & START) && (flags & BACK)) {
00662                 if (qflag || !(flags & TOPREVFILE)) return;
00663                 if (nextfile(-1)) quit();
00664         }
00665         /*
00666          * Does the command stick around for LASTCOMM?
00667          */
00668         if (flags & STICKY) {
00669                 lastcomm = comm;
00670                 lastcount = count;
00671         }
00672         if (!count) {
00673                 if (flags & NEEDS_COUNT) count = 1;
00674         }
00675         else {
00676                 /*
00677                  * Does the command adapt the screensize?
00678                  */
00679                 if (flags & SCREENSIZE_ADAPT) {
00680                         temp = maxpagesize;
00681                         if ((unsigned) count < temp) {
00682                                 temp = count;
00683                         }
00684                         if (temp < MINPAGESIZE) {
00685                                 temp = MINPAGESIZE;
00686                         }
00687                         count = 0;
00688                         pagesize = temp;
00689                 }
00690                 /*
00691                  * Does the command adapt the scrollsize?
00692                  */
00693                 if (flags & SCROLLSIZE_ADAPT) {
00694                         temp = maxpagesize - 1;
00695                         if ((unsigned) count < temp) {
00696                                 temp = (int) count;
00697                         }
00698                         scrollsize = temp;
00699                         count = 0;
00700                 }
00701         }
00702         /*
00703          * Now execute the command.
00704          */
00705         (*(pcomm->c_func))(count);
00706 }

Generated on Fri Apr 14 22:57:13 2006 for minix by  doxygen 1.4.6