Logo Search packages:      
Sourcecode: vigor version File versions  Download package

ex_read.c

/*-
 * Copyright (c) 1992, 1993, 1994
 *    The Regents of the University of California.  All rights reserved.
 * Copyright (c) 1992, 1993, 1994, 1995, 1996
 *    Keith Bostic.  All rights reserved.
 *
 * See the LICENSE file for redistribution information.
 */

#include "config.h"

#ifndef lint
static const char sccsid[] = "@(#)ex_read.c     10.38 (Berkeley) 8/12/96";
#endif /* not lint */

#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/time.h>

#include <bitstring.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../common/common.h"
#include "../vi/vi.h"

/*
 * ex_read --     :read [file]
 *          :read [!cmd]
 *    Read from a file or utility.
 *
 * !!!
 * Historical vi wouldn't undo a filter read, for no apparent reason.
 *
 * PUBLIC: int ex_read __P((SCR *, EXCMD *));
 */
int
ex_read(sp, cmdp)
      SCR *sp;
      EXCMD *cmdp;
{
      enum { R_ARG, R_EXPANDARG, R_FILTER } which;
      struct stat sb;
      CHAR_T *arg, *name;
      EX_PRIVATE *exp;
      FILE *fp;
      FREF *frp;
      GS *gp;
      MARK rm;
      recno_t nlines;
      size_t arglen;
      int argc, rval;
      char *p;

      gp = sp->gp;

      /*
       * 0 args: read the current pathname.
       * 1 args: check for "read !arg".
       */
      switch (cmdp->argc) {
      case 0:
            which = R_ARG;
            break;
      case 1:
            arg = cmdp->argv[0]->bp;
            arglen = cmdp->argv[0]->len;
            if (*arg == '!') {
                  ++arg;
                  --arglen;
                  which = R_FILTER;

                  /* Secure means no shell access. */
                  if (O_ISSET(sp, O_SECURE)) {
                        ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
                        return (1);
                  }
            } else
                  which = R_EXPANDARG;
            break;
      default:
            abort();
            /* NOTREACHED */
      }

      /* Load a temporary file if no file being edited. */
      if (sp->ep == NULL) {
            if ((frp = file_add(sp, NULL)) == NULL)
                  return (1);
            if (file_init(sp, frp, NULL, 0))
                  return (1);
      }

      switch (which) {
      case R_FILTER:
            /*
             * File name and bang expand the user's argument.  If
             * we don't get an additional argument, it's illegal.
             */
            argc = cmdp->argc;
            if (argv_exp1(sp, cmdp, arg, arglen, 1))
                  return (1);
            if (argc == cmdp->argc) {
                  ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
                  return (1);
            }
            argc = cmdp->argc - 1;

            /* Set the last bang command. */
            exp = EXP(sp);
            if (exp->lastbcomm != NULL)
                  free(exp->lastbcomm);
            if ((exp->lastbcomm =
                strdup(cmdp->argv[argc]->bp)) == NULL) {
                  msgq(sp, M_SYSERR, NULL);
                  return (1);
            }

            /*
             * Vi redisplayed the user's argument if it changed, ex
             * always displayed a !, plus the user's argument if it
             * changed.
             */
            if (F_ISSET(sp, SC_VI)) {
                  if (F_ISSET(cmdp, E_MODIFY))
                        (void)vs_update(sp, "!", cmdp->argv[argc]->bp);
            } else {
                  if (F_ISSET(cmdp, E_MODIFY))
                        (void)ex_printf(sp,
                            "!%s\n", cmdp->argv[argc]->bp);
                  else
                        (void)ex_puts(sp, "!\n");
                  (void)ex_fflush(sp);
            }

            /*
             * Historically, filter reads as the first ex command didn't
             * wait for the user. If SC_SCR_EXWROTE not already set, set
             * the don't-wait flag.
             */
            if (!F_ISSET(sp, SC_SCR_EXWROTE))
                  F_SET(sp, SC_EX_WAIT_NO);

            /*
             * Switch into ex canonical mode.  The reason to restore the
             * original terminal modes for read filters is so that users
             * can do things like ":r! cat /dev/tty".
             *
             * !!!
             * We do not output an extra <newline>, so that we don't touch
             * the screen on a normal read.
             */
            if (F_ISSET(sp, SC_VI)) {
                  if (gp->scr_screen(sp, SC_EX)) {
                        ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
                        return (1);
                  }
                  /*
                   * !!!
                   * Historically, the read command doesn't switch to
                   * the alternate X11 xterm screen, if doing a filter
                   * read -- don't set SA_ALTERNATE.
                   */
                  F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
            }

            if (ex_filter(sp, cmdp, &cmdp->addr1,
                NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
                  return (1);

            /* The filter version of read set the autoprint flag. */
            F_SET(cmdp, E_AUTOPRINT);

            /*
             * If in vi mode, move to the first nonblank.  Might have
             * switched into ex mode, so saved the original SC_VI value.
             */
            sp->lno = rm.lno;
            if (F_ISSET(sp, SC_VI)) {
                  sp->cno = 0;
                  (void)nonblank(sp, sp->lno, &sp->cno);
            }
            return (0);
      case R_ARG:
            name = sp->frp->name;
            break;
      case R_EXPANDARG:
            if (argv_exp2(sp, cmdp, arg, arglen))
                  return (1);
            /*
             *  0 args: impossible.
             *  1 args: impossible (I hope).
             *  2 args: read it.
             * >2 args: object, too many args.
             *
             * The 1 args case depends on the argv_sexp() function refusing
             * to return success without at least one non-blank character.
             */
            switch (cmdp->argc) {
            case 0:
            case 1:
                  abort();
                  /* NOTREACHED */
            case 2:
                  name = cmdp->argv[1]->bp;
                  /*
                   * !!!
                   * Historically, the read and write commands renamed
                   * "unnamed" files, or, if the file had a name, set
                   * the alternate file name.
                   */
                  if (F_ISSET(sp->frp, FR_TMPFILE) &&
                      !F_ISSET(sp->frp, FR_EXNAMED)) {
                        if ((p = v_strdup(sp, cmdp->argv[1]->bp,
                            cmdp->argv[1]->len)) != NULL) {
                              free(sp->frp->name);
                              sp->frp->name = p;
                        }
                        /*
                         * The file has a real name, it's no longer a
                         * temporary, clear the temporary file flags.
                         */
                        F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
                        F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);

                        /* Notify the screen. */
                        (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
                  } else
                        set_alt_name(sp, name);
                  break;
            default:
                  ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
                  return (1);
            
            }
            break;
      }

      /*
       * !!!
       * Historically, vi did not permit reads from non-regular files, nor
       * did it distinguish between "read !" and "read!", so there was no
       * way to "force" it.  We permit reading from named pipes too, since
       * they didn't exist when the original implementation of vi was done
       * and they seem a reasonable addition.
       */
      if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
            msgq_str(sp, M_SYSERR, name, "%s");
            return (1);
      }
      if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
            (void)fclose(fp);
            msgq(sp, M_ERR,
                "145|Only regular files and named pipes may be read");
            return (1);
      }

      /* Try and get a lock. */
      if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
            msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);

      rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);

      /*
       * In vi, set the cursor to the first line read in, if anything read
       * in, otherwise, the address.  (Historic vi set it to the line after
       * the address regardless, but since that line may not exist we don't
       * bother.)
       *
       * In ex, set the cursor to the last line read in, if anything read in,
       * otherwise, the address.
       */
      if (F_ISSET(sp, SC_VI)) {
            sp->lno = cmdp->addr1.lno;
            if (nlines)
                  ++sp->lno;
      } else
            sp->lno = cmdp->addr1.lno + nlines;
      return (rval);
}

