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