1*2a988851Sagc /* $NetBSD: bufgap.c,v 1.1 2014/03/09 00:15:45 agc Exp $ */
2*2a988851Sagc 
3*2a988851Sagc /*-
4*2a988851Sagc  * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
5*2a988851Sagc  * All rights reserved.
6*2a988851Sagc  *
7*2a988851Sagc  * This code is derived from software contributed to The NetBSD Foundation
8*2a988851Sagc  * by Alistair Crooks (agc@NetBSD.org)
9*2a988851Sagc  *
10*2a988851Sagc  * Redistribution and use in source and binary forms, with or without
11*2a988851Sagc  * modification, are permitted provided that the following conditions
12*2a988851Sagc  * are met:
13*2a988851Sagc  * 1. Redistributions of source code must retain the above copyright
14*2a988851Sagc  *    notice, this list of conditions and the following disclaimer.
15*2a988851Sagc  * 2. Redistributions in binary form must reproduce the above copyright
16*2a988851Sagc  *    notice, this list of conditions and the following disclaimer in the
17*2a988851Sagc  *    documentation and/or other materials provided with the distribution.
18*2a988851Sagc  *
19*2a988851Sagc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*2a988851Sagc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*2a988851Sagc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*2a988851Sagc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*2a988851Sagc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*2a988851Sagc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*2a988851Sagc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*2a988851Sagc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*2a988851Sagc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*2a988851Sagc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*2a988851Sagc  * POSSIBILITY OF SUCH DAMAGE.
30*2a988851Sagc  */
31*2a988851Sagc #include "config.h"
32*2a988851Sagc 
33*2a988851Sagc #include <sys/types.h>
34*2a988851Sagc #include <sys/stat.h>
35*2a988851Sagc 
36*2a988851Sagc #include <ctype.h>
37*2a988851Sagc #include <stdio.h>
38*2a988851Sagc #include <stdlib.h>
39*2a988851Sagc #include <string.h>
40*2a988851Sagc #include <unistd.h>
41*2a988851Sagc 
42*2a988851Sagc #include "bufgap.h"
43*2a988851Sagc #include "defs.h"
44*2a988851Sagc 
45*2a988851Sagc /* macros to get subscripts in buffer */
46*2a988851Sagc #define AFTSUB(bp, n)	((bp)->buf[(int)n])
47*2a988851Sagc #define BEFSUB(bp, n)	((bp)->buf[(int)((bp)->size - (n) - 1)])
48*2a988851Sagc 
49*2a988851Sagc /* initial allocation size */
50*2a988851Sagc #ifndef CHUNKSIZE
51*2a988851Sagc #define CHUNKSIZE	256
52*2a988851Sagc #endif
53*2a988851Sagc 
54*2a988851Sagc #ifndef KiB
55*2a988851Sagc #define KiB(x)	((x) * 1024)
56*2a988851Sagc #endif
57*2a988851Sagc 
58*2a988851Sagc #define BGCHUNKSIZE	KiB(4)
59*2a988851Sagc 
60*2a988851Sagc #ifndef __UNCONST
61*2a988851Sagc #define __UNCONST(a)       ((void *)(unsigned long)(const void *)(a))
62*2a988851Sagc #endif
63*2a988851Sagc 
64*2a988851Sagc #ifndef USE_UTF
65*2a988851Sagc #define USE_UTF	0
66*2a988851Sagc #endif
67*2a988851Sagc 
68*2a988851Sagc #if !USE_UTF
69*2a988851Sagc #define Rune		char
70*2a988851Sagc #define	utfbytes(x)	strlen(x)
71*2a988851Sagc #define	utfrune(a, b)	strchr(a, b)
72*2a988851Sagc #define	utfnlen(a, b)	bounded_strlen(a, b)
73*2a988851Sagc 
74*2a988851Sagc static size_t
bounded_strlen(const char * s,size_t maxlen)75*2a988851Sagc bounded_strlen(const char *s, size_t maxlen)
76*2a988851Sagc {
77*2a988851Sagc 	size_t	n;
78*2a988851Sagc 
79*2a988851Sagc 	for (n = 0 ; n < maxlen && s[n] != 0x0 ; n++) {
80*2a988851Sagc 	}
81*2a988851Sagc 	return n;
82*2a988851Sagc }
83*2a988851Sagc 
84*2a988851Sagc static int
chartorune(Rune * rp,char * s)85*2a988851Sagc chartorune(Rune *rp, char *s)
86*2a988851Sagc {
87*2a988851Sagc 	*rp = s[0];
88*2a988851Sagc 	return 1;
89*2a988851Sagc }
90*2a988851Sagc 
91*2a988851Sagc static int
priorrune(Rune * rp,char * s)92*2a988851Sagc priorrune(Rune *rp, char *s)
93*2a988851Sagc {
94*2a988851Sagc 	*rp = s[0];
95*2a988851Sagc 	return 1;
96*2a988851Sagc }
97*2a988851Sagc #else
98*2a988851Sagc #include "ure.h"
99*2a988851Sagc #endif
100*2a988851Sagc 
101*2a988851Sagc /* save `n' chars of `s' in malloc'd memory */
102*2a988851Sagc static char *
strnsave(char * s,int n)103*2a988851Sagc strnsave(char *s, int n)
104*2a988851Sagc {
105*2a988851Sagc 	char	*cp;
106*2a988851Sagc 
107*2a988851Sagc 	if (n < 0) {
108*2a988851Sagc 		n = (int)strlen(s);
109*2a988851Sagc 	}
110*2a988851Sagc 	NEWARRAY(char, cp, n + 1, "strnsave", return NULL);
111*2a988851Sagc 	(void) memcpy(cp, s, (size_t)n);
112*2a988851Sagc 	cp[n] = 0x0;
113*2a988851Sagc 	return cp;
114*2a988851Sagc }
115*2a988851Sagc 
116*2a988851Sagc /* open a file in a buffer gap structure */
117*2a988851Sagc int
bufgap_open(bufgap_t * bp,const char * f)118*2a988851Sagc bufgap_open(bufgap_t *bp, const char *f)
119*2a988851Sagc {
120*2a988851Sagc 	struct stat	 s;
121*2a988851Sagc 	int64_t		 cc;
122*2a988851Sagc 	FILE		*filep;
123*2a988851Sagc 	char		*cp;
124*2a988851Sagc 
125*2a988851Sagc 	(void) memset(bp, 0x0, sizeof(*bp));
126*2a988851Sagc 	filep = NULL;
127*2a988851Sagc 	if (f != NULL && (filep = fopen(f, "r")) == NULL) {
128*2a988851Sagc 		return 0;
129*2a988851Sagc 	}
130*2a988851Sagc 	if (f == NULL) {
131*2a988851Sagc 		bp->size = BGCHUNKSIZE;
132*2a988851Sagc 		NEWARRAY(char, bp->buf, bp->size, "f_open", return 0);
133*2a988851Sagc 	} else {
134*2a988851Sagc 		(void) fstat(fileno(filep), &s);
135*2a988851Sagc 		bp->size = (int) ((s.st_size / BGCHUNKSIZE) + 1) * BGCHUNKSIZE;
136*2a988851Sagc 		NEWARRAY(char, bp->buf, bp->size, "f_open", return 0);
137*2a988851Sagc 		cc = fread(&BEFSUB(bp, s.st_size), sizeof(char),
138*2a988851Sagc 						(size_t)s.st_size, filep);
139*2a988851Sagc 		(void) fclose(filep);
140*2a988851Sagc 		if (cc != s.st_size) {
141*2a988851Sagc 			FREE(bp->buf);
142*2a988851Sagc 			FREE(bp);
143*2a988851Sagc 			return 0;
144*2a988851Sagc 		}
145*2a988851Sagc 		bp->name = strnsave(__UNCONST(f), (int)utfbytes(__UNCONST(f)));
146*2a988851Sagc 		bp->bbc = s.st_size;
147*2a988851Sagc 		cp = &BEFSUB(bp, cc);
148*2a988851Sagc 		for (;;) {
149*2a988851Sagc 			if ((cp = utfrune(cp, '\n')) == NULL) {
150*2a988851Sagc 				break;
151*2a988851Sagc 			}
152*2a988851Sagc 			bp->blc++;
153*2a988851Sagc 			cp++;
154*2a988851Sagc 		}
155*2a988851Sagc 		bp->bcc = utfnlen(&BEFSUB(bp, cc), (size_t)cc);
156*2a988851Sagc 	}
157*2a988851Sagc 	return 1;
158*2a988851Sagc }
159*2a988851Sagc 
160*2a988851Sagc /* close a buffer gapped file */
161*2a988851Sagc void
bufgap_close(bufgap_t * bp)162*2a988851Sagc bufgap_close(bufgap_t *bp)
163*2a988851Sagc {
164*2a988851Sagc 	FREE(bp->buf);
165*2a988851Sagc }
166*2a988851Sagc 
167*2a988851Sagc /* move forwards `n' chars/bytes in a buffer gap */
168*2a988851Sagc int
bufgap_forwards(bufgap_t * bp,uint64_t n,int type)169*2a988851Sagc bufgap_forwards(bufgap_t *bp, uint64_t n, int type)
170*2a988851Sagc {
171*2a988851Sagc 	Rune	r;
172*2a988851Sagc 	int	rlen;
173*2a988851Sagc 
174*2a988851Sagc 	switch(type) {
175*2a988851Sagc 	case BGChar:
176*2a988851Sagc 		if (bp->bcc >= n) {
177*2a988851Sagc 			while (n-- > 0) {
178*2a988851Sagc 				rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
179*2a988851Sagc 				if (rlen == 1) {
180*2a988851Sagc 					AFTSUB(bp, bp->abc) = BEFSUB(bp, bp->bbc);
181*2a988851Sagc 				} else {
182*2a988851Sagc 					(void) memmove(&AFTSUB(bp, bp->abc),
183*2a988851Sagc 							&BEFSUB(bp, bp->bbc),
184*2a988851Sagc 							(size_t)rlen);
185*2a988851Sagc 				}
186*2a988851Sagc 				bp->acc++;
187*2a988851Sagc 				bp->bcc--;
188*2a988851Sagc 				bp->abc += rlen;
189*2a988851Sagc 				bp->bbc -= rlen;
190*2a988851Sagc 				if (r == '\n') {
191*2a988851Sagc 					bp->alc++;
192*2a988851Sagc 					bp->blc--;
193*2a988851Sagc 				}
194*2a988851Sagc 			}
195*2a988851Sagc 			return 1;
196*2a988851Sagc 		}
197*2a988851Sagc 		break;
198*2a988851Sagc 	case BGByte:
199*2a988851Sagc 		if (bp->bbc >= n) {
200*2a988851Sagc 			for ( ; n > 0 ; n -= rlen) {
201*2a988851Sagc 				rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
202*2a988851Sagc 				if (rlen == 1) {
203*2a988851Sagc 					AFTSUB(bp, bp->abc) = BEFSUB(bp, bp->bbc);
204*2a988851Sagc 				} else {
205*2a988851Sagc 					(void) memmove(&AFTSUB(bp, bp->abc),
206*2a988851Sagc 							&BEFSUB(bp, bp->bbc),
207*2a988851Sagc 							(size_t)rlen);
208*2a988851Sagc 				}
209*2a988851Sagc 				bp->acc++;
210*2a988851Sagc 				bp->bcc--;
211*2a988851Sagc 				bp->abc += rlen;
212*2a988851Sagc 				bp->bbc -= rlen;
213*2a988851Sagc 				if (r == '\n') {
214*2a988851Sagc 					bp->alc++;
215*2a988851Sagc 					bp->blc--;
216*2a988851Sagc 				}
217*2a988851Sagc 			}
218*2a988851Sagc 			return 1;
219*2a988851Sagc 		}
220*2a988851Sagc 	}
221*2a988851Sagc 	return 0;
222*2a988851Sagc }
223*2a988851Sagc 
224*2a988851Sagc /* move backwards `n' chars in a buffer gap */
225*2a988851Sagc int
bufgap_backwards(bufgap_t * bp,uint64_t n,int type)226*2a988851Sagc bufgap_backwards(bufgap_t *bp, uint64_t n, int type)
227*2a988851Sagc {
228*2a988851Sagc 	Rune	r;
229*2a988851Sagc 	int	rlen;
230*2a988851Sagc 
231*2a988851Sagc 	switch(type) {
232*2a988851Sagc 	case BGChar:
233*2a988851Sagc 		if (bp->acc >= n) {
234*2a988851Sagc 			while (n-- > 0) {
235*2a988851Sagc 				rlen = priorrune(&r, &AFTSUB(bp, bp->abc));
236*2a988851Sagc 				bp->bcc++;
237*2a988851Sagc 				bp->acc--;
238*2a988851Sagc 				bp->bbc += rlen;
239*2a988851Sagc 				bp->abc -= rlen;
240*2a988851Sagc 				if (rlen == 1) {
241*2a988851Sagc 					BEFSUB(bp, bp->bbc) = AFTSUB(bp, bp->abc);
242*2a988851Sagc 				} else {
243*2a988851Sagc 					(void) memmove(&BEFSUB(bp, bp->bbc),
244*2a988851Sagc 							&AFTSUB(bp, bp->abc),
245*2a988851Sagc 							(size_t)rlen);
246*2a988851Sagc 				}
247*2a988851Sagc 				if (r == '\n') {
248*2a988851Sagc 					bp->blc++;
249*2a988851Sagc 					bp->alc--;
250*2a988851Sagc 				}
251*2a988851Sagc 			}
252*2a988851Sagc 			return 1;
253*2a988851Sagc 		}
254*2a988851Sagc 		break;
255*2a988851Sagc 	case BGByte:
256*2a988851Sagc 		if (bp->acc >= n) {
257*2a988851Sagc 			for ( ; n > 0 ; n -= rlen) {
258*2a988851Sagc 				rlen = priorrune(&r, &AFTSUB(bp, bp->abc));
259*2a988851Sagc 				bp->bcc++;
260*2a988851Sagc 				bp->acc--;
261*2a988851Sagc 				bp->bbc += rlen;
262*2a988851Sagc 				bp->abc -= rlen;
263*2a988851Sagc 				if (rlen == 1) {
264*2a988851Sagc 					BEFSUB(bp, bp->bbc) = AFTSUB(bp, bp->abc);
265*2a988851Sagc 				} else {
266*2a988851Sagc 					(void) memmove(&BEFSUB(bp, bp->bbc),
267*2a988851Sagc 							&AFTSUB(bp, bp->abc),
268*2a988851Sagc 							(size_t)rlen);
269*2a988851Sagc 				}
270*2a988851Sagc 				if (r == '\n') {
271*2a988851Sagc 					bp->blc++;
272*2a988851Sagc 					bp->alc--;
273*2a988851Sagc 				}
274*2a988851Sagc 			}
275*2a988851Sagc 			return 1;
276*2a988851Sagc 		}
277*2a988851Sagc 	}
278*2a988851Sagc 	return 0;
279*2a988851Sagc }
280*2a988851Sagc 
281*2a988851Sagc /* move within a buffer gap */
282*2a988851Sagc int
bufgap_seek(bufgap_t * bp,int64_t off,int whence,int type)283*2a988851Sagc bufgap_seek(bufgap_t *bp, int64_t off, int whence, int type)
284*2a988851Sagc {
285*2a988851Sagc 	switch(type) {
286*2a988851Sagc 	case BGLine:
287*2a988851Sagc 		switch(whence) {
288*2a988851Sagc 		case BGFromBOF:
289*2a988851Sagc 			if (off < 0 || off > (int64_t)(bp->alc + bp->blc)) {
290*2a988851Sagc 				return 0;
291*2a988851Sagc 			}
292*2a988851Sagc 			if (off < (int64_t)bp->alc) {
293*2a988851Sagc 				while (off <= (int64_t)bp->alc && bufgap_backwards(bp, 1, BGChar)) {
294*2a988851Sagc 				}
295*2a988851Sagc 				if (off > 0) {
296*2a988851Sagc 					(void) bufgap_forwards(bp, 1, BGChar);
297*2a988851Sagc 				}
298*2a988851Sagc 			} else if (off > (int64_t)bp->alc) {
299*2a988851Sagc 				while (off > (int64_t)bp->alc && bufgap_forwards(bp, 1, BGChar)) {
300*2a988851Sagc 				}
301*2a988851Sagc 			}
302*2a988851Sagc 			return 1;
303*2a988851Sagc 		case BGFromHere:
304*2a988851Sagc 			return bufgap_seek(bp, (int64_t)(bp->alc + off), BGFromBOF, BGLine);
305*2a988851Sagc 		case BGFromEOF:
306*2a988851Sagc 			return bufgap_seek(bp, (int64_t)(bp->alc + bp->blc + off), BGFromBOF, BGLine);
307*2a988851Sagc 		}
308*2a988851Sagc 		break;
309*2a988851Sagc 	case BGChar:
310*2a988851Sagc 		switch(whence) {
311*2a988851Sagc 		case BGFromBOF:
312*2a988851Sagc 			if (off < 0 || off > (int64_t)(bp->acc + bp->bcc)) {
313*2a988851Sagc 				return 0;
314*2a988851Sagc 			}
315*2a988851Sagc 			if (off < (int64_t)bp->acc) {
316*2a988851Sagc 				return bufgap_backwards(bp, bp->acc - off, BGChar);
317*2a988851Sagc 			} else if (off > (int64_t)bp->acc) {
318*2a988851Sagc 				return bufgap_forwards(bp, off - bp->acc, BGChar);
319*2a988851Sagc 			}
320*2a988851Sagc 			return 1;
321*2a988851Sagc 		case BGFromHere:
322*2a988851Sagc 			return bufgap_seek(bp, (int64_t)(bp->acc + off), BGFromBOF, BGChar);
323*2a988851Sagc 		case BGFromEOF:
324*2a988851Sagc 			return bufgap_seek(bp, (int64_t)(bp->acc + bp->bcc + off), BGFromBOF, BGChar);
325*2a988851Sagc 		}
326*2a988851Sagc 		break;
327*2a988851Sagc 	case BGByte:
328*2a988851Sagc 		switch(whence) {
329*2a988851Sagc 		case BGFromBOF:
330*2a988851Sagc 			if (off < 0 || off > (int64_t)(bp->abc + bp->bbc)) {
331*2a988851Sagc 				return 0;
332*2a988851Sagc 			}
333*2a988851Sagc 			if (off < (int64_t)bp->abc) {
334*2a988851Sagc 				return bufgap_backwards(bp, bp->abc - off, BGByte);
335*2a988851Sagc 			} else if (off > (int64_t)bp->abc) {
336*2a988851Sagc 				return bufgap_forwards(bp, off - bp->abc, BGByte);
337*2a988851Sagc 			}
338*2a988851Sagc 			return 1;
339*2a988851Sagc 		case BGFromHere:
340*2a988851Sagc 			return bufgap_seek(bp, (int64_t)(bp->abc + off), BGFromBOF, BGByte);
341*2a988851Sagc 		case BGFromEOF:
342*2a988851Sagc 			return bufgap_seek(bp, (int64_t)(bp->abc + bp->bbc + off), BGFromBOF, BGByte);
343*2a988851Sagc 		}
344*2a988851Sagc 		break;
345*2a988851Sagc 	}
346*2a988851Sagc 	return 0;
347*2a988851Sagc }
348*2a988851Sagc 
349*2a988851Sagc /* return a pointer to the text in the buffer gap */
350*2a988851Sagc char *
bufgap_getstr(bufgap_t * bp)351*2a988851Sagc bufgap_getstr(bufgap_t *bp)
352*2a988851Sagc {
353*2a988851Sagc 	return &BEFSUB(bp, bp->bbc);
354*2a988851Sagc }
355*2a988851Sagc 
356*2a988851Sagc /* return the binary text in the buffer gap */
357*2a988851Sagc int
bufgap_getbin(bufgap_t * bp,void * dst,size_t len)358*2a988851Sagc bufgap_getbin(bufgap_t *bp, void *dst, size_t len)
359*2a988851Sagc {
360*2a988851Sagc 	int	cc;
361*2a988851Sagc 
362*2a988851Sagc 	cc = (bp->bcc < len) ? (int)bp->bcc : (int)len;
363*2a988851Sagc 	(void) memcpy(dst, &BEFSUB(bp, bp->bbc), len);
364*2a988851Sagc 	return cc;
365*2a988851Sagc }
366*2a988851Sagc 
367*2a988851Sagc /* return offset (from beginning/end) in a buffer gap */
368*2a988851Sagc int64_t
bufgap_tell(bufgap_t * bp,int whence,int type)369*2a988851Sagc bufgap_tell(bufgap_t *bp, int whence, int type)
370*2a988851Sagc {
371*2a988851Sagc 	switch(whence) {
372*2a988851Sagc 	case BGFromBOF:
373*2a988851Sagc 		return (type == BGLine) ? bp->alc :
374*2a988851Sagc 			(type == BGByte) ? bp->abc : bp->acc;
375*2a988851Sagc 	case BGFromEOF:
376*2a988851Sagc 		return (type == BGLine) ? bp->blc :
377*2a988851Sagc 			(type == BGByte) ? bp->bbc : bp->bcc;
378*2a988851Sagc 	default:
379*2a988851Sagc 		(void) fprintf(stderr, "weird whence in bufgap_tell\n");
380*2a988851Sagc 		break;
381*2a988851Sagc 	}
382*2a988851Sagc 	return (int64_t)0;
383*2a988851Sagc }
384*2a988851Sagc 
385*2a988851Sagc /* return size of buffer gap */
386*2a988851Sagc int64_t
bufgap_size(bufgap_t * bp,int type)387*2a988851Sagc bufgap_size(bufgap_t *bp, int type)
388*2a988851Sagc {
389*2a988851Sagc 	return (type == BGLine) ? bp->alc + bp->blc :
390*2a988851Sagc 		(type == BGChar) ? bp->acc + bp->bcc :
391*2a988851Sagc 			bp->abc + bp->bbc;
392*2a988851Sagc }
393*2a988851Sagc 
394*2a988851Sagc /* insert `n' chars of `s' in a buffer gap */
395*2a988851Sagc int
bufgap_insert(bufgap_t * bp,const char * s,int n)396*2a988851Sagc bufgap_insert(bufgap_t *bp, const char *s, int n)
397*2a988851Sagc {
398*2a988851Sagc 	int64_t	off;
399*2a988851Sagc 	Rune	r;
400*2a988851Sagc 	int	rlen;
401*2a988851Sagc 	int	i;
402*2a988851Sagc 
403*2a988851Sagc 	if (n < 0) {
404*2a988851Sagc 		n = (int)strlen(s);
405*2a988851Sagc 	}
406*2a988851Sagc 	for (i = 0 ; i < n ; i += rlen) {
407*2a988851Sagc 		if (bp->bbc + bp->abc == bp->size) {
408*2a988851Sagc 			off = bufgap_tell(bp, BGFromBOF, BGChar);
409*2a988851Sagc 			(void) bufgap_seek(bp, 0, BGFromEOF, BGChar);
410*2a988851Sagc 			bp->size *= 2;
411*2a988851Sagc 			RENEW(char, bp->buf, bp->size, "bufgap_insert", return 0);
412*2a988851Sagc 			(void) bufgap_seek(bp, off, BGFromBOF, BGChar);
413*2a988851Sagc 		}
414*2a988851Sagc 		if ((rlen = chartorune(&r, __UNCONST(s))) == 1) {
415*2a988851Sagc 			AFTSUB(bp, bp->abc) = *s;
416*2a988851Sagc 		} else {
417*2a988851Sagc 			(void) memmove(&AFTSUB(bp, bp->abc), s, (size_t)rlen);
418*2a988851Sagc 		}
419*2a988851Sagc 		if (r == '\n') {
420*2a988851Sagc 			bp->alc++;
421*2a988851Sagc 		}
422*2a988851Sagc 		bp->modified = 1;
423*2a988851Sagc 		bp->abc += rlen;
424*2a988851Sagc 		bp->acc++;
425*2a988851Sagc 		s += rlen;
426*2a988851Sagc 	}
427*2a988851Sagc 	return 1;
428*2a988851Sagc }
429*2a988851Sagc 
430*2a988851Sagc /* delete `n' bytes from the buffer gap */
431*2a988851Sagc int
bufgap_delete(bufgap_t * bp,uint64_t n)432*2a988851Sagc bufgap_delete(bufgap_t *bp, uint64_t n)
433*2a988851Sagc {
434*2a988851Sagc 	uint64_t	i;
435*2a988851Sagc 	Rune		r;
436*2a988851Sagc 	int		rlen;
437*2a988851Sagc 
438*2a988851Sagc 	if (n <= bp->bbc) {
439*2a988851Sagc 		for (i = 0 ; i < n ; i += rlen) {
440*2a988851Sagc 			rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
441*2a988851Sagc 			if (r == '\n') {
442*2a988851Sagc 				bp->blc--;
443*2a988851Sagc 			}
444*2a988851Sagc 			bp->bbc -= rlen;
445*2a988851Sagc 			bp->bcc--;
446*2a988851Sagc 			bp->modified = 1;
447*2a988851Sagc 		}
448*2a988851Sagc 		return 1;
449*2a988851Sagc 	}
450*2a988851Sagc 	return 0;
451*2a988851Sagc }
452*2a988851Sagc 
453*2a988851Sagc /* look at a character in a buffer gap `delta' UTF chars away */
454*2a988851Sagc int
bufgap_peek(bufgap_t * bp,int64_t delta)455*2a988851Sagc bufgap_peek(bufgap_t *bp, int64_t delta)
456*2a988851Sagc {
457*2a988851Sagc 	int	ch;
458*2a988851Sagc 
459*2a988851Sagc 	if (delta != 0) {
460*2a988851Sagc 		if (!bufgap_seek(bp, delta, BGFromHere, BGChar)) {
461*2a988851Sagc 			return -1;
462*2a988851Sagc 		}
463*2a988851Sagc 	}
464*2a988851Sagc 	ch = BEFSUB(bp, bp->bbc);
465*2a988851Sagc 	if (delta != 0) {
466*2a988851Sagc 		(void) bufgap_seek(bp, -delta, BGFromHere, BGChar);
467*2a988851Sagc 	}
468*2a988851Sagc 	return ch;
469*2a988851Sagc }
470*2a988851Sagc 
471*2a988851Sagc /* return, in malloc'd storage, text from the buffer gap */
472*2a988851Sagc char *
bufgap_gettext(bufgap_t * bp,int64_t from,int64_t to)473*2a988851Sagc bufgap_gettext(bufgap_t *bp, int64_t from, int64_t to)
474*2a988851Sagc {
475*2a988851Sagc 	int64_t	 off;
476*2a988851Sagc 	int64_t	 n;
477*2a988851Sagc 	char	*text;
478*2a988851Sagc 
479*2a988851Sagc 	off = bufgap_tell(bp, BGFromBOF, BGChar);
480*2a988851Sagc 	NEWARRAY(char, text, (to - from + 1), "bufgap_gettext", return NULL);
481*2a988851Sagc 	(void) bufgap_seek(bp, from, BGFromBOF, BGChar);
482*2a988851Sagc 	for (n = 0 ; n < to - from ; n++) {
483*2a988851Sagc 		text[(int)n] = BEFSUB(bp, bp->bbc - n);
484*2a988851Sagc 	}
485*2a988851Sagc 	text[(int)n] = 0x0;
486*2a988851Sagc 	(void) bufgap_seek(bp, off, BGFromBOF, BGChar);
487*2a988851Sagc 	return text;
488*2a988851Sagc }
489*2a988851Sagc 
490*2a988851Sagc /* return 1 if we wrote the file correctly */
491*2a988851Sagc int
bufgap_write(bufgap_t * bp,FILE * filep)492*2a988851Sagc bufgap_write(bufgap_t *bp, FILE *filep)
493*2a988851Sagc {
494*2a988851Sagc 	if (fwrite(bp->buf, sizeof(char), (size_t)bp->abc, filep) != (size_t)bp->abc) {
495*2a988851Sagc 		return 0;
496*2a988851Sagc 	}
497*2a988851Sagc 	if (fwrite(&BEFSUB(bp, bp->bbc), sizeof(char), (size_t)bp->bbc, filep) != (size_t)bp->bbc) {
498*2a988851Sagc 		return 0;
499*2a988851Sagc 	}
500*2a988851Sagc 	return 1;
501*2a988851Sagc }
502*2a988851Sagc 
503*2a988851Sagc /* tell if the buffer gap is dirty - has been modified */
504*2a988851Sagc int
bufgap_dirty(bufgap_t * bp)505*2a988851Sagc bufgap_dirty(bufgap_t *bp)
506*2a988851Sagc {
507*2a988851Sagc 	return (int)bp->modified;
508*2a988851Sagc }
509