1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3 *
4 * Copyright (C) 1997 University of Chicago.
5 * See COPYRIGHT notice in top-level directory.
6 */
7
8 #include "adio.h"
9
10 /* style: allow:sprintf:3 sig:0 */
11
12 /*
13 * Below are the "safe" versions of the various string and printf
14 * operations. They are directly taken from MPICH, with MPIU replaced by ADIOI.
15 */
16
17 /*
18 * ADIOI_Strncpy - Copy at most n character. Stop once a null is reached.
19 *
20 * This is different from strncpy, which null pads so that exactly
21 * n characters are copied. The strncpy behavior is correct for many
22 * applications because it guarantees that the string has no uninitialized
23 * data.
24 *
25 * If n characters are copied without reaching a null, return an error.
26 * Otherwise, return 0.
27 *
28 */
29 /*@ ADIOI_Strncpy - Copy a string with a maximum length
30
31 Input Parameters:
32 + instr - String to copy
33 - maxlen - Maximum total length of 'outstr'
34
35 Output Parameters:
36 . outstr - String to copy into
37
38 Notes:
39 This routine is the routine that you wish 'strncpy' was. In copying
40 'instr' to 'outstr', it stops when either the end of 'outstr' (the
41 null character) is seen or the maximum length 'maxlen' is reached.
42 Unlike 'strncpy', it does not add enough nulls to 'outstr' after
43 copying 'instr' in order to move precisely 'maxlen' characters.
44 Thus, this routine may be used anywhere 'strcpy' is used, without any
45 performance cost related to large values of 'maxlen'.
46
47 Module:
48 Utility
49 @*/
50 int ADIOI_Strncpy( char *dest, const char *src, size_t n )
51 {
52 char * restrict d_ptr = dest;
53 const char * restrict s_ptr = src;
54 register int i;
55
56 i = (int)n;
57 while (*s_ptr && i-- > 0) {
58 *d_ptr++ = *s_ptr++;
59 }
60
61 if (i > 0) {
62 *d_ptr = 0;
63 return 0;
64 }
65 else
66 /* We may want to force an error message here, at least in the
67 debugging version */
68 return 1;
69 }
70
71 /* Append src to dest, but only allow dest to contain n characters (including
72 any null, which is always added to the end of the line */
73 /*@ ADIOI_Strnapp - Append to a string with a maximum length
74
75 Input Parameters:
76 + instr - String to copy
77 - maxlen - Maximum total length of 'outstr'
78
79 Output Parameters:
80 . outstr - String to copy into
81
82 Notes:
83 This routine is similar to 'strncat' except that the 'maxlen' argument
84 is the maximum total length of 'outstr', rather than the maximum
85 number of characters to move from 'instr'. Thus, this routine is
86 easier to use when the declared size of 'instr' is known.
87
88 Module:
89 Utility
90 @*/
91 int ADIOI_Strnapp( char *dest, const char *src, size_t n )
92 {
93 char * restrict d_ptr = dest;
94 const char * restrict s_ptr = src;
95 register int i;
96
97 /* Get to the end of dest */
98 i = (int)n;
99 while (i-- > 0 && *d_ptr) d_ptr++;
100 if (i <= 0) return 1;
101
102 /* Append. d_ptr points at first null and i is remaining space. */
103 while (*s_ptr && i-- > 0) {
104 *d_ptr++ = *s_ptr++;
105 }
106
107 /* We allow i >= (not just >) here because the first while decrements
108 i by one more than there are characters, leaving room for the null */
109 if (i >= 0) {
110 *d_ptr = 0;
111 return 0;
112 }
113 else {
114 /* Force the null at the end */
115 *--d_ptr = 0;
116
117 /* We may want to force an error message here, at least in the
118 debugging version */
119 return 1;
120 }
121 }
122
123 /*@
124 ADIOI_Strdup - Duplicate a string
125
126 Synopsis:
127 .vb
128 char *ADIOI_Strdup( const char *str )
129 .ve
130
131 Input Parameters:
132 . str - null-terminated string to duplicate
133
134 Return value:
135 A pointer to a copy of the string, including the terminating null. A
136 null pointer is returned on error, such as out-of-memory.
137
138 Notes:
139 Like 'ADIOI_Malloc' and 'ADIOI_Free', this will often be implemented as a
140 macro but may use 'ADIOI_trstrdup' to provide a tracing version.
141
142 Module:
143 Utility
144 @*/
145 char *ADIOI_Strdup( const char *str )
146 {
147 char *p = ADIOI_Malloc( strlen(str) + 1 );
148 char *in_p = (char *)str;
149 char *save_p;
150
151 save_p = p;
152 if (p) {
153 while (*in_p) {
154 *p++ = *in_p++;
155 }
156 *p = '\0';
157 }
158 return save_p;
159 }
160
161
162 /*
163 * We need an snprintf replacement for systems without one
164 */
165 #ifndef HAVE_SNPRINTF
166 #include <ctype.h>
167 /* FIXME: Really need a check for varargs.h vs stdarg.h */
168 #include <stdarg.h>
169 /*
170 * This is an approximate form which is suitable for most uses within
171 * the MPICH code
172 */
173 int ADIOI_Snprintf( char *str, size_t size, const char *format, ... )
174 {
175 int n;
176 const char *p;
177 char *out_str = str;
178 va_list list;
179
180 va_start(list, format);
181
182 p = format;
183 while (*p && size > 0) {
184 char *nf;
185
186 nf = strchr(p, '%');
187 if (!nf) {
188 /* No more format characters */
189 while (size-- > 0 && *p) {
190 *out_str++ = *p++;
191 }
192 }
193 else {
194 int nc;
195 int width = -1;
196
197 /* Copy until nf */
198 while (p < nf && size-- > 0) {
199 *out_str++ = *p++;
200 }
201 /* p now points at nf */
202 /* Handle the format character */
203 nc = nf[1];
204 if (isdigit(nc)) {
205 /* Get the field width */
206 /* FIXME : Assumes ASCII */
207 width = nc - '0';
208 p = nf + 2;
209 while (*p && isdigit(*p)) {
210 width = 10 * width + (*p++ - '0');
211 }
212 /* When there is no longer a digit, get the format
213 character */
214 nc = *p++;
215 }
216 else {
217 /* Skip over the format string */
218 p += 2;
219 }
220
221 switch (nc) {
222 case '%':
223 *out_str++ = '%';
224 size--;
225 break;
226
227 case 'd':
228 {
229 int val;
230 char tmp[20];
231 char *t = tmp;
232 /* Get the argument, of integer type */
233 val = va_arg( list, int );
234 sprintf( tmp, "%d", val );
235 if (width > 0) {
236 int tmplen = strlen(tmp);
237 /* If a width was specified, pad with spaces on the
238 left (on the right if %-3d given; not implemented yet */
239 while (size-- > 0 && width-- > tmplen)
240 *out_str++ = ' ';
241 }
242 while (size-- > 0 && *t) {
243 *out_str++ = *t++;
244 }
245 }
246 break;
247
248 case 'x':
249 {
250 int val;
251 char tmp[20];
252 char *t = tmp;
253 /* Get the argument, of integer type */
254 val = va_arg( list, int );
255 sprintf( tmp, "%x", val );
256 if (width > 0) {
257 int tmplen = strlen(tmp);
258 /* If a width was specified, pad with spaces on the
259 left (on the right if %-3d given; not implemented yet */
260 while (size-- > 0 && width-- > tmplen)
261 *out_str++ = ' ';
262 }
263 while (size-- > 0 && *t) {
264 *out_str++ = *t++;
265 }
266 }
267 break;
268
269 case 'p':
270 {
271 void *val;
272 char tmp[20];
273 char *t = tmp;
274 val = va_arg( list, void * );
275 sprintf( tmp, "%p", val );
276 if (width > 0) {
277 int tmplen = strlen(tmp);
278 /* If a width was specified, pad with spaces on the
279 left (on the right if %-3d given; not implemented yet */
280 while (size-- > 0 && width-- > tmplen)
281 *out_str++ = ' ';
282 }
283 while (size-- > 0 && *t) {
284 *out_str++ = *t++;
285 }
286 }
287 break;
288
289 case 's':
290 {
291 char *s_arg;
292 /* Get the argument, of pointer to char type */
293 s_arg = va_arg( list, char * );
294 while (size-- > 0 && s_arg && *s_arg) {
295 *out_str++ = *s_arg++;
296 }
297 }
298 break;
299
300 default:
301 /* Error, unknown case */
302 return -1;
303 break;
304 }
305 }
306 }
307
308 va_end(list);
309
310 if (size-- > 0) *out_str++ = '\0';
311
312 n = (int)(out_str - str);
313 return n;
314 }
315 #endif