blob: b4c8a701a74420086df74afe16c1e6b85be1b4a8 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2*(C) Copyright 2008 Marvell International Ltd.
3* All Rights Reserved
4******************************************************************************/
5/*****************************************************************************
6* Utility Library
7*
8* DESCRIPTION
9* Functions to manage variable-length character strings.
10*
11* EXAMPLE USAGE
12*
13* {
14* utlVString_T v_string;
15*
16* utlInitVString(&v_string);
17*
18* if (utlVStringCat(&v_string, "one ") != utlSUCCESS)
19* <handle error here>
20*
21* if (utlVStringCat(&v_string, "two ") != utlSUCCESS)
22* <handle error here>
23*
24* if (utlVStringCat(&v_string, "three ") != utlSUCCESS)
25* <handle error here>
26*
27* (void) printf("string: %s\n", utlVString(&v_string))
28*
29* <use `v_string' here>
30*
31* if (utlVStringFree(&v_string) != utlSUCCESS)
32* <handle error here>
33*
34* {
35* utlVString_T print_v_string;
36*
37* utlInitVString(&print_v_string);
38*
39* (void) utlVStringPrintF(&print_v_string, "my %s string", "format");
40*
41* <use `print_v_string' here>
42*
43* if (utlVStringFree(&v_string) != utlSUCCESS)
44* <handle error here>
45* }
46* }
47*
48*****************************************************************************/
49
50#include <stdio.h>
51#include <stdarg.h>
52#include <string.h>
53#include <time.h>
54
55#include "utlTypes.h"
56
57#include "utlError.h"
58#include "utlMalloc.h"
59#include "utlTime.h"
60#include "utlVString.h"
61
62
63/*---------------------------------------------------------------------------*
64* FUNCTION
65* utlVStringReserve(v_string_p, n)
66* INPUT
67* v_string_p == pointer to an initialized utlVString_T structure
68* n == the number of characters to reserve space for
69* OUTPUT
70* *v_string_p == the updated utlVString_T structure
71* RETURNS
72* utlSUCCESS for success, utlFAILED for failure.
73* DESCRIPTION
74* Reserves space for `n' additional characters in the variable-length
75* string specified by `v_string_p'.
76*---------------------------------------------------------------------------*/
77utlReturnCode_T utlVStringReserve(const utlVString_P v_string_p,
78 const size_t n)
79{
80 utlAssert(v_string_p != NULL);
81
82 /*--- make room ---*/
83 if (v_string_p->size == (size_t)0)
84 {
85 size_t size;
86
87 size = n + 1;
88
89 /*--- for improved performance, add some bonus space ---*/
90 size += 32;
91
92 if ((v_string_p->s_p = utlMalloc(size * sizeof(char))) == NULL)
93 return utlFAILED;
94
95 v_string_p->size = size;
96
97 v_string_p->s_p[0] = '\0';
98
99 }
100 else if ((n + v_string_p->length + 1) > v_string_p->size)
101 {
102 size_t new_size;
103 char *new_s_p;
104
105 new_size = n + v_string_p->length + 1;
106
107 /*--- for improved performance, add some bonus space ---*/
108 if (v_string_p->size < 128) new_size += 32;
109 else if (v_string_p->size < 1024) new_size += 128;
110 else if (v_string_p->size < 4096) new_size += 1024;
111 else if (v_string_p->size < 8192) new_size += 4096;
112 else new_size += 8192;
113
114 if ((new_s_p = (char *)utlRealloc(v_string_p->s_p, new_size * sizeof(char))) == NULL)
115 return utlFAILED;
116
117 v_string_p->s_p = new_s_p;
118 v_string_p->size = new_size;
119 }
120
121 return utlSUCCESS;
122}
123
124/*---------------------------------------------------------------------------*
125* FUNCTION
126* utlVStringCat(v_string_p, s_p)
127* INPUT
128* v_string_p == pointer to an initialized utlVString_T structure
129* s_p == pointer to the string to concatenate
130* OUTPUT
131* *v_string_p == the updated utlVString_T structure
132* RETURNS
133* utlSUCCESS for success, utlFAILED for failure.
134* DESCRIPTION
135* Concatenates the string `s_p' onto the end of the string stored in
136* the variable-length string specified by `v_string_p'.
137*---------------------------------------------------------------------------*/
138utlReturnCode_T utlVStringCat(const utlVString_P v_string_p,
139 const char *s_p)
140{
141 size_t len;
142
143 utlAssert(v_string_p != NULL);
144
145 /*--- nothing to concatenate? ---*/
146 if (s_p == NULL)
147 {
148 if (utlVStringReserve(v_string_p, 0) != utlSUCCESS)
149 return utlFAILED;
150
151 return utlSUCCESS;
152 }
153
154 len = strlen(s_p);
155
156 if (utlVStringReserve(v_string_p, len) != utlSUCCESS)
157 return utlFAILED;
158
159 /*--- concatenate! ---*/
160 {
161 const char *src_p;
162 char *dest_p;
163
164 for (src_p = s_p, dest_p = v_string_p->s_p + v_string_p->length; *src_p != '\0'; src_p++)
165 {
166 *dest_p++ = *src_p;
167 }
168 *dest_p = '\0';
169 }
170
171 v_string_p->length += len;
172
173 return utlSUCCESS;
174}
175
176/*---------------------------------------------------------------------------*
177* FUNCTION
178* utlVStringFree(v_string_p)
179* INPUT
180* v_string_p == pointer to an initialized utlVString_T structure
181* OUTPUT
182* *v_string_p == the updated utlVString_T structure
183* RETURNS
184* utlSUCCESS for success, utlFAILED for failure.
185* DESCRIPTION
186* Frees the resource consumed by the variable-length string specified
187* by `v_string_p'.
188*---------------------------------------------------------------------------*/
189utlReturnCode_T utlVStringFree(const utlVString_P v_string_p)
190{
191 utlAssert(v_string_p != NULL);
192
193 if (v_string_p->s_p != NULL)
194 {
195 utlFree(v_string_p->s_p);
196 v_string_p->length = 0;
197 v_string_p->size = 0;
198 }
199
200 return utlSUCCESS;
201}
202
203/*---------------------------------------------------------------------------*
204* FUNCTION
205* utlVStringVPrintF(v_string_p, format_p, va_arg_p)
206* INPUT
207* v_string_p == pointer to an initialized utlVString_T structure
208* format_p == a null terminated format string
209* va_arg_p == argument pointer
210* OUTPUT
211* *v_string_p == the updated utlVString_T structure
212* RETURNS
213* the number of characters placed into `v_string_p' for success,
214* utlFAILED for failure.
215* DESCRIPTION
216* Similar to vsprintf(), but prints into a variable-length string.
217*---------------------------------------------------------------------------*/
218int utlVStringVPrintF(const utlVString_P v_string_p,
219 const char *format_p,
220 va_list va_arg_p)
221{
222 int c_count;
223 size_t len;
224
225 /*--- check parameters ---*/
226 utlAssert(v_string_p != NULL);
227 utlAssert(format_p != NULL);
228
229 /*--- compute length of format string (for use in estimating) ---*/
230 len = strlen(format_p);
231
232 c_count = 0;
233
234 /*--- keep trying to sprintf() until the string buffer is big enough ---*/
235 do {
236 /* is string buffer too small? */
237 if ((v_string_p->length + len + 250 + c_count) > v_string_p->size)
238 {
239 size_t new_size;
240 char *new_v_string_p;
241
242 /*--- compute new string-buffer size ---*/
243 new_size = (2 * v_string_p->size) + len + 256;
244
245 /*--- make string-buffer a little bigger ---*/
246 if ((new_v_string_p = utlRealloc(v_string_p->s_p, new_size * sizeof(char))) == NULL)
247 return utlFAILED;
248
249 v_string_p->size = new_size;
250 v_string_p->s_p = new_v_string_p;
251 }
252
253 /* attempt to append new string */
254 c_count = vsnprintf(v_string_p->s_p + v_string_p->length,
255 v_string_p->size - v_string_p->length,
256 format_p,
257 va_arg_p);
258 } while (((size_t)c_count >= (v_string_p->size - len - 1)) || (c_count < 0));
259
260 v_string_p->length += strlen(v_string_p->s_p + v_string_p->length);
261
262 return c_count;
263}
264
265/*---------------------------------------------------------------------------*
266* FUNCTION
267* utlVStringPrintF(v_string_p, format_p, ...)
268* INPUT
269* v_string_p == pointer to an initialized utlVString_T structure
270* format_p == a null terminated format string
271* ... == zero or more additional arguments
272* OUTPUT
273* *v_string_p == the updated utlVString_T structure
274* RETURNS
275* the number of characters placed into `v_string_p' for success,
276* utlFAILED for failure.
277* DESCRIPTION
278* Similar to sprintf(), but prints into a variable-length string.
279*---------------------------------------------------------------------------*/
280int utlVStringPrintF(const utlVString_P v_string_p,
281 const char *format_p,
282 ...)
283{
284 va_list va_arg_p;
285 int rv;
286
287 utlAssert(v_string_p != NULL);
288 utlAssert(format_p != NULL);
289
290 va_start(va_arg_p, format_p);
291 rv = utlVStringVPrintF(v_string_p, format_p, va_arg_p);
292 va_end(va_arg_p);
293
294 return rv;
295}
296
297/*---------------------------------------------------------------------------*
298* FUNCTION
299* utlVStringPuts(v_string_p, file_p)
300* INPUT
301* v_string_p == pointer to an initialized utlVString_T structure
302* file_p == the stream to direct the output to
303* OUTPUT
304* none
305* RETURNS
306* utlSUCCESS for success, utlFAILED for failure.
307* DESCRIPTION
308* Prints the character string specified by `v_string_p' to the specified
309* file descriptor.
310*---------------------------------------------------------------------------*/
311utlReturnCode_T utlVStringPuts(const utlVString_P2c v_string_p,
312 FILE *file_p)
313{
314 char *c_p;
315
316 utlAssert(v_string_p != NULL);
317
318 if ((c_p = utlVString(v_string_p)) == NULL)
319 return utlSUCCESS;
320
321 /*--- the following loop addresses a problem on the target hardware
322 where TX buffer over-run errors occur when we try to print very
323 long variable-length strings. This loop prints one line at a
324 time, pausing 10 msec between each iteration. */
325 while (*c_p != '\0')
326 {
327 char *end_p;
328
329 /*--- search for end of this line ---*/
330 if ((end_p = strchr(c_p, '\n')) == NULL)
331 {
332 (void)fprintf(file_p, "%s\n", c_p);
333 break;
334 }
335
336 /*--- print line ---*/
337 (void)fprintf(file_p, "%.*s\n", (int)(end_p - c_p), c_p);
338
339 /*--- pause 10 milliseconds ---*/
340 {
341 utlRelativeTime_T delay;
342
343 delay.seconds = 0;
344 delay.nanoseconds = 10000;
345 (void)utlPause(&delay);
346 }
347
348 /*--- note where the next line starts ---*/
349 c_p = end_p + 1;
350 }
351
352 return utlSUCCESS;
353}
354
355#ifdef utlTEST
356/*---------------------------------------------------------------------------*
357* FUNCTION
358* vStringTest()
359* INPUT
360* none
361* OUTPUT
362* none
363* RETURNS
364* "true" for pass, "false" for failure
365*---------------------------------------------------------------------------*/
366bool vStringTest(void)
367{
368 utlVString_T v_string = utlEMPTY_VSTRING;
369 int i;
370
371 /*--- test utlVStringCat() -----------------------------------------------*/
372 utlInitVString(&v_string);
373
374 if (utlVStringCat(&v_string, "abc") != utlSUCCESS)
375 {
376 (void)fprintf(stderr, "vStringTest: utlVStringCat(1) failed\n");
377 return false;
378 }
379
380 if (utlVStringCat(&v_string, "def") != utlSUCCESS)
381 {
382 (void)fprintf(stderr, "vStringTest: utlVStringCat(2) failed\n");
383 return false;
384 }
385
386 if (utlVStringCat(&v_string, "ghi") != utlSUCCESS)
387 {
388 (void)fprintf(stderr, "vStringTest: utlVStringCat(3) failed\n");
389 return false;
390 }
391
392 if (strcmp("abcdefghi", utlVString(&v_string)) != 0)
393 {
394 (void)fprintf(stderr, "vStringTest: utlVStringCat(4) failed\n");
395 return false;
396 }
397
398 if (utlVStringFree(&v_string) != utlSUCCESS)
399 {
400 (void)fprintf(stderr, "vStringTest: utlVStringCat(5) failed\n");
401 return false;
402 }
403
404
405 if (utlVStringCat(&v_string, "") != utlSUCCESS)
406 {
407 (void)fprintf(stderr, "vStringTest: utlVStringCat(6) failed\n");
408 return false;
409 }
410
411 for (i = 0; i < 2000; i++)
412 {
413 if (utlVStringCat(&v_string, "x") != utlSUCCESS)
414 {
415 (void)fprintf(stderr, "vStringTest: utlVStringCat(7) failed\n");
416 return false;
417 }
418 }
419
420 if (utlVStringFree(&v_string) != utlSUCCESS)
421 {
422 (void)fprintf(stderr, "vStringTest: utlVStringCat(8) failed\n");
423 return false;
424 }
425
426
427 /*--- test utlVStringPrintF() -----------------------------------------------*/
428 utlInitVString(&v_string);
429
430 if (utlVStringPrintF(&v_string, "abc") != 3)
431 {
432 (void)fprintf(stderr, "vStringTest: utlVStringPrintF(1) failed\n");
433 return false;
434 }
435
436 if (utlVStringPrintF(&v_string, "[%d]", 1) != 3)
437 {
438 (void)fprintf(stderr, "vStringTest: utlVStringPrintF(2) failed\n");
439 return false;
440 }
441
442 if (strcmp(utlVString(&v_string), "abc[1]") != 0)
443 {
444 (void)fprintf(stderr, "vStringTest: utlVStringPrintF(3) failed\n");
445 return false;
446 }
447
448 if (utlVStringFree(&v_string) != utlSUCCESS)
449 {
450 (void)fprintf(stderr, "vStringTest: utlVStringPrintF(4) failed\n");
451 return false;
452 }
453
454 return true;
455}
456#endif /* utlTEST */
457