1 /* ------------------------------------------------------------ */
2 /*
3 HTTrack Website Copier, Offline Browser for Windows and Unix
4 Copyright (C) 1998-2017 Xavier Roche and other contributors
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19 Important notes:
20
21 - We hereby ask people using this source NOT to use it in purpose of grabbing
22 emails addresses, or collecting any other private information on persons.
23 This would disgrace our work, and spoil the many hours we spent on it.
24
25 Please visit our Website: http://www.httrack.com
26 */
27
28 /* ------------------------------------------------------------ */
29 /* File: Strings */
30 /* Author: Xavier Roche */
31 /* ------------------------------------------------------------ */
32
33 /* Safer Strings ; standalone .h library */
34
35 #ifndef HTS_STRINGS_DEFSTATIC
36 #define HTS_STRINGS_DEFSTATIC
37
38 /* System definitions. */
39 #include <string.h>
40
41 /* GCC extension */
42 #ifndef HTS_UNUSED
43 #ifdef __GNUC__
44 #define HTS_UNUSED __attribute__ ((unused))
45 #define HTS_STATIC static __attribute__ ((unused))
46 #define HTS_PRINTF_FUN(fmt, arg) __attribute__ ((format (printf, fmt, arg)))
47 #else
48 #define HTS_UNUSED
49 #define HTS_STATIC static
50 #define HTS_PRINTF_FUN(fmt, arg)
51 #endif
52 #endif
53
54 /** Forward definitions **/
55 #ifndef HTS_DEF_FWSTRUCT_String
56 #define HTS_DEF_FWSTRUCT_String
57 typedef struct String String;
58 #endif
59 #ifndef HTS_DEF_STRUCT_String
60 #define HTS_DEF_STRUCT_String
61 struct String {
62 char *buffer_;
63 size_t length_;
64 size_t capacity_;
65 };
66 #endif
67
68 /** Allocator **/
69 #ifndef STRING_REALLOC
70 #define STRING_REALLOC(BUFF, SIZE) ( (char*) realloc(BUFF, SIZE) )
71 #define STRING_FREE(BUFF) free(BUFF)
72 #endif
73 #ifndef STRING_ASSERT
74 #include <assert.h>
75 #define STRING_ASSERT(EXP) assert(EXP)
76 #endif
77
78 /** An empty string **/
79 #define STRING_EMPTY { (char*) NULL, 0, 0 }
80
81 /** String buffer **/
82 #define StringBuff(BLK) ( (const char*) ((BLK).buffer_) )
83
84 /** String buffer (read/write) **/
85 #define StringBuffRW(BLK) ((BLK).buffer_)
86
87 /** String length **/
88 #define StringLength(BLK) ((BLK).length_)
89
90 /** String not empty ? **/
91 #define StringNotEmpty(BLK) ( StringLength(BLK) > 0 )
92
93 /** String capacity **/
94 #define StringCapacity(BLK) ((BLK).capacity_)
95
96 /** Subcharacter **/
97 #define StringSub(BLK, POS) ( StringBuff(BLK)[POS] )
98
99 /** Subcharacter (read/write) **/
100 #define StringSubRW(BLK, POS) ( StringBuffRW(BLK)[POS] )
101
102 /** Subcharacter (read/write) **/
103 #define StringSubRW(BLK, POS) ( StringBuffRW(BLK)[POS] )
104
105 /** Right subcharacter **/
106 #define StringRight(BLK, POS) ( StringBuff(BLK)[StringLength(BLK) - POS] )
107
108 /** Right subcharacter (read/write) **/
109 #define StringRightRW(BLK, POS) ( StringBuffRW(BLK)[StringLength(BLK) - POS] )
110
111 /** Remove the utter right character from the string. **/
112 #define StringPopRight(BLK) do { \
113 StringBuffRW(BLK)[--StringLength(BLK)] = '\0'; \
114 } while(0)
115
116 /** Ensure the string is large enough for exactly CAPACITY bytes overall (including \0). **/
117 #define StringRoomTotal(BLK, CAPACITY) do { \
118 const size_t capacity_ = (size_t) (CAPACITY); \
119 while ((BLK).capacity_ < capacity_) { \
120 if ((BLK).capacity_ < 16) { \
121 (BLK).capacity_ = 16; \
122 } else { \
123 (BLK).capacity_ *= 2; \
124 } \
125 (BLK).buffer_ = STRING_REALLOC((BLK).buffer_, (BLK).capacity_); \
126 STRING_ASSERT((BLK).buffer_ != NULL); \
127 } \
128 } while(0)
129
130 /** Ensure the string is large enough for exactly SIZE more characters (not including \0). **/
131 #define StringRoom(BLK, SIZE) StringRoomTotal(BLK, StringLength(BLK) + (SIZE) + 1)
132
133 /** Return the RW buffer for a strcat() operation of at most SIZE characters. **/
134 #define StringBuffN(BLK, SIZE) StringBuffN_(&(BLK), SIZE)
StringBuffN_(String * blk,int size)135 HTS_STATIC char *StringBuffN_(String * blk, int size) {
136 StringRoom(*blk, size);
137 return StringBuffRW(*blk);
138 }
139
140 /** Initialize a string. **/
141 #define StringInit(BLK) do { \
142 (BLK).buffer_ = NULL; \
143 (BLK).capacity_ = 0; \
144 (BLK).length_ = 0; \
145 } while(0)
146
147 /** Clear a string (set its length to 0) **/
148 #define StringClear(BLK) do { \
149 (BLK).length_ = 0; \
150 StringRoom(BLK, 0); \
151 (BLK).buffer_[0] = '\0'; \
152 } while(0)
153
154 /** Set the length of a string to 'SIZE'. If SIZE is negative, check the size using strlen(). **/
155 #define StringSetLength(BLK, SIZE) do { \
156 if (SIZE >= 0) { \
157 (BLK).length_ = SIZE; \
158 } else { \
159 (BLK).length_ = strlen((BLK).buffer_); \
160 } \
161 } while(0)
162
163 /** Free a string (release memory) **/
164 #define StringFree(BLK) do { \
165 if ((BLK).buffer_ != NULL) { \
166 STRING_FREE((BLK).buffer_); \
167 (BLK).buffer_ = NULL; \
168 } \
169 (BLK).capacity_ = 0; \
170 (BLK).length_ = 0; \
171 } while(0)
172
173 /** Assign an allocated pointer to a a string.
174 The pointer _MUST_ be compatible with STRING_REALLOC() and STRING_FREE() **/
175 #define StringSetBuffer(BLK, STR) do { \
176 size_t len__ = strlen( STR ); \
177 StringFree(BLK); \
178 (BLK).buffer_ = ( STR ); \
179 (BLK).capacity_ = len__; \
180 (BLK).length_ = len__; \
181 } while(0)
182
183 /** Append a memory block to a string **/
184 #define StringMemcat(BLK, STR, SIZE) do { \
185 const char* str_mc_ = (STR); \
186 const size_t size_mc_ = (size_t) (SIZE); \
187 StringRoom(BLK, size_mc_); \
188 if (size_mc_ > 0) { \
189 memcpy((BLK).buffer_ + (BLK).length_, str_mc_, size_mc_); \
190 (BLK).length_ += size_mc_; \
191 } \
192 *((BLK).buffer_ + (BLK).length_) = '\0'; \
193 } while(0)
194
195 /** Copy a memory block to a string **/
196 #define StringMemcpy(BLK, STR, SIZE) do { \
197 (BLK).length_ = 0; \
198 StringMemcat(BLK, STR, SIZE); \
199 } while(0)
200
201 /** Add a character **/
202 #define StringAddchar(BLK, c) do { \
203 String * const s__ = &(BLK); \
204 char c__ = (c); \
205 StringRoom(*s__, 1); \
206 StringBuffRW(*s__)[StringLength(*s__)++] = c__; \
207 StringBuffRW(*s__)[StringLength(*s__) ] = 0; \
208 } while(0)
209
210 /** Acquire a string ; it's the client's responsability to free() it **/
StringAcquire(String * blk)211 HTS_STATIC char *StringAcquire(String * blk) {
212 char *buff = StringBuffRW(*blk);
213
214 StringBuffRW(*blk) = NULL;
215 StringCapacity(*blk) = 0;
216 StringLength(*blk) = 0;
217 return buff;
218 }
219
220 /** Clone a string. **/
StringDup(const String * src)221 HTS_STATIC String StringDup(const String * src) {
222 String s = STRING_EMPTY;
223
224 StringMemcat(s, StringBuff(*src), StringLength(*src));
225 return s;
226 }
227
228 /** Attach a string using a pointer. **/
StringAttach(String * blk,char ** str)229 HTS_STATIC void StringAttach(String * blk, char **str) {
230 StringFree(*blk);
231 if (str != NULL && *str != NULL) {
232 StringBuffRW(*blk) = *str;
233 StringCapacity(*blk) = StringLength(*blk) = strlen(StringBuff(*blk));
234 *str = NULL;
235 }
236 }
237
238 /** Append a string to another one. **/
239 #define StringCat(BLK, STR) do { \
240 const char *const str__ = ( STR ); \
241 if (str__ != NULL) { \
242 const size_t size__ = strlen(str__); \
243 StringMemcat(BLK, str__, size__); \
244 } \
245 } while(0)
246
247 #define StringCatN(BLK, STR, SIZE) do { \
248 const char *str__ = ( STR ); \
249 if (str__ != NULL) { \
250 size_t size__ = strlen(str__); \
251 if (size__ > (SIZE)) { \
252 size__ = (SIZE); \
253 } \
254 StringMemcat(BLK, str__, size__); \
255 } \
256 } while(0)
257
258 #define StringCopyN(BLK, STR, SIZE) do { \
259 const char *str__ = ( STR ); \
260 const size_t usize__ = (SIZE); \
261 (BLK).length_ = 0; \
262 if (str__ != NULL) { \
263 size_t size__ = strlen(str__); \
264 if (size__ > usize__ ) { \
265 size__ = usize__; \
266 } \
267 StringMemcat(BLK, str__, size__); \
268 } else { \
269 StringClear(BLK); \
270 } \
271 } while(0)
272
273 #define StringCopyS(blk, blk2) StringCopyN(blk, (blk2).buffer_, (blk2).length_)
274
275 /** Copy a string to another one. **/
276 #define StringCopy(BLK, STR) do { \
277 const char *str__ = ( STR ); \
278 if (str__ != NULL) { \
279 size_t size__ = strlen(str__); \
280 StringMemcpy(BLK, str__, size__); \
281 } else { \
282 StringClear(BLK); \
283 } \
284 } while(0)
285
286 /** Copy a (potentially overlapping) string to another one. **/
287 #define StringCopyOverlapped(BLK, STR) do { \
288 String s__ = STRING_EMPTY; \
289 StringCopy(s__, STR); \
290 StringCopyS(BLK, s__); \
291 StringFree(s__); \
292 } while(0)
293
294 #endif
295