xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/bufgap.c (revision abb0f93cd77b67f080613360c65701f85e5f5cfe)
1 /* $NetBSD: bufgap.c,v 1.2 2009/12/06 17:43:05 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)	strnlen(a, b)
85 
86 static int
87 chartorune(Rune *rp, char *s)
88 {
89 	*rp = s[0];
90 	return 1;
91 }
92 
93 static int
94 priorrune(Rune *rp, char *s)
95 {
96 	*rp = s[0];
97 	return 1;
98 }
99 #else
100 #include "ure.h"
101 #endif
102 
103 /* save `n' chars of `s' in malloc'd memory */
104 static char *
105 strnsave(char *s, int n)
106 {
107 	char	*cp;
108 
109 	if (n < 0) {
110 		n = strlen(s);
111 	}
112 	NEWARRAY(char, cp, n + 1, "strnsave", return NULL);
113 	(void) memcpy(cp, s, (size_t)n);
114 	cp[n] = 0x0;
115 	return cp;
116 }
117 
118 /* open a file in a buffer gap structure */
119 int
120 bufgap_open(bufgap_t *bp, const char *f)
121 {
122 	struct stat	 s;
123 	int64_t		 cc;
124 	FILE		*filep;
125 	char		*cp;
126 
127 	(void) memset(bp, 0x0, sizeof(*bp));
128 	filep = NULL;
129 	if (f != NULL && (filep = fopen(f, "r")) == NULL) {
130 		return 0;
131 	}
132 	if (f == NULL) {
133 		bp->size = BGCHUNKSIZE;
134 		NEWARRAY(char, bp->buf, bp->size, "f_open", return 0);
135 	} else {
136 		(void) fstat(fileno(filep), &s);
137 		bp->size = (int) ((s.st_size / BGCHUNKSIZE) + 1) * BGCHUNKSIZE;
138 		NEWARRAY(char, bp->buf, bp->size, "f_open", return 0);
139 		cc = fread(&BEFSUB(bp, s.st_size), sizeof(char),
140 						(size_t)s.st_size, filep);
141 		(void) fclose(filep);
142 		if (cc != s.st_size) {
143 			FREE(bp->buf);
144 			FREE(bp);
145 			return 0;
146 		}
147 		bp->name = strnsave(__UNCONST(f), (int)utfbytes(__UNCONST(f)));
148 		bp->bbc = s.st_size;
149 		cp = &BEFSUB(bp, cc);
150 		for (;;) {
151 			if ((cp = utfrune(cp, '\n')) == NULL) {
152 				break;
153 			}
154 			bp->blc++;
155 			cp++;
156 		}
157 		bp->bcc = utfnlen(&BEFSUB(bp, cc), (size_t)cc);
158 	}
159 	return 1;
160 }
161 
162 /* close a buffer gapped file */
163 void
164 bufgap_close(bufgap_t *bp)
165 {
166 	FREE(bp->buf);
167 }
168 
169 /* move forwards `n' chars/bytes in a buffer gap */
170 int
171 bufgap_forwards(bufgap_t *bp, uint64_t n, int type)
172 {
173 	Rune	r;
174 	int	rlen;
175 
176 	switch(type) {
177 	case BGChar:
178 		if (bp->bcc >= n) {
179 			while (n-- > 0) {
180 				rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
181 				if (rlen == 1) {
182 					AFTSUB(bp, bp->abc) = BEFSUB(bp, bp->bbc);
183 				} else {
184 					(void) memmove(&AFTSUB(bp, bp->abc),
185 							&BEFSUB(bp, bp->bbc),
186 							(size_t)rlen);
187 				}
188 				bp->acc++;
189 				bp->bcc--;
190 				bp->abc += rlen;
191 				bp->bbc -= rlen;
192 				if (r == '\n') {
193 					bp->alc++;
194 					bp->blc--;
195 				}
196 			}
197 			return 1;
198 		}
199 		break;
200 	case BGByte:
201 		if (bp->bbc >= n) {
202 			for ( ; n > 0 ; n -= rlen) {
203 				rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
204 				if (rlen == 1) {
205 					AFTSUB(bp, bp->abc) = BEFSUB(bp, bp->bbc);
206 				} else {
207 					(void) memmove(&AFTSUB(bp, bp->abc),
208 							&BEFSUB(bp, bp->bbc),
209 							(size_t)rlen);
210 				}
211 				bp->acc++;
212 				bp->bcc--;
213 				bp->abc += rlen;
214 				bp->bbc -= rlen;
215 				if (r == '\n') {
216 					bp->alc++;
217 					bp->blc--;
218 				}
219 			}
220 			return 1;
221 		}
222 	}
223 	return 0;
224 }
225 
226 /* move backwards `n' chars in a buffer gap */
227 int
228 bufgap_backwards(bufgap_t *bp, uint64_t n, int type)
229 {
230 	Rune	r;
231 	int	rlen;
232 
233 	switch(type) {
234 	case BGChar:
235 		if (bp->acc >= n) {
236 			while (n-- > 0) {
237 				rlen = priorrune(&r, &AFTSUB(bp, bp->abc));
238 				bp->bcc++;
239 				bp->acc--;
240 				bp->bbc += rlen;
241 				bp->abc -= rlen;
242 				if (rlen == 1) {
243 					BEFSUB(bp, bp->bbc) = AFTSUB(bp, bp->abc);
244 				} else {
245 					(void) memmove(&BEFSUB(bp, bp->bbc),
246 							&AFTSUB(bp, bp->abc),
247 							(size_t)rlen);
248 				}
249 				if (r == '\n') {
250 					bp->blc++;
251 					bp->alc--;
252 				}
253 			}
254 			return 1;
255 		}
256 		break;
257 	case BGByte:
258 		if (bp->acc >= n) {
259 			for ( ; n > 0 ; n -= rlen) {
260 				rlen = priorrune(&r, &AFTSUB(bp, bp->abc));
261 				bp->bcc++;
262 				bp->acc--;
263 				bp->bbc += rlen;
264 				bp->abc -= rlen;
265 				if (rlen == 1) {
266 					BEFSUB(bp, bp->bbc) = AFTSUB(bp, bp->abc);
267 				} else {
268 					(void) memmove(&BEFSUB(bp, bp->bbc),
269 							&AFTSUB(bp, bp->abc),
270 							(size_t)rlen);
271 				}
272 				if (r == '\n') {
273 					bp->blc++;
274 					bp->alc--;
275 				}
276 			}
277 			return 1;
278 		}
279 	}
280 	return 0;
281 }
282 
283 /* move within a buffer gap */
284 int
285 bufgap_seek(bufgap_t *bp, int64_t off, int whence, int type)
286 {
287 	switch(type) {
288 	case BGLine:
289 		switch(whence) {
290 		case BGFromBOF:
291 			if (off < 0 || off > (int64_t)(bp->alc + bp->blc)) {
292 				return 0;
293 			}
294 			if (off < (int64_t)bp->alc) {
295 				while (off <= (int64_t)bp->alc && bufgap_backwards(bp, 1, BGChar)) {
296 				}
297 				if (off > 0) {
298 					(void) bufgap_forwards(bp, 1, BGChar);
299 				}
300 			} else if (off > (int64_t)bp->alc) {
301 				while (off > (int64_t)bp->alc && bufgap_forwards(bp, 1, BGChar)) {
302 				}
303 			}
304 			return 1;
305 		case BGFromHere:
306 			return bufgap_seek(bp, (int64_t)(bp->alc + off), BGFromBOF, BGLine);
307 		case BGFromEOF:
308 			return bufgap_seek(bp, (int64_t)(bp->alc + bp->blc + off), BGFromBOF, BGLine);
309 		}
310 		break;
311 	case BGChar:
312 		switch(whence) {
313 		case BGFromBOF:
314 			if (off < 0 || off > (int64_t)(bp->acc + bp->bcc)) {
315 				return 0;
316 			}
317 			if (off < (int64_t)bp->acc) {
318 				return bufgap_backwards(bp, bp->acc - off, BGChar);
319 			} else if (off > (int64_t)bp->acc) {
320 				return bufgap_forwards(bp, off - bp->acc, BGChar);
321 			}
322 			return 1;
323 		case BGFromHere:
324 			return bufgap_seek(bp, (int64_t)(bp->acc + off), BGFromBOF, BGChar);
325 		case BGFromEOF:
326 			return bufgap_seek(bp, (int64_t)(bp->acc + bp->bcc + off), BGFromBOF, BGChar);
327 		}
328 		break;
329 	case BGByte:
330 		switch(whence) {
331 		case BGFromBOF:
332 			if (off < 0 || off > (int64_t)(bp->abc + bp->bbc)) {
333 				return 0;
334 			}
335 			if (off < (int64_t)bp->abc) {
336 				return bufgap_backwards(bp, bp->abc - off, BGByte);
337 			} else if (off > (int64_t)bp->abc) {
338 				return bufgap_forwards(bp, off - bp->abc, BGByte);
339 			}
340 			return 1;
341 		case BGFromHere:
342 			return bufgap_seek(bp, (int64_t)(bp->abc + off), BGFromBOF, BGByte);
343 		case BGFromEOF:
344 			return bufgap_seek(bp, (int64_t)(bp->abc + bp->bbc + off), BGFromBOF, BGByte);
345 		}
346 		break;
347 	}
348 	return 0;
349 }
350 
351 /* return a pointer to the text in the buffer gap */
352 char *
353 bufgap_getstr(bufgap_t *bp)
354 {
355 	return &BEFSUB(bp, bp->bbc);
356 }
357 
358 /* return the binary text in the buffer gap */
359 int
360 bufgap_getbin(bufgap_t *bp, void *dst, size_t len)
361 {
362 	int	cc;
363 
364 	cc = (bp->bcc < len) ? (int)bp->bcc : (int)len;
365 	(void) memcpy(dst, &BEFSUB(bp, bp->bbc), len);
366 	return cc;
367 }
368 
369 /* return offset (from beginning/end) in a buffer gap */
370 int64_t
371 bufgap_tell(bufgap_t *bp, int whence, int type)
372 {
373 	switch(whence) {
374 	case BGFromBOF:
375 		return (type == BGLine) ? bp->alc :
376 			(type == BGByte) ? bp->abc : bp->acc;
377 	case BGFromEOF:
378 		return (type == BGLine) ? bp->blc :
379 			(type == BGByte) ? bp->bbc : bp->bcc;
380 	default:
381 		(void) fprintf(stderr, "weird whence in bufgap_tell\n");
382 		break;
383 	}
384 	return (int64_t)0;
385 }
386 
387 /* return size of buffer gap */
388 int64_t
389 bufgap_size(bufgap_t *bp, int type)
390 {
391 	return (type == BGLine) ? bp->alc + bp->blc :
392 		(type == BGChar) ? bp->acc + bp->bcc :
393 			bp->abc + bp->bbc;
394 }
395 
396 /* insert `n' chars of `s' in a buffer gap */
397 int
398 bufgap_insert(bufgap_t *bp, const char *s, int n)
399 {
400 	int64_t	off;
401 	Rune	r;
402 	int	rlen;
403 	int	i;
404 
405 	if (n < 0) {
406 		n = strlen(s);
407 	}
408 	for (i = 0 ; i < n ; i += rlen) {
409 		if (bp->bbc + bp->abc == bp->size) {
410 			off = bufgap_tell(bp, BGFromBOF, BGChar);
411 			(void) bufgap_seek(bp, 0, BGFromEOF, BGChar);
412 			bp->size *= 2;
413 			RENEW(char, bp->buf, bp->size, "bufgap_insert", return 0);
414 			(void) bufgap_seek(bp, off, BGFromBOF, BGChar);
415 		}
416 		if ((rlen = chartorune(&r, __UNCONST(s))) == 1) {
417 			AFTSUB(bp, bp->abc) = *s;
418 		} else {
419 			(void) memmove(&AFTSUB(bp, bp->abc), s, (size_t)rlen);
420 		}
421 		if (r == '\n') {
422 			bp->alc++;
423 		}
424 		bp->modified = 1;
425 		bp->abc += rlen;
426 		bp->acc++;
427 		s += rlen;
428 	}
429 	return 1;
430 }
431 
432 /* delete `n' bytes from the buffer gap */
433 int
434 bufgap_delete(bufgap_t *bp, uint64_t n)
435 {
436 	uint64_t	i;
437 	Rune		r;
438 	int		rlen;
439 
440 	if (n <= bp->bbc) {
441 		for (i = 0 ; i < n ; i += rlen) {
442 			rlen = chartorune(&r, &BEFSUB(bp, bp->bbc));
443 			if (r == '\n') {
444 				bp->blc--;
445 			}
446 			bp->bbc -= rlen;
447 			bp->bcc--;
448 			bp->modified = 1;
449 		}
450 		return 1;
451 	}
452 	return 0;
453 }
454 
455 /* look at a character in a buffer gap `delta' UTF chars away */
456 int
457 bufgap_peek(bufgap_t *bp, int64_t delta)
458 {
459 	int	ch;
460 
461 	if (delta != 0) {
462 		if (!bufgap_seek(bp, delta, BGFromHere, BGChar)) {
463 			return -1;
464 		}
465 	}
466 	ch = BEFSUB(bp, bp->bbc);
467 	if (delta != 0) {
468 		(void) bufgap_seek(bp, -delta, BGFromHere, BGChar);
469 	}
470 	return ch;
471 }
472 
473 /* return, in malloc'd storage, text from the buffer gap */
474 char *
475 bufgap_gettext(bufgap_t *bp, int64_t from, int64_t to)
476 {
477 	int64_t	 off;
478 	int64_t	 n;
479 	char	*text;
480 
481 	off = bufgap_tell(bp, BGFromBOF, BGChar);
482 	NEWARRAY(char, text, (to - from + 1), "bufgap_gettext", return NULL);
483 	(void) bufgap_seek(bp, from, BGFromBOF, BGChar);
484 	for (n = 0 ; n < to - from ; n++) {
485 		text[(int)n] = BEFSUB(bp, bp->bbc - n);
486 	}
487 	text[(int)n] = 0x0;
488 	(void) bufgap_seek(bp, off, BGFromBOF, BGChar);
489 	return text;
490 }
491 
492 /* return 1 if we wrote the file correctly */
493 int
494 bufgap_write(bufgap_t *bp, FILE *filep)
495 {
496 	if (fwrite(bp->buf, sizeof(char), (size_t)bp->abc, filep) != (size_t)bp->abc) {
497 		return 0;
498 	}
499 	if (fwrite(&BEFSUB(bp, bp->bbc), sizeof(char), (size_t)bp->bbc, filep) != (size_t)bp->bbc) {
500 		return 0;
501 	}
502 	return 1;
503 }
504 
505 /* tell if the buffer gap is dirty - has been modified */
506 int
507 bufgap_dirty(bufgap_t *bp)
508 {
509 	return (int)bp->modified;
510 }
511