home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ex / ex_join.c < prev    next >
C/C++ Source or Header  |  1996-09-15  |  5KB  |  178 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_join.c    10.10 (Berkeley) 9/15/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18.  
  19. #include <bitstring.h>
  20. #include <ctype.h>
  21. #include <limits.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. #include "../common/common.h"
  27.  
  28. /*
  29.  * ex_join -- :[line [,line]] j[oin][!] [count] [flags]
  30.  *    Join lines.
  31.  *
  32.  * PUBLIC: int ex_join __P((SCR *, EXCMD *));
  33.  */
  34. int
  35. ex_join(sp, cmdp)
  36.     SCR *sp;
  37.     EXCMD *cmdp;
  38. {
  39.     recno_t from, to;
  40.     size_t blen, clen, len, tlen;
  41.     int echar, extra, first;
  42.     char *bp, *p, *tbp;
  43.  
  44.     NEEDFILE(sp, cmdp);
  45.  
  46.     from = cmdp->addr1.lno;
  47.     to = cmdp->addr2.lno;
  48.  
  49.     /* Check for no lines to join. */
  50.     if (!db_exist(sp, from + 1)) {
  51.         msgq(sp, M_ERR, "131|No following lines to join");
  52.         return (1);
  53.     }
  54.  
  55.     GET_SPACE_RET(sp, bp, blen, 256);
  56.  
  57.     /*
  58.      * The count for the join command was off-by-one,
  59.      * historically, to other counts for other commands.
  60.      */
  61.     if (FL_ISSET(cmdp->iflags, E_C_COUNT))
  62.         ++cmdp->addr2.lno;
  63.  
  64.     /*
  65.      * If only a single address specified, or, the same address
  66.      * specified twice, the from/two addresses will be the same.
  67.      */
  68.     if (cmdp->addr1.lno == cmdp->addr2.lno)
  69.         ++cmdp->addr2.lno;
  70.  
  71.     clen = tlen = 0;
  72.         for (first = 1,
  73.         from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
  74.         /*
  75.          * Get next line.  Historic versions of vi allowed "10J" while
  76.          * less than 10 lines from the end-of-file, so we do too.
  77.          */
  78.         if (db_get(sp, from, 0, &p, &len)) {
  79.             cmdp->addr2.lno = from - 1;
  80.             break;
  81.         }
  82.  
  83.         /* Empty lines just go away. */
  84.         if (len == 0)
  85.             continue;
  86.  
  87.         /*
  88.          * Get more space if necessary.  Note, tlen isn't the length
  89.          * of the new line, it's roughly the amount of space needed.
  90.          * tbp - bp is the length of the new line.
  91.          */
  92.         tlen += len + 2;
  93.         ADD_SPACE_RET(sp, bp, blen, tlen);
  94.         tbp = bp + clen;
  95.  
  96.         /*
  97.          * Historic practice:
  98.          *
  99.          * If force specified, join without modification.
  100.          * If the current line ends with whitespace, strip leading
  101.          *    whitespace from the joined line.
  102.          * If the next line starts with a ), do nothing.
  103.          * If the current line ends with ., insert two spaces.
  104.          * Else, insert one space.
  105.          *
  106.          * One change -- add ? and ! to the list of characters for
  107.          * which we insert two spaces.  I expect that POSIX 1003.2
  108.          * will require this as well.
  109.          *
  110.          * Echar is the last character in the last line joined.
  111.          */
  112.         extra = 0;
  113.         if (!first && !FL_ISSET(cmdp->iflags, E_C_FORCE)) {
  114.             if (isblank(echar))
  115.                 for (; len && isblank(*p); --len, ++p);
  116.             else if (p[0] != ')') {
  117.                 if (strchr(".?!", echar)) {
  118.                     *tbp++ = ' ';
  119.                     ++clen;
  120.                     extra = 1;
  121.                 }
  122.                 *tbp++ = ' ';
  123.                 ++clen;
  124.                 for (; len && isblank(*p); --len, ++p);
  125.             }
  126.         }
  127.  
  128.         if (len != 0) {
  129.             memcpy(tbp, p, len);
  130.             tbp += len;
  131.             clen += len;
  132.             echar = p[len - 1];
  133.         } else
  134.             echar = ' ';
  135.  
  136.         /*
  137.          * Historic practice for vi was to put the cursor at the first
  138.          * inserted whitespace character, if there was one, or the
  139.          * first character of the joined line, if there wasn't, or the
  140.          * last character of the line if joined to an empty line.  If
  141.          * a count was specified, the cursor was moved as described
  142.          * for the first line joined, ignoring subsequent lines.  If
  143.          * the join was a ':' command, the cursor was placed at the
  144.          * first non-blank character of the line unless the cursor was
  145.          * "attracted" to the end of line when the command was executed
  146.          * in which case it moved to the new end of line.  There are
  147.          * probably several more special cases, but frankly, my dear,
  148.          * I don't give a damn.  This implementation puts the cursor
  149.          * on the first inserted whitespace character, the first
  150.          * character of the joined line, or the last character of the
  151.          * line regardless.  Note, if the cursor isn't on the joined
  152.          * line (possible with : commands), it is reset to the starting
  153.          * line.
  154.          */
  155.         if (first) {
  156.             sp->cno = (tbp - bp) - (1 + extra);
  157.             first = 0;
  158.         } else
  159.             sp->cno = (tbp - bp) - len - (1 + extra);
  160.     }
  161.     sp->lno = cmdp->addr1.lno;
  162.  
  163.     /* Delete the joined lines. */
  164.         for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; to > from; --to)
  165.         if (db_delete(sp, to))
  166.             goto err;
  167.  
  168.     /* If the original line changed, reset it. */
  169.     if (!first && db_set(sp, from, bp, tbp - bp)) {
  170. err:        FREE_SPACE(sp, bp, blen);
  171.         return (1);
  172.     }
  173.     FREE_SPACE(sp, bp, blen);
  174.  
  175.     sp->rptlines[L_JOINED] += (cmdp->addr2.lno - cmdp->addr1.lno) + 1;
  176.     return (0);
  177. }
  178.