xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/bufgap.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /* $NetBSD: bufgap.c,v 1.4 2010/08/15 16:10:56 agc Exp $ */
2 
3 /*-
4  * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Alistair Crooks (agc@NetBSD.org)
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  *
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.
30  */
31 #include "config.h"
32 
33 #ifdef HAVE_SYS_TYPES_H
34 #include <sys/types.h>
35 #endif
36 
37 #ifdef HAVE_SYS_STAT_H
38 #include <sys/stat.h>
39 #endif
40 
41 #include <stdio.h>
42 
43 #include <stdlib.h>
44 
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 
49 #ifdef HAVE_STRING_H
50 #include <string.h>
51 #endif
52 
53 #include "fastctype.h"
54 #include "bufgap.h"
55 #include "defs.h"
56 
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)])
60 
61 /* initial allocation size */
62 #ifndef CHUNKSIZE
63 #define CHUNKSIZE	256
64 #endif
65 
66 #ifndef KiB
67 #define KiB(x)	((x) * 1024)
68 #endif
69 
70 #define BGCHUNKSIZE	KiB(4)
71 
72 #ifndef __UNCONST
73 #define __UNCONST(a)       ((void *)(unsigned long)(const void *)(a))
74 #endif
75 
76 #ifndef USE_UTF
77 #define USE_UTF	0
78 #endif
79 
80 #if !USE_UTF
81 #define Rune		char
82 #define	utfbytes(x)	strlen(x)
83 #define	utfrune(a, b)	strchr(a, b)
84 #define	utfnlen(a, b)	bounded_strlen(a, b)
85 
86 static size_t
87 bounded_strlen(const char *s, size_t maxlen)
88 {
89 	size_t	n;
90 
91 	for (n = 0 ; n < maxlen && s[n] != 0x0 ; n++) {
92 	}
93 	return n;
94 }
95 
96 static int
97 chartorune(Rune *rp, char *s)
98 {
99 	*rp = s[0];
100 	return 1;
101 }
102 
103 static int
104 priorrune(Rune *rp, char *s)
105 {
106 	*rp = s[0];
107 	return 1;
108 }
109 #else
110 #include "ure.h"
111 #endif
112 
113 /* save `n' chars of `s' in malloc'd memory */
114 static char *
115 strnsave(char *s, int n)
116 {
117 	char	*cp;
118 
119 	if (n < 0) {
120 		n = (int)strlen(s);
121 	}
122 	NEWARRAY(char, cp, n + 1, "strnsave", return NULL);
123 	(void) memcpy(cp, s, (size_t)n);
124 	cp[n] = 0x0;
125 	return cp;
126 }
127 
128 /* open a file in a buffer gap structure */
129 int
130 bufgap_open(bufgap_t *bp, const char *f)
131 {
132 	struct stat	 s;
133 	int64_t		 cc;
134 	FILE		*filep;
135 	char		*cp;
136 
137 	(void) memset(bp, 0x0, sizeof(*bp));
138 	filep = NULL;
139 	if (f != NULL && (filep = fopen(f, "r")) == NULL) {
140 		return 0;
141 	}
142 	if (f == NULL) {
143 		bp->size = BGCHUNKSIZE;
144 		NEWARRAY(char, bp->buf, bp->size, "f_open", return 0);
145 	} else {
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) {
153 			FREE(bp->buf);
154 			FREE(bp);
155 			return 0;
156 		}
157 		bp->name = strnsave(__UNCONST(f), (int)utfbytes(__UNCONST(f)));
158 		bp->bbc = s.st_size;
159 		cp = &BEFSUB(bp, cc);
160 		for (;;) {
161 			if ((cp = utfrune(cp, '\n')) == NULL) {
162 				break;
163 			}
164 			bp->blc++;
165 			cp++;
166 		}
167 		bp->bcc = utfnlen(&BEFSUB(bp, cc), (size_t)cc);
168 	}
169 	return 1;
170 }
171 
172 /* close a buffer gapped file */
173 void
174 bufgap_close(bufgap_t *bp)
175 {
176 	FREE(bp->buf);
177 }
178 
179 /* move forwards `n' chars/bytes in a buffer gap */
180 int
181 bufgap_forwards(bufgap_t *bp, uint64_t n, int type)
182 {
183 	Rune	r;
184 	int	rlen;
185 
186 	switch(type) {
187 	case BGChar:
188 		if (bp->bcc >= n) {
189 			while (n-- > 0) {
190 				rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
191 				if (rlen == 1) {
192 					AFTSUB(bp, bp->abc) = BEFSUB(bp, bp->bbc);
193 				} else {
194 					(void) memmove(&AFTSUB(bp, bp->abc),
195 							&BEFSUB(bp, bp->bbc),
196 							(size_t)rlen);
197 				}
198 				bp->acc++;
199 				bp->bcc--;
200 				bp->abc += rlen;
201 				bp->bbc -= rlen;
202 				if (r == '\n') {
203 					bp->alc++;
204 					bp->blc--;
205 				}
206 			}
207 			return 1;
208 		}
209 		break;
210 	case BGByte:
211 		if (bp->bbc >= n) {
212 			for ( ; n > 0 ; n -= rlen) {
213 				rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
214 				if (rlen == 1) {
215 					AFTSUB(bp, bp->abc) = BEFSUB(bp, bp->bbc);
216 				} else {
217 					(void) memmove(&AFTSUB(bp, bp->abc),
218 							&BEFSUB(bp, bp->bbc),
219 							(size_t)rlen);
220 				}
221 				bp->acc++;
222 				bp->bcc--;
223 				bp->abc += rlen;
224 				bp->bbc -= rlen;
225 				if (r == '\n') {
226 					bp->alc++;
227 					bp->blc--;
228 				}
229 			}
230 			return 1;
231 		}
232 	}
233 	return 0;
234 }
235 
236 /* move backwards `n' chars in a buffer gap */
237 int
238 bufgap_backwards(bufgap_t *bp, uint64_t n, int type)
239 {
240 	Rune	r;
241 	int	rlen;
242 
243 	switch(type) {
244 	case BGChar:
245 		if (bp->acc >= n) {
246 			while (n-- > 0) {
247 				rlen = priorrune(&r, &AFTSUB(bp, bp->abc));
248 				bp->bcc++;
249 				bp->acc--;
250 				bp->bbc += rlen;
251 				bp->abc -= rlen;
252 				if (rlen == 1) {
253 					BEFSUB(bp, bp->bbc) = AFTSUB(bp, bp->abc);
254 				} else {
255 					(void) memmove(&BEFSUB(bp, bp->bbc),
256 							&AFTSUB(bp, bp->abc),
257 							(size_t)rlen);
258 				}
259 				if (r == '\n') {
260 					bp->blc++;
261 					bp->alc--;
262 				}
263 			}
264 			return 1;
265 		}
266 		break;
267 	case BGByte:
268 		if (bp->acc >= n) {
269 			for ( ; n > 0 ; n -= rlen) {
270 				rlen = priorrune(&r, &AFTSUB(bp, bp->abc));
271 				bp->bcc++;
272 				bp->acc--;
273 				bp->bbc += rlen;
274 				bp->abc -= rlen;
275 				if (rlen == 1) {
276 					BEFSUB(bp, bp->bbc) = AFTSUB(bp, bp->abc);
277 				} else {
278 					(void) memmove(&BEFSUB(bp, bp->bbc),
279 							&AFTSUB(bp, bp->abc),
280 							(size_t)rlen);
281 				}
282 				if (r == '\n') {
283 					bp->blc++;
284 					bp->alc--;
285 				}
286 			}
287 			return 1;
288 		}
289 	}
290 	return 0;
291 }
292 
293 /* move within a buffer gap */
294 int
295 bufgap_seek(bufgap_t *bp, int64_t off, int whence, int type)
296 {
297 	switch(type) {
298 	case BGLine:
299 		switch(whence) {
300 		case BGFromBOF:
301 			if (off < 0 || off > (int64_t)(bp->alc + bp->blc)) {
302 				return 0;
303 			}
304 			if (off < (int64_t)bp->alc) {
305 				while (off <= (int64_t)bp->alc && bufgap_backwards(bp, 1, BGChar)) {
306 				}
307 				if (off > 0) {
308 					(void) bufgap_forwards(bp, 1, BGChar);
309 				}
310 			} else if (off > (int64_t)bp->alc) {
311 				while (off > (int64_t)bp->alc && bufgap_forwards(bp, 1, BGChar)) {
312 				}
313 			}
314 			return 1;
315 		case BGFromHere:
316 			return bufgap_seek(bp, (int64_t)(bp->alc + off), BGFromBOF, BGLine);
317 		case BGFromEOF:
318 			return bufgap_seek(bp, (int64_t)(bp->alc + bp->blc + off), BGFromBOF, BGLine);
319 		}
320 		break;
321 	case BGChar:
322 		switch(whence) {
323 		case BGFromBOF:
324 			if (off < 0 || off > (int64_t)(bp->acc + bp->bcc)) {
325 				return 0;
326 			}
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);
331 			}
332 			return 1;
333 		case BGFromHere:
334 			return bufgap_seek(bp, (int64_t)(bp->acc + off), BGFromBOF, BGChar);
335 		case BGFromEOF:
336 			return bufgap_seek(bp, (int64_t)(bp->acc + bp->bcc + off), BGFromBOF, BGChar);
337 		}
338 		break;
339 	case BGByte:
340 		switch(whence) {
341 		case BGFromBOF:
342 			if (off < 0 || off > (int64_t)(bp->abc + bp->bbc)) {
343 				return 0;
344 			}
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);
349 			}
350 			return 1;
351 		case BGFromHere:
352 			return bufgap_seek(bp, (int64_t)(bp->abc + off), BGFromBOF, BGByte);
353 		case BGFromEOF:
354 			return bufgap_seek(bp, (int64_t)(bp->abc + bp->bbc + off), BGFromBOF, BGByte);
355 		}
356 		break;
357 	}
358 	return 0;
359 }
360 
361 /* return a pointer to the text in the buffer gap */
362 char *
363 bufgap_getstr(bufgap_t *bp)
364 {
365 	return &BEFSUB(bp, bp->bbc);
366 }
367 
368 /* return the binary text in the buffer gap */
369 int
370 bufgap_getbin(bufgap_t *bp, void *dst, size_t len)
371 {
372 	int	cc;
373 
374 	cc = (bp->bcc < len) ? (int)bp->bcc : (int)len;
375 	(void) memcpy(dst, &BEFSUB(bp, bp->bbc), len);
376 	return cc;
377 }
378 
379 /* return offset (from beginning/end) in a buffer gap */
380 int64_t
381 bufgap_tell(bufgap_t *bp, int whence, int type)
382 {
383 	switch(whence) {
384 	case BGFromBOF:
385 		return (type == BGLine) ? bp->alc :
386 			(type == BGByte) ? bp->abc : bp->acc;
387 	case BGFromEOF:
388 		return (type == BGLine) ? bp->blc :
389 			(type == BGByte) ? bp->bbc : bp->bcc;
390 	default:
391 		(void) fprintf(stderr, "weird whence in bufgap_tell\n");
392 		break;
393 	}
394 	return (int64_t)0;
395 }
396 
397 /* return size of buffer gap */
398 int64_t
399 bufgap_size(bufgap_t *bp, int type)
400 {
401 	return (type == BGLine) ? bp->alc + bp->blc :
402 		(type == BGChar) ? bp->acc + bp->bcc :
403 			bp->abc + bp->bbc;
404 }
405 
406 /* insert `n' chars of `s' in a buffer gap */
407 int
408 bufgap_insert(bufgap_t *bp, const char *s, int n)
409 {
410 	int64_t	off;
411 	Rune	r;
412 	int	rlen;
413 	int	i;
414 
415 	if (n < 0) {
416 		n = (int)strlen(s);
417 	}
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);
422 			bp->size *= 2;
423 			RENEW(char, bp->buf, bp->size, "bufgap_insert", return 0);
424 			(void) bufgap_seek(bp, off, BGFromBOF, BGChar);
425 		}
426 		if ((rlen = chartorune(&r, __UNCONST(s))) == 1) {
427 			AFTSUB(bp, bp->abc) = *s;
428 		} else {
429 			(void) memmove(&AFTSUB(bp, bp->abc), s, (size_t)rlen);
430 		}
431 		if (r == '\n') {
432 			bp->alc++;
433 		}
434 		bp->modified = 1;
435 		bp->abc += rlen;
436 		bp->acc++;
437 		s += rlen;
438 	}
439 	return 1;
440 }
441 
442 /* delete `n' bytes from the buffer gap */
443 int
444 bufgap_delete(bufgap_t *bp, uint64_t n)
445 {
446 	uint64_t	i;
447 	Rune		r;
448 	int		rlen;
449 
450 	if (n <= bp->bbc) {
451 		for (i = 0 ; i < n ; i += rlen) {
452 			rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
453 			if (r == '\n') {
454 				bp->blc--;
455 			}
456 			bp->bbc -= rlen;
457 			bp->bcc--;
458 			bp->modified = 1;
459 		}
460 		return 1;
461 	}
462 	return 0;
463 }
464 
465 /* look at a character in a buffer gap `delta' UTF chars away */
466 int
467 bufgap_peek(bufgap_t *bp, int64_t delta)
468 {
469 	int	ch;
470 
471 	if (delta != 0) {
472 		if (!bufgap_seek(bp, delta, BGFromHere, BGChar)) {
473 			return -1;
474 		}
475 	}
476 	ch = BEFSUB(bp, bp->bbc);
477 	if (delta != 0) {
478 		(void) bufgap_seek(bp, -delta, BGFromHere, BGChar);
479 	}
480 	return ch;
481 }
482 
483 /* return, in malloc'd storage, text from the buffer gap */
484 char *
485 bufgap_gettext(bufgap_t *bp, int64_t from, int64_t to)
486 {
487 	int64_t	 off;
488 	int64_t	 n;
489 	char	*text;
490 
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);
496 	}
497 	text[(int)n] = 0x0;
498 	(void) bufgap_seek(bp, off, BGFromBOF, BGChar);
499 	return text;
500 }
501 
502 /* return 1 if we wrote the file correctly */
503 int
504 bufgap_write(bufgap_t *bp, FILE *filep)
505 {
506 	if (fwrite(bp->buf, sizeof(char), (size_t)bp->abc, filep) != (size_t)bp->abc) {
507 		return 0;
508 	}
509 	if (fwrite(&BEFSUB(bp, bp->bbc), sizeof(char), (size_t)bp->bbc, filep) != (size_t)bp->bbc) {
510 		return 0;
511 	}
512 	return 1;
513 }
514 
515 /* tell if the buffer gap is dirty - has been modified */
516 int
517 bufgap_dirty(bufgap_t *bp)
518 {
519 	return (int)bp->modified;
520 }
521