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