Skip to content

Commit ab600e2

Browse files
committed
WIP: Apply delimiter to read built-in
1 parent 42b76c3 commit ab600e2

File tree

3 files changed

+80
-55
lines changed

3 files changed

+80
-55
lines changed

input.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ inputresult_T input_file(struct xwcsbuf_T *buf, void *inputinfo)
110110
* INPUT_ERROR if an error occurred before reading any characters */
111111
inputresult_T read_input(
112112
xwcsbuf_T *buf, struct input_file_info_T *info, bool trap)
113+
{
114+
return read_input_delimited(buf, info, trap, L'\n');
115+
}
116+
117+
/* Like `read_input', but reads input until a delimiter character is found. */
118+
inputresult_T read_input_delimited(
119+
xwcsbuf_T *buf, struct input_file_info_T *info, bool trap,
120+
wchar_t delimiter)
113121
{
114122
if (info->bufsize == 1 && is_seekable_file(info->fd))
115123
return optimized_read_input(buf, info, trap);
@@ -170,7 +178,7 @@ inputresult_T read_input(
170178
default:
171179
info->bufpos += convcount;
172180
buf->contents[++buf->length] = L'\0';
173-
if (buf->contents[buf->length - 1] == L'\n')
181+
if (buf->contents[buf->length - 1] == delimiter)
174182
goto end;
175183
break;
176184
}

input.h

+4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ struct input_file_info_T;
5959
extern inputresult_T read_input(
6060
struct xwcsbuf_T *buf, struct input_file_info_T *info, _Bool trap)
6161
__attribute__((nonnull));
62+
extern inputresult_T read_input_delimited(
63+
struct xwcsbuf_T *buf, struct input_file_info_T *info, _Bool trap,
64+
wchar_t delimiter)
65+
__attribute__((nonnull));
6266

6367
/* The type of input functions.
6468
* An input function reads input and appends it to buffer `buf'.

variable.c

+67-54
Original file line numberDiff line numberDiff line change
@@ -1608,12 +1608,13 @@ static bool read_with_prompt(
16081608
static struct promptset_T promptset_for_read(
16091609
bool firstline, const struct reading_option_T *ro)
16101610
__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)
16171618
__attribute__((nonnull));
16181619
static void assign_array(const wchar_t *name, const plist_T *ranges, size_t i)
16191620
__attribute__((nonnull));
@@ -2843,30 +2844,37 @@ int read_builtin(int argc, void **argv)
28432844
bool read_with_prompt(
28442845
xwcsbuf_T *buf, xstrbuf_T *cc, const struct reading_option_T *ro)
28452846
{
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+
28462853
bool firstline = true;
28472854
bool completed = false;
28482855
bool use_prompt = is_interactive_now && isatty(STDIN_FILENO);
28492856

28502857
while (!completed) {
2851-
wchar_t *line;
2858+
xwcsbuf_T line;
28522859
if (use_prompt) {
28532860
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);
28552862
free_prompt(prompt);
28562863
} else {
2857-
line = read_one_line();
2864+
line = read_one_line(delimiter);
28582865
}
2859-
if (line == NULL)
2866+
if (line.contents == NULL)
28602867
return false;
28612868

28622869
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);
28652872
completed = true;
28662873
} else {
2867-
completed = unescape_line(line, buf, cc);
2874+
completed =
2875+
line.length == 0 || unescape_line(&line, buf, cc, delimiter);
28682876
}
2869-
free(line);
2877+
wb_destroy(&line);
28702878

28712879
firstline = false;
28722880
}
@@ -2892,23 +2900,28 @@ struct promptset_T promptset_for_read(
28922900

28932901
/* Reads one line from the standard input with the specified prompt.
28942902
* 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)
28982907
{
2899-
wchar_t *line;
2908+
xwcsbuf_T buf;
29002909

29012910
if (lineedit) {
29022911
#if YASH_ENABLE_LINEEDIT
2903-
if (shopt_lineedit != SHOPT_NOLINEEDIT) {
2912+
if (delimiter == L'\n' && shopt_lineedit != SHOPT_NOLINEEDIT) {
2913+
wchar_t *line;
29042914
switch (le_readline(prompt, false, &line)) {
29052915
case INPUT_OK:
2906-
return line;
2916+
wb_initwith(&buf, line);
2917+
return buf;
29072918
case INPUT_EOF:
2908-
return xwcsdup(L"");
2919+
wb_init(&buf);
2920+
return buf;
29092921
case INPUT_INTERRUPTED:
29102922
set_interrupted();
2911-
return NULL;
2923+
buf.contents = NULL;
2924+
return buf;
29122925
case INPUT_ERROR:
29132926
break;
29142927
}
@@ -2919,58 +2932,58 @@ wchar_t *read_one_line_with_prompt(struct promptset_T prompt, bool lineedit)
29192932
print_prompt(prompt.main);
29202933
print_prompt(prompt.styler);
29212934

2922-
line = read_one_line();
2935+
buf = read_one_line(delimiter);
29232936

29242937
print_prompt(PROMPT_RESET);
29252938

2926-
return line;
2939+
return buf;
29272940
}
29282941

29292942
/* Reads one line from the standard input without printing any prompt or using
29302943
* line-editing.
29312944
* The result is returned as a newly-malloced wide string. The result is null
29322945
* iff an error occurs. */
2933-
wchar_t *read_one_line(void)
2946+
xwcsbuf_T read_one_line(wchar_t delimiter)
29342947
{
29352948
xwcsbuf_T buf;
29362949
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;
29412959
}
29422960

29432961
/* Parses a string that may contain backslash escapes.
29442962
* Unescaped `line' is appended to `buf' with a corresponding charcategory_T
29452963
* 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)
29682974
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;
29692984
}
2970-
wb_wccat(buf, *line);
2971-
sb_ccat(cc, CC_SOFT_EXPANSION | (splitchar ? 0 : CC_QUOTED));
2972-
line++;
29732985
}
2986+
return false;
29742987
}
29752988

29762989
/* Assigns a result of field-splitting contained in `ranges' to an array named

0 commit comments

Comments
 (0)