995
|
1 /*
|
|
2 * The functions in this file are a general set of line management utilities.
|
|
3 * They are the only routines that touch the text. They also touch the buffer
|
|
4 * and window structures, to make sure that the necessary updating gets done.
|
|
5 * There are routines in this file that handle the kill buffer too. It i
|
|
6 sn't
|
|
7 * here for any good reason.
|
|
8 *
|
|
9 * Note that this code only updates the dot and mark values in the window list.
|
|
10 * Since all the code acts on the current window, the buffer that we are
|
|
11 * editing must be being displayed, which means that "b_nwnd" is non zero,
|
|
12 * which means that the dot and mark values in the buffer headers are nonsense.
|
|
13 */
|
|
14
|
|
15 #include <stdio.h>
|
|
16 #include "ueed.h"
|
|
17
|
|
18 #define NBLOCK 16 /* Line block chunk size */
|
|
19 #define KBLOCK 256 /* Kill buffer block size */
|
|
20
|
|
21 extern char *kbufp; /* Kill buffer data */
|
|
22 extern int kused; /* # of bytes used in KB */
|
|
23 extern int ksize; /* # of bytes allocated in KB */
|
|
24
|
|
25 /*
|
|
26 * Insert a newline into the buffer at the current location of dot in the
|
|
27 * current window. The funny ass-backwards way it does things is not a botch;
|
|
28 * it just makes the last line in the file not a special case. Return TRUE if
|
|
29 * everything works out and FALSE on error (memory allocation failure). The
|
|
30 * update of dot and mark is a bit easier then in the above case, because the
|
|
31 * split forces more updating.
|
|
32 */
|
|
33 lnewline()
|
|
34 {
|
|
35 register char *cp1;
|
|
36 register char *cp2;
|
|
37 register LINE *lp1;
|
|
38 register LINE *lp2;
|
|
39 register int doto;
|
|
40 register WINDOW *wp;
|
|
41
|
|
42 lchange(WFHARD);
|
|
43 lp1 = curwp->w_dotp; /* Get the address and */
|
|
44 doto = curwp->w_doto; /* offset of "." */
|
|
45 if ((lp2=lalloc(doto)) == NULL) /* New first half line */
|
|
46 return (FALSE);
|
|
47 cp1 = &lp1->l_text[0]; /* Shuffle text around */
|
|
48 cp2 = &lp2->l_text[0];
|
|
49 while (cp1 != &lp1->l_text[doto])
|
|
50 *cp2++ = *cp1++;
|
|
51 cp2 = &lp1->l_text[0];
|
|
52 while (cp1 != &lp1->l_text[lp1->l_used])
|
|
53 *cp2++ = *cp1++;
|
|
54 lp1->l_used -= doto;
|
|
55 lp2->l_bp = lp1->l_bp;
|
|
56 lp1->l_bp = lp2;
|
|
57 lp2->l_bp->l_fp = lp2;
|
|
58 lp2->l_fp = lp1;
|
|
59 wp = wheadp; /* Windows */
|
|
60 while (wp != NULL) {
|
|
61 if (wp->w_linep == lp1)
|
|
62 wp->w_linep = lp2;
|
|
63 if (wp->w_dotp == lp1) {
|
|
64 if (wp->w_doto < doto)
|
|
65 wp->w_dotp = lp2;
|
|
66 else
|
|
67 wp->w_doto -= doto;
|
|
68 }
|
|
69 if (wp->w_markp == lp1) {
|
|
70 if (wp->w_marko < doto)
|
|
71 wp->w_markp = lp2;
|
|
72 else
|
|
73 wp->w_marko -= doto;
|
|
74 }
|
|
75 wp = wp->w_wndp;
|
|
76 }
|
|
77 return (TRUE);
|
|
78 }
|
|
79
|
|
80 /*
|
|
81 * This function deletes "n" bytes, starting at dot. It understands how do deal
|
|
82 * with end of lines, etc. It returns TRUE if all of the characters were
|
|
83 * deleted, and FALSE if they were not (because dot ran into the end of the
|
|
84 * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
|
|
85 */
|
|
86 ldelete(n, kflag)
|
|
87 {
|
|
88 register char *cp1;
|
|
89 register char *cp2;
|
|
90 register LINE *dotp;
|
|
91 register int doto;
|
|
92 register int chunk;
|
|
93 register WINDOW *wp;
|
|
94
|
|
95 while (n != 0) {
|
|
96 dotp = curwp->w_dotp;
|
|
97 doto = curwp->w_doto;
|
|
98 if (dotp == curbp->b_linep) /* Hit end of buffer. */
|
|
99 return (FALSE);
|
|
100 chunk = dotp->l_used-doto; /* Size of chunk. */
|
|
101 if (chunk > n)
|
|
102 chunk = n;
|
|
103 if (chunk == 0) { /* End of line, merge. */
|
|
104 lchange(WFHARD);
|
|
105 if (ldelnewline() == FALSE
|
|
106 || (kflag!=FALSE && kinsert('\n')==FALSE))
|
|
107 return (FALSE);
|
|
108 --n;
|
|
109 continue;
|
|
110 }
|
|
111 lchange(WFEDIT);
|
|
112 cp1 = &dotp->l_text[doto]; /* Scrunch text. */
|
|
113 cp2 = cp1 + chunk;
|
|
114 if (kflag != FALSE) { /* Kill? */
|
|
115 while (cp1 != cp2) {
|
|
116 if (kinsert(*cp1) == FALSE)
|
|
117 return (FALSE);
|
|
118 ++cp1;
|
|
119 }
|
|
120 cp1 = &dotp->l_text[doto];
|
|
121 }
|
|
122 while (cp2 != &dotp->l_text[dotp->l_used])
|
|
123 *cp1++ = *cp2++;
|
|
124 dotp->l_used -= chunk;
|
|
125 wp = wheadp; /* Fix windows */
|
|
126 while (wp != NULL) {
|
|
127 if (wp->w_dotp==dotp && wp->w_doto>=doto) {
|
|
128 wp->w_doto -= chunk;
|
|
129 if (wp->w_doto < doto)
|
|
130 wp->w_doto = doto;
|
|
131 }
|
|
132 if (wp->w_markp==dotp && wp->w_marko>=doto) {
|
|
133 wp->w_marko -= chunk;
|
|
134 if (wp->w_marko < doto)
|
|
135 wp->w_marko = doto;
|
|
136 }
|
|
137 wp = wp->w_wndp;
|
|
138 }
|
|
139 n -= chunk;
|
|
140 }
|
|
141 return (TRUE);
|
|
142 }
|
|
143
|
|
144 /*
|
|
145 * Delete a newline. Join the current line with the next line. If the next line
|
|
146 * is the magic header line always return TRUE; merging the last line with the
|
|
147 * header line can be thought of as always being a successful operation, even
|
|
148 * if nothing is done, and this makes the kill buffer work "right". Easy cases
|
|
149 * can be done by shuffling data around. Hard cases require that lines be moved
|
|
150 * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
|
|
151 * "ldelete" only.
|
|
152 */
|
|
153 ldelnewline()
|
|
154 {
|
|
155 register char *cp1;
|
|
156 register char *cp2;
|
|
157 register LINE *lp1;
|
|
158 register LINE *lp2;
|
|
159 register LINE *lp3;
|
|
160 register WINDOW *wp;
|
|
161
|
|
162 lp1 = curwp->w_dotp;
|
|
163 lp2 = lp1->l_fp;
|
|
164 if (lp2 == curbp->b_linep) { /* At the buffer end. */
|
|
165 if (lp1->l_used == 0) /* Blank line. */
|
|
166 lfree(lp1);
|
|
167 return (TRUE);
|
|
168 }
|
|
169 if (lp2->l_used <= lp1->l_size-lp1->l_used) {
|
|
170 cp1 = &lp1->l_text[lp1->l_used];
|
|
171 cp2 = &lp2->l_text[0];
|
|
172 while (cp2 != &lp2->l_text[lp2->l_used])
|
|
173 *cp1++ = *cp2++;
|
|
174 wp = wheadp;
|
|
175 while (wp != NULL) {
|
|
176 if (wp->w_linep == lp2)
|
|
177 wp->w_linep = lp1;
|
|
178 if (wp->w_dotp == lp2) {
|
|
179 wp->w_dotp = lp1;
|
|
180 wp->w_doto += lp1->l_used;
|
|
181 }
|
|
182 if (wp->w_markp == lp2) {
|
|
183 wp->w_markp = lp1;
|
|
184 wp->w_marko += lp1->l_used;
|
|
185 }
|
|
186 wp = wp->w_wndp;
|
|
187 }
|
|
188 lp1->l_used += lp2->l_used;
|
|
189 lp1->l_fp = lp2->l_fp;
|
|
190 lp2->l_fp->l_bp = lp1;
|
|
191 free((char *) lp2);
|
|
192 return (TRUE);
|
|
193 }
|
|
194 if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
|
|
195 return (FALSE);
|
|
196 cp1 = &lp1->l_text[0];
|
|
197 cp2 = &lp3->l_text[0];
|
|
198 while (cp1 != &lp1->l_text[lp1->l_used])
|
|
199 *cp2++ = *cp1++;
|
|
200 cp1 = &lp2->l_text[0];
|
|
201 while (cp1 != &lp2->l_text[lp2->l_used])
|
|
202 *cp2++ = *cp1++;
|
|
203 lp1->l_bp->l_fp = lp3;
|
|
204 lp3->l_fp = lp2->l_fp;
|
|
205 lp2->l_fp->l_bp = lp3;
|
|
206 lp3->l_bp = lp1->l_bp;
|
|
207 wp = wheadp;
|
|
208 while (wp != NULL) {
|
|
209 if (wp->w_linep==lp1 || wp->w_linep==lp2)
|
|
210 wp->w_linep = lp3;
|
|
211 if (wp->w_dotp == lp1)
|
|
212 wp->w_dotp = lp3;
|
|
213 else if (wp->w_dotp == lp2) {
|
|
214 wp->w_dotp = lp3;
|
|
215 wp->w_doto += lp1->l_used;
|
|
216 }
|
|
217 if (wp->w_markp == lp1)
|
|
218 wp->w_markp = lp3;
|
|
219 else if (wp->w_markp == lp2) {
|
|
220 wp->w_markp = lp3;
|
|
221 wp->w_marko += lp1->l_used;
|
|
222 }
|
|
223 wp = wp->w_wndp;
|
|
224 }
|
|
225 free((char *) lp1);
|
|
226 free((char *) lp2);
|
|
227 return (TRUE);
|
|
228 }
|
|
229
|
|
230 /*
|
|
231 * Delete all of the text saved in the kill buffer. Called by commands when a
|
|
232 * new kill context is being created. The kill buffer array is released, just
|
|
233 * in case the buffer has grown to immense size. No errors.
|
|
234 */
|
|
235 kdelete()
|
|
236 {
|
|
237 if (kbufp != NULL) {
|
|
238 free((char *) kbufp);
|
|
239 kbufp = NULL;
|
|
240 kused = 0;
|
|
241 ksize = 0;
|
|
242 }
|
|
243 }
|
|
244
|
|
245 /*
|
|
246 * Insert a character to the kill buffer, enlarging the buffer if there isn't
|
|
247 * any room. Always grow the buffer in chunks, on the assumption that if you
|
|
248 * put something in the kill buffer you are going to put more stuff there too
|
|
249 * later. Return TRUE if all is well, and FALSE on errors.
|
|
250 */
|
|
251 kinsert(c)
|
|
252 {
|
|
253 register char *nbufp;
|
|
254 register int i;
|
|
255
|
|
256 if (kused == ksize) {
|
|
257 if ((nbufp=malloc(ksize+KBLOCK)) == NULL)
|
|
258 return (FALSE);
|
|
259 for (i=0; i<ksize; ++i)
|
|
260 nbufp[i] = kbufp[i];
|
|
261 if (kbufp != NULL)
|
|
262 free((char *) kbufp);
|
|
263 kbufp = nbufp;
|
|
264 ksize += KBLOCK;
|
|
265 }
|
|
266 kbufp[kused++] = c;
|
|
267 return (TRUE);
|
|
268 }
|
|
269
|
|
270 /*
|
|
271 * This function gets characters from the kill buffer. If the character index
|
|
272 * "n" is off the end, it returns "-1". This lets the caller just scan along
|
|
273 * until it gets a "-1" back.
|
|
274 */
|
|
275 kremove(n)
|
|
276 {
|
|
277 if (n >= kused)
|
|
278 return (-1);
|
|
279 else
|
|
280 return (kbufp[n] & 0xFF);
|
|
281 }
|
|
282
|
|
283
|
|
284
|