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