home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ex / ex_append.c < prev    next >
C/C++ Source or Header  |  1996-10-23  |  7KB  |  278 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_append.c    10.30 (Berkeley) 10/23/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18.  
  19. #include <bitstring.h>
  20. #include <limits.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <unistd.h>
  24.  
  25. #include "../common/common.h"
  26.  
  27. enum which {APPEND, CHANGE, INSERT};
  28.  
  29. static int ex_aci __P((SCR *, EXCMD *, enum which));
  30.  
  31. /*
  32.  * ex_append -- :[line] a[ppend][!]
  33.  *    Append one or more lines of new text after the specified line,
  34.  *    or the current line if no address is specified.
  35.  *
  36.  * PUBLIC: int ex_append __P((SCR *, EXCMD *));
  37.  */
  38. int
  39. ex_append(sp, cmdp)
  40.     SCR *sp;
  41.     EXCMD *cmdp;
  42. {
  43.     return (ex_aci(sp, cmdp, APPEND));
  44. }
  45.  
  46. /*
  47.  * ex_change -- :[line[,line]] c[hange][!] [count]
  48.  *    Change one or more lines to the input text.
  49.  *
  50.  * PUBLIC: int ex_change __P((SCR *, EXCMD *));
  51.  */
  52. int
  53. ex_change(sp, cmdp)
  54.     SCR *sp;
  55.     EXCMD *cmdp;
  56. {
  57.     return (ex_aci(sp, cmdp, CHANGE));
  58. }
  59.  
  60. /*
  61.  * ex_insert -- :[line] i[nsert][!]
  62.  *    Insert one or more lines of new text before the specified line,
  63.  *    or the current line if no address is specified.
  64.  *
  65.  * PUBLIC: int ex_insert __P((SCR *, EXCMD *));
  66.  */
  67. int
  68. ex_insert(sp, cmdp)
  69.     SCR *sp;
  70.     EXCMD *cmdp;
  71. {
  72.     return (ex_aci(sp, cmdp, INSERT));
  73. }
  74.  
  75. /*
  76.  * ex_aci --
  77.  *    Append, change, insert in ex.
  78.  */
  79. static int
  80. ex_aci(sp, cmdp, cmd)
  81.     SCR *sp;
  82.     EXCMD *cmdp;
  83.     enum which cmd;
  84. {
  85.     CHAR_T *p, *t;
  86.     GS *gp;
  87.     TEXT *tp;
  88.     TEXTH tiq;
  89.     recno_t cnt, lno;
  90.     size_t len;
  91.     u_int32_t flags;
  92.     int need_newline;
  93.  
  94.     gp = sp->gp;
  95.     NEEDFILE(sp, cmdp);
  96.  
  97.     /*
  98.      * If doing a change, replace lines for as long as possible.  Then,
  99.      * append more lines or delete remaining lines.  Changes to an empty
  100.      * file are appends, inserts are the same as appends to the previous
  101.      * line.
  102.      *
  103.      * !!!
  104.      * Set the address to which we'll append.  We set sp->lno to this
  105.      * address as well so that autoindent works correctly when get text
  106.      * from the user.
  107.      */
  108.     lno = cmdp->addr1.lno;
  109.     sp->lno = lno;
  110.     if ((cmd == CHANGE || cmd == INSERT) && lno != 0)
  111.         --lno;
  112.  
  113.     /*
  114.      * !!!
  115.      * If the file isn't empty, cut changes into the unnamed buffer.
  116.      */
  117.     if (cmd == CHANGE && cmdp->addr1.lno != 0 &&
  118.         (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE) ||
  119.         del(sp, &cmdp->addr1, &cmdp->addr2, 1)))
  120.         return (1);
  121.  
  122.     /*
  123.      * !!!
  124.      * Anything that was left after the command separator becomes part
  125.      * of the inserted text.  Apparently, it was common usage to enter:
  126.      *
  127.      *    :g/pattern/append|stuff1
  128.      *
  129.      * and append the line of text "stuff1" to the lines containing the
  130.      * pattern.  It was also historically legal to enter:
  131.      *
  132.      *    :append|stuff1
  133.      *    stuff2
  134.      *    .
  135.      *
  136.      * and the text on the ex command line would be appended as well as
  137.      * the text inserted after it.  There was an historic bug however,
  138.      * that the user had to enter *two* terminating lines (the '.' lines)
  139.      * to terminate text input mode, in this case.  This whole thing
  140.      * could be taken too far, however.  Entering:
  141.      *
  142.      *    :append|stuff1\
  143.      *    stuff2
  144.      *    stuff3
  145.      *    .
  146.      *
  147.      * i.e. mixing and matching the forms confused the historic vi, and,
  148.      * not only did it take two terminating lines to terminate text input
  149.      * mode, but the trailing backslashes were retained on the input.  We
  150.      * match historic practice except that we discard the backslashes.
  151.      *
  152.      * Input lines specified on the ex command line lines are separated by
  153.      * <newline>s.  If there is a trailing delimiter an empty line was
  154.      * inserted.  There may also be a leading delimiter, which is ignored
  155.      * unless it's also a trailing delimiter.  It is possible to encounter
  156.      * a termination line, i.e. a single '.', in a global command, but not
  157.      * necessary if the text insert command was the last of the global
  158.      * commands.
  159.      */
  160.     if (cmdp->save_cmdlen != 0) {
  161.         for (p = cmdp->save_cmd,
  162.             len = cmdp->save_cmdlen; len > 0; p = t) {
  163.             for (t = p; len > 0 && t[0] != '\n'; ++t, --len);
  164.             if (t != p || len == 0) {
  165.                 if (F_ISSET(sp, SC_EX_GLOBAL) &&
  166.                     t - p == 1 && p[0] == '.') {
  167.                     ++t;
  168.                     if (len > 0)
  169.                         --len;
  170.                     break;
  171.                 }
  172.                 if (db_append(sp, 1, lno++, p, t - p))
  173.                     return (1);
  174.             }
  175.             if (len != 0) {
  176.                 ++t;
  177.                 if (--len == 0 &&
  178.                     db_append(sp, 1, lno++, "", 0))
  179.                     return (1);
  180.             }
  181.         }
  182.         /*
  183.          * If there's any remaining text, we're in a global, and
  184.          * there's more command to parse.
  185.          *
  186.          * !!!
  187.          * We depend on the fact that non-global commands will eat the
  188.          * rest of the command line as text input, and before getting
  189.          * any text input from the user.  Otherwise, we'd have to save
  190.          * off the command text before or during the call to the text
  191.          * input function below.
  192.          */
  193.         if (len != 0)
  194.             cmdp->save_cmd = t;
  195.         cmdp->save_cmdlen = len;
  196.     }
  197.  
  198.     if (F_ISSET(sp, SC_EX_GLOBAL)) {
  199.         if ((sp->lno = lno) == 0 && db_exist(sp, 1))
  200.             sp->lno = 1;
  201.         return (0);
  202.     }
  203.  
  204.     /*
  205.      * If not in a global command, read from the terminal.
  206.      *
  207.      * If this code is called by vi, we want to reset the terminal and use
  208.      * ex's line get routine.  It actually works fine if we use vi's get
  209.      * routine, but it doesn't look as nice.  Maybe if we had a separate
  210.      * window or something, but getting a line at a time looks awkward.
  211.      * However, depending on the screen that we're using, that may not
  212.      * be possible.
  213.      */
  214.     if (F_ISSET(sp, SC_VI)) {
  215.         if (gp->scr_screen(sp, SC_EX)) {
  216.             ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
  217.             return (1);
  218.         }
  219.  
  220.         /* If we're still in the vi screen, move out explicitly. */
  221.         need_newline = !F_ISSET(sp, SC_SCR_EXWROTE);
  222.         F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
  223.         if (need_newline)
  224.             (void)ex_puts(sp, "\n");
  225.  
  226.         /*
  227.          * !!!
  228.          * Users of historical versions of vi sometimes get confused
  229.          * when they enter append mode, and can't seem to get out of
  230.          * it.  Give them an informational message.
  231.          */
  232.         (void)ex_puts(sp,
  233.             msg_cat(sp, "273|Entering ex input mode.", NULL));
  234.         (void)ex_puts(sp, "\n");
  235.         (void)ex_fflush(sp);
  236.     }
  237.  
  238.     /*
  239.      * Set input flags; the ! flag turns off autoindent for append,
  240.      * change and insert.
  241.      */
  242.     LF_INIT(TXT_DOTTERM | TXT_NUMBER);
  243.     if (!FL_ISSET(cmdp->iflags, E_C_FORCE) && O_ISSET(sp, O_AUTOINDENT))
  244.         LF_SET(TXT_AUTOINDENT);
  245.     if (O_ISSET(sp, O_BEAUTIFY))
  246.         LF_SET(TXT_BEAUTIFY);
  247.  
  248.     /*
  249.      * This code can't use the common screen TEXTH structure (sp->tiq),
  250.      * as it may already be in use, e.g. ":append|s/abc/ABC/" would fail
  251.      * as we are only halfway through the text when the append code fires.
  252.      * Use a local structure instead.  (The ex code would have to use a
  253.      * local structure except that we're guaranteed to finish remaining
  254.      * characters in the common TEXTH structure when they were inserted
  255.      * into the file, above.)
  256.      */
  257.     memset(&tiq, 0, sizeof(TEXTH));
  258.     CIRCLEQ_INIT(&tiq);
  259.  
  260.     if (ex_txt(sp, &tiq, 0, flags))
  261.         return (1);
  262.  
  263.     for (cnt = 0, tp = tiq.cqh_first;
  264.         tp != (TEXT *)&tiq; ++cnt, tp = tp->q.cqe_next)
  265.         if (db_append(sp, 1, lno++, tp->lb, tp->len))
  266.             return (1);
  267.  
  268.     /*
  269.      * Set sp->lno to the final line number value (correcting for a
  270.      * possible 0 value) as that's historically correct for the final
  271.      * line value, whether or not the user entered any text.
  272.      */
  273.     if ((sp->lno = lno) == 0 && db_exist(sp, 1))
  274.         sp->lno = 1;
  275.  
  276.     return (0);
  277. }
  278.