1 /* ebuf.c - an expanding buffer */
2 
3 /*  Copyright 1993 Mark Russell, University of Kent at Canterbury
4  *
5  *  You can do what you like with this source code as long as
6  *  you don't try to make money out of it and you include an
7  *  unaltered copy of this message (including the copyright).
8  */
9 
10 char ukcprog_ebuf_sccsid[] = "$Id: ebuf.c,v 1.7 1995/11/26 15:59:21 mtr Exp $ UKC";
11 
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "ukcprog.h"
16 
17 struct ebuf_s {
18 	bool eb_errors_are_fatal;
19 	char *eb_buf;
20 	size_t eb_bufsize;
21 	size_t eb_pos;
22 };
23 
24 ebuf_t *
ebuf_create(errors_are_fatal)25 ebuf_create(errors_are_fatal)
26 bool errors_are_fatal;
27 {
28 	ebuf_t *eb;
29 	char *buf;
30 	size_t bufsize;
31 
32 	bufsize = 100;
33 
34 	if (errors_are_fatal) {
35 		eb = (ebuf_t *)e_malloc(sizeof(ebuf_t));
36 		buf = e_malloc(bufsize);
37 	}
38 	else {
39 		if ((eb = (ebuf_t *)malloc(sizeof(ebuf_t))) == NULL)
40 			return NULL;
41 		if ((buf = malloc(bufsize)) == NULL) {
42 			free((char *)eb);
43 			return NULL;
44 		}
45 	}
46 
47 	eb->eb_errors_are_fatal = errors_are_fatal;
48 	eb->eb_buf = buf;
49 	eb->eb_bufsize = bufsize;
50 	eb->eb_pos = 0;
51 
52 	return eb;
53 }
54 
55 void
ebuf_reset(eb)56 ebuf_reset(eb)
57 ebuf_t *eb;
58 {
59 	eb->eb_pos = 0;
60 }
61 
62 /*  We would like this to take a pointer to a size_t, but that would
63  *  break existing code (when compiling with gcc).  Maybe later.
64  */
65 voidptr
ebuf_get(eb,p_len)66 ebuf_get(eb, p_len)
67 ebuf_t *eb;
68 int *p_len;
69 {
70 	if (p_len != NULL)
71 		*p_len = eb->eb_pos;
72 	return eb->eb_buf;
73 }
74 
75 ebuf_t *
ebuf_start(eb,errors_are_fatal)76 ebuf_start(eb, errors_are_fatal)
77 ebuf_t *eb;
78 bool errors_are_fatal;
79 {
80 	if (eb == NULL)
81 		eb = ebuf_create(errors_are_fatal);
82 	else
83 		ebuf_reset(eb);
84 
85 	return eb;
86 }
87 
88 void
ebuf_free(eb)89 ebuf_free(eb)
90 ebuf_t *eb;
91 {
92 	free(eb->eb_buf);
93 	free((char *)eb);
94 }
95 
96 int
ebuf_add(eb,buf,count)97 ebuf_add(eb, buf, count)
98 ebuf_t *eb;
99 constvoidptr buf;
100 size_t count;
101 {
102 	size_t size;
103 
104 	for (size = eb->eb_bufsize; eb->eb_pos + count > size; size *= 2)
105 		;
106 
107 	if (size != eb->eb_bufsize) {
108 		if ((eb->eb_buf = realloc(eb->eb_buf, size)) == NULL) {
109 			if (eb->eb_errors_are_fatal)
110 				panic("realloc failed in ebuf_add");
111 			return -1;
112 		}
113 		eb->eb_bufsize = size;
114 	}
115 
116 	memcpy(eb->eb_buf + eb->eb_pos, buf, count);
117 	eb->eb_pos += count;
118 
119 	return 0;
120 }
121 
122 int
ebuf_addstr(eb,str)123 ebuf_addstr(eb, str)
124 ebuf_t *eb;
125 const char *str;
126 {
127 	return ebuf_add(eb, str, strlen(str));
128 }
129