1 /*
2 *
3 * CLEX File Manager
4 *
5 * Copyright (C) 2001-2018 Vlado Potisk <vlado_potisk@clex.sk>
6 *
7 * CLEX is free software without warranty of any kind; see the
8 * GNU General Public License as set out in the "COPYING" document
9 * which accompanies the CLEX File Manager package.
10 *
11 * CLEX can be downloaded from http://www.clex.sk
12 *
13 */
14
15 #include "clexheaders.h"
16
17 #include <stdarg.h> /* va_list */
18 #include <stdlib.h> /* free() */
19 #include <string.h> /* strlen() */
20
21 #include "util.h" /* emalloc() */
22
23 /*
24 * The USTRING structure (defined in ustring.h) can store a string
25 * of unlimited length. The memory is allocated dynamically.
26 *
27 * - to initialize (to NULL ptr value) before first use:
28 * - static and global variables are initialized by default,
29 * but if you prefer explicit initialization:
30 * static USTRING us = UNULL;
31 * which is equivalent to
32 * static USTRING us = { 0, 0 };
33 * - dynamic variables are initialized this way:
34 * US_INIT(ustring);
35 * - to re-initialize, e.g. before deallocating dynamic USTRING:
36 * us_reset();
37 * - to store a string: (us_copy accepts also a null ptr)
38 * us_copy();
39 * or
40 * us_copyn();
41 * - to retrieve a string:
42 * USTR(us)
43 * or
44 * PUSTR(pus)
45 * - to edit stored name:
46 * a) allocate enough memory with us_setsize() or us_resize()
47 * b) edit the string starting at USTR() location
48 *
49 * WARNING: US_INIT, USTR, and PUSTR are macros
50 */
51
52 /* these are tunable parameters */
53 /* ALLOC_UNIT in ustring.h */
54 #define MINIMUM_FREE (4 * ALLOC_UNIT)
55
56 /*
57 * SHOULD_CHANGE_ALLOC() is true if
58 * 1) we need more memory, or
59 * 2) we can free considerable amount of memory (MINIMUM_FREE)
60 */
61 #define SHOULD_CHANGE_ALLOC(RQ) \
62 (pustr->USalloc < RQ || pustr->USalloc >= RQ + MINIMUM_FREE)
63
64 /* memory is allocated in chunks to prevent excessive resizing */
65 #define ROUND_ALLOC(RQ) \
66 ((1 + (RQ - 1) / ALLOC_UNIT) * ALLOC_UNIT)
67 /* note that ROUND_ALLOC(0) is ALLOC_UNIT and not 0 */
68
69 /* clear the data and free the memory */
70 void
us_reset(USTRING * pustr)71 us_reset(USTRING *pustr)
72 {
73 if (pustr->USalloc) {
74 free(pustr->USstr);
75 pustr->USalloc = 0;
76 }
77 pustr->USstr = 0;
78 }
79
80 /* wchar version */
81 void
usw_reset(USTRINGW * pustr)82 usw_reset(USTRINGW *pustr)
83 {
84 if (pustr->USalloc) {
85 free(pustr->USstr);
86 pustr->USalloc = 0;
87 }
88 pustr->USstr = 0;
89 }
90
91 /* us_setsize() makes room for at least 'req' characters */
92 size_t
us_setsize(USTRING * pustr,size_t req)93 us_setsize(USTRING *pustr, size_t req)
94 {
95 if (SHOULD_CHANGE_ALLOC(req)) {
96 if (pustr->USalloc)
97 free(pustr->USstr);
98 pustr->USalloc = ROUND_ALLOC(req);
99 pustr->USstr = emalloc(pustr->USalloc);
100 }
101
102 return pustr->USalloc; /* real buffer size is returned */
103 }
104
105 /* wchar version; note that 'req' is in characters, not bytes */
106 size_t
usw_setsize(USTRINGW * pustr,size_t req)107 usw_setsize(USTRINGW *pustr, size_t req)
108 {
109 if (SHOULD_CHANGE_ALLOC(req)) {
110 if (pustr->USalloc)
111 free(pustr->USstr);
112 pustr->USalloc = ROUND_ALLOC(req);
113 pustr->USstr = emalloc(sizeof(wchar_t) * pustr->USalloc);
114 }
115
116 return pustr->USalloc;
117 }
118
119 /* like us_setsize(), but preserving contents */
120 size_t
us_resize(USTRING * pustr,size_t req)121 us_resize(USTRING *pustr, size_t req)
122 {
123 if (SHOULD_CHANGE_ALLOC(req)) {
124 pustr->USalloc = ROUND_ALLOC(req);
125 pustr->USstr = erealloc(pustr->USstr,pustr->USalloc);
126 }
127
128 return pustr->USalloc;
129 }
130
131
132 /* wchar version */
133 size_t
usw_resize(USTRINGW * pustr,size_t req)134 usw_resize(USTRINGW *pustr, size_t req)
135 {
136 if (SHOULD_CHANGE_ALLOC(req)) {
137 pustr->USalloc = ROUND_ALLOC(req);
138 pustr->USstr = erealloc(pustr->USstr,sizeof(wchar_t) * pustr->USalloc);
139 }
140
141 return pustr->USalloc;
142 }
143
144 /* quick alternative to copy */
145 void
us_xchg(USTRING * s1,USTRING * s2)146 us_xchg(USTRING *s1, USTRING *s2)
147 {
148 char *xstr;
149 size_t xalloc;
150
151 xstr = s1->USstr;
152 s1->USstr = s2->USstr;
153 s2->USstr = xstr;
154
155 xalloc = s1->USalloc;
156 s1->USalloc = s2->USalloc;
157 s2->USalloc = xalloc;
158 }
159
160 /* wchar version */
161 void
usw_xchg(USTRINGW * s1,USTRINGW * s2)162 usw_xchg(USTRINGW *s1, USTRINGW *s2)
163 {
164 wchar_t *xstr;
165 size_t xalloc;
166
167 xstr = s1->USstr;
168 s1->USstr = s2->USstr;
169 s2->USstr = xstr;
170
171 xalloc = s1->USalloc;
172 s1->USalloc = s2->USalloc;
173 s2->USalloc = xalloc;
174 }
175
176 char *
us_copy(USTRING * pustr,const char * src)177 us_copy(USTRING *pustr, const char *src)
178 {
179 if (src == 0) {
180 us_reset(pustr);
181 return 0;
182 }
183 us_setsize(pustr,strlen(src) + 1);
184 strcpy(pustr->USstr,src);
185 return pustr->USstr;
186 }
187
188 /* wchar version */
189 wchar_t *
usw_copy(USTRINGW * pustr,const wchar_t * src)190 usw_copy(USTRINGW *pustr, const wchar_t *src)
191 {
192 if (src == 0) {
193 usw_reset(pustr);
194 return 0;
195 }
196 usw_setsize(pustr,wcslen(src) + 1);
197 wcscpy(pustr->USstr,src);
198 return pustr->USstr;
199 }
200
201 /* note: us_copyn() adds terminating null byte */
202 char *
us_copyn(USTRING * pustr,const char * src,size_t len)203 us_copyn(USTRING *pustr, const char *src, size_t len)
204 {
205 char *dst;
206
207 us_setsize(pustr,len + 1);
208 dst = pustr->USstr;
209 dst[len] = '\0';
210 while (len-- > 0)
211 dst[len] = src[len];
212 return dst;
213 }
214
215 /* wchar version */
216 wchar_t *
usw_copyn(USTRINGW * pustr,const wchar_t * src,size_t len)217 usw_copyn(USTRINGW *pustr, const wchar_t *src, size_t len)
218 {
219 wchar_t *dst;
220
221 usw_setsize(pustr,len + 1);
222 dst = pustr->USstr;
223 dst[len] = L'\0';
224 while (len-- > 0)
225 dst[len] = src[len];
226 return dst;
227 }
228
229 /* concatenation: us_cat(&ustring, str1, str2, ..., strN, (char *)0); */
230 void
us_cat(USTRING * pustr,...)231 us_cat(USTRING *pustr, ...)
232 {
233 size_t len;
234 char *str;
235 va_list argptr;
236
237 va_start(argptr,pustr);
238 for (len = 1; (str = va_arg(argptr, char *)); )
239 len += strlen(str);
240 va_end(argptr);
241 us_setsize(pustr,len);
242
243 va_start(argptr,pustr);
244 for (len = 0; (str = va_arg(argptr, char *)); ) {
245 strcpy(pustr->USstr + len,str);
246 len += strlen(str);
247 }
248 va_end(argptr);
249 }
250
251 /* wchar version */
252 void
usw_cat(USTRINGW * pustr,...)253 usw_cat(USTRINGW *pustr, ...)
254 {
255 size_t len;
256 wchar_t *str;
257 va_list argptr;
258
259 va_start(argptr,pustr);
260 for (len = 1; (str = va_arg(argptr, wchar_t *)); )
261 len += wcslen(str);
262 va_end(argptr);
263 usw_setsize(pustr,len);
264
265 va_start(argptr,pustr);
266 for (len = 0; (str = va_arg(argptr, wchar_t *)); ) {
267 wcscpy(pustr->USstr + len,str);
268 len += wcslen(str);
269 }
270 va_end(argptr);
271 }
272