|
|
1.1 root 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.
6: * It isn't here for any good reason.
7: *
8: * Note that this code only updates the dot and mark values in the window list.
9: * Since all the code acts on the current window, the buffer that we are
10: * editing must be being displayed, which means that "b_nwnd" is non zero,
11: * which means that the dot and mark values in the buffer headers are nonsense.
12: */
13: #include <stdio.h>
14: #include "ed.h"
15:
16: #define NBLOCK 16 /* Line block chunk size */
17: #define KBLOCK 256 /* Kill buffer block size */
18:
19: uchar *kbufp = NULL; /* Kill buffer data */
20: int kused = 0; /* # of bytes used in KB */
21: int ksize = 0; /* # of bytes allocated in KB */
22:
23: /*
24: * This routine allocates a block of memory large enough to hold a LINE
25: * containing "used" characters. The block is always rounded up a bit.
26: * Return a pointer to the new block, or NULL if there isn't any memory left.
27: * Print a message in the message line if no space.
28: */
29: LINE *
30: lalloc(used)
31: register int used;
32: {
33: register LINE *lp;
34: register int size;
35:
36: size = (used+NBLOCK-1) & ~(NBLOCK-1);
37: if (size == 0) /* Assume that an empty */
38: size = NBLOCK; /* line is for type-in. */
39: if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
40: mlwrite("Cannot allocate %d bytes", size);
41: return (NULL);
42: }
43: lp->l_size = size;
44: lp->l_used = used;
45: lp->l_lnumber = 0; /* This is a new line... */
46: return (lp);
47: }
48:
49: /*
50: * Delete line "lp". Fix all of the links that might point at it (they are
51: * moved to offset 0 of the next line. Unlink the line from whatever buffer it
52: * might be in. Release the memory. The buffers are updated too; the magic
53: * conditions described in the above comments don't hold here.
54: */
55: lfree(lp)
56: register LINE *lp;
57: {
58: register BUFFER *bp;
59: register WINDOW *wp;
60:
61: wp = wheadp;
62: while (wp != NULL) {
63: if (wp->w_linep == lp)
64: wp->w_linep = lp->l_fp;
65: if (wp->w_dotp == lp) {
66: wp->w_dotp = lp->l_fp;
67: wp->w_doto = 0;
68: }
69: if (wp->w_markp == lp) {
70: wp->w_markp = lp->l_fp;
71: wp->w_marko = 0;
72: }
73: wp = wp->w_wndp;
74: }
75: bp = bheadp;
76: while (bp != NULL) {
77: if (bp->b_nwnd == 0) {
78: if (bp->b_dotp == lp) {
79: bp->b_dotp = lp->l_fp;
80: bp->b_doto = 0;
81: }
82: if (bp->b_markp == lp) {
83: bp->b_markp = lp->l_fp;
84: bp->b_marko = 0;
85: }
86: }
87: bp = bp->b_bufp;
88: }
89: lp->l_bp->l_fp = lp->l_fp;
90: lp->l_fp->l_bp = lp->l_bp;
91: free((char *) lp);
92: }
93:
94: /*
95: * This routine gets called when a character is changed in place in the
96: * current buffer. It updates all of the required flags in the buffer and
97: * window system. The flag used is passed as an argument; if the buffer is
98: * being displayed in more than 1 window we change EDIT to HARD.
99: * Set MODE if the mode line needs to be updated (the "*" has to be set).
100: */
101: lchange(flag)
102: register int flag;
103: {
104: register WINDOW *wp;
105:
106: if (curbp->b_nwnd != 1) /* Ensure hard. */
107: flag = WFHARD;
108: if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
109: flag |= WFMODE; /* update mode lines. */
110: curbp->b_flag |= BFCHG;
111: }
112: wp = wheadp;
113: while (wp != NULL) {
114: if (wp->w_bufp == curbp)
115: wp->w_flag |= flag;
116: wp = wp->w_wndp;
117: }
118: }
119:
120: /*
121: * Insert "n" copies of the character "c" at the current location of dot.
122: * In the easy case all that happens is the text is stored in the line.
123: * In the hard case, the line has to be reallocated.
124: * When the window list is updated, take special care; I screwed it up once.
125: * You always update dot in the current window. You update mark, and a
126: * dot in another window, if it is greater than the place where you did
127: * the insert.
128: * Return TRUE if all is well, and FALSE on errors.
129: */
130: linsert(n, c)
131: {
132: register uchar *cp1;
133: register uchar *cp2;
134: register LINE *lp1;
135: register LINE *lp2;
136: register LINE *lp3;
137: register int doto;
138: register int i;
139: register WINDOW *wp;
140:
141: lchange(WFEDIT);
142: lp1 = curwp->w_dotp; /* Current line */
143: if (lp1 == curbp->b_linep) { /* At the end: special */
144: if (curwp->w_doto != 0) {
145: mlwrite("bug: linsert");
146: return (FALSE);
147: }
148: if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
149: return (FALSE);
150: lp3 = lp1->l_bp; /* Previous line */
151: lp3->l_fp = lp2; /* Link in */
152: lp2->l_fp = lp1;
153: lp1->l_bp = lp2;
154: lp2->l_bp = lp3;
155: for (i=0; i<n; ++i)
156: lp2->l_text[i] = c;
157: curwp->w_dotp = lp2;
158: curwp->w_doto = n;
159: return (TRUE);
160: }
161: doto = curwp->w_doto; /* Save for later. */
162: if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
163: if ((lp2=lalloc(lp1->l_used+n)) == NULL)
164: return (FALSE);
165: cp1 = &lp1->l_text[0];
166: cp2 = &lp2->l_text[0];
167: while (cp1 != &lp1->l_text[doto])
168: *cp2++ = *cp1++;
169: cp2 += n;
170: while (cp1 != &lp1->l_text[lp1->l_used])
171: *cp2++ = *cp1++;
172: lp1->l_bp->l_fp = lp2;
173: lp2->l_fp = lp1->l_fp;
174: lp1->l_fp->l_bp = lp2;
175: lp2->l_bp = lp1->l_bp;
176: free((char *) lp1);
177: } else { /* Easy: in place */
178: lp2 = lp1; /* Pretend new line */
179: lp2->l_used += n;
180: cp2 = &lp1->l_text[lp1->l_used];
181: cp1 = cp2-n;
182: while (cp1 != &lp1->l_text[doto])
183: *--cp2 = *--cp1;
184: }
185: for (i=0; i<n; ++i) /* Add the characters */
186: lp2->l_text[doto+i] = c;
187: wp = wheadp; /* Update windows */
188: while (wp != NULL) {
189: if (wp->w_linep == lp1)
190: wp->w_linep = lp2;
191: if (wp->w_dotp == lp1) {
192: wp->w_dotp = lp2;
193: if (wp==curwp || wp->w_doto>doto)
194: wp->w_doto += n;
195: }
196: if (wp->w_markp == lp1) {
197: wp->w_markp = lp2;
198: if (wp->w_marko > doto)
199: wp->w_marko += n;
200: }
201: wp = wp->w_wndp;
202: }
203: return (TRUE);
204: }
205:
206: /*
207: * Insert a newline into the buffer at the current location of dot in the
208: * current window. The funny ass-backwards way it does things is not a botch;
209: * it just makes the last line in the file not a special case. Return TRUE if
210: * everything works out and FALSE on error (memory allocation failure).
211: * The update of dot and mark is a bit easier then in the above case, because
212: * the split forces more updating.
213: */
214: lnewline()
215: {
216: register uchar *cp1;
217: register uchar *cp2;
218: register LINE *lp1;
219: register LINE *lp2;
220: register int doto;
221: register WINDOW *wp;
222:
223: lchange(WFHARD);
224: lp1 = curwp->w_dotp; /* Get the address and */
225: doto = curwp->w_doto; /* offset of "." */
226: if ((lp2=lalloc(doto)) == NULL) /* New first half line */
227: return (FALSE);
228: cp1 = &lp1->l_text[0]; /* Shuffle text around */
229: cp2 = &lp2->l_text[0];
230: while (cp1 != &lp1->l_text[doto])
231: *cp2++ = *cp1++;
232: cp2 = &lp1->l_text[0];
233: while (cp1 != &lp1->l_text[lp1->l_used])
234: *cp2++ = *cp1++;
235: lp1->l_used -= doto;
236: lp2->l_bp = lp1->l_bp;
237: lp1->l_bp = lp2;
238: lp2->l_bp->l_fp = lp2;
239: lp2->l_fp = lp1;
240: wp = wheadp; /* Windows */
241: while (wp != NULL) {
242: if (wp->w_linep == lp1)
243: wp->w_linep = lp2;
244: if (wp->w_dotp == lp1) {
245: if (wp->w_doto < doto)
246: wp->w_dotp = lp2;
247: else
248: wp->w_doto -= doto;
249: }
250: if (wp->w_markp == lp1) {
251: if (wp->w_marko < doto)
252: wp->w_markp = lp2;
253: else
254: wp->w_marko -= doto;
255: }
256: wp = wp->w_wndp;
257: }
258: return (TRUE);
259: }
260:
261: /*
262: * This function deletes "n" bytes, starting at dot. It understands how to deal
263: * with end of lines, etc. It returns TRUE if all of the characters were
264: * deleted, and FALSE if they were not (because dot ran into the end of
265: * the buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
266: */
267: ldelete(n, kflag)
268: {
269: register uchar *cp1;
270: register uchar *cp2;
271: register LINE *dotp;
272: register int doto;
273: register int chunk;
274: register WINDOW *wp;
275:
276: while (n != 0) {
277: dotp = curwp->w_dotp;
278: doto = curwp->w_doto;
279: if (dotp == curbp->b_linep) /* Hit end of buffer. */
280: return (FALSE);
281: chunk = dotp->l_used-doto; /* Size of chunk. */
282: if (chunk > n)
283: chunk = n;
284: if (chunk == 0) { /* End of line, merge. */
285: lchange(WFHARD);
286: if (ldelnewline() == FALSE
287: || (kflag!=FALSE && kinsert('\n')==FALSE))
288: return (FALSE);
289: --n;
290: continue;
291: }
292: lchange(WFEDIT);
293: cp1 = &dotp->l_text[doto]; /* Scrunch text. */
294: cp2 = cp1 + chunk;
295: if (kflag != FALSE) { /* Kill? */
296: while (cp1 != cp2) {
297: if (kinsert(*cp1) == FALSE)
298: return (FALSE);
299: ++cp1;
300: }
301: cp1 = &dotp->l_text[doto];
302: }
303: while (cp2 != &dotp->l_text[dotp->l_used])
304: *cp1++ = *cp2++;
305: dotp->l_used -= chunk;
306: wp = wheadp; /* Fix windows */
307: while (wp != NULL) {
308: if (wp->w_dotp==dotp && wp->w_doto>=doto) {
309: wp->w_doto -= chunk;
310: if (wp->w_doto < doto)
311: wp->w_doto = doto;
312: }
313: if (wp->w_markp==dotp && wp->w_marko>=doto) {
314: wp->w_marko -= chunk;
315: if (wp->w_marko < doto)
316: wp->w_marko = doto;
317: }
318: wp = wp->w_wndp;
319: }
320: n -= chunk;
321: }
322: return (TRUE);
323: }
324:
325: /*
326: * Delete a newline. Join the current line with the next line. If the next
327: * line is the magic header line always return TRUE; merging the last line
328: * with the header line can be thought of as always being a successful
329: * operation, even if nothing is done, and this makes the kill buffer
330: * work "right". Easy cases can be done by shuffling data around.
331: * Hard cases require that lines be moved about in memory.
332: * Return FALSE on error and TRUE if all looks ok. Called by "ldelete" only.
333: */
334: ldelnewline()
335: {
336: register uchar *cp1;
337: register uchar *cp2;
338: register LINE *lp1;
339: register LINE *lp2;
340: register LINE *lp3;
341: register WINDOW *wp;
342:
343: lp1 = curwp->w_dotp; /* This line... */
344: lp2 = lp1->l_fp; /* The next line... */
345:
346: if (lp2 == curbp->b_linep) { /* At the buffer end. */
347: if (lp1->l_used == 0) /* Blank line. */
348: lfree(lp1);
349: return (TRUE);
350: }
351: /* Fix file-line numbers. */
352: if ((lp1->l_used == 0) || (lp1->l_lnumber == 0))
353: lp1->l_lnumber = lp2->l_lnumber;
354:
355: if (lp2->l_used <= lp1->l_size-lp1->l_used) {
356: cp1 = &lp1->l_text[lp1->l_used];
357: cp2 = &lp2->l_text[0];
358: while (cp2 != &lp2->l_text[lp2->l_used])
359: *cp1++ = *cp2++;
360: wp = wheadp;
361: while (wp != NULL) {
362: if (wp->w_linep == lp2)
363: wp->w_linep = lp1;
364: if (wp->w_dotp == lp2) {
365: wp->w_dotp = lp1;
366: wp->w_doto += lp1->l_used;
367: }
368: if (wp->w_markp == lp2) {
369: wp->w_markp = lp1;
370: wp->w_marko += lp1->l_used;
371: }
372: wp = wp->w_wndp;
373: }
374: lp1->l_used += lp2->l_used;
375: lp1->l_fp = lp2->l_fp;
376: lp2->l_fp->l_bp = lp1;
377: free((char *) lp2);
378: return (TRUE);
379: }
380: if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
381: return (FALSE);
382: cp1 = &lp1->l_text[0];
383: cp2 = &lp3->l_text[0];
384: while (cp1 != &lp1->l_text[lp1->l_used])
385: *cp2++ = *cp1++;
386: cp1 = &lp2->l_text[0];
387: while (cp1 != &lp2->l_text[lp2->l_used])
388: *cp2++ = *cp1++;
389: lp1->l_bp->l_fp = lp3;
390: lp3->l_fp = lp2->l_fp;
391: lp2->l_fp->l_bp = lp3;
392: lp3->l_bp = lp1->l_bp;
393: wp = wheadp;
394: while (wp != NULL) {
395: if (wp->w_linep==lp1 || wp->w_linep==lp2)
396: wp->w_linep = lp3;
397: if (wp->w_dotp == lp1)
398: wp->w_dotp = lp3;
399: else if (wp->w_dotp == lp2) {
400: wp->w_dotp = lp3;
401: wp->w_doto += lp1->l_used;
402: }
403: if (wp->w_markp == lp1)
404: wp->w_markp = lp3;
405: else if (wp->w_markp == lp2) {
406: wp->w_markp = lp3;
407: wp->w_marko += lp1->l_used;
408: }
409: wp = wp->w_wndp;
410: }
411: free((char *) lp1);
412: free((char *) lp2);
413: return (TRUE);
414: }
415:
416: /*
417: * Delete all of the text saved in the kill buffer. Called by commands when
418: * a new kill context is being created. The kill buffer array is released,
419: * just in case the buffer has grown to immense size. No errors.
420: */
421: kdelete()
422: {
423: if (kbufp != NULL) {
424: free((char *) kbufp);
425: kbufp = NULL;
426: kused = 0;
427: ksize = 0;
428: }
429: }
430:
431: /*
432: * Insert a character to the kill buffer, enlarging the buffer if there
433: * isn't any room. Always grow the buffer in chunks, on the assumption
434: * that if you put something in the kill buffer you are going to put more
435: * stuff there too later. Return TRUE if all is well, and FALSE on errors.
436: */
437: kinsert(c)
438: {
439: register uchar *nbufp;
440: register int i;
441:
442: if (kused == ksize) {
443: if ((nbufp=malloc(ksize+KBLOCK)) == NULL)
444: return (FALSE);
445: for (i=0; i<ksize; ++i)
446: nbufp[i] = kbufp[i];
447: if (kbufp != NULL)
448: free((char *) kbufp);
449: kbufp = nbufp;
450: ksize += KBLOCK;
451: }
452: kbufp[kused++] = c;
453: return (TRUE);
454: }
455:
456: /*
457: * This function gets characters from the kill buffer. If the character index
458: * "n" is off the end, it returns "-1". This lets the caller just scan along
459: * until it gets a "-1" back.
460: */
461: kremove(n)
462: {
463: if (n >= kused)
464: return (-1);
465: else
466: return (kbufp[n] & 0xFF);
467: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.