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