home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ex / ex_read.c < prev    next >
C/C++ Source or Header  |  1996-08-12  |  8KB  |  361 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1992, 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)ex_read.c    10.38 (Berkeley) 8/12/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18. #include <sys/stat.h>
  19. #include <sys/time.h>
  20.  
  21. #include <bitstring.h>
  22. #include <ctype.h>
  23. #include <errno.h>
  24. #include <limits.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28.  
  29. #include "../common/common.h"
  30. #include "../vi/vi.h"
  31.  
  32. /*
  33.  * ex_read --    :read [file]
  34.  *        :read [!cmd]
  35.  *    Read from a file or utility.
  36.  *
  37.  * !!!
  38.  * Historical vi wouldn't undo a filter read, for no apparent reason.
  39.  *
  40.  * PUBLIC: int ex_read __P((SCR *, EXCMD *));
  41.  */
  42. int
  43. ex_read(sp, cmdp)
  44.     SCR *sp;
  45.     EXCMD *cmdp;
  46. {
  47.     enum { R_ARG, R_EXPANDARG, R_FILTER } which;
  48.     struct stat sb;
  49.     CHAR_T *arg, *name;
  50.     EX_PRIVATE *exp;
  51.     FILE *fp;
  52.     FREF *frp;
  53.     GS *gp;
  54.     MARK rm;
  55.     recno_t nlines;
  56.     size_t arglen;
  57.     int argc, rval;
  58.     char *p;
  59.  
  60.     gp = sp->gp;
  61.  
  62.     /*
  63.      * 0 args: read the current pathname.
  64.      * 1 args: check for "read !arg".
  65.      */
  66.     switch (cmdp->argc) {
  67.     case 0:
  68.         which = R_ARG;
  69.         break;
  70.     case 1:
  71.         arg = cmdp->argv[0]->bp;
  72.         arglen = cmdp->argv[0]->len;
  73.         if (*arg == '!') {
  74.             ++arg;
  75.             --arglen;
  76.             which = R_FILTER;
  77.  
  78.             /* Secure means no shell access. */
  79.             if (O_ISSET(sp, O_SECURE)) {
  80.                 ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
  81.                 return (1);
  82.             }
  83.         } else
  84.             which = R_EXPANDARG;
  85.         break;
  86.     default:
  87.         abort();
  88.         /* NOTREACHED */
  89.     }
  90.  
  91.     /* Load a temporary file if no file being edited. */
  92.     if (sp->ep == NULL) {
  93.         if ((frp = file_add(sp, NULL)) == NULL)
  94.             return (1);
  95.         if (file_init(sp, frp, NULL, 0))
  96.             return (1);
  97.     }
  98.  
  99.     switch (which) {
  100.     case R_FILTER:
  101.         /*
  102.          * File name and bang expand the user's argument.  If
  103.          * we don't get an additional argument, it's illegal.
  104.          */
  105.         argc = cmdp->argc;
  106.         if (argv_exp1(sp, cmdp, arg, arglen, 1))
  107.             return (1);
  108.         if (argc == cmdp->argc) {
  109.             ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
  110.             return (1);
  111.         }
  112.         argc = cmdp->argc - 1;
  113.  
  114.         /* Set the last bang command. */
  115.         exp = EXP(sp);
  116.         if (exp->lastbcomm != NULL)
  117.             free(exp->lastbcomm);
  118.         if ((exp->lastbcomm =
  119.             strdup(cmdp->argv[argc]->bp)) == NULL) {
  120.             msgq(sp, M_SYSERR, NULL);
  121.             return (1);
  122.         }
  123.  
  124.         /*
  125.          * Vi redisplayed the user's argument if it changed, ex
  126.          * always displayed a !, plus the user's argument if it
  127.          * changed.
  128.          */
  129.         if (F_ISSET(sp, SC_VI)) {
  130.             if (F_ISSET(cmdp, E_MODIFY))
  131.                 (void)vs_update(sp, "!", cmdp->argv[argc]->bp);
  132.         } else {
  133.             if (F_ISSET(cmdp, E_MODIFY))
  134.                 (void)ex_printf(sp,
  135.                     "!%s\n", cmdp->argv[argc]->bp);
  136.             else
  137.                 (void)ex_puts(sp, "!\n");
  138.             (void)ex_fflush(sp);
  139.         }
  140.  
  141.         /*
  142.          * Historically, filter reads as the first ex command didn't
  143.          * wait for the user. If SC_SCR_EXWROTE not already set, set
  144.          * the don't-wait flag.
  145.          */
  146.         if (!F_ISSET(sp, SC_SCR_EXWROTE))
  147.             F_SET(sp, SC_EX_WAIT_NO);
  148.  
  149.         /*
  150.          * Switch into ex canonical mode.  The reason to restore the
  151.          * original terminal modes for read filters is so that users
  152.          * can do things like ":r! cat /dev/tty".
  153.          *
  154.          * !!!
  155.          * We do not output an extra <newline>, so that we don't touch
  156.          * the screen on a normal read.
  157.          */
  158.         if (F_ISSET(sp, SC_VI)) {
  159.             if (gp->scr_screen(sp, SC_EX)) {
  160.                 ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
  161.                 return (1);
  162.             }
  163.             /*
  164.              * !!!
  165.              * Historically, the read command doesn't switch to
  166.              * the alternate X11 xterm screen, if doing a filter
  167.              * read -- don't set SA_ALTERNATE.
  168.              */
  169.             F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
  170.         }
  171.  
  172.         if (ex_filter(sp, cmdp, &cmdp->addr1,
  173.             NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
  174.             return (1);
  175.  
  176.         /* The filter version of read set the autoprint flag. */
  177.         F_SET(cmdp, E_AUTOPRINT);
  178.  
  179.         /*
  180.          * If in vi mode, move to the first nonblank.  Might have
  181.          * switched into ex mode, so saved the original SC_VI value.
  182.          */
  183.         sp->lno = rm.lno;
  184.         if (F_ISSET(sp, SC_VI)) {
  185.             sp->cno = 0;
  186.             (void)nonblank(sp, sp->lno, &sp->cno);
  187.         }
  188.         return (0);
  189.     case R_ARG:
  190.         name = sp->frp->name;
  191.         break;
  192.     case R_EXPANDARG:
  193.         if (argv_exp2(sp, cmdp, arg, arglen))
  194.             return (1);
  195.         /*
  196.          *  0 args: impossible.
  197.          *  1 args: impossible (I hope).
  198.          *  2 args: read it.
  199.          * >2 args: object, too many args.
  200.          *
  201.          * The 1 args case depends on the argv_sexp() function refusing
  202.          * to return success without at least one non-blank character.
  203.          */
  204.         switch (cmdp->argc) {
  205.         case 0:
  206.         case 1:
  207.             abort();
  208.             /* NOTREACHED */
  209.         case 2:
  210.             name = cmdp->argv[1]->bp;
  211.             /*
  212.              * !!!
  213.              * Historically, the read and write commands renamed
  214.              * "unnamed" files, or, if the file had a name, set
  215.              * the alternate file name.
  216.              */
  217.             if (F_ISSET(sp->frp, FR_TMPFILE) &&
  218.                 !F_ISSET(sp->frp, FR_EXNAMED)) {
  219.                 if ((p = v_strdup(sp, cmdp->argv[1]->bp,
  220.                     cmdp->argv[1]->len)) != NULL) {
  221.                     free(sp->frp->name);
  222.                     sp->frp->name = p;
  223.                 }
  224.                 /*
  225.                  * The file has a real name, it's no longer a
  226.                  * temporary, clear the temporary file flags.
  227.                  */
  228.                 F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
  229.                 F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);
  230.  
  231.                 /* Notify the screen. */
  232.                 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
  233.             } else
  234.                 set_alt_name(sp, name);
  235.             break;
  236.         default:
  237.             ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
  238.             return (1);
  239.         
  240.         }
  241.         break;
  242.     }
  243.  
  244.     /*
  245.      * !!!
  246.      * Historically, vi did not permit reads from non-regular files, nor
  247.      * did it distinguish between "read !" and "read!", so there was no
  248.      * way to "force" it.  We permit reading from named pipes too, since
  249.      * they didn't exist when the original implementation of vi was done
  250.      * and they seem a reasonable addition.
  251.      */
  252.     if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
  253.         msgq_str(sp, M_SYSERR, name, "%s");
  254.         return (1);
  255.     }
  256.     if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
  257.         (void)fclose(fp);
  258.         msgq(sp, M_ERR,
  259.             "145|Only regular files and named pipes may be read");
  260.         return (1);
  261.     }
  262.  
  263.     /* Try and get a lock. */
  264.     if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
  265.         msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);
  266.  
  267.     rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
  268.  
  269.     /*
  270.      * In vi, set the cursor to the first line read in, if anything read
  271.      * in, otherwise, the address.  (Historic vi set it to the line after
  272.      * the address regardless, but since that line may not exist we don't
  273.      * bother.)
  274.      *
  275.      * In ex, set the cursor to the last line read in, if anything read in,
  276.      * otherwise, the address.
  277.      */
  278.     if (F_ISSET(sp, SC_VI)) {
  279.         sp->lno = cmdp->addr1.lno;
  280.         if (nlines)
  281.             ++sp->lno;
  282.     } else
  283.         sp->lno = cmdp->addr1.lno + nlines;
  284.     return (rval);
  285. }
  286.  
  287. /*
  288.  * ex_readfp --
  289.  *    Read lines into the file.
  290.  *
  291.  * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
  292.  */
  293. int
  294. ex_readfp(sp, name, fp, fm, nlinesp, silent)
  295.     SCR *sp;
  296.     char *name;
  297.     FILE *fp;
  298.     MARK *fm;
  299.     recno_t *nlinesp;
  300.     int silent;
  301. {
  302.     EX_PRIVATE *exp;
  303.     GS *gp;
  304.     recno_t lcnt, lno;
  305.     size_t len;
  306.     u_long ccnt;            /* XXX: can't print off_t portably. */
  307.     int nf, rval;
  308.     char *p;
  309.  
  310.     gp = sp->gp;
  311.     exp = EXP(sp);
  312.  
  313.     /*
  314.      * Add in the lines from the output.  Insertion starts at the line
  315.      * following the address.
  316.      */
  317.     ccnt = 0;
  318.     lcnt = 0;
  319.     p = "147|Reading...";
  320.     for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
  321.         if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
  322.             if (INTERRUPTED(sp))
  323.                 break;
  324.             if (!silent) {
  325.                 gp->scr_busy(sp, p,
  326.                     p == NULL ? BUSY_UPDATE : BUSY_ON);
  327.                 p = NULL;
  328.             }
  329.         }
  330.         if (db_append(sp, 1, lno, exp->ibp, len))
  331.             goto err;
  332.         ccnt += len;
  333.     }
  334.  
  335.     if (ferror(fp) || fclose(fp))
  336.         goto err;
  337.  
  338.     /* Return the number of lines read in. */
  339.     if (nlinesp != NULL)
  340.         *nlinesp = lcnt;
  341.  
  342.     if (!silent) {
  343.         p = msg_print(sp, name, &nf);
  344.         msgq(sp, M_INFO,
  345.             "148|%s: %lu lines, %lu characters", p, lcnt, ccnt);
  346.         if (nf)
  347.             FREE_SPACE(sp, p, 0);
  348.     }
  349.  
  350.     rval = 0;
  351.     if (0) {
  352. err:        msgq_str(sp, M_SYSERR, name, "%s");
  353.         (void)fclose(fp);
  354.         rval = 1;
  355.     }
  356.  
  357.     if (!silent)
  358.         gp->scr_busy(sp, NULL, BUSY_OFF);
  359.     return (rval);
  360. }
  361.