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