1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 /*
4 * Concatenates/copies strings. In any case, terminates in all cases
5 * with '\0' and moves the @dest pointer forward to the added '\0'.
6 * Returns the remaining size, and 0 if the string was truncated.
7 *
8 * Due to the intended usage, these helpers silently noop invocations
9 * having zero size. This is technically an exception to the above
10 * statement "terminates in all cases". It's unexpected for such calls to
11 * occur outside of a loop where this is the preferred behavior.
12 */
13
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <string.h>
17
18 #include "string-util.h"
19 #include "strxcpyx.h"
20
strnpcpy_full(char ** dest,size_t size,const char * src,size_t len,bool * ret_truncated)21 size_t strnpcpy_full(char **dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
22 bool truncated = false;
23
24 assert(dest);
25 assert(src);
26
27 if (size == 0) {
28 if (ret_truncated)
29 *ret_truncated = len > 0;
30 return 0;
31 }
32
33 if (len >= size) {
34 if (size > 1)
35 *dest = mempcpy(*dest, src, size-1);
36 size = 0;
37 truncated = true;
38 } else if (len > 0) {
39 *dest = mempcpy(*dest, src, len);
40 size -= len;
41 }
42
43 if (ret_truncated)
44 *ret_truncated = truncated;
45
46 *dest[0] = '\0';
47 return size;
48 }
49
strpcpy_full(char ** dest,size_t size,const char * src,bool * ret_truncated)50 size_t strpcpy_full(char **dest, size_t size, const char *src, bool *ret_truncated) {
51 assert(dest);
52 assert(src);
53
54 return strnpcpy_full(dest, size, src, strlen(src), ret_truncated);
55 }
56
strpcpyf_full(char ** dest,size_t size,bool * ret_truncated,const char * src,...)57 size_t strpcpyf_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
58 bool truncated = false;
59 va_list va;
60 int i;
61
62 assert(dest);
63 assert(src);
64
65 va_start(va, src);
66 i = vsnprintf(*dest, size, src, va);
67 va_end(va);
68
69 if (i < (int) size) {
70 *dest += i;
71 size -= i;
72 } else {
73 size = 0;
74 truncated = i > 0;
75 }
76
77 if (ret_truncated)
78 *ret_truncated = truncated;
79
80 return size;
81 }
82
strpcpyl_full(char ** dest,size_t size,bool * ret_truncated,const char * src,...)83 size_t strpcpyl_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
84 bool truncated = false;
85 va_list va;
86
87 assert(dest);
88 assert(src);
89
90 va_start(va, src);
91 do {
92 bool t;
93
94 size = strpcpy_full(dest, size, src, &t);
95 truncated = truncated || t;
96 src = va_arg(va, char *);
97 } while (src);
98 va_end(va);
99
100 if (ret_truncated)
101 *ret_truncated = truncated;
102 return size;
103 }
104
strnscpy_full(char * dest,size_t size,const char * src,size_t len,bool * ret_truncated)105 size_t strnscpy_full(char *dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
106 char *s;
107
108 assert(dest);
109 assert(src);
110
111 s = dest;
112 return strnpcpy_full(&s, size, src, len, ret_truncated);
113 }
114
strscpy_full(char * dest,size_t size,const char * src,bool * ret_truncated)115 size_t strscpy_full(char *dest, size_t size, const char *src, bool *ret_truncated) {
116 assert(dest);
117 assert(src);
118
119 return strnscpy_full(dest, size, src, strlen(src), ret_truncated);
120 }
121
strscpyl_full(char * dest,size_t size,bool * ret_truncated,const char * src,...)122 size_t strscpyl_full(char *dest, size_t size, bool *ret_truncated, const char *src, ...) {
123 bool truncated = false;
124 va_list va;
125 char *s;
126
127 assert(dest);
128 assert(src);
129
130 va_start(va, src);
131 s = dest;
132 do {
133 bool t;
134
135 size = strpcpy_full(&s, size, src, &t);
136 truncated = truncated || t;
137 src = va_arg(va, char *);
138 } while (src);
139 va_end(va);
140
141 if (ret_truncated)
142 *ret_truncated = truncated;
143
144 return size;
145 }
146