1 /* $NetBSD: bufgap.c,v 1.2 2009/12/06 17:43:05 agc Exp $ */
4 * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Alistair Crooks (agc@NetBSD.org)
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
37 #ifdef HAVE_SYS_STAT_H
53 #include "fastctype.h"
57 /* macros to get subscripts in buffer */
58 #define AFTSUB(bp, n) ((bp)->buf[(int)n])
59 #define BEFSUB(bp, n) ((bp)->buf[(int)((bp)->size - (n) - 1)])
61 /* initial allocation size */
67 #define KiB(x) ((x) * 1024)
70 #define BGCHUNKSIZE KiB(4)
73 #define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
82 #define utfbytes(x) strlen(x)
83 #define utfrune(a, b) strchr(a, b)
84 #define utfnlen(a, b) bounded_strlen(a, b)
87 bounded_strlen(const char *s
, size_t maxlen
)
91 for (n
= 0 ; n
< maxlen
&& s
[n
] != 0x0 ; n
++) {
97 chartorune(Rune
*rp
, char *s
)
104 priorrune(Rune
*rp
, char *s
)
113 /* save `n' chars of `s' in malloc'd memory */
115 strnsave(char *s
, int n
)
122 NEWARRAY(char, cp
, n
+ 1, "strnsave", return NULL
);
123 (void) memcpy(cp
, s
, (size_t)n
);
128 /* open a file in a buffer gap structure */
130 bufgap_open(bufgap_t
*bp
, const char *f
)
137 (void) memset(bp
, 0x0, sizeof(*bp
));
139 if (f
!= NULL
&& (filep
= fopen(f
, "r")) == NULL
) {
143 bp
->size
= BGCHUNKSIZE
;
144 NEWARRAY(char, bp
->buf
, bp
->size
, "f_open", return 0);
146 (void) fstat(fileno(filep
), &s
);
147 bp
->size
= (int) ((s
.st_size
/ BGCHUNKSIZE
) + 1) * BGCHUNKSIZE
;
148 NEWARRAY(char, bp
->buf
, bp
->size
, "f_open", return 0);
149 cc
= fread(&BEFSUB(bp
, s
.st_size
), sizeof(char),
150 (size_t)s
.st_size
, filep
);
151 (void) fclose(filep
);
152 if (cc
!= s
.st_size
) {
157 bp
->name
= strnsave(__UNCONST(f
), (int)utfbytes(__UNCONST(f
)));
159 cp
= &BEFSUB(bp
, cc
);
161 if ((cp
= utfrune(cp
, '\n')) == NULL
) {
167 bp
->bcc
= utfnlen(&BEFSUB(bp
, cc
), (size_t)cc
);
172 /* close a buffer gapped file */
174 bufgap_close(bufgap_t
*bp
)
179 /* move forwards `n' chars/bytes in a buffer gap */
181 bufgap_forwards(bufgap_t
*bp
, uint64_t n
, int type
)
190 rlen
= chartorune(&r
, &BEFSUB(bp
, bp
->bbc
));
192 AFTSUB(bp
, bp
->abc
) = BEFSUB(bp
, bp
->bbc
);
194 (void) memmove(&AFTSUB(bp
, bp
->abc
),
195 &BEFSUB(bp
, bp
->bbc
),
212 for ( ; n
> 0 ; n
-= rlen
) {
213 rlen
= chartorune(&r
, &BEFSUB(bp
, bp
->bbc
));
215 AFTSUB(bp
, bp
->abc
) = BEFSUB(bp
, bp
->bbc
);
217 (void) memmove(&AFTSUB(bp
, bp
->abc
),
218 &BEFSUB(bp
, bp
->bbc
),
236 /* move backwards `n' chars in a buffer gap */
238 bufgap_backwards(bufgap_t
*bp
, uint64_t n
, int type
)
247 rlen
= priorrune(&r
, &AFTSUB(bp
, bp
->abc
));
253 BEFSUB(bp
, bp
->bbc
) = AFTSUB(bp
, bp
->abc
);
255 (void) memmove(&BEFSUB(bp
, bp
->bbc
),
256 &AFTSUB(bp
, bp
->abc
),
269 for ( ; n
> 0 ; n
-= rlen
) {
270 rlen
= priorrune(&r
, &AFTSUB(bp
, bp
->abc
));
276 BEFSUB(bp
, bp
->bbc
) = AFTSUB(bp
, bp
->abc
);
278 (void) memmove(&BEFSUB(bp
, bp
->bbc
),
279 &AFTSUB(bp
, bp
->abc
),
293 /* move within a buffer gap */
295 bufgap_seek(bufgap_t
*bp
, int64_t off
, int whence
, int type
)
301 if (off
< 0 || off
> (int64_t)(bp
->alc
+ bp
->blc
)) {
304 if (off
< (int64_t)bp
->alc
) {
305 while (off
<= (int64_t)bp
->alc
&& bufgap_backwards(bp
, 1, BGChar
)) {
308 (void) bufgap_forwards(bp
, 1, BGChar
);
310 } else if (off
> (int64_t)bp
->alc
) {
311 while (off
> (int64_t)bp
->alc
&& bufgap_forwards(bp
, 1, BGChar
)) {
316 return bufgap_seek(bp
, (int64_t)(bp
->alc
+ off
), BGFromBOF
, BGLine
);
318 return bufgap_seek(bp
, (int64_t)(bp
->alc
+ bp
->blc
+ off
), BGFromBOF
, BGLine
);
324 if (off
< 0 || off
> (int64_t)(bp
->acc
+ bp
->bcc
)) {
327 if (off
< (int64_t)bp
->acc
) {
328 return bufgap_backwards(bp
, bp
->acc
- off
, BGChar
);
329 } else if (off
> (int64_t)bp
->acc
) {
330 return bufgap_forwards(bp
, off
- bp
->acc
, BGChar
);
334 return bufgap_seek(bp
, (int64_t)(bp
->acc
+ off
), BGFromBOF
, BGChar
);
336 return bufgap_seek(bp
, (int64_t)(bp
->acc
+ bp
->bcc
+ off
), BGFromBOF
, BGChar
);
342 if (off
< 0 || off
> (int64_t)(bp
->abc
+ bp
->bbc
)) {
345 if (off
< (int64_t)bp
->abc
) {
346 return bufgap_backwards(bp
, bp
->abc
- off
, BGByte
);
347 } else if (off
> (int64_t)bp
->abc
) {
348 return bufgap_forwards(bp
, off
- bp
->abc
, BGByte
);
352 return bufgap_seek(bp
, (int64_t)(bp
->abc
+ off
), BGFromBOF
, BGByte
);
354 return bufgap_seek(bp
, (int64_t)(bp
->abc
+ bp
->bbc
+ off
), BGFromBOF
, BGByte
);
361 /* return a pointer to the text in the buffer gap */
363 bufgap_getstr(bufgap_t
*bp
)
365 return &BEFSUB(bp
, bp
->bbc
);
368 /* return the binary text in the buffer gap */
370 bufgap_getbin(bufgap_t
*bp
, void *dst
, size_t len
)
374 cc
= (bp
->bcc
< len
) ? (int)bp
->bcc
: (int)len
;
375 (void) memcpy(dst
, &BEFSUB(bp
, bp
->bbc
), len
);
379 /* return offset (from beginning/end) in a buffer gap */
381 bufgap_tell(bufgap_t
*bp
, int whence
, int type
)
385 return (type
== BGLine
) ? bp
->alc
:
386 (type
== BGByte
) ? bp
->abc
: bp
->acc
;
388 return (type
== BGLine
) ? bp
->blc
:
389 (type
== BGByte
) ? bp
->bbc
: bp
->bcc
;
391 (void) fprintf(stderr
, "weird whence in bufgap_tell\n");
397 /* return size of buffer gap */
399 bufgap_size(bufgap_t
*bp
, int type
)
401 return (type
== BGLine
) ? bp
->alc
+ bp
->blc
:
402 (type
== BGChar
) ? bp
->acc
+ bp
->bcc
:
406 /* insert `n' chars of `s' in a buffer gap */
408 bufgap_insert(bufgap_t
*bp
, const char *s
, int n
)
418 for (i
= 0 ; i
< n
; i
+= rlen
) {
419 if (bp
->bbc
+ bp
->abc
== bp
->size
) {
420 off
= bufgap_tell(bp
, BGFromBOF
, BGChar
);
421 (void) bufgap_seek(bp
, 0, BGFromEOF
, BGChar
);
423 RENEW(char, bp
->buf
, bp
->size
, "bufgap_insert", return 0);
424 (void) bufgap_seek(bp
, off
, BGFromBOF
, BGChar
);
426 if ((rlen
= chartorune(&r
, __UNCONST(s
))) == 1) {
427 AFTSUB(bp
, bp
->abc
) = *s
;
429 (void) memmove(&AFTSUB(bp
, bp
->abc
), s
, (size_t)rlen
);
442 /* delete `n' bytes from the buffer gap */
444 bufgap_delete(bufgap_t
*bp
, uint64_t n
)
451 for (i
= 0 ; i
< n
; i
+= rlen
) {
452 rlen
= chartorune(&r
, &BEFSUB(bp
, bp
->bbc
));
465 /* look at a character in a buffer gap `delta' UTF chars away */
467 bufgap_peek(bufgap_t
*bp
, int64_t delta
)
472 if (!bufgap_seek(bp
, delta
, BGFromHere
, BGChar
)) {
476 ch
= BEFSUB(bp
, bp
->bbc
);
478 (void) bufgap_seek(bp
, -delta
, BGFromHere
, BGChar
);
483 /* return, in malloc'd storage, text from the buffer gap */
485 bufgap_gettext(bufgap_t
*bp
, int64_t from
, int64_t to
)
491 off
= bufgap_tell(bp
, BGFromBOF
, BGChar
);
492 NEWARRAY(char, text
, (to
- from
+ 1), "bufgap_gettext", return NULL
);
493 (void) bufgap_seek(bp
, from
, BGFromBOF
, BGChar
);
494 for (n
= 0 ; n
< to
- from
; n
++) {
495 text
[(int)n
] = BEFSUB(bp
, bp
->bbc
- n
);
498 (void) bufgap_seek(bp
, off
, BGFromBOF
, BGChar
);
502 /* return 1 if we wrote the file correctly */
504 bufgap_write(bufgap_t
*bp
, FILE *filep
)
506 if (fwrite(bp
->buf
, sizeof(char), (size_t)bp
->abc
, filep
) != (size_t)bp
->abc
) {
509 if (fwrite(&BEFSUB(bp
, bp
->bbc
), sizeof(char), (size_t)bp
->bbc
, filep
) != (size_t)bp
->bbc
) {
515 /* tell if the buffer gap is dirty - has been modified */
517 bufgap_dirty(bufgap_t
*bp
)
519 return (int)bp
->modified
;