*** ../bash-3.2-patched/builtins/read.def 2007-08-25 13:47:07.000000000 -0400 --- builtins/read.def 2008-02-09 16:34:39.000000000 -0500 *************** *** 1,7 **** This file is read.def, from which is created read.c. It implements the builtin "read" in Bash. ! Copyright (C) 1987-2005 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. --- 1,7 ---- This file is read.def, from which is created read.c. It implements the builtin "read" in Bash. ! Copyright (C) 1987-2008 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. *************** *** 23,50 **** $BUILTIN read $FUNCTION read_builtin ! $SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...] ! One line is read from the standard input, or from file descriptor FD if the ! -u option is supplied, and the first word is assigned to the first NAME, ! the second word to the second NAME, and so on, with leftover words assigned ! to the last NAME. Only the characters found in $IFS are recognized as word ! delimiters. If no NAMEs are supplied, the line read is stored in the REPLY ! variable. If the -r option is given, this signifies `raw' input, and ! backslash escaping is disabled. The -d option causes read to continue ! until the first character of DELIM is read, rather than newline. If the -p ! option is supplied, the string PROMPT is output without a trailing newline ! before attempting to read. If -a is supplied, the words read are assigned ! to sequential indices of ARRAY, starting at zero. If -e is supplied and ! the shell is interactive, readline is used to obtain the line. If -n is ! supplied with a non-zero NCHARS argument, read returns after NCHARS ! characters have been read. The -s option causes input coming from a ! terminal to not be echoed. ! ! The -t option causes read to time out and return failure if a complete line ! of input is not read within TIMEOUT seconds. If the TMOUT variable is set, ! its value is the default timeout. The return code is zero, unless end-of-file ! is encountered, read times out, or an invalid file descriptor is supplied as ! the argument to -u. $END #include --- 23,57 ---- $BUILTIN read $FUNCTION read_builtin ! $SHORT_DOC read [-ers] [-a array] [-d delim] [-n nchars] [-p prompt] [-t timeout] [-u fd] [name ...] ! Reads a single line from the standard input, or from file descriptor FD ! if the -u option is supplied. The line is split into fields as with word ! splitting, and the first word is assigned to the first NAME, the second ! word to the second NAME, and so on, with any leftover words assigned to ! the last NAME. Only the characters found in $IFS are recognized as word ! delimiters. ! ! If no NAMEs are supplied, the line read is stored in the REPLY variable. ! ! Options: ! -a array assign the words read to sequential indices of the array ! variable ARRAY, starting at zero ! -d delim continue until the first character of DELIM is read, rather ! than newline ! -e use Readline to obtain the line in an interactive shell ! -n nchars return after reading NCHARS characters rather than waiting ! for a newline ! -p prompt output the string PROMPT without a trailing newline before ! attempting to read ! -r do not allow backslashes to escape any characters ! -s do not echo input coming from a terminal ! -t timeout time out and return failure if a complete line of input is ! not read withint TIMEOUT seconds. The value of the TMOUT ! variable is the default timeout. ! -u fd read from file descriptor FD instead of the standard input ! ! The return code is zero, unless end-of-file is encountered, read times out, ! or an invalid file descriptor is supplied as the argument to -u. $END #include *************** *** 87,92 **** --- 94,105 ---- extern int errno; #endif + struct ttsave + { + int fd; + TTYSTRUCT *attrs; + }; + #if defined (READLINE) static void reset_attempted_completion_function __P((char *)); static char *edit_line __P((char *)); *************** *** 94,99 **** --- 107,116 ---- static void reset_eol_delim __P((char *)); #endif static SHELL_VAR *bind_read_variable __P((char *, char *)); + #if defined (HANDLE_MULTIBYTE) + static int read_mbchar __P((int, char *, int, int, int)); + #endif + static void ttyrestore __P((struct ttsave *)); static sighandler sigalrm __P((int)); static void reset_alarm __P((void)); *************** *** 134,142 **** intmax_t intval; char c; char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname; ! char *e, *t, *t1, *ps2; struct stat tsb; SHELL_VAR *var; #if defined (ARRAY_VARS) WORD_LIST *alist; #endif --- 151,161 ---- intmax_t intval; char c; char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname; ! char *e, *t, *t1, *ps2, *tofree; struct stat tsb; SHELL_VAR *var; + TTYSTRUCT ttattrs, ttset; + struct ttsave termsave; #if defined (ARRAY_VARS) WORD_LIST *alist; #endif *************** *** 263,268 **** --- 282,289 ---- ifs_chars = getifs (); if (ifs_chars == 0) /* XXX - shouldn't happen */ ifs_chars = ""; + for (skip_ctlesc = skip_ctlnul = 0, e = ifs_chars; *e; e++) + skip_ctlesc |= *e == CTLESC, skip_ctlnul |= *e == CTLNUL; input_string = (char *)xmalloc (size = 112); /* XXX was 128 */ *************** *** 326,333 **** --- 347,359 ---- code = setjmp (alrmbuf); if (code) { + #if 0 run_unwind_frame ("read_builtin"); return (EXECUTION_FAILURE); + #else + retval = EXECUTION_FAILURE; + goto assign_vars; + #endif } old_alrm = set_signal_handler (SIGALRM, sigalrm); add_unwind_protect (reset_alarm, (char *)NULL); *************** *** 361,379 **** #endif if (input_is_tty) { ! ttsave (); if (silent) ! ttcbreak (); else ! ttonechar (); ! add_unwind_protect ((Function *)ttrestore, (char *)NULL); } } else if (silent) /* turn off echo but leave term in canonical mode */ { ! ttsave (); ! ttnoecho (); ! add_unwind_protect ((Function *)ttrestore, (char *)NULL); } /* This *must* be the top unwind-protect on the stack, so the manipulation --- 387,416 ---- #endif if (input_is_tty) { ! /* ttsave() */ ! termsave.fd = fd; ! ttgetattr (fd, &ttattrs); ! termsave.attrs = &ttattrs; ! ! ttset = ttattrs; if (silent) ! ttfd_cbreak (fd, &ttset); /* ttcbreak () */ else ! ttfd_onechar (fd, &ttset); /* ttonechar () */ ! add_unwind_protect ((Function *)ttyrestore, (char *)&termsave); } } else if (silent) /* turn off echo but leave term in canonical mode */ { ! /* ttsave (); */ ! termsave.fd = fd; ! ttgetattr (fd, &ttattrs); ! termsave.attrs = &ttattrs; ! ! ttset = ttattrs; ! ttfd_noecho (fd, &ttset); /* ttnoecho (); */ ! ! add_unwind_protect ((Function *)ttyrestore, (char *)&termsave); } /* This *must* be the top unwind-protect on the stack, so the manipulation *************** *** 439,445 **** } #endif ! if (i + 2 >= size) { input_string = (char *)xrealloc (input_string, size += 128); remove_unwind_protect (); --- 476,482 ---- } #endif ! if (i + 4 >= size) /* XXX was i + 2; use i + 4 for multibyte/read_mbchar */ { input_string = (char *)xrealloc (input_string, size += 128); remove_unwind_protect (); *************** *** 462,479 **** continue; } if (c == '\\' && raw == 0) { pass_next++; ! saw_escape++; ! input_string[i++] = CTLESC; continue; } if ((unsigned char)c == delim) break; ! if (c == CTLESC || c == CTLNUL) { saw_escape++; input_string[i++] = CTLESC; --- 499,520 ---- continue; } + /* This may cause problems if IFS contains CTLESC */ if (c == '\\' && raw == 0) { pass_next++; ! if (skip_ctlesc == 0) ! { ! saw_escape++; ! input_string[i++] = CTLESC; ! } continue; } if ((unsigned char)c == delim) break; ! if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL)) { saw_escape++; input_string[i++] = CTLESC; *************** *** 481,486 **** --- 522,536 ---- add_char: input_string[i++] = c; + + #if defined (HANDLE_MULTIBYTE) + if (nchars > 0 && MB_CUR_MAX > 1) + { + input_string[i] = '\0'; /* for simplicity and debugging */ + i += read_mbchar (fd, input_string, i, c, unbuffered_read); + } + #endif + nr++; if (nchars > 0 && nr >= nchars) *************** *** 513,522 **** else #endif if (input_is_tty) ! ttrestore (); } else if (silent) ! ttrestore (); if (unbuffered_read == 0) zsyncfd (fd); --- 563,572 ---- else #endif if (input_is_tty) ! ttyrestore (&termsave); } else if (silent) ! ttyrestore (&termsave); if (unbuffered_read == 0) zsyncfd (fd); *************** *** 527,532 **** --- 577,584 ---- retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS; + assign_vars: + #if defined (ARRAY_VARS) /* If -a was given, take the string read, break it into a list of words, an assign them to `arrayname' in turn. */ *************** *** 603,609 **** for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++) ; input_string = t; - for (; list->next; list = list->next) { varname = list->word->word; --- 655,660 ---- *************** *** 674,685 **** #else /* Check whether or not the number of fields is exactly the same as the number of variables. */ if (*input_string) { t1 = input_string; t = get_word_from_string (&input_string, ifs_chars, &e); if (*input_string == 0) ! input_string = t; else input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape); } --- 725,737 ---- #else /* Check whether or not the number of fields is exactly the same as the number of variables. */ + tofree = NULL; if (*input_string) { t1 = input_string; t = get_word_from_string (&input_string, ifs_chars, &e); if (*input_string == 0) ! tofree = input_string = t; else input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape); } *************** *** 694,699 **** --- 746,753 ---- else var = bind_read_variable (list->word->word, input_string); stupidly_hack_special_variables (list->word->word); + FREE (tofree); + if (var) VUNSETATTR (var, att_invisible); xfree (orig_input_string); *************** *** 715,720 **** --- 769,830 ---- #endif /* !ARRAY_VARS */ } + #if defined (HANDLE_MULTIBYTE) + static int + read_mbchar (fd, string, ind, ch, unbuffered) + int fd; + char *string; + int ind, ch, unbuffered; + { + char mbchar[MB_LEN_MAX + 1]; + int i, n, r; + char c; + size_t ret; + mbstate_t ps, ps_back; + wchar_t wc; + + memset (&ps, '\0', sizeof (mbstate_t)); + memset (&ps_back, '\0', sizeof (mbstate_t)); + + mbchar[0] = ch; + i = 1; + for (n = 0; n <= MB_LEN_MAX; n++) + { + ps_back = ps; + ret = mbrtowc (&wc, mbchar, i, &ps); + if (ret == (size_t)-2) + { + ps = ps_back; + if (unbuffered) + r = zread (fd, &c, 1); + else + r = zreadc (fd, &c); + if (r < 0) + goto mbchar_return; + mbchar[i++] = c; + continue; + } + else if (ret == (size_t)-1 || ret == (size_t)0 || ret > (size_t)0) + break; + } + + mbchar_return: + if (i > 1) /* read a multibyte char */ + /* mbchar[0] is already string[ind-1] */ + for (r = 1; r < i; r++) + string[ind+r-1] = mbchar[r]; + return i - 1; + } + #endif + + + static void + ttyrestore (ttp) + struct ttsave *ttp; + { + ttsetattr (ttp->fd, ttp->attrs); + } + #if defined (READLINE) static rl_completion_func_t *old_attempted_completion_function = 0;