home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ex / ex_write.c < prev    next >
C/C++ Source or Header  |  1996-07-12  |  8KB  |  376 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_write.c    10.30 (Berkeley) 7/12/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18. #include <sys/stat.h>
  19.  
  20. #include <bitstring.h>
  21. #include <ctype.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <limits.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29.  
  30. #include "../common/common.h"
  31.  
  32. enum which {WN, WQ, WRITE, XIT};
  33. static int exwr __P((SCR *, EXCMD *, enum which));
  34.  
  35. /*
  36.  * ex_wn --    :wn[!] [>>] [file]
  37.  *    Write to a file and switch to the next one.
  38.  *
  39.  * PUBLIC: int ex_wn __P((SCR *, EXCMD *));
  40.  */
  41. int
  42. ex_wn(sp, cmdp)
  43.     SCR *sp;
  44.     EXCMD *cmdp;
  45. {
  46.     if (exwr(sp, cmdp, WN))
  47.         return (1);
  48.     if (file_m3(sp, 0))
  49.         return (1);
  50.  
  51.     /* The file name isn't a new file to edit. */
  52.     cmdp->argc = 0;
  53.  
  54.     return (ex_next(sp, cmdp));
  55. }
  56.  
  57. /*
  58.  * ex_wq --    :wq[!] [>>] [file]
  59.  *    Write to a file and quit.
  60.  *
  61.  * PUBLIC: int ex_wq __P((SCR *, EXCMD *));
  62.  */
  63. int
  64. ex_wq(sp, cmdp)
  65.     SCR *sp;
  66.     EXCMD *cmdp;
  67. {
  68.     int force;
  69.  
  70.     if (exwr(sp, cmdp, WQ))
  71.         return (1);
  72.     if (file_m3(sp, 0))
  73.         return (1);
  74.  
  75.     force = FL_ISSET(cmdp->iflags, E_C_FORCE);
  76.  
  77.     if (ex_ncheck(sp, force))
  78.         return (1);
  79.  
  80.     F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT);
  81.     return (0);
  82. }
  83.  
  84. /*
  85.  * ex_write --    :write[!] [>>] [file]
  86.  *        :write [!] [cmd]
  87.  *    Write to a file.
  88.  *
  89.  * PUBLIC: int ex_write __P((SCR *, EXCMD *));
  90.  */
  91. int
  92. ex_write(sp, cmdp)
  93.     SCR *sp;
  94.     EXCMD *cmdp;
  95. {
  96.     return (exwr(sp, cmdp, WRITE));
  97. }
  98.  
  99.  
  100. /*
  101.  * ex_xit -- :x[it]! [file]
  102.  *    Write out any modifications and quit.
  103.  *
  104.  * PUBLIC: int ex_xit __P((SCR *, EXCMD *));
  105.  */
  106. int
  107. ex_xit(sp, cmdp)
  108.     SCR *sp;
  109.     EXCMD *cmdp;
  110. {
  111.     int force;
  112.  
  113.     NEEDFILE(sp, cmdp);
  114.  
  115.     if (F_ISSET(sp->ep, F_MODIFIED) && exwr(sp, cmdp, XIT))
  116.         return (1);
  117.     if (file_m3(sp, 0))
  118.         return (1);
  119.  
  120.     force = FL_ISSET(cmdp->iflags, E_C_FORCE);
  121.  
  122.     if (ex_ncheck(sp, force))
  123.         return (1);
  124.  
  125.     F_SET(sp, force ? SC_EXIT_FORCE : SC_EXIT);
  126.     return (0);
  127. }
  128.  
  129. /*
  130.  * exwr --
  131.  *    The guts of the ex write commands.
  132.  */
  133. static int
  134. exwr(sp, cmdp, cmd)
  135.     SCR *sp;
  136.     EXCMD *cmdp;
  137.     enum which cmd;
  138. {
  139.     MARK rm;
  140.     int flags;
  141.     char *name, *p;
  142.  
  143.     NEEDFILE(sp, cmdp);
  144.  
  145.     /* All write commands can have an associated '!'. */
  146.     LF_INIT(FS_POSSIBLE);
  147.     if (FL_ISSET(cmdp->iflags, E_C_FORCE))
  148.         LF_SET(FS_FORCE);
  149.  
  150.     /* Skip any leading whitespace. */
  151.     if (cmdp->argc != 0)
  152.         for (p = cmdp->argv[0]->bp; *p != '\0' && isblank(*p); ++p);
  153.  
  154.     /* If "write !" it's a pipe to a utility. */
  155.     if (cmdp->argc != 0 && cmd == WRITE && *p == '!') {
  156.         /* Secure means no shell access. */
  157.         if (O_ISSET(sp, O_SECURE)) {
  158.             ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
  159.             return (1);
  160.         }
  161.  
  162.         /* Expand the argument. */
  163.         for (++p; *p && isblank(*p); ++p);
  164.         if (*p == '\0') {
  165.             ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
  166.             return (1);
  167.         }
  168.         if (argv_exp1(sp, cmdp, p, strlen(p), 1))
  169.             return (1);
  170.  
  171.         /*
  172.          * Historically, vi waited after a write filter even if there
  173.          * wasn't any output from the command.  People complained when
  174.          * nvi waited only if there was output, wanting the visual cue
  175.          * that the program hadn't written anything.
  176.          */
  177.         F_SET(sp, SC_EX_WAIT_YES);
  178.  
  179.         /*
  180.          * !!!
  181.          * Ignore the return cursor position, the cursor doesn't
  182.          * move.
  183.          */
  184.         if (ex_filter(sp, cmdp, &cmdp->addr1,
  185.             &cmdp->addr2, &rm, cmdp->argv[1]->bp, FILTER_WRITE))
  186.             return (1);
  187.  
  188.         /* Ex terminates with a bang, even if the command fails. */
  189.         if (!F_ISSET(sp, SC_VI) && !F_ISSET(sp, SC_EX_SILENT))
  190.             (void)ex_puts(sp, "!\n");
  191.  
  192.         return (0);
  193.     }
  194.  
  195.     /* Set the FS_ALL flag if we're writing the entire file. */
  196.     if (cmdp->addr1.lno <= 1 && !db_exist(sp, cmdp->addr2.lno + 1))
  197.         LF_SET(FS_ALL);
  198.  
  199.     /* If "write >>" it's an append to a file. */
  200.     if (cmdp->argc != 0 && cmd != XIT && p[0] == '>' && p[1] == '>') {
  201.         LF_SET(FS_APPEND);
  202.  
  203.         /* Skip ">>" and whitespace. */
  204.         for (p += 2; *p && isblank(*p); ++p);
  205.     }
  206.  
  207.     /* If no other arguments, just write the file back. */
  208.     if (cmdp->argc == 0 || *p == '\0')
  209.         return (file_write(sp,
  210.             &cmdp->addr1, &cmdp->addr2, NULL, flags));
  211.  
  212.     /* Build an argv so we get an argument count and file expansion. */
  213.     if (argv_exp2(sp, cmdp, p, strlen(p)))
  214.         return (1);
  215.  
  216.     /*
  217.      *  0 args: impossible.
  218.      *  1 args: impossible (I hope).
  219.      *  2 args: read it.
  220.      * >2 args: object, too many args.
  221.      *
  222.      * The 1 args case depends on the argv_sexp() function refusing
  223.      * to return success without at least one non-blank character.
  224.      */
  225.     switch (cmdp->argc) {
  226.     case 0:
  227.     case 1:
  228.         abort();
  229.         /* NOTREACHED */
  230.     case 2:
  231.         name = cmdp->argv[1]->bp;
  232.  
  233.         /*
  234.          * !!!
  235.          * Historically, the read and write commands renamed
  236.          * "unnamed" files, or, if the file had a name, set
  237.          * the alternate file name.
  238.          */
  239.         if (F_ISSET(sp->frp, FR_TMPFILE) &&
  240.             !F_ISSET(sp->frp, FR_EXNAMED)) {
  241.             if ((p = v_strdup(sp,
  242.                 cmdp->argv[1]->bp, cmdp->argv[1]->len)) != NULL) {
  243.                 free(sp->frp->name);
  244.                 sp->frp->name = p;
  245.             }
  246.             /*
  247.              * The file has a real name, it's no longer a
  248.              * temporary, clear the temporary file flags.
  249.              *
  250.              * !!!
  251.              * If we're writing the whole file, FR_NAMECHANGE
  252.              * will be cleared by the write routine -- this is
  253.              * historic practice.
  254.              */
  255.             F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
  256.             F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);
  257.  
  258.             /* Notify the screen. */
  259.             (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
  260.         } else
  261.             set_alt_name(sp, name);
  262.         break;
  263.     default:
  264.         ex_emsg(sp, p, EXM_FILECOUNT);
  265.         return (1);
  266.     }
  267.  
  268.     return (file_write(sp, &cmdp->addr1, &cmdp->addr2, name, flags));
  269. }
  270.  
  271. /*
  272.  * ex_writefp --
  273.  *    Write a range of lines to a FILE *.
  274.  *
  275.  * PUBLIC: int ex_writefp __P((SCR *,
  276.  * PUBLIC:    char *, FILE *, MARK *, MARK *, u_long *, u_long *, int));
  277.  */
  278. int
  279. ex_writefp(sp, name, fp, fm, tm, nlno, nch, silent)
  280.     SCR *sp;
  281.     char *name;
  282.     FILE *fp;
  283.     MARK *fm, *tm;
  284.     u_long *nlno, *nch;
  285.     int silent;
  286. {
  287.     struct stat sb;
  288.     GS *gp;
  289.     u_long ccnt;            /* XXX: can't print off_t portably. */
  290.     recno_t fline, tline, lcnt;
  291.     size_t len;
  292.     int rval;
  293.     char *msg, *p;
  294.  
  295.     gp = sp->gp;
  296.     fline = fm->lno;
  297.     tline = tm->lno;
  298.  
  299.     if (nlno != NULL) {
  300.         *nch = 0;
  301.         *nlno = 0;
  302.     }
  303.  
  304.     /*
  305.      * The vi filter code has multiple processes running simultaneously,
  306.      * and one of them calls ex_writefp().  The "unsafe" function calls
  307.      * in this code are to db_get() and msgq().  Db_get() is safe, see
  308.      * the comment in ex_filter.c:ex_filter() for details.  We don't call
  309.      * msgq if the multiple process bit in the EXF is set.
  310.      *
  311.      * !!!
  312.      * Historic vi permitted files of 0 length to be written.  However,
  313.      * since the way vi got around dealing with "empty" files was to
  314.      * always have a line in the file no matter what, it wrote them as
  315.      * files of a single, empty line.  We write empty files.
  316.      *
  317.      * "Alex, I'll take vi trivia for $1000."
  318.      */
  319.     ccnt = 0;
  320.     lcnt = 0;
  321.     msg = "253|Writing...";
  322.     if (tline != 0)
  323.         for (; fline <= tline; ++fline, ++lcnt) {
  324.             /* Caller has to provide any interrupt message. */
  325.             if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
  326.                 if (INTERRUPTED(sp))
  327.                     break;
  328.                 if (!silent) {
  329.                     gp->scr_busy(sp, msg, msg == NULL ?
  330.                         BUSY_UPDATE : BUSY_ON);
  331.                     msg = NULL;
  332.                 }
  333.             }
  334.             if (db_get(sp, fline, DBG_FATAL, &p, &len))
  335.                 goto err;
  336.             if (fwrite(p, 1, len, fp) != len)
  337.                 goto err;
  338.             ccnt += len;
  339.             if (putc('\n', fp) != '\n')
  340.                 break;
  341.             ++ccnt;
  342.         }
  343.  
  344.     if (fflush(fp))
  345.         goto err;
  346.     /*
  347.      * XXX
  348.      * I don't trust NFS -- check to make sure that we're talking to
  349.      * a regular file and sync so that NFS is forced to flush.
  350.      */
  351.     if (!fstat(fileno(fp), &sb) &&
  352.         S_ISREG(sb.st_mode) && fsync(fileno(fp)))
  353.         goto err;
  354.  
  355.     if (fclose(fp))
  356.         goto err;
  357.  
  358.     rval = 0;
  359.     if (0) {
  360. err:        if (!F_ISSET(sp->ep, F_MULTILOCK))
  361.             msgq_str(sp, M_SYSERR, name, "%s");
  362.         (void)fclose(fp);
  363.         rval = 1;
  364.     }
  365.  
  366.     if (!silent)
  367.         gp->scr_busy(sp, NULL, BUSY_OFF);
  368.  
  369.     /* Report the possibly partial transfer. */
  370.     if (nlno != NULL) {
  371.         *nch = ccnt;
  372.         *nlno = lcnt;
  373.     }
  374.     return (rval);
  375. }
  376.