1 /*  -*- Mode: C -*-  */
2 
3 /* filament.h --- a bit like a string but different =)O|
4  * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
5  * Originally by Gary V. Vaughan, 1998
6  * This file is part of Snprintfv
7  *
8  * Snprintfv is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) any later version.
12  *
13  * Snprintfv program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses>.
20  *
21  * As a special exception to the GNU General Public License, if you
22  * distribute this file as part of a program that also links with and
23  * uses the libopts library from AutoGen, you may include it under
24  * the same distribution terms used by the libopts library.
25  */
26 
27 /* Code: */
28 
29 #ifndef FILAMENT_H
30 #define FILAMENT_H 1
31 
32 #include <snprintfv/compat.h>
33 
34 #ifdef __cplusplus
35 extern "C"
36 {
37 #if 0
38 /* This brace is so that emacs can still indent properly: */ }
39 #endif
40 #endif				/* __cplusplus */
41 
42 #define FILAMENT_BUFSIZ       (512 - sizeof(char *) - (2 * sizeof(size_t)))
43 
44 /**
45  * Filament:
46  * Opaque data type used to hold 8-bit clean dynamic strings which know
47  * their own length and resize themselves to avoid buffer overruns.
48  **/
49 typedef struct filament Filament;
50 
51 struct filament
52 {
53   char *value;                  /* pointer to the start of the string */
54   size_t length;                /* length of the string */
55   size_t size;                  /* total memory allocated */
56   char buffer[FILAMENT_BUFSIZ]; /* usually string == &buffer[0] */
57 };
58 
59 /**
60  * filnew: constructor
61  * @init: address of the first byte to copy into the new object.
62  * @len:  the number of bytes to copy into the new object.
63  *
64  * Create a new Filament object, initialised to hold a copy of the
65  * first @len bytes starting at address @init.  If @init is NULL, or
66  * @len is 0 (or less), then the initialised Filament will return the
67  * empty string, "", if its value is queried.
68  *
69  * Return value:
70  * A newly created Filament object is returned.
71  **/
72 extern Filament *
73 filnew (const char *const init, size_t len);
74 
75 /**
76  * filinit:
77  * @fil: The Filament object to initialise.
78  * @init: address of the first byte to copy into the new object.
79  * @len:  the number of bytes to copy into the new object.
80  *
81  * Initialise a Filament object to hold a copy of the first @len bytes
82  * starting at address @init.  If @init is NULL, or @len is 0 (or less),
83  * then the Filament will be reset to hold the empty string, "".
84  *
85  * Return value:
86  * The initialised Filament object is returned.
87  **/
88 extern Filament *
89 filinit (Filament *fil, const char *const init, size_t len);
90 
91 /**
92  * fildelete: destructor
93  * @fil: The Filament object for recycling.
94  *
95  * The memory being used by @fil is recycled.
96  *
97  * Return value:
98  * The original contents of @fil are converted to a null terminated
99  * string which is returned, either to be freed itself or else used
100  * as a normal C string.  The entire Filament contents are copied into
101  * this string including any embedded nulls.
102  **/
103 extern char *
104 fildelete (Filament *fil);
105 
106 /**
107  * _fil_extend:
108  * @fil: The Filament object which may need more string space.
109  * @len: The length of the data to be stored in @fil.
110  * @copy: whether to copy data from the static buffer on reallocation.
111  *
112  * This function will will assign a bigger block of memory to @fil
113  * considering the space left in @fil and @len, the length required
114  * for the prospective contents.
115  */
116 extern void
117 _fil_extend (Filament *fil, size_t len, bool copy);
118 
119 #line 60 "filament.in"
120 
121 /* Save the overhead of a function call in the great majority of cases. */
122 #define fil_maybe_extend(fil, len, copy)  \
123   (((len)>=(fil)->size) ? _fil_extend((fil), (len), (copy)) : (void)0)
124 
125 /**
126  * filval:
127  * @fil: The Filament object being queried.
128  *
129  * Return value:
130  * A pointer to the null terminated string held by the Filament
131  * object is returned.  Since the @fil may contain embedded nulls, it
132  * is not entirely safe to use the strfoo() API to examine the contents
133  * of the return value.
134  **/
135 SNV_INLINE char *
filval(Filament * fil)136 filval (Filament *fil)
137 {
138   /* Because we have been careful to ensure there is always at least
139      one spare byte of allocated memory, it is safe to set it here. */
140   fil->value[fil->length] = '\0';
141   return (char *) (fil->value);
142 }
143 
144 /**
145  * fillen:
146  * @fil: The Filament object being queried.
147  *
148  * Return value:
149  * The length of @fil, including any embedded nulls, but excluding the
150  * terminating null, is returned.
151  **/
152 SNV_INLINE size_t
fillen(Filament * fil)153 fillen (Filament *fil)
154 {
155   return fil->length;
156 }
157 
158 /**
159  * filelt:
160  * @fil: The Filament being queried.
161  * @n: A zero based index into @fil.
162  *
163  * This function looks for the @n'th element of @fil.
164  *
165  * Return value:
166  * If @n is an index inside the Filament @fil, then the character stored
167  * at that index cast to an int is returned, otherwise @n is outside
168  * this range and -1 is returned.
169  **/
170 SNV_INLINE int
filelt(Filament * fil,ssize_t n)171 filelt (Filament *fil, ssize_t n)
172 {
173   if ((n >= 0) && (n < (ssize_t)fil->length))
174     return (int) fil->value[n];
175   else
176     return -1;
177 }
178 
179 /**
180  * filncat:
181  * @fil: The destination Filament of the concatenation.
182  * @str: The address of the source bytes for concatenation.
183  * @n: The number of bytes to be copied from @str.
184  *
185  * @n bytes starting with the byte at address @str are destructively
186  * concatenated to @fil.  If necessary, @fil is dynamically reallocated
187  * to make room for this operation.
188  *
189  * Return value:
190  * A pointer to the (not null terminated) string which is the result
191  * of this concatenation is returned.
192  **/
193 SNV_INLINE char *
filncat(Filament * fil,const char * str,size_t n)194 filncat (Filament *fil, const char *str, size_t n)
195 {
196   fil_maybe_extend (fil, n + fil->length, true);
197   memcpy (fil->value + fil->length, str, n);
198   fil->length += n;
199   return fil->value;
200 }
201 
202 /**
203  * filcat:
204  * @fil: The destination Filament of the concatenation.
205  * @str: The address of the source bytes for concatenation.
206  *
207  * The bytes starting at address @str upto and including the first null
208  * byte encountered are destructively concatenated to @fil.  If
209  * necessary @fil is dynamically reallocated to make room for this
210  * operation.
211  *
212  * Return value:
213  * A pointer to the (not null terminated) string which is the result
214  * of this concatenation is returned.
215  **/
216 SNV_INLINE char *
filcat(Filament * fil,const char * str)217 filcat (Filament *fil, const char *str)
218 {
219   size_t length = strlen (str);
220   return filncat (fil, str, length);
221 }
222 
223 /**
224  * filccat:
225  * @fil: The destination Filament of the concatenation.
226  * @c: The character to append to @fil.
227  *
228  * @c is destructively concatenated to @fil.  If necessary, @fil is
229  * dynamically reallocated to make room for this operation.  When used
230  * repeatedly this function is less efficient than %filncat,
231  * since it must check whether to extend the filament before each
232  * character is appended.
233  *
234  * Return value:
235  * A pointer to the (not null terminated) string which is the result
236  * of this concatenation is returned.
237  **/
238 SNV_INLINE char *
filccat(Filament * fil,int c)239 filccat (Filament *fil, int c)
240 {
241   fil_maybe_extend (fil, 1 + fil->length, true);
242   fil->value[fil->length++] = (char)(c & 0xFF);
243   return fil->value;
244 }
245 
246 #ifdef __cplusplus
247 #if 0
248 /* This brace is so that emacs can still indent properly: */
249 {
250 #endif
251 }
252 #endif /* __cplusplus */
253 
254 #endif /* FILAMENT_H */
255 
256 /* filament.h ends here */
257