]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/strxcpyx.c
9126e1dfe26d51b23e8fae67f18908968b5e0f80
[thirdparty/systemd.git] / src / basic / strxcpyx.c
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 <stdio.h>
15 #include <string.h>
16
17 #include "strxcpyx.h"
18
19 size_t strnpcpy_full(char **dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
20 bool truncated = false;
21
22 assert(dest);
23 assert(src);
24
25 if (size == 0) {
26 if (ret_truncated)
27 *ret_truncated = len > 0;
28 return 0;
29 }
30
31 if (len >= size) {
32 if (size > 1)
33 *dest = mempcpy(*dest, src, size-1);
34 size = 0;
35 truncated = true;
36 } else if (len > 0) {
37 *dest = mempcpy(*dest, src, len);
38 size -= len;
39 }
40
41 if (ret_truncated)
42 *ret_truncated = truncated;
43
44 *dest[0] = '\0';
45 return size;
46 }
47
48 size_t strpcpy_full(char **dest, size_t size, const char *src, bool *ret_truncated) {
49 assert(dest);
50 assert(src);
51
52 return strnpcpy_full(dest, size, src, strlen(src), ret_truncated);
53 }
54
55 size_t strpcpyf_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
56 bool truncated = false;
57 va_list va;
58 int i;
59
60 assert(dest);
61 assert(src);
62
63 va_start(va, src);
64 i = vsnprintf(*dest, size, src, va);
65 va_end(va);
66
67 if (i < (int) size) {
68 *dest += i;
69 size -= i;
70 } else {
71 size = 0;
72 truncated = i > 0;
73 }
74
75 if (ret_truncated)
76 *ret_truncated = truncated;
77
78 return size;
79 }
80
81 size_t strpcpyl_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
82 bool truncated = false;
83 va_list va;
84
85 assert(dest);
86 assert(src);
87
88 va_start(va, src);
89 do {
90 bool t;
91
92 size = strpcpy_full(dest, size, src, &t);
93 truncated = truncated || t;
94 src = va_arg(va, char *);
95 } while (src);
96 va_end(va);
97
98 if (ret_truncated)
99 *ret_truncated = truncated;
100 return size;
101 }
102
103 size_t strnscpy_full(char *dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
104 char *s;
105
106 assert(dest);
107 assert(src);
108
109 s = dest;
110 return strnpcpy_full(&s, size, src, len, ret_truncated);
111 }
112
113 size_t strscpy_full(char *dest, size_t size, const char *src, bool *ret_truncated) {
114 assert(dest);
115 assert(src);
116
117 return strnscpy_full(dest, size, src, strlen(src), ret_truncated);
118 }
119
120 size_t strscpyl_full(char *dest, size_t size, bool *ret_truncated, const char *src, ...) {
121 bool truncated = false;
122 va_list va;
123 char *s;
124
125 assert(dest);
126 assert(src);
127
128 va_start(va, src);
129 s = dest;
130 do {
131 bool t;
132
133 size = strpcpy_full(&s, size, src, &t);
134 truncated = truncated || t;
135 src = va_arg(va, char *);
136 } while (src);
137 va_end(va);
138
139 if (ret_truncated)
140 *ret_truncated = truncated;
141
142 return size;
143 }