1 /*
2 * Copyright (C) by Argonne National Laboratory
3 * See COPYRIGHT in top-level directory
4 */
5
6 #include "mpl.h"
7
8 #ifdef MPL_HAVE_MATH_H
9 #include <math.h>
10 #endif
11 /* ctype is needed for isspace and isascii (isspace is only defined for
12 values on which isascii returns true). */
13 #include <ctype.h>
14
encode_buffer(char * dest,int dest_length,const char * src,int src_length,int * num_encoded)15 static int encode_buffer(char *dest, int dest_length, const char *src,
16 int src_length, int *num_encoded)
17 {
18 int num_used;
19 int n = 0;
20 if (src_length == 0) {
21 if (dest_length > 2) {
22 *dest = MPL_STR_QUOTE_CHAR;
23 dest++;
24 *dest = MPL_STR_QUOTE_CHAR;
25 dest++;
26 *dest = '\0';
27 *num_encoded = 0;
28 return MPL_SUCCESS;
29 } else {
30 return MPL_ERR_STR_TRUNCATED;
31 }
32 }
33 while (src_length && dest_length) {
34 num_used = MPL_snprintf(dest, dest_length, "%02X", (unsigned char) *src);
35 if (num_used < 0) {
36 *num_encoded = n;
37 return MPL_ERR_STR_TRUNCATED;
38 }
39 /*MPL_DBG_MSG_FMT(STRING,VERBOSE,(MPL_DBG_FDEST," %c = %c%c",
40 * ch, dest[0], dest[1])); */
41 dest += num_used;
42 dest_length -= num_used;
43 src++;
44 n++;
45 src_length--;
46 }
47 *num_encoded = n;
48 return src_length ? MPL_ERR_STR_TRUNCATED : MPL_SUCCESS;
49 }
50
decode_buffer(const char * str,char * dest,int length,int * num_decoded)51 static int decode_buffer(const char *str, char *dest, int length, int *num_decoded)
52 {
53 char hex[3];
54 int value;
55 int n = 0;
56
57 if (str == NULL || dest == NULL || num_decoded == NULL)
58 return MPL_ERR_STR_FAIL;
59 if (length < 1) {
60 *num_decoded = 0;
61 if (*str == '\0')
62 return MPL_SUCCESS;
63 return MPL_ERR_STR_TRUNCATED;
64 }
65 if (*str == MPL_STR_QUOTE_CHAR)
66 str++;
67 hex[2] = '\0';
68 while (*str != '\0' && *str != MPL_STR_SEPAR_CHAR && *str != MPL_STR_QUOTE_CHAR && length) {
69 hex[0] = *str;
70 str++;
71 hex[1] = *str;
72 str++;
73 if (0 == sscanf(hex, "%X", &value))
74 return MPL_ERR_STR_TRUNCATED;
75 *dest = (char) value;
76 /*MPL_DBG_MSG_FMT(STRING,VERBOSE,(MPL_DBG_FDEST," %s = %c",
77 * hex, *dest)); */
78 dest++;
79 n++;
80 length--;
81 }
82 *num_decoded = n;
83 if (length == 0) {
84 if (*str != '\0' && *str != MPL_STR_SEPAR_CHAR && *str != MPL_STR_QUOTE_CHAR)
85 return MPL_ERR_STR_TRUNCATED;
86 }
87 return MPL_SUCCESS;
88 }
89
first_token(const char * str)90 static const char *first_token(const char *str)
91 {
92 if (str == NULL)
93 return NULL;
94 /* isspace is defined only if isascii is true */
95 while (/*isascii(*str) && isspace(*str) */ *str == MPL_STR_SEPAR_CHAR)
96 str++;
97 if (*str == '\0')
98 return NULL;
99 return str;
100 }
101
next_token(const char * str)102 static const char *next_token(const char *str)
103 {
104 if (str == NULL)
105 return NULL;
106 str = first_token(str);
107 if (str == NULL)
108 return NULL;
109 if (*str == MPL_STR_QUOTE_CHAR) {
110 /* move over string */
111 str++; /* move over the first quote */
112 if (*str == '\0')
113 return NULL;
114 while (*str != MPL_STR_QUOTE_CHAR) {
115 /* move until the last quote, ignoring escaped quotes */
116 if (*str == MPL_STR_ESCAPE_CHAR) {
117 str++;
118 if (*str == MPL_STR_QUOTE_CHAR)
119 str++;
120 } else {
121 str++;
122 }
123 if (*str == '\0')
124 return NULL;
125 }
126 str++; /* move over the last quote */
127 } else {
128 if (*str == MPL_STR_DELIM_CHAR) {
129 /* move over the DELIM token */
130 str++;
131 } else {
132 /* move over literal */
133 while (/*(isascii(*str) &&
134 * !isspace(*str)) && */
135 *str != MPL_STR_SEPAR_CHAR && *str != MPL_STR_DELIM_CHAR && *str != '\0')
136 str++;
137 }
138 }
139 return first_token(str);
140 }
141
compare_token(const char * token,const char * str)142 static int compare_token(const char *token, const char *str)
143 {
144 if (token == NULL || str == NULL)
145 return -1;
146
147 if (*token == MPL_STR_QUOTE_CHAR) {
148 /* compare quoted strings */
149 token++; /* move over the first quote */
150 /* compare characters until reaching the end of the string or the
151 * end quote character */
152 for (;;) {
153 if (*token == MPL_STR_ESCAPE_CHAR) {
154 if (*(token + 1) == MPL_STR_QUOTE_CHAR) {
155 /* move over the escape character if the next character
156 * is a quote character */
157 token++;
158 }
159 if (*token != *str)
160 break;
161 } else {
162 if (*token != *str || *token == MPL_STR_QUOTE_CHAR)
163 break;
164 }
165 if (*str == '\0')
166 break;
167 token++;
168 str++;
169 }
170 if (*str == '\0' && *token == MPL_STR_QUOTE_CHAR)
171 return 0;
172 if (*token == MPL_STR_QUOTE_CHAR)
173 return 1;
174 if (*str < *token)
175 return -1;
176 return 1;
177 }
178
179 /* compare DELIM token */
180 if (*token == MPL_STR_DELIM_CHAR) {
181 if (*str == MPL_STR_DELIM_CHAR) {
182 str++;
183 if (*str == '\0')
184 return 0;
185 return 1;
186 }
187 if (*token < *str)
188 return -1;
189 return 1;
190 }
191
192 /* compare literals */
193 while (*token == *str &&
194 *str != '\0' && *token != MPL_STR_DELIM_CHAR && (*token != MPL_STR_SEPAR_CHAR)) {
195 token++;
196 str++;
197 }
198 if ((*str == '\0') &&
199 (*token == MPL_STR_DELIM_CHAR || (*token == MPL_STR_SEPAR_CHAR) || *token == '\0'))
200 return 0;
201 if (*token == MPL_STR_DELIM_CHAR || (*token == MPL_STR_SEPAR_CHAR) || *token < *str)
202 return -1;
203 return 1;
204 }
205
206
token_copy(const char * token,char * str,int maxlen)207 static int token_copy(const char *token, char *str, int maxlen)
208 {
209 /* check parameters */
210 if (token == NULL || str == NULL)
211 return MPL_ERR_STR_FAIL;
212
213 /* check special buffer lengths */
214 if (maxlen < 1)
215 return MPL_ERR_STR_FAIL;
216 if (maxlen == 1) {
217 *str = '\0';
218 return (str[0] == '\0') ? MPL_SUCCESS : MPL_ERR_STR_TRUNCATED;
219 }
220
221 /* cosy up to the token */
222 token = first_token(token);
223 if (token == NULL) {
224 *str = '\0';
225 return MPL_SUCCESS;
226 }
227
228 if (*token == MPL_STR_DELIM_CHAR) {
229 /* copy the special deliminator token */
230 str[0] = MPL_STR_DELIM_CHAR;
231 str[1] = '\0';
232 return MPL_SUCCESS;
233 }
234
235 if (*token == MPL_STR_QUOTE_CHAR) {
236 /* quoted copy */
237 token++; /* move over the first quote */
238 do {
239 if (*token == MPL_STR_ESCAPE_CHAR) {
240 if (*(token + 1) == MPL_STR_QUOTE_CHAR)
241 token++;
242 *str = *token;
243 } else {
244 if (*token == MPL_STR_QUOTE_CHAR) {
245 *str = '\0';
246 return MPL_SUCCESS;
247 }
248 *str = *token;
249 }
250 str++;
251 token++;
252 maxlen--;
253 } while (maxlen);
254 /* we've run out of destination characters so back up and null
255 * terminate the string */
256 str--;
257 *str = '\0';
258 return MPL_ERR_STR_TRUNCATED;
259 }
260
261 /* literal copy */
262 while (*token != MPL_STR_DELIM_CHAR &&
263 (*token != MPL_STR_SEPAR_CHAR) && *token != '\0' && maxlen) {
264 *str = *token;
265 str++;
266 token++;
267 maxlen--;
268 }
269 if (maxlen) {
270 *str = '\0';
271 return MPL_SUCCESS;
272 }
273 str--;
274 *str = '\0';
275 return MPL_ERR_STR_TRUNCATED;
276 }
277
278 /*@ MPL_str_get_string_arg - Extract an option from a string with a
279 maximum length
280
281 Input Parameters:
282 + str - Source string
283 . key - key
284 - maxlen - Maximum total length of 'val'
285
286 Output Parameters:
287 . val - output string
288
289 Return value:
290 MPL_SUCCESS, MPL_ERR_STR_NOMEM, MPL_ERR_STR
291
292 Notes:
293 This routine searches for a "key = value" entry in a string
294
295 Module:
296 Utility
297 @*/
MPL_str_get_string_arg(const char * str,const char * flag,char * val,int maxlen)298 int MPL_str_get_string_arg(const char *str, const char *flag, char *val, int maxlen)
299 {
300 if (maxlen < 1)
301 return MPL_ERR_STR_FAIL;
302
303 /* line up with the first token */
304 str = first_token(str);
305 if (str == NULL)
306 return MPL_ERR_STR_FAIL;
307
308 /* This loop will match the first instance of "flag = value" in the string. */
309 do {
310 if (compare_token(str, flag) == 0) {
311 str = next_token(str);
312 if (compare_token(str, MPL_STR_DELIM_STR) == 0) {
313 str = next_token(str);
314 if (str == NULL)
315 return MPL_ERR_STR_FAIL;
316 return token_copy(str, val, maxlen);
317 }
318 } else {
319 str = next_token(str);
320 }
321 } while (str);
322 return MPL_ERR_STR_FAIL;
323 }
324
325 /*@ MPL_str_get_binary_arg - Extract an option from a string with a maximum
326 length
327
328 Input Parameters:
329 + str - Source string
330 . key - key
331 - maxlen - Maximum total length of 'buffer'
332
333 Output Parameters:
334 + buffer - output buffer
335 - out_length - output length
336
337 Return value:
338 MPL_SUCCESS, MPL_ERR_STR_NOMEM, MPL_ERR_STR
339
340 Notes:
341 This routine searches for a "key = value" entry in a string and decodes
342 the value
343 back to binary data. The data must have been encoded with
344 MPL_str_add_binary_arg.
345
346 Module:
347 Utility
348 @*/
MPL_str_get_binary_arg(const char * str,const char * flag,char * buffer,int maxlen,int * out_length)349 int MPL_str_get_binary_arg(const char *str, const char *flag, char *buffer,
350 int maxlen, int *out_length)
351 {
352 if (maxlen < 1)
353 return MPL_ERR_STR_FAIL;
354
355 /* line up with the first token */
356 str = first_token(str);
357 if (str == NULL)
358 return MPL_ERR_STR_FAIL;
359
360 /* This loop will match the first instance of "flag = value" in the string. */
361 do {
362 if (compare_token(str, flag) == 0) {
363 str = next_token(str);
364 if (compare_token(str, MPL_STR_DELIM_STR) == 0) {
365 str = next_token(str);
366 if (str == NULL)
367 return MPL_ERR_STR_FAIL;
368 return decode_buffer(str, buffer, maxlen, out_length);
369 }
370 } else {
371 str = next_token(str);
372 }
373 } while (str);
374 return MPL_ERR_STR_FAIL;
375 }
376
377 /*@ MPL_str_get_int_arg - Extract an option from a string
378
379 Input Parameters:
380 + str - Source string
381 - key - key
382
383 Output Parameters:
384 . val_ptr - pointer to the output integer
385
386 Return value:
387 MPL_SUCCESS, MPL_ERR_STR_NOMEM, MPL_ERR_STR
388
389 Notes:
390 This routine searches for a "key = value" entry in a string and decodes the value
391 back to an int.
392
393 Module:
394 Utility
395 @*/
MPL_str_get_int_arg(const char * str,const char * flag,int * val_ptr)396 int MPL_str_get_int_arg(const char *str, const char *flag, int *val_ptr)
397 {
398 int result;
399 char int_str[12];
400
401 result = MPL_str_get_string_arg(str, flag, int_str, 12);
402 if (result == MPL_SUCCESS) {
403 *val_ptr = atoi(int_str);
404 return MPL_SUCCESS;
405 }
406 return result;
407 }
408
409 /* quoted_printf does not NULL terminate the string if maxlen is reached */
quoted_printf(char * str,int maxlen,const char * val)410 static int quoted_printf(char *str, int maxlen, const char *val)
411 {
412 int count = 0;
413 if (maxlen < 1)
414 return 0;
415 *str = MPL_STR_QUOTE_CHAR;
416 str++;
417 maxlen--;
418 count++;
419 while (maxlen) {
420 if (*val == '\0')
421 break;
422 if (*val == MPL_STR_QUOTE_CHAR) {
423 *str = MPL_STR_ESCAPE_CHAR;
424 str++;
425 maxlen--;
426 count++;
427 if (maxlen == 0)
428 return count;
429 }
430 *str = *val;
431 str++;
432 maxlen--;
433 count++;
434 val++;
435 }
436 if (maxlen) {
437 *str = MPL_STR_QUOTE_CHAR;
438 str++;
439 maxlen--;
440 count++;
441 if (maxlen == 0)
442 return count;
443 *str = '\0';
444 }
445 return count;
446 }
447
448 /*@ MPL_str_add_string - Add a string to a string
449
450 Input Parameters:
451 + str_ptr - pointer to the destination string
452 . maxlen_ptr - pointer to the maximum length of '*str_ptr'
453 - val - string to add
454
455 Output Parameters:
456 + str_ptr - The string pointer is updated to the next available location in
457 the string
458 - maxlen_ptr - maxlen is decremented by the amount str_ptr is incremented
459
460 Return value:
461 MPL_SUCCESS, MPL_ERR_STR_NOMEM, MPL_ERR_STR
462
463 Notes:
464 This routine adds a string to a string in such a way that
465 MPL_str_get_string can
466 retreive the same string back. It takes into account spaces and quote
467 characters.
468 The string pointer is updated to the start of the next string in the
469 string and maxlen is updated accordingly.
470
471 Module:
472 Utility
473 @*/
MPL_str_add_string(char ** str_ptr,int * maxlen_ptr,const char * val)474 int MPL_str_add_string(char **str_ptr, int *maxlen_ptr, const char *val)
475 {
476 int num_chars;
477 char *str;
478 int maxlen;
479
480 str = *str_ptr;
481 maxlen = *maxlen_ptr;
482
483 if (strchr(val, MPL_STR_SEPAR_CHAR) ||
484 strchr(val, MPL_STR_QUOTE_CHAR) || strchr(val, MPL_STR_DELIM_CHAR)) {
485 num_chars = quoted_printf(str, maxlen, val);
486 if (num_chars == maxlen) {
487 /* truncation, cleanup string */
488 *str = '\0';
489 return -1;
490 }
491 if (num_chars < maxlen - 1) {
492 str[num_chars] = MPL_STR_SEPAR_CHAR;
493 str[num_chars + 1] = '\0';
494 num_chars++;
495 } else {
496 str[num_chars] = '\0';
497 }
498 } else {
499 if (*val == '\0') {
500 num_chars = MPL_snprintf(str, maxlen, MPL_STR_QUOTE_STR MPL_STR_QUOTE_STR /*"\"\"" */);
501 } else {
502 num_chars = MPL_snprintf(str, maxlen, "%s%c", val, MPL_STR_SEPAR_CHAR);
503 }
504 if (num_chars == maxlen) {
505 *str = '\0';
506 return -1;
507 }
508 }
509 *str_ptr += num_chars;
510 *maxlen_ptr -= num_chars;
511 return 0;
512 }
513
514 /*@ MPL_str_get_string - Get the next string from a string
515
516 Input Parameters:
517 + str_ptr - pointer to the destination string
518 - maxlen_ptr - pointer to the maximum length of '*str_ptr'
519
520 Output Parameters:
521 + str_ptr - location of the next string
522 - val - location to store the string
523
524 Return value:
525 MPL_SUCCESS, MPL_ERR_STR_NOMEM, MPL_ERR_STR
526
527 Return Value:
528 The return value is 0 for success, -1 for insufficient buffer space, and
529 1 for failure.
530
531 Notes:
532 This routine gets a string that was previously added by
533 MPL_str_add_string.
534 It takes into account spaces and quote characters. The string pointer is
535 updated to the start of the next string in the string.
536
537 Module:
538 Utility
539 @*/
MPL_str_get_string(char ** str_ptr,char * val,int maxlen)540 int MPL_str_get_string(char **str_ptr, char *val, int maxlen)
541 {
542 int result;
543 char *str;
544
545 if (str_ptr == NULL) {
546 return -2;
547 }
548
549 str = *str_ptr;
550
551 if (maxlen < 1) {
552 return 0;
553 }
554
555 /* line up with the first token */
556 str = (char *) first_token(str);
557 if (str == NULL) {
558 return 0;
559 }
560
561 /* copy the token */
562 result = token_copy(str, val, maxlen);
563 if (result == MPL_SUCCESS) {
564 str = (char *) next_token(str);
565 *str_ptr = str;
566 return 0;
567 } else if (result == MPL_ERR_STR_TRUNCATED) {
568 return -1;
569 }
570
571 /* failure */
572 return -2;
573 }
574
575 /*@ MPL_str_add_string_arg - Add an option to a string with a maximum length
576
577 Input Parameters:
578 + str_ptr - Pointer to the destination string
579 . maxlen_ptr - Pointer to the maximum total length of '*str_ptr'
580 . key - key
581 - val - input string
582
583 Output Parameters:
584 + str_ptr - The string pointer is updated to the next available location in
585 the string
586 - maxlen_ptr - maxlen is reduced by the number of characters written
587
588 Return value:
589 MPL_SUCCESS, MPL_ERR_STR_NOMEM, MPL_ERR_STR
590
591 Notes:
592 This routine adds a string option to a string in the form "key = value".
593
594 Module:
595 Utility
596 @*/
MPL_str_add_string_arg(char ** str_ptr,int * maxlen_ptr,const char * flag,const char * val)597 int MPL_str_add_string_arg(char **str_ptr, int *maxlen_ptr, const char *flag, const char *val)
598 {
599 int num_chars;
600 char **orig_str_ptr;
601
602 if (maxlen_ptr == NULL)
603 return MPL_ERR_STR_FAIL;
604
605 orig_str_ptr = str_ptr;
606
607 if (*maxlen_ptr < 1)
608 return MPL_ERR_STR_FAIL;
609
610 /* add the flag */
611 if (strstr(flag, MPL_STR_SEPAR_STR) || strstr(flag, MPL_STR_DELIM_STR) ||
612 flag[0] == MPL_STR_QUOTE_CHAR) {
613 num_chars = quoted_printf(*str_ptr, *maxlen_ptr, flag);
614 } else {
615 num_chars = MPL_snprintf(*str_ptr, *maxlen_ptr, "%s", flag);
616 }
617 *maxlen_ptr = *maxlen_ptr - num_chars;
618 if (*maxlen_ptr < 1) {
619 MPL_DBG_MSG_S(MPIR_DBG_STRING, VERBOSE, "partial argument added to string: '%s'", *str_ptr);
620 **str_ptr = '\0';
621 return MPL_ERR_STR_NOMEM;
622 }
623 *str_ptr = *str_ptr + num_chars;
624
625 /* add the deliminator character */
626 **str_ptr = MPL_STR_DELIM_CHAR;
627 *str_ptr = *str_ptr + 1;
628 *maxlen_ptr = *maxlen_ptr - 1;
629
630 /* add the value string */
631 if (strstr(val, MPL_STR_SEPAR_STR) || strstr(val, MPL_STR_DELIM_STR) ||
632 val[0] == MPL_STR_QUOTE_CHAR) {
633 num_chars = quoted_printf(*str_ptr, *maxlen_ptr, val);
634 } else {
635 if (*val == '\0') {
636 num_chars = MPL_snprintf(*str_ptr, *maxlen_ptr,
637 MPL_STR_QUOTE_STR MPL_STR_QUOTE_STR /*"\"\"" */);
638 } else {
639 num_chars = MPL_snprintf(*str_ptr, *maxlen_ptr, "%s", val);
640 }
641 }
642 *str_ptr = *str_ptr + num_chars;
643 *maxlen_ptr = *maxlen_ptr - num_chars;
644 if (*maxlen_ptr < 2) {
645 MPL_DBG_MSG_S(MPIR_DBG_STRING, VERBOSE, "partial argument added to string: '%s'", *str_ptr);
646 **orig_str_ptr = '\0';
647 return MPL_ERR_STR_NOMEM;
648 }
649
650 /* add the trailing space */
651 **str_ptr = MPL_STR_SEPAR_CHAR;
652 *str_ptr = *str_ptr + 1;
653 **str_ptr = '\0';
654 *maxlen_ptr = *maxlen_ptr - 1;
655
656 return MPL_SUCCESS;
657 }
658
659 /*@ MPL_str_add_int_arg - Add an option to a string with a maximum length
660
661 Input Parameters:
662 + str_ptr - Pointer to the destination string
663 . maxlen_ptr - Pointer to the maximum total length of '*str_ptr'
664 . key - key
665 - val - input integer
666
667 Output Parameters:
668 + str_ptr - The string pointer is updated to the next available location in
669 the string
670 - maxlen_ptr - maxlen is reduced by the number of characters written
671
672 Return value:
673 MPL_SUCCESS, MPL_ERR_STR_NOMEM, MPL_ERR_STR
674
675 Notes:
676 This routine adds an integer option to a string in the form "key = value".
677
678 Module:
679 Utility
680 @*/
MPL_str_add_int_arg(char ** str_ptr,int * maxlen_ptr,const char * flag,int val)681 int MPL_str_add_int_arg(char **str_ptr, int *maxlen_ptr, const char *flag, int val)
682 {
683 char val_str[12];
684 MPL_snprintf(val_str, 12, "%d", val);
685 return MPL_str_add_string_arg(str_ptr, maxlen_ptr, flag, val_str);
686 }
687
688 /*@ MPL_str_add_binary_arg - Add an option to a string with a maximum length
689
690 Input Parameters:
691 + str_ptr - Pointer to the destination string
692 . maxlen_ptr - Pointer to the maximum total length of '*str_ptr'
693 . key - key
694 . val - input data
695 - length - length of the input data
696
697 Output Parameters:
698 + str_ptr - The string pointer is updated to the next available location in
699 the string
700 - maxlen_ptr - maxlen is reduced by the number of characters written
701
702 Return value:
703 MPL_SUCCESS, MPL_ERR_STR_NOMEM, MPL_ERR_STR
704
705 Notes:
706 This routine encodes binary data into a string option in the form
707 "key = encoded_value".
708
709 Module:
710 Utility
711 @*/
MPL_str_add_binary_arg(char ** str_ptr,int * maxlen_ptr,const char * flag,const char * buffer,int length)712 int MPL_str_add_binary_arg(char **str_ptr, int *maxlen_ptr, const char *flag,
713 const char *buffer, int length)
714 {
715 int result;
716 int num_chars;
717 char **orig_str_ptr;
718
719 if (maxlen_ptr == NULL)
720 return MPL_ERR_STR_FAIL;
721
722 orig_str_ptr = str_ptr;
723
724 if (*maxlen_ptr < 1)
725 return MPL_ERR_STR_FAIL;
726
727 /* add the flag */
728 if (strstr(flag, MPL_STR_SEPAR_STR) || strstr(flag, MPL_STR_DELIM_STR) ||
729 flag[0] == MPL_STR_QUOTE_CHAR) {
730 num_chars = quoted_printf(*str_ptr, *maxlen_ptr, flag);
731 } else {
732 num_chars = MPL_snprintf(*str_ptr, *maxlen_ptr, "%s", flag);
733 }
734 *maxlen_ptr = *maxlen_ptr - num_chars;
735 if (*maxlen_ptr < 1) {
736 MPL_DBG_MSG_S(MPIR_DBG_STRING, VERBOSE, "partial argument added to string: '%s'", *str_ptr);
737 **str_ptr = '\0';
738 return MPL_ERR_STR_NOMEM;
739 }
740 *str_ptr = *str_ptr + num_chars;
741
742 /* add the deliminator character */
743 **str_ptr = MPL_STR_DELIM_CHAR;
744 *str_ptr = *str_ptr + 1;
745 *maxlen_ptr = *maxlen_ptr - 1;
746
747 /* add the value string */
748 result = encode_buffer(*str_ptr, *maxlen_ptr, buffer, length, &num_chars);
749 if (result != MPL_SUCCESS) {
750 **orig_str_ptr = '\0';
751 return result;
752 }
753 num_chars = num_chars * 2; /* the encoding function turns one source
754 * character into two destination characters */
755 *str_ptr = *str_ptr + num_chars;
756 *maxlen_ptr = *maxlen_ptr - num_chars;
757 if (*maxlen_ptr < 2) {
758 MPL_DBG_MSG_S(MPIR_DBG_STRING, VERBOSE, "partial argument added to string: '%s'", *str_ptr);
759 **orig_str_ptr = '\0';
760 return MPL_ERR_STR_NOMEM;
761 }
762
763 /* add the trailing space */
764 **str_ptr = MPL_STR_SEPAR_CHAR;
765 *str_ptr = *str_ptr + 1;
766 **str_ptr = '\0';
767 *maxlen_ptr = *maxlen_ptr - 1;
768
769 return MPL_SUCCESS;
770 }
771