Skip to content

Commit 7d218f9

Browse files
GUIDINGLIxiaoxiang781216
authored andcommitted
libc: add nx_strdup() & nx_strndup() support
Signed-off-by: ligd <[email protected]>
1 parent 10659a8 commit 7d218f9

File tree

6 files changed

+199
-0
lines changed

6 files changed

+199
-0
lines changed

include/stdio.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,16 @@ int remove(FAR const char *path);
266266
#ifndef __KERNEL__
267267
int pclose(FILE *stream);
268268
FILE *popen(FAR const char *command, FAR const char *mode) popen_like;
269+
#else
270+
#define asprintf(p, f, ...) nx_asprintf(p, f, ##__VA_ARGS__)
271+
#define vasprintf(p, f, a) nx_vasprintf(p, f, a)
269272
#endif
270273

274+
int nx_asprintf(FAR char **ptr, FAR const IPTR char *fmt, ...)
275+
printf_like(2, 3);
276+
int nx_vasprintf(FAR char **ptr, FAR const IPTR char *fmt, va_list ap)
277+
printf_like(2, 0);
278+
271279
#if CONFIG_FORTIFY_SOURCE > 0
272280
fortify_function(fgets) FAR char *fgets(FAR char *s, int n, FAR FILE *stream)
273281
{

include/string.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ FAR void *memmem(FAR const void *haystack, size_t haystacklen,
110110
void explicit_bzero(FAR void *s, size_t n);
111111
int timingsafe_bcmp(FAR const void *b1, FAR const void *b2, size_t n);
112112

113+
#ifdef __KERNEL__
114+
# define strdup(s) nx_strdup(s)
115+
# define strndup(s,sz) nx_strndup(s,sz)
116+
#endif
117+
118+
FAR char *nx_strdup(FAR const char *s) malloc_like;
119+
FAR char *nx_strndup(FAR const char *s, size_t size) malloc_like;
120+
113121
#if CONFIG_FORTIFY_SOURCE > 0
114122
fortify_function(strcat) FAR char *strcat(FAR char *dest,
115123
FAR const char *src)

libs/libc/stdio/lib_asprintf.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,38 @@
3030
* Public Functions
3131
****************************************************************************/
3232

33+
/****************************************************************************
34+
* Name: nx_asprintf
35+
*
36+
* Description:
37+
* This function is similar to sprintf, except that it dynamically
38+
* allocates a string (as with kmm_malloc) to hold the output, instead of
39+
* putting the output in a buffer you allocate in advance. The ptr
40+
* argument should be the address of a char * object, and a successful
41+
* call to asprintf stores a pointer to the newly allocated string at that
42+
* location.
43+
*
44+
* Returned Value:
45+
* The returned value is the number of characters allocated for the buffer,
46+
* or less than zero if an error occurred. Usually this means that the
47+
* buffer could not be allocated.
48+
*
49+
****************************************************************************/
50+
51+
int nx_asprintf(FAR char **ptr, FAR const IPTR char *fmt, ...)
52+
{
53+
va_list ap;
54+
int ret;
55+
56+
/* Let vasprintf do all of the work */
57+
58+
va_start(ap, fmt);
59+
ret = nx_vasprintf(ptr, fmt, ap);
60+
va_end(ap);
61+
62+
return ret;
63+
}
64+
3365
/****************************************************************************
3466
* Name: asprintf
3567
*
@@ -48,6 +80,7 @@
4880
*
4981
****************************************************************************/
5082

83+
#undef asprintf
5184
int asprintf(FAR char **ptr, FAR const IPTR char *fmt, ...)
5285
{
5386
va_list ap;

libs/libc/stdio/lib_vasprintf.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,101 @@
3434
* Public Functions
3535
****************************************************************************/
3636

37+
/****************************************************************************
38+
* Name: nx_vasprintf
39+
*
40+
* Description:
41+
* This function is similar to vsprintf, except that it dynamically
42+
* allocates a string (as with kmm_malloc) to hold the output, instead of
43+
* putting the output in a buffer you allocate in advance. The ptr
44+
* argument should be the address of a char * object, and a successful
45+
* call to vasprintf stores a pointer to the newly allocated string at that
46+
* location.
47+
*
48+
* Returned Value:
49+
* The returned value is the number of characters allocated for the buffer,
50+
* or less than zero if an error occurred. Usually this means that the
51+
* buffer could not be allocated.
52+
*
53+
****************************************************************************/
54+
55+
int nx_vasprintf(FAR char **ptr, FAR const IPTR char *fmt, va_list ap)
56+
{
57+
struct lib_outstream_s nulloutstream;
58+
struct lib_memoutstream_s memoutstream;
59+
60+
/* On some architectures, va_list is really a pointer to a structure on
61+
* the stack. And the va_arg builtin will modify that instance of va_list.
62+
* Since vasprintf traverse the parameters in the va_list twice, the
63+
* va_list will be altered in this first cases and the second usage will
64+
* fail. This is a known issue with x86_64.
65+
*/
66+
67+
#ifdef va_copy
68+
va_list ap2;
69+
#endif
70+
FAR char *buf;
71+
int nbytes;
72+
73+
DEBUGASSERT(ptr != NULL && fmt != NULL);
74+
75+
#ifdef va_copy
76+
va_copy(ap2, ap);
77+
#endif
78+
79+
/* First, use a nullstream to get the size of the buffer. The number
80+
* of bytes returned may or may not include the null terminator.
81+
*/
82+
83+
lib_nulloutstream(&nulloutstream);
84+
lib_vsprintf(&nulloutstream, fmt, ap);
85+
86+
/* Then allocate a buffer to hold that number of characters, adding one
87+
* for the null terminator.
88+
*/
89+
90+
buf = kmm_malloc(nulloutstream.nput + 1);
91+
if (buf == NULL)
92+
{
93+
#ifdef va_copy
94+
va_end(ap2);
95+
#endif
96+
return ERROR;
97+
}
98+
99+
/* Initialize a memory stream to write into the allocated buffer. The
100+
* memory stream will reserve one byte at the end of the buffer for the
101+
* null terminator and will not report this in the number of output bytes.
102+
*/
103+
104+
lib_memoutstream(&memoutstream, buf, nulloutstream.nput + 1);
105+
106+
/* Then let lib_vsprintf do it's real thing */
107+
108+
#ifdef va_copy
109+
nbytes = lib_vsprintf(&memoutstream.common, fmt, ap2);
110+
va_end(ap2);
111+
#else
112+
nbytes = lib_vsprintf(&memoutstream.common, fmt, ap);
113+
#endif
114+
115+
/* Return a pointer to the string to the caller. NOTE: the memstream put()
116+
* method has already added the NUL terminator to the end of the string
117+
* (not included in the nput count).
118+
*/
119+
120+
DEBUGASSERT(nbytes < 0 || nbytes == nulloutstream.nput);
121+
122+
if (nbytes < 0)
123+
{
124+
kmm_free(buf);
125+
return ERROR;
126+
}
127+
128+
*ptr = buf;
129+
return nbytes;
130+
}
131+
37132
/****************************************************************************
38133
* Name: vasprintf
39134
*
@@ -52,6 +147,7 @@
52147
*
53148
****************************************************************************/
54149

150+
#undef vasprintf
55151
int vasprintf(FAR char **ptr, FAR const IPTR char *fmt, va_list ap)
56152
{
57153
struct lib_outstream_s nulloutstream;

libs/libc/string/lib_strdup.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,16 @@ FAR char *strdup(FAR const char *s)
4747

4848
return news;
4949
}
50+
51+
FAR char *nx_strdup(FAR const char *s)
52+
{
53+
size_t size = strlen(s) + 1;
54+
FAR char *news = (FAR char *)kmm_malloc(size);
55+
56+
if (news != NULL)
57+
{
58+
strlcpy(news, s, size);
59+
}
60+
61+
return news;
62+
}

libs/libc/string/lib_strndup.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,47 @@
3434
* Public Functions
3535
****************************************************************************/
3636

37+
/****************************************************************************
38+
* Name: nx_strndup
39+
*
40+
* Description:
41+
* The strndup() function is equivalent to the strdup() function,
42+
* duplicating the provided 's' in a new block of memory allocated as
43+
* if by using kmm_malloc(), with the exception being that strndup() copies
44+
* at most 'size' plus one bytes into the newly allocated memory,
45+
* terminating the new string with a NUL character. If the length of 's'
46+
* is larger than 'size', only 'size' bytes will be duplicated. If
47+
* 'size' is larger than the length of 's', all bytes in s will be
48+
* copied into the new memory buffer, including the terminating NUL
49+
* character. The newly created string will always be properly
50+
* terminated.
51+
*
52+
****************************************************************************/
53+
54+
FAR char *nx_strndup(FAR const char *s, size_t size)
55+
{
56+
FAR char *news;
57+
58+
/* Get the size of the new string (limited to size) */
59+
60+
size_t allocsize = strnlen(s, size);
61+
62+
/* Allocate the new string, adding 1 for the NUL terminator */
63+
64+
news = (FAR char *)kmm_malloc(allocsize + 1);
65+
if (news != NULL)
66+
{
67+
/* Copy the string into the allocated memory and add a NUL
68+
* terminator in any case.
69+
*/
70+
71+
memcpy(news, s, allocsize);
72+
news[allocsize] = '\0';
73+
}
74+
75+
return news;
76+
}
77+
3778
/****************************************************************************
3879
* Name: strndup
3980
*

0 commit comments

Comments
 (0)