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