2 * Copyright 2001-2020 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
11 #include "internal/cryptlib.h"
12 #include <openssl/e_os2.h>
13 #include <openssl/buffer.h>
14 #include <openssl/ui.h>
15 #include <openssl/err.h>
18 DEFINE_STACK_OF(UI_STRING
)
22 return UI_new_method(NULL
);
25 UI
*UI_new_method(const UI_METHOD
*method
)
27 UI
*ret
= OPENSSL_zalloc(sizeof(*ret
));
30 UIerr(UI_F_UI_NEW_METHOD
, ERR_R_MALLOC_FAILURE
);
34 ret
->lock
= CRYPTO_THREAD_lock_new();
35 if (ret
->lock
== NULL
) {
36 UIerr(UI_F_UI_NEW_METHOD
, ERR_R_MALLOC_FAILURE
);
42 method
= UI_get_default_method();
47 if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI
, ret
, &ret
->ex_data
)) {
54 static void free_string(UI_STRING
*uis
)
56 if (uis
->flags
& OUT_STRING_FREEABLE
) {
57 OPENSSL_free((char *)uis
->out_string
);
60 OPENSSL_free((char *)uis
->_
.boolean_data
.action_desc
);
61 OPENSSL_free((char *)uis
->_
.boolean_data
.ok_chars
);
62 OPENSSL_free((char *)uis
->_
.boolean_data
.cancel_chars
);
79 if ((ui
->flags
& UI_FLAG_DUPL_DATA
) != 0) {
80 ui
->meth
->ui_destroy_data(ui
, ui
->user_data
);
82 sk_UI_STRING_pop_free(ui
->strings
, free_string
);
83 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI
, ui
, &ui
->ex_data
);
84 CRYPTO_THREAD_lock_free(ui
->lock
);
88 static int allocate_string_stack(UI
*ui
)
90 if (ui
->strings
== NULL
) {
91 ui
->strings
= sk_UI_STRING_new_null();
92 if (ui
->strings
== NULL
) {
99 static UI_STRING
*general_allocate_prompt(UI
*ui
, const char *prompt
,
101 enum UI_string_types type
,
102 int input_flags
, char *result_buf
)
104 UI_STRING
*ret
= NULL
;
106 if (prompt
== NULL
) {
107 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT
, ERR_R_PASSED_NULL_PARAMETER
);
108 } else if ((type
== UIT_PROMPT
|| type
== UIT_VERIFY
109 || type
== UIT_BOOLEAN
) && result_buf
== NULL
) {
110 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT
, UI_R_NO_RESULT_BUFFER
);
111 } else if ((ret
= OPENSSL_malloc(sizeof(*ret
))) != NULL
) {
112 ret
->out_string
= prompt
;
113 ret
->flags
= prompt_freeable
? OUT_STRING_FREEABLE
: 0;
114 ret
->input_flags
= input_flags
;
116 ret
->result_buf
= result_buf
;
121 static int general_allocate_string(UI
*ui
, const char *prompt
,
123 enum UI_string_types type
, int input_flags
,
124 char *result_buf
, int minsize
, int maxsize
,
125 const char *test_buf
)
128 UI_STRING
*s
= general_allocate_prompt(ui
, prompt
, prompt_freeable
,
129 type
, input_flags
, result_buf
);
132 if (allocate_string_stack(ui
) >= 0) {
133 s
->_
.string_data
.result_minsize
= minsize
;
134 s
->_
.string_data
.result_maxsize
= maxsize
;
135 s
->_
.string_data
.test_buf
= test_buf
;
136 ret
= sk_UI_STRING_push(ui
->strings
, s
);
137 /* sk_push() returns 0 on error. Let's adapt that */
148 static int general_allocate_boolean(UI
*ui
,
150 const char *action_desc
,
151 const char *ok_chars
,
152 const char *cancel_chars
,
154 enum UI_string_types type
,
155 int input_flags
, char *result_buf
)
161 if (ok_chars
== NULL
) {
162 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
, ERR_R_PASSED_NULL_PARAMETER
);
163 } else if (cancel_chars
== NULL
) {
164 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
, ERR_R_PASSED_NULL_PARAMETER
);
166 for (p
= ok_chars
; *p
!= '\0'; p
++) {
167 if (strchr(cancel_chars
, *p
) != NULL
) {
168 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
,
169 UI_R_COMMON_OK_AND_CANCEL_CHARACTERS
);
173 s
= general_allocate_prompt(ui
, prompt
, prompt_freeable
,
174 type
, input_flags
, result_buf
);
177 if (allocate_string_stack(ui
) >= 0) {
178 s
->_
.boolean_data
.action_desc
= action_desc
;
179 s
->_
.boolean_data
.ok_chars
= ok_chars
;
180 s
->_
.boolean_data
.cancel_chars
= cancel_chars
;
181 ret
= sk_UI_STRING_push(ui
->strings
, s
);
183 * sk_push() returns 0 on error. Let's adapt that
197 * Returns the index to the place in the stack or -1 for error. Uses a
198 * direct reference to the prompt.
200 int UI_add_input_string(UI
*ui
, const char *prompt
, int flags
,
201 char *result_buf
, int minsize
, int maxsize
)
203 return general_allocate_string(ui
, prompt
, 0,
204 UIT_PROMPT
, flags
, result_buf
, minsize
,
208 /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
209 int UI_dup_input_string(UI
*ui
, const char *prompt
, int flags
,
210 char *result_buf
, int minsize
, int maxsize
)
212 char *prompt_copy
= NULL
;
214 if (prompt
!= NULL
) {
215 prompt_copy
= OPENSSL_strdup(prompt
);
216 if (prompt_copy
== NULL
) {
217 UIerr(UI_F_UI_DUP_INPUT_STRING
, ERR_R_MALLOC_FAILURE
);
222 return general_allocate_string(ui
, prompt_copy
, 1,
223 UIT_PROMPT
, flags
, result_buf
, minsize
,
227 int UI_add_verify_string(UI
*ui
, const char *prompt
, int flags
,
228 char *result_buf
, int minsize
, int maxsize
,
229 const char *test_buf
)
231 return general_allocate_string(ui
, prompt
, 0,
232 UIT_VERIFY
, flags
, result_buf
, minsize
,
236 int UI_dup_verify_string(UI
*ui
, const char *prompt
, int flags
,
237 char *result_buf
, int minsize
, int maxsize
,
238 const char *test_buf
)
240 char *prompt_copy
= NULL
;
242 if (prompt
!= NULL
) {
243 prompt_copy
= OPENSSL_strdup(prompt
);
244 if (prompt_copy
== NULL
) {
245 UIerr(UI_F_UI_DUP_VERIFY_STRING
, ERR_R_MALLOC_FAILURE
);
250 return general_allocate_string(ui
, prompt_copy
, 1,
251 UIT_VERIFY
, flags
, result_buf
, minsize
,
255 int UI_add_input_boolean(UI
*ui
, const char *prompt
, const char *action_desc
,
256 const char *ok_chars
, const char *cancel_chars
,
257 int flags
, char *result_buf
)
259 return general_allocate_boolean(ui
, prompt
, action_desc
,
260 ok_chars
, cancel_chars
, 0, UIT_BOOLEAN
,
264 int UI_dup_input_boolean(UI
*ui
, const char *prompt
, const char *action_desc
,
265 const char *ok_chars
, const char *cancel_chars
,
266 int flags
, char *result_buf
)
268 char *prompt_copy
= NULL
;
269 char *action_desc_copy
= NULL
;
270 char *ok_chars_copy
= NULL
;
271 char *cancel_chars_copy
= NULL
;
273 if (prompt
!= NULL
) {
274 prompt_copy
= OPENSSL_strdup(prompt
);
275 if (prompt_copy
== NULL
) {
276 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
281 if (action_desc
!= NULL
) {
282 action_desc_copy
= OPENSSL_strdup(action_desc
);
283 if (action_desc_copy
== NULL
) {
284 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
289 if (ok_chars
!= NULL
) {
290 ok_chars_copy
= OPENSSL_strdup(ok_chars
);
291 if (ok_chars_copy
== NULL
) {
292 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
297 if (cancel_chars
!= NULL
) {
298 cancel_chars_copy
= OPENSSL_strdup(cancel_chars
);
299 if (cancel_chars_copy
== NULL
) {
300 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
305 return general_allocate_boolean(ui
, prompt_copy
, action_desc_copy
,
306 ok_chars_copy
, cancel_chars_copy
, 1,
307 UIT_BOOLEAN
, flags
, result_buf
);
309 OPENSSL_free(prompt_copy
);
310 OPENSSL_free(action_desc_copy
);
311 OPENSSL_free(ok_chars_copy
);
312 OPENSSL_free(cancel_chars_copy
);
316 int UI_add_info_string(UI
*ui
, const char *text
)
318 return general_allocate_string(ui
, text
, 0, UIT_INFO
, 0, NULL
, 0, 0,
322 int UI_dup_info_string(UI
*ui
, const char *text
)
324 char *text_copy
= NULL
;
327 text_copy
= OPENSSL_strdup(text
);
328 if (text_copy
== NULL
) {
329 UIerr(UI_F_UI_DUP_INFO_STRING
, ERR_R_MALLOC_FAILURE
);
334 return general_allocate_string(ui
, text_copy
, 1, UIT_INFO
, 0, NULL
,
338 int UI_add_error_string(UI
*ui
, const char *text
)
340 return general_allocate_string(ui
, text
, 0, UIT_ERROR
, 0, NULL
, 0, 0,
344 int UI_dup_error_string(UI
*ui
, const char *text
)
346 char *text_copy
= NULL
;
349 text_copy
= OPENSSL_strdup(text
);
350 if (text_copy
== NULL
) {
351 UIerr(UI_F_UI_DUP_ERROR_STRING
, ERR_R_MALLOC_FAILURE
);
355 return general_allocate_string(ui
, text_copy
, 1, UIT_ERROR
, 0, NULL
,
359 char *UI_construct_prompt(UI
*ui
, const char *object_desc
,
360 const char *object_name
)
364 if (ui
->meth
->ui_construct_prompt
!= NULL
)
365 prompt
= ui
->meth
->ui_construct_prompt(ui
, object_desc
, object_name
);
367 char prompt1
[] = "Enter ";
368 char prompt2
[] = " for ";
369 char prompt3
[] = ":";
372 if (object_desc
== NULL
)
374 len
= sizeof(prompt1
) - 1 + strlen(object_desc
);
375 if (object_name
!= NULL
)
376 len
+= sizeof(prompt2
) - 1 + strlen(object_name
);
377 len
+= sizeof(prompt3
) - 1;
379 if ((prompt
= OPENSSL_malloc(len
+ 1)) == NULL
) {
380 UIerr(UI_F_UI_CONSTRUCT_PROMPT
, ERR_R_MALLOC_FAILURE
);
383 OPENSSL_strlcpy(prompt
, prompt1
, len
+ 1);
384 OPENSSL_strlcat(prompt
, object_desc
, len
+ 1);
385 if (object_name
!= NULL
) {
386 OPENSSL_strlcat(prompt
, prompt2
, len
+ 1);
387 OPENSSL_strlcat(prompt
, object_name
, len
+ 1);
389 OPENSSL_strlcat(prompt
, prompt3
, len
+ 1);
394 void *UI_add_user_data(UI
*ui
, void *user_data
)
396 void *old_data
= ui
->user_data
;
398 if ((ui
->flags
& UI_FLAG_DUPL_DATA
) != 0) {
399 ui
->meth
->ui_destroy_data(ui
, old_data
);
402 ui
->user_data
= user_data
;
403 ui
->flags
&= ~UI_FLAG_DUPL_DATA
;
407 int UI_dup_user_data(UI
*ui
, void *user_data
)
409 void *duplicate
= NULL
;
411 if (ui
->meth
->ui_duplicate_data
== NULL
412 || ui
->meth
->ui_destroy_data
== NULL
) {
413 UIerr(UI_F_UI_DUP_USER_DATA
, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED
);
417 duplicate
= ui
->meth
->ui_duplicate_data(ui
, user_data
);
418 if (duplicate
== NULL
) {
419 UIerr(UI_F_UI_DUP_USER_DATA
, ERR_R_MALLOC_FAILURE
);
423 (void)UI_add_user_data(ui
, duplicate
);
424 ui
->flags
|= UI_FLAG_DUPL_DATA
;
429 void *UI_get0_user_data(UI
*ui
)
431 return ui
->user_data
;
434 const char *UI_get0_result(UI
*ui
, int i
)
437 UIerr(UI_F_UI_GET0_RESULT
, UI_R_INDEX_TOO_SMALL
);
440 if (i
>= sk_UI_STRING_num(ui
->strings
)) {
441 UIerr(UI_F_UI_GET0_RESULT
, UI_R_INDEX_TOO_LARGE
);
444 return UI_get0_result_string(sk_UI_STRING_value(ui
->strings
, i
));
447 int UI_get_result_length(UI
*ui
, int i
)
450 UIerr(UI_F_UI_GET_RESULT_LENGTH
, UI_R_INDEX_TOO_SMALL
);
453 if (i
>= sk_UI_STRING_num(ui
->strings
)) {
454 UIerr(UI_F_UI_GET_RESULT_LENGTH
, UI_R_INDEX_TOO_LARGE
);
457 return UI_get_result_string_length(sk_UI_STRING_value(ui
->strings
, i
));
460 static int print_error(const char *str
, size_t len
, UI
*ui
)
464 memset(&uis
, 0, sizeof(uis
));
465 uis
.type
= UIT_ERROR
;
466 uis
.out_string
= str
;
468 if (ui
->meth
->ui_write_string
!= NULL
469 && ui
->meth
->ui_write_string(ui
, &uis
) <= 0)
474 int UI_process(UI
*ui
)
477 const char *state
= "processing";
479 if (ui
->meth
->ui_open_session
!= NULL
480 && ui
->meth
->ui_open_session(ui
) <= 0) {
481 state
= "opening session";
486 if (ui
->flags
& UI_FLAG_PRINT_ERRORS
)
487 ERR_print_errors_cb((int (*)(const char *, size_t, void *))
488 print_error
, (void *)ui
);
490 for (i
= 0; i
< sk_UI_STRING_num(ui
->strings
); i
++) {
491 if (ui
->meth
->ui_write_string
!= NULL
492 && (ui
->meth
->ui_write_string(ui
,
493 sk_UI_STRING_value(ui
->strings
, i
))
496 state
= "writing strings";
502 if (ui
->meth
->ui_flush
!= NULL
)
503 switch (ui
->meth
->ui_flush(ui
)) {
504 case -1: /* Interrupt/Cancel/something... */
505 ui
->flags
&= ~UI_FLAG_REDOABLE
;
512 default: /* Success */
517 for (i
= 0; i
< sk_UI_STRING_num(ui
->strings
); i
++) {
518 if (ui
->meth
->ui_read_string
!= NULL
) {
519 switch (ui
->meth
->ui_read_string(ui
,
520 sk_UI_STRING_value(ui
->strings
,
522 case -1: /* Interrupt/Cancel/something... */
523 ui
->flags
&= ~UI_FLAG_REDOABLE
;
527 state
= "reading strings";
530 default: /* Success */
539 if (ui
->meth
->ui_close_session
!= NULL
540 && ui
->meth
->ui_close_session(ui
) <= 0) {
542 state
= "closing session";
547 UIerr(UI_F_UI_PROCESS
, UI_R_PROCESSING_ERROR
);
548 ERR_add_error_data(2, "while ", state
);
553 int UI_ctrl(UI
*ui
, int cmd
, long i
, void *p
, void (*f
) (void))
556 UIerr(UI_F_UI_CTRL
, ERR_R_PASSED_NULL_PARAMETER
);
560 case UI_CTRL_PRINT_ERRORS
:
562 int save_flag
= ! !(ui
->flags
& UI_FLAG_PRINT_ERRORS
);
564 ui
->flags
|= UI_FLAG_PRINT_ERRORS
;
566 ui
->flags
&= ~UI_FLAG_PRINT_ERRORS
;
569 case UI_CTRL_IS_REDOABLE
:
570 return ! !(ui
->flags
& UI_FLAG_REDOABLE
);
574 UIerr(UI_F_UI_CTRL
, UI_R_UNKNOWN_CONTROL_COMMAND
);
578 int UI_set_ex_data(UI
*r
, int idx
, void *arg
)
580 return CRYPTO_set_ex_data(&r
->ex_data
, idx
, arg
);
583 void *UI_get_ex_data(const UI
*r
, int idx
)
585 return CRYPTO_get_ex_data(&r
->ex_data
, idx
);
588 const UI_METHOD
*UI_get_method(UI
*ui
)
593 const UI_METHOD
*UI_set_method(UI
*ui
, const UI_METHOD
*meth
)
599 UI_METHOD
*UI_create_method(const char *name
)
601 UI_METHOD
*ui_method
= NULL
;
603 if ((ui_method
= OPENSSL_zalloc(sizeof(*ui_method
))) == NULL
604 || (ui_method
->name
= OPENSSL_strdup(name
)) == NULL
605 || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD
, ui_method
,
606 &ui_method
->ex_data
)) {
608 OPENSSL_free(ui_method
->name
);
609 OPENSSL_free(ui_method
);
610 UIerr(UI_F_UI_CREATE_METHOD
, ERR_R_MALLOC_FAILURE
);
617 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
618 * (that is, it hasn't been allocated using UI_create_method(), you deserve
619 * anything Murphy can throw at you and more! You have been warned.
621 void UI_destroy_method(UI_METHOD
*ui_method
)
623 if (ui_method
== NULL
)
625 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD
, ui_method
,
626 &ui_method
->ex_data
);
627 OPENSSL_free(ui_method
->name
);
628 ui_method
->name
= NULL
;
629 OPENSSL_free(ui_method
);
632 int UI_method_set_opener(UI_METHOD
*method
, int (*opener
) (UI
*ui
))
634 if (method
!= NULL
) {
635 method
->ui_open_session
= opener
;
641 int UI_method_set_writer(UI_METHOD
*method
,
642 int (*writer
) (UI
*ui
, UI_STRING
*uis
))
644 if (method
!= NULL
) {
645 method
->ui_write_string
= writer
;
651 int UI_method_set_flusher(UI_METHOD
*method
, int (*flusher
) (UI
*ui
))
653 if (method
!= NULL
) {
654 method
->ui_flush
= flusher
;
660 int UI_method_set_reader(UI_METHOD
*method
,
661 int (*reader
) (UI
*ui
, UI_STRING
*uis
))
663 if (method
!= NULL
) {
664 method
->ui_read_string
= reader
;
670 int UI_method_set_closer(UI_METHOD
*method
, int (*closer
) (UI
*ui
))
672 if (method
!= NULL
) {
673 method
->ui_close_session
= closer
;
679 int UI_method_set_data_duplicator(UI_METHOD
*method
,
680 void *(*duplicator
) (UI
*ui
, void *ui_data
),
681 void (*destructor
)(UI
*ui
, void *ui_data
))
683 if (method
!= NULL
) {
684 method
->ui_duplicate_data
= duplicator
;
685 method
->ui_destroy_data
= destructor
;
691 int UI_method_set_prompt_constructor(UI_METHOD
*method
,
692 char *(*prompt_constructor
) (UI
*ui
,
698 if (method
!= NULL
) {
699 method
->ui_construct_prompt
= prompt_constructor
;
705 int UI_method_set_ex_data(UI_METHOD
*method
, int idx
, void *data
)
707 return CRYPTO_set_ex_data(&method
->ex_data
, idx
, data
);
710 int (*UI_method_get_opener(const UI_METHOD
*method
)) (UI
*)
713 return method
->ui_open_session
;
717 int (*UI_method_get_writer(const UI_METHOD
*method
)) (UI
*, UI_STRING
*)
720 return method
->ui_write_string
;
724 int (*UI_method_get_flusher(const UI_METHOD
*method
)) (UI
*)
727 return method
->ui_flush
;
731 int (*UI_method_get_reader(const UI_METHOD
*method
)) (UI
*, UI_STRING
*)
734 return method
->ui_read_string
;
738 int (*UI_method_get_closer(const UI_METHOD
*method
)) (UI
*)
741 return method
->ui_close_session
;
745 char *(*UI_method_get_prompt_constructor(const UI_METHOD
*method
))
746 (UI
*, const char *, const char *)
749 return method
->ui_construct_prompt
;
753 void *(*UI_method_get_data_duplicator(const UI_METHOD
*method
)) (UI
*, void *)
756 return method
->ui_duplicate_data
;
760 void (*UI_method_get_data_destructor(const UI_METHOD
*method
)) (UI
*, void *)
763 return method
->ui_destroy_data
;
767 const void *UI_method_get_ex_data(const UI_METHOD
*method
, int idx
)
769 return CRYPTO_get_ex_data(&method
->ex_data
, idx
);
772 enum UI_string_types
UI_get_string_type(UI_STRING
*uis
)
777 int UI_get_input_flags(UI_STRING
*uis
)
779 return uis
->input_flags
;
782 const char *UI_get0_output_string(UI_STRING
*uis
)
784 return uis
->out_string
;
787 const char *UI_get0_action_string(UI_STRING
*uis
)
791 return uis
->_
.boolean_data
.action_desc
;
802 const char *UI_get0_result_string(UI_STRING
*uis
)
807 return uis
->result_buf
;
817 int UI_get_result_string_length(UI_STRING
*uis
)
822 return uis
->result_len
;
832 const char *UI_get0_test_string(UI_STRING
*uis
)
836 return uis
->_
.string_data
.test_buf
;
847 int UI_get_result_minsize(UI_STRING
*uis
)
852 return uis
->_
.string_data
.result_minsize
;
862 int UI_get_result_maxsize(UI_STRING
*uis
)
867 return uis
->_
.string_data
.result_maxsize
;
877 int UI_set_result(UI
*ui
, UI_STRING
*uis
, const char *result
)
879 return UI_set_result_ex(ui
, uis
, result
, strlen(result
));
882 int UI_set_result_ex(UI
*ui
, UI_STRING
*uis
, const char *result
, int len
)
884 ui
->flags
&= ~UI_FLAG_REDOABLE
;
890 char number1
[DECIMAL_SIZE(uis
->_
.string_data
.result_minsize
) + 1];
891 char number2
[DECIMAL_SIZE(uis
->_
.string_data
.result_maxsize
) + 1];
893 BIO_snprintf(number1
, sizeof(number1
), "%d",
894 uis
->_
.string_data
.result_minsize
);
895 BIO_snprintf(number2
, sizeof(number2
), "%d",
896 uis
->_
.string_data
.result_maxsize
);
898 if (len
< uis
->_
.string_data
.result_minsize
) {
899 ui
->flags
|= UI_FLAG_REDOABLE
;
900 UIerr(UI_F_UI_SET_RESULT_EX
, UI_R_RESULT_TOO_SMALL
);
901 ERR_add_error_data(5, "You must type in ",
902 number1
, " to ", number2
, " characters");
905 if (len
> uis
->_
.string_data
.result_maxsize
) {
906 ui
->flags
|= UI_FLAG_REDOABLE
;
907 UIerr(UI_F_UI_SET_RESULT_EX
, UI_R_RESULT_TOO_LARGE
);
908 ERR_add_error_data(5, "You must type in ",
909 number1
, " to ", number2
, " characters");
914 if (uis
->result_buf
== NULL
) {
915 UIerr(UI_F_UI_SET_RESULT_EX
, UI_R_NO_RESULT_BUFFER
);
919 memcpy(uis
->result_buf
, result
, len
);
920 if (len
<= uis
->_
.string_data
.result_maxsize
)
921 uis
->result_buf
[len
] = '\0';
922 uis
->result_len
= len
;
928 if (uis
->result_buf
== NULL
) {
929 UIerr(UI_F_UI_SET_RESULT_EX
, UI_R_NO_RESULT_BUFFER
);
933 uis
->result_buf
[0] = '\0';
934 for (p
= result
; *p
; p
++) {
935 if (strchr(uis
->_
.boolean_data
.ok_chars
, *p
)) {
936 uis
->result_buf
[0] = uis
->_
.boolean_data
.ok_chars
[0];
939 if (strchr(uis
->_
.boolean_data
.cancel_chars
, *p
)) {
940 uis
->result_buf
[0] = uis
->_
.boolean_data
.cancel_chars
[0];