@@ -1608,12 +1608,13 @@ static bool read_with_prompt(
1608
1608
static struct promptset_T promptset_for_read (
1609
1609
bool firstline , const struct reading_option_T * ro )
1610
1610
__attribute__((nonnull ,warn_unused_result ));
1611
- static wchar_t * read_one_line_with_prompt (
1612
- struct promptset_T prompt , bool lineedit )
1613
- __attribute__((malloc ,warn_unused_result ));
1614
- static wchar_t * read_one_line (void )
1615
- __attribute__((malloc ,warn_unused_result ));
1616
- static bool unescape_line (const wchar_t * line , xwcsbuf_T * buf , xstrbuf_T * cc )
1611
+ static xwcsbuf_T read_one_line_with_prompt (
1612
+ struct promptset_T prompt , wchar_t delimiter , bool lineedit )
1613
+ __attribute__((warn_unused_result ));
1614
+ static xwcsbuf_T read_one_line (wchar_t delimiter )
1615
+ __attribute__((warn_unused_result ));
1616
+ static bool unescape_line (
1617
+ const xwcsbuf_T * line , xwcsbuf_T * buf , xstrbuf_T * cc , wchar_t delimiter )
1617
1618
__attribute__((nonnull ));
1618
1619
static void assign_array (const wchar_t * name , const plist_T * ranges , size_t i )
1619
1620
__attribute__((nonnull ));
@@ -2843,30 +2844,37 @@ int read_builtin(int argc, void **argv)
2843
2844
bool read_with_prompt (
2844
2845
xwcsbuf_T * buf , xstrbuf_T * cc , const struct reading_option_T * ro )
2845
2846
{
2847
+ if (wcslen (ro -> delimiter ) > 1 ) {
2848
+ xerror (0 , Ngt ("multi-character delimiter is not supported" ));
2849
+ return false;
2850
+ }
2851
+ wchar_t delimiter = ro -> delimiter [0 ];
2852
+
2846
2853
bool firstline = true;
2847
2854
bool completed = false;
2848
2855
bool use_prompt = is_interactive_now && isatty (STDIN_FILENO );
2849
2856
2850
2857
while (!completed ) {
2851
- wchar_t * line ;
2858
+ xwcsbuf_T line ;
2852
2859
if (use_prompt ) {
2853
2860
struct promptset_T prompt = promptset_for_read (firstline , ro );
2854
- line = read_one_line_with_prompt (prompt , ro -> lineedit );
2861
+ line = read_one_line_with_prompt (prompt , delimiter , ro -> lineedit );
2855
2862
free_prompt (prompt );
2856
2863
} else {
2857
- line = read_one_line ();
2864
+ line = read_one_line (delimiter );
2858
2865
}
2859
- if (line == NULL )
2866
+ if (line . contents == NULL )
2860
2867
return false;
2861
2868
2862
2869
if (ro -> raw ) {
2863
- wb_cat (buf , line );
2864
- sb_ccat_repeat (cc , CC_SOFT_EXPANSION , wcslen ( line ) );
2870
+ wb_cat (buf , line . contents );
2871
+ sb_ccat_repeat (cc , CC_SOFT_EXPANSION , line . length );
2865
2872
completed = true;
2866
2873
} else {
2867
- completed = unescape_line (line , buf , cc );
2874
+ completed =
2875
+ line .length == 0 || unescape_line (& line , buf , cc , delimiter );
2868
2876
}
2869
- free ( line );
2877
+ wb_destroy ( & line );
2870
2878
2871
2879
firstline = false;
2872
2880
}
@@ -2892,23 +2900,28 @@ struct promptset_T promptset_for_read(
2892
2900
2893
2901
/* Reads one line from the standard input with the specified prompt.
2894
2902
* If `lineedit' is true, use line-editing if possible.
2895
- * The result is returned as a newly-malloced wide string. The result is null
2896
- * iff an error occurs. */
2897
- wchar_t * read_one_line_with_prompt (struct promptset_T prompt , bool lineedit )
2903
+ * The result is returned as a wide string buffer. The buffer contents are NULL
2904
+ * if an error occurs. */
2905
+ xwcsbuf_T read_one_line_with_prompt (
2906
+ struct promptset_T prompt , wchar_t delimiter , bool lineedit )
2898
2907
{
2899
- wchar_t * line ;
2908
+ xwcsbuf_T buf ;
2900
2909
2901
2910
if (lineedit ) {
2902
2911
#if YASH_ENABLE_LINEEDIT
2903
- if (shopt_lineedit != SHOPT_NOLINEEDIT ) {
2912
+ if (delimiter == L'\n' && shopt_lineedit != SHOPT_NOLINEEDIT ) {
2913
+ wchar_t * line ;
2904
2914
switch (le_readline (prompt , false, & line )) {
2905
2915
case INPUT_OK :
2906
- return line ;
2916
+ wb_initwith (& buf , line );
2917
+ return buf ;
2907
2918
case INPUT_EOF :
2908
- return xwcsdup (L"" );
2919
+ wb_init (& buf );
2920
+ return buf ;
2909
2921
case INPUT_INTERRUPTED :
2910
2922
set_interrupted ();
2911
- return NULL ;
2923
+ buf .contents = NULL ;
2924
+ return buf ;
2912
2925
case INPUT_ERROR :
2913
2926
break ;
2914
2927
}
@@ -2919,58 +2932,58 @@ wchar_t *read_one_line_with_prompt(struct promptset_T prompt, bool lineedit)
2919
2932
print_prompt (prompt .main );
2920
2933
print_prompt (prompt .styler );
2921
2934
2922
- line = read_one_line ();
2935
+ buf = read_one_line (delimiter );
2923
2936
2924
2937
print_prompt (PROMPT_RESET );
2925
2938
2926
- return line ;
2939
+ return buf ;
2927
2940
}
2928
2941
2929
2942
/* Reads one line from the standard input without printing any prompt or using
2930
2943
* line-editing.
2931
2944
* The result is returned as a newly-malloced wide string. The result is null
2932
2945
* iff an error occurs. */
2933
- wchar_t * read_one_line (void )
2946
+ xwcsbuf_T read_one_line (wchar_t delimiter )
2934
2947
{
2935
2948
xwcsbuf_T buf ;
2936
2949
wb_init (& buf );
2937
- if (read_input (& buf , stdin_input_file_info , false) != INPUT_ERROR )
2938
- return wb_towcs (& buf );
2939
- wb_destroy (& buf );
2940
- return NULL ;
2950
+
2951
+ inputresult_T result =
2952
+ read_input_delimited (& buf , stdin_input_file_info , false, delimiter );
2953
+
2954
+ if (result == INPUT_ERROR ) {
2955
+ wb_destroy (& buf );
2956
+ buf .contents = NULL ;
2957
+ }
2958
+ return buf ;
2941
2959
}
2942
2960
2943
2961
/* Parses a string that may contain backslash escapes.
2944
2962
* Unescaped `line' is appended to `buf' with a corresponding charcategory_T
2945
2963
* string appended to `cc'.
2946
- * The result is false iff `line' ends with a line continuation.
2947
- * The line continuation is not appended to `buf'. */
2948
- bool unescape_line (const wchar_t * line , xwcsbuf_T * buf , xstrbuf_T * cc )
2949
- {
2950
- for (;;) {
2951
- bool splitchar ;
2952
-
2953
- switch (* line ) {
2954
- case L'\0' :
2955
- return true;
2956
- case L'\\' :
2957
- line ++ ;
2958
- switch (* line ) {
2959
- case L'\0' :
2960
- return true;
2961
- case L'\n' :
2962
- return false;
2963
- }
2964
- splitchar = false;
2965
- break ;
2966
- default :
2967
- splitchar = true;
2964
+ * The result is false iff the read built-in should read the next line, that is,
2965
+ * the line does not end with an unescaped delimiter.
2966
+ * Line continuations are skipped and not appended to `buf' or `cc'. */
2967
+ bool unescape_line (
2968
+ const xwcsbuf_T * line , xwcsbuf_T * buf , xstrbuf_T * cc , wchar_t delimiter )
2969
+ {
2970
+ for (size_t i = 0 ; i < line -> length ; i ++ ) {
2971
+ if (line -> contents [i ] == L'\\' ) {
2972
+ i ++ ;
2973
+ if (i == line -> length )
2968
2974
break ;
2975
+ if (line -> contents [i ] == L'\n' )
2976
+ continue ;
2977
+ wb_wccat (buf , line -> contents [i ]);
2978
+ sb_ccat (cc , CC_SOFT_EXPANSION | CC_QUOTED );
2979
+ } else {
2980
+ wb_wccat (buf , line -> contents [i ]);
2981
+ sb_ccat (cc , CC_SOFT_EXPANSION );
2982
+ if (line -> contents [i ] == delimiter )
2983
+ return true;
2969
2984
}
2970
- wb_wccat (buf , * line );
2971
- sb_ccat (cc , CC_SOFT_EXPANSION | (splitchar ? 0 : CC_QUOTED ));
2972
- line ++ ;
2973
2985
}
2986
+ return false;
2974
2987
}
2975
2988
2976
2989
/* Assigns a result of field-splitting contained in `ranges' to an array named
0 commit comments