/*
 * ex_readfp --
 *    Read lines into the file.
 *
 * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
 */
int
ex_readfp(sp, name, fp, fm, nlinesp, silent)
      SCR *sp;
      char *name;
      FILE *fp;
      MARK *fm;
      recno_t *nlinesp;
      int silent;
{
      EX_PRIVATE *exp;
      GS *gp;
      recno_t lcnt, lno;
      size_t len;
      u_long ccnt;                  /* XXX: can't print off_t portably. */
      int nf, rval;
      char *p;

      gp = sp->gp;
      exp = EXP(sp);

      /*
       * Add in the lines from the output.  Insertion starts at the line
       * following the address.
       */
      ccnt = 0;
      lcnt = 0;
      p = "147|Reading...";
      for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
            if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
                  if (INTERRUPTED(sp))
                        break;
                  if (!silent) {
                        gp->scr_busy(sp, p,
                            p == NULL ? BUSY_UPDATE : BUSY_ON);
                        p = NULL;
                  }
            }
            if (db_append(sp, 1, lno, exp->ibp, len))
                  goto err;
            ccnt += len;
      }

      if (ferror(fp) || fclose(fp))
            goto err;

      /* Return the number of lines read in. */
      if (nlinesp != NULL)
            *nlinesp = lcnt;

      if (!silent) {
            p = msg_print(sp, name, &nf);
            msgq(sp, M_INFO,
                "148|%s: %lu lines, %lu characters", p, lcnt, ccnt);
            if (nf)
                  FREE_SPACE(sp, p, 0);
      }

      rval = 0;
      if (0) {
err:        msgq_str(sp, M_SYSERR, name, "%s");
            (void)fclose(fp);
            rval = 1;
      }

      if (!silent)
            gp->scr_busy(sp, NULL, BUSY_OFF);
      return (rval);
}

Generated by  Doxygen 1.6.0   Back to index