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