]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
more changes to avoid expanding associative array subscripts twice; internal debuggin...
authorChet Ramey <chet.ramey@case.edu>
Wed, 22 Dec 2021 21:05:39 +0000 (16:05 -0500)
committerChet Ramey <chet.ramey@case.edu>
Wed, 22 Dec 2021 21:05:39 +0000 (16:05 -0500)
27 files changed:
CWRU/CWRU.chlog
MANIFEST
arrayfunc.c
builtins/command.def
builtins/common.c
builtins/evalstring.c
doc/bash.1
doc/bashref.texi
error.c
error.h
execute_cmd.c
jobs.c
parse.y
po/zh_CN.gmo
po/zh_CN.po
subst.c
tests/RUN-ONE-TEST
tests/assoc.right
tests/assoc.tests
tests/assoc16.sub [new file with mode: 0644]
tests/comsub5.sub
tests/heredoc.right
tests/heredoc.tests
tests/heredoc7.sub [new file with mode: 0644]
trap.c
unwind_prot.c
variables.c

index fc00c5a055fefefe32a27077c5fe2b3dd8612eb0..fe24b64173085e973e51f689181b4446aec6b026 100644 (file)
@@ -2737,3 +2737,55 @@ parse.y
        - parse_comsub: make sure the first call to shell_getc to check whether
          or not it's an arithmetic expansion skips a quoted newline. From a
          report by Robert Elz <kre@munnari.OZ.AU>
+
+                                  12/21
+                                  -----
+subst.c
+       - parameter_brace_remove_pattern,parameter_brace_patsub,parameter_brace_casemod,
+         parameter_brace_transform,parameter_brace_substring: now take an
+         array_eltstate_t * argument in place of the arrayind_t argument, pass
+         it to get_var_and_type; this generalizes the indexed array behavior
+         of expanding array subscripts once to associative arrays via an
+         eventual call to array_value_internal with a non-null KEY member
+       - get_var_and_type: now takes an array_eltstate_t * argument in place
+         of the arrayind_t argument; use it in calls to array_value so we
+         can only expand array subscripts once whether they are indexed or
+         associative arrays
+       - parameter_brace_expand_word: take an array_eltstate_t * argument in
+         place of the arrayind_t * argument; pass it to array_value; use a
+         static version (which we init and flush) if the argument passed is
+         NULL so we can get the right state passed back and forth
+       - parameter_brace_expand: pass a pointer to a static array_eltstate_t
+         to parameter_brace_expand_word, and use that in the various calls to
+         parameter_brace_XXX functions that perform specific expansions in
+         place of the old arrayind_t argument; make sure to flush it before
+         returning, even on errors
+
+                                  12/22
+                                  -----
+{trap,variables}.c
+       - internal_warning: calls changed to use translatable strings
+         consistently
+
+error.[ch]
+       - internal_debug: new function, prints a message like internal_warning,
+         no-op if DEBUG is not defined
+       - INTERNAL_DEBUG: macro that expands to internal_debug when DEBUG is
+         defined, and nothing otherwise
+
+{jobs,trap}.c
+       - changed some internal_warning and internal_inform calls to use
+         internal_debug, since they were active only when DEBUG is defined
+
+parse.y
+       - parse_comsub: add internal_debug call when a command substitution
+         ends with unterminated here-documents
+
+builtins/common.c
+       - number_of_args: unconditionally return posparam_count
+
+{jobs,execute_cmd,subst}.c,parse.y,builtins/{command.def,evalstring.c}
+       - INTERNAL_DEBUG: use instead of calls to itrace protected by #ifdef
+         DEBUG
+
+
index 0e1bd57105bf5702b46cad272ba6f585fbde5b9d..2111707170c5f7b25aac7382427f67f4b18c9ac9 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -953,6 +953,7 @@ tests/assoc12.sub   f
 tests/assoc13.sub      f
 tests/assoc14.sub      f
 tests/assoc15.sub      f
+tests/assoc16.sub      f
 tests/attr.tests       f
 tests/attr.right       f
 tests/attr1.sub                f
@@ -1157,6 +1158,7 @@ tests/heredoc3.sub        f
 tests/heredoc4.sub     f
 tests/heredoc5.sub     f
 tests/heredoc6.sub     f
+tests/heredoc7.sub     f
 tests/herestr.tests    f
 tests/herestr.right    f
 tests/herestr1.sub     f
index 7b6feb52f28641e95d11cc60896344ac4d50fb65..11b03ca96119c945408a8ed42530b9eb77154992 100644 (file)
@@ -1556,8 +1556,6 @@ array_value_internal (s, quoted, flags, estatep)
        }
       else if (assoc_p (var))
        {
-if (flags & AV_USEIND)
-  itrace("array_value_internal: %s: assoc var with AV_USEIND: %s", dollar_vars[0], s);
          t[len - 1] = '\0';
          if (estatep)
            estatep->type = ARRAY_ASSOC;
index acd46cc1be0062d1ca15777821e1b309645bdb3e..3efdbe6bcb434ac7679ec0674ea2e579015e533c 100644 (file)
@@ -124,9 +124,7 @@ command_builtin (list)
 
 #define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN | (use_standard_path ? CMD_STDPATH : 0))
 
-#ifdef DEBUG
-  itrace("command_builtin: running execute_command for `%s'", list->word->word);
-#endif
+  INTERNAL_DEBUG (("command_builtin: running execute_command for `%s'", list->word->word));
 
   /* We don't want this to be reparsed (consider command echo 'foo &'), so
      just make a simple_command structure and call execute_command with it. */
index f703011895a6bc6120456faf34fb612f847b18af..e168d875e43bdd1599cdbf8552f0895aae7952ce 100644 (file)
@@ -458,7 +458,7 @@ shift_args (times)
 int
 number_of_args ()
 {
-#ifdef DEBUG
+#if 0
   register WORD_LIST *list;
   int n;
 
@@ -469,9 +469,9 @@ number_of_args ()
 
 if (n != posparam_count)
   itrace("number_of_args: n (%d) != posparam_count (%d)", n, posparam_count);
-#endif
-
+#else
   return posparam_count;
+#endif
 }
 
 static int changed_dollar_vars;
index 59c0fad19c3f9d13b52788bf0d087611be8f4681..3801a7a07800897183a5d90d5a406954315413e1 100644 (file)
@@ -614,9 +614,8 @@ parse_string (string, from_file, flags, cmdp, endp)
 
       if (code)
        {
-#if defined (DEBUG)
-itrace("parse_string: longjmp executed: code = %d", code);
-#endif
+         INTERNAL_DEBUG(("parse_string: longjmp executed: code = %d", code));
+
          should_jump_to_top_level = 0;
          switch (code)
            {
index 43fc4530302d0ce74cfd013c1cf1274fe884f9fb..34a01f468f36bbded291915aeda0f2f69175e879 100644 (file)
@@ -9953,7 +9953,9 @@ Exit after reading and executing one command.
 .TP 8
 .B \-u
 Treat unset variables and parameters other than the special
-parameters "@" and "*" as an error when performing
+parameters "@" and "*",
+or array variables subscripted with "@" or "*",
+as an error when performing
 parameter expansion.  If expansion is attempted on an
 unset variable or parameter, the shell prints an error message, and,
 if not interactive, exits with a non-zero status.
index f831ff049ab86b37c16644c35832ec25c270ca27..df64c302705288ca4dfb180a13143ec94cf606f5 100644 (file)
@@ -5370,7 +5370,9 @@ Exit after reading and executing one command.
 
 @item -u
 Treat unset variables and parameters other than the special parameters
-@samp{@@} or @samp{*} as an error when performing parameter expansion.
+@samp{@@} or @samp{*},
+or array variables subscripted with @samp{@@} or @samp{*},
+as an error when performing parameter expansion.
 An error message will be written to the standard error, and a non-interactive
 shell will exit.
 
diff --git a/error.c b/error.c
index b0ac7950fd4ec900cb4e669f61e421d9d3aec943..3e7a2d6170df22c56d115a76637714c3e42bb959 100644 (file)
--- a/error.c
+++ b/error.c
@@ -294,6 +294,32 @@ internal_inform (format, va_alist)
   va_end (args);
 }
 
+void
+#if defined (PREFER_STDARG)
+internal_debug (const char *format, ...)
+#else
+internal_debug (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+#ifdef DEBUG
+  va_list args;
+
+  error_prolog (1);
+  fprintf (stderr, _("DEBUG warning: "));
+
+  SH_VA_START (args, format);
+
+  vfprintf (stderr, format, args);
+  fprintf (stderr, "\n");
+
+  va_end (args);
+#else
+  return;
+#endif
+}
+
 void
 #if defined (PREFER_STDARG)
 sys_error (const char *format, ...)
diff --git a/error.h b/error.h
index 30828095b13b51eabbc59a2d406b35bdcd3ade5f..785c1deb5a9f80ab39eee3d5d02aea3af4eb6293 100644 (file)
--- a/error.h
+++ b/error.h
@@ -50,6 +50,9 @@ extern void internal_error PARAMS((const char *, ...))  __attribute__((__format_
 /* Report an internal warning. */
 extern void internal_warning PARAMS((const char *, ...))  __attribute__((__format__ (printf, 1, 2)));
 
+/* Report an internal warning for debugging purposes. */
+extern void internal_debug PARAMS((const char *, ...))  __attribute__((__format__ (printf, 1, 2)));
+
 /* Report an internal informational notice. */
 extern void internal_inform PARAMS((const char *, ...))  __attribute__((__format__ (printf, 1, 2)));
 
@@ -70,4 +73,10 @@ extern void err_badarraysub PARAMS((const char *));
 extern void err_unboundvar PARAMS((const char *));
 extern void err_readonly PARAMS((const char *));
 
+#ifdef DEBUG
+#  define INTERNAL_DEBUG(x)    internal_debug x
+#else
+#  define INTERNAL_DEBUG(x)
+#endif
+
 #endif /* !_ERROR_H_ */
index f2a08bf70cd8bb77070deb0066184abcefd35ca2..b4f71b195845e9bcdbbbb81ab37be0cbe0da8a7c 100644 (file)
@@ -1837,9 +1837,7 @@ cpl_delete (pid)
   if (p == 0)
     return 0;          /* not found */
 
-#if defined (DEBUG)
-  itrace("cpl_delete: deleting %d", pid);
-#endif
+  INTERNAL_DEBUG (("cpl_delete: deleting %d", pid));
 
   /* Housekeeping in the border cases. */
   if (p == coproc_list.head)
@@ -1870,11 +1868,7 @@ cpl_reap ()
       if (p->coproc->c_flags & COPROC_DEAD)
        {
          coproc_list.ncoproc--;        /* keep running count, fix up pointers later */
-
-#if defined (DEBUG)
-         itrace("cpl_reap: deleting %d", p->coproc->c_pid);
-#endif
-
+         INTERNAL_DEBUG (("cpl_reap: deleting %d", p->coproc->c_pid));
          coproc_dispose (p->coproc);
          cpe_dispose (p);
        }
diff --git a/jobs.c b/jobs.c
index 867a047722c773f48caef41bae4bbcf4d5504c9c..d211656083bb03d9ab1151e8f0ee707c2a1d6f4d 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -835,9 +835,7 @@ bgp_add (pid, status)
   /* XXX - what if psi == *bucket? */
   if (psi == *bucket)
     {
-#ifdef DEBUG
-      internal_warning ("hashed pid %d (pid %d) collides with bgpids.head, skipping", psi, pid);
-#endif
+      internal_debug ("hashed pid %d (pid %d) collides with bgpids.head, skipping", psi, pid);
       bgpids.storage[psi].pid = NO_PID;                /* make sure */
       psi = bgp_getindex ();                   /* skip to next one */
     }
@@ -1223,12 +1221,10 @@ cleanup_dead_jobs ()
   /* XXX could use js.j_firstj and js.j_lastj here */
   for (i = 0; i < js.j_jobslots; i++)
     {
-#if defined (DEBUG)
       if (i < js.j_firstj && jobs[i])
-       itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+       INTERNAL_DEBUG (("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj));
       if (i > js.j_lastj && jobs[i])
-       itrace("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
-#endif
+       INTERNAL_DEBUG(("cleanup_dead_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj));
 
       if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
        delete_job (i, 0);
@@ -1275,16 +1271,12 @@ delete_old_job (pid)
   job = find_job (pid, 0, &p);
   if (job != NO_JOB)
     {
-#ifdef DEBUG
-      itrace ("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state);
-#endif
+      INTERNAL_DEBUG (("delete_old_job: found pid %d in job %d with state %d", pid, job, jobs[job]->state));
       if (JOBSTATE (job) == JDEAD)
        delete_job (job, DEL_NOBGPID);
       else
        {
-#ifdef DEBUG
-         internal_warning (_("forked pid %d appears in running job %d"), pid, job+1);
-#endif
+         internal_debug (_("forked pid %d appears in running job %d"), pid, job+1);
          if (p)
            p->pid = 0;
        }
@@ -1432,9 +1424,7 @@ delete_job (job_index, dflags)
       js.j_ndead--;
       if (js.c_reaped < 0)
        {
-#ifdef DEBUG
-         itrace("delete_job (%d pgrp %d): js.c_reaped (%d) < 0 ndel = %d js.j_ndead = %d", job_index, temp->pgrp, js.c_reaped, ndel, js.j_ndead);
-#endif
+         INTERNAL_DEBUG (("delete_job (%d pgrp %d): js.c_reaped (%d) < 0 ndel = %d js.j_ndead = %d", job_index, temp->pgrp, js.c_reaped, ndel, js.j_ndead));
          js.c_reaped = 0;
        }
     }
@@ -1506,10 +1496,8 @@ add_process (name, pid)
   p = find_process (pid, 0, &j);
   if (p)
     {
-#  ifdef DEBUG
       if (j == NO_JOB)
-       internal_warning ("add_process: process %5ld (%s) in the_pipeline", (long)p->pid, p->command);
-#  endif
+       internal_debug ("add_process: process %5ld (%s) in the_pipeline", (long)p->pid, p->command);
       if (PALIVE (p))
        internal_warning (_("add_process: pid %5ld (%s) marked as still alive"), (long)p->pid, p->command);
       p->running = PS_RECYCLED;                /* mark as recycled */
@@ -1621,12 +1609,11 @@ map_over_jobs (func, arg1, arg2)
   /* XXX could use js.j_firstj here */
   for (i = result = 0; i < js.j_jobslots; i++)
     {
-#if defined (DEBUG)
       if (i < js.j_firstj && jobs[i])
-       itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+       INTERNAL_DEBUG (("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj));
       if (i > js.j_lastj && jobs[i])
-       itrace("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
-#endif
+       INTERNAL_DEBUG (("map_over_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj));
+
       if (jobs[i])
        {
          result = (*func)(jobs[i], arg1, arg2, i);
@@ -1785,12 +1772,11 @@ find_job (pid, alive_only, procp)
   /* XXX could use js.j_firstj here, and should check js.j_lastj */
   for (i = 0; i < js.j_jobslots; i++)
     {
-#if defined (DEBUG)
       if (i < js.j_firstj && jobs[i])
-       itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+       INTERNAL_DEBUG (("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj));
       if (i > js.j_lastj && jobs[i])
-       itrace("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
-#endif
+       INTERNAL_DEBUG (("find_job: job %d non-null after js.j_lastj (%d)", i, js.j_lastj));
+
       if (jobs[i])
        {
          p = jobs[i]->pipe;
@@ -2675,12 +2661,11 @@ wait_for_background_pids (ps)
       /* XXX could use js.j_firstj and js.j_lastj here */
       for (i = 0; i < js.j_jobslots; i++)
        {
-#if defined (DEBUG)
          if (i < js.j_firstj && jobs[i])
-           itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+           INTERNAL_DEBUG (("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj));
          if (i > js.j_lastj && jobs[i])
-           itrace("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
-#endif
+           INTERNAL_DEBUG (("wait_for_background_pids: job %d non-null after js.j_lastj (%d)", i, js.j_lastj));
+
          if (jobs[i] && STOPPED (i))
            {
              builtin_warning ("job %d[%d] stopped", i+1, find_last_pid (i, 0));
@@ -2940,11 +2925,7 @@ wait_for (pid, flags)
 
       temp_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
       if (temp_sigint_handler == wait_sigint_handler)
-       {
-#if defined (DEBUG)
-         internal_warning ("wait_for: recursively setting old_sigint_handler to wait_sigint_handler: running_trap = %d", running_trap);
-#endif
-       }
+       internal_debug ("wait_for: recursively setting old_sigint_handler to wait_sigint_handler: running_trap = %d", running_trap);
       else
        old_sigint_handler = temp_sigint_handler;
       waiting_for_child = 0;
@@ -4712,9 +4693,7 @@ maybe_give_terminal_to (opgrp, npgrp, flags)
     }
   else if (tpgrp != opgrp)
     {
-#if defined (DEBUG)
-      internal_warning ("%d: maybe_give_terminal_to: terminal pgrp == %d shell pgrp = %d new pgrp = %d in_background = %d", (int)getpid(), tpgrp, opgrp, npgrp, running_in_background);
-#endif
+      internal_debug ("%d: maybe_give_terminal_to: terminal pgrp == %d shell pgrp = %d new pgrp = %d in_background = %d", (int)getpid(), tpgrp, opgrp, npgrp, running_in_background);
       return -1;
     }
   else
@@ -4743,12 +4722,11 @@ delete_all_jobs (running_only)
       /* XXX could use js.j_firstj here */
       for (i = 0; i < js.j_jobslots; i++)
        {
-#if defined (DEBUG)
          if (i < js.j_firstj && jobs[i])
-           itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+           INTERNAL_DEBUG (("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj));
          if (i > js.j_lastj && jobs[i])
-           itrace("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
-#endif
+           INTERNAL_DEBUG (("delete_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj));
+
          if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
            /* We don't want to add any of these pids to bgpids.  If running_only
               is non-zero, we don't want to add running jobs to the list.
@@ -4804,12 +4782,11 @@ count_all_jobs ()
   /* XXX could use js.j_firstj here */
   for (i = n = 0; i < js.j_jobslots; i++)
     {
-#if defined (DEBUG)
       if (i < js.j_firstj && jobs[i])
-       itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+       INTERNAL_DEBUG (("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj));
       if (i > js.j_lastj && jobs[i])
-       itrace("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
-#endif
+       INTERNAL_DEBUG (("count_all_jobs: job %d non-null after js.j_lastj (%d)", i, js.j_lastj));
+
       if (jobs[i] && DEADJOB(i) == 0)
        n++;
     }
@@ -4879,12 +4856,11 @@ mark_dead_jobs_as_notified (force)
   /* XXX could use js.j_firstj here */
   for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++)
     {
-#if defined (DEBUG)
       if (i < js.j_firstj && jobs[i])
-       itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+       INTERNAL_DEBUG (("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj));
       if (i > js.j_lastj && jobs[i])
-       itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
-#endif
+       INTERNAL_DEBUG (("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj));
+
       if (jobs[i] && DEADJOB (i))
        {
          ndead++;
@@ -4892,14 +4868,12 @@ mark_dead_jobs_as_notified (force)
        }
     }
 
-#ifdef DEBUG
 # if 0
   if (ndeadproc != js.c_reaped)
     itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped);
 # endif
   if (ndead != js.j_ndead)
-    itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead);
-#endif
+    INTERNAL_DEBUG (("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead));
 
   if (js.c_childmax < 0)
     set_maxchild (0);
@@ -4932,12 +4906,11 @@ itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", j
     {
       if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
        {
-#if defined (DEBUG)
          if (i < js.j_firstj && jobs[i])
-           itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
+           INTERNAL_DEBUG (("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj));
          if (i > js.j_lastj && jobs[i])
-           itrace("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj);
-#endif
+           INTERNAL_DEBUG (("mark_dead_jobs_as_notified: job %d non-null after js.j_lastj (%d)", i, js.j_lastj));
+
          /* If marking this job as notified would drop us down below
             child_max, don't mark it so we can keep at least child_max
             statuses.  XXX -- need to check what Posix actually says
diff --git a/parse.y b/parse.y
index cae84e33712d05e6f6ba1b5b7036e36430cf211c..e3b6e6d86fdefbb09529149080a9e69d6bb230af 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -2071,12 +2071,7 @@ read_a_line (remove_quoted_newline)
 
       /* Ignore null bytes in input. */
       if (c == 0)
-       {
-#if 0
-         internal_warning ("read_a_line: ignored null byte in input");
-#endif
-         continue;
-       }
+       continue;
 
       /* If there is no more input, then we return NULL. */
       if (c == EOF)
@@ -2405,9 +2400,6 @@ shell_getc (remove_quoted_newline)
 
          if (c == '\0')
            {
-#if 0
-             internal_warning ("shell_getc: ignored null byte in input");
-#endif
              /* If we get EOS while parsing a string, treat it as EOF so we
                 don't just keep looping. Happens very rarely */
              if (bash_input.type == st_string)
@@ -2769,9 +2761,8 @@ shell_ungets (s)
     {
       /* Harder case: pushing back input string that's longer than what we've
         consumed from shell_input_line so far. */
-#ifdef DEBUG
-itrace("shell_ungets: not at end of shell_input_line");
-#endif
+      INTERNAL_DEBUG (("shell_ungets: not at end of shell_input_line"));
+
       chars_left = shell_input_line_len - shell_input_line_index;
       if (shell_input_line_size <= (slen + chars_left))
        RESIZE_MALLOCED_BUFFER (shell_input_line, shell_input_line_index, chars_left + slen + 1, shell_input_line_size, 64);
@@ -3411,9 +3402,7 @@ read_token (command)
      we are eval'ing a string that is an incomplete command), return EOF */
   if (character == '\0' && bash_input.type == st_string && expanding_alias() == 0)
     {
-#if defined (DEBUG)
-itrace("shell_getc: bash_input.location.string = `%s'", bash_input.location.string);
-#endif
+      INTERNAL_DEBUG (("shell_getc: bash_input.location.string = `%s'", bash_input.location.string));
       EOF_Reached = 1;
       return (yacc_EOF);
     }
@@ -4096,11 +4085,11 @@ parse_comsub (qc, open, close, lenp, flags)
 
   r = yyparse ();
 
-  if (need_here_doc)
-{
-itrace("parse_comsub: need_here_doc = %d after yyparse()?", need_here_doc);
-    gather_here_documents ();
-}
+  if (need_here_doc > 0)
+    {
+      internal_debug("command substitution: %d unterminated here-document%s", need_here_doc, (need_here_doc == 1) ? "" : "s");
+      gather_here_documents ();
+    }
 
   parsed_command = global_command;
 
@@ -4115,7 +4104,7 @@ itrace("parse_comsub: need_here_doc = %d after yyparse()?", need_here_doc);
 
   if (current_token != shell_eof_token)
     {
-itrace("current_token (%d) != shell_eof_token (%c)", current_token, shell_eof_token);
+INTERNAL_DEBUG(("current_token (%d) != shell_eof_token (%c)", current_token, shell_eof_token));
       token_to_read = current_token;
       return (&matched_pair_error);
     }
index 6d2dc9f92280a3857cba3b92576b27e2c04c40a1..e08b766d68a1b92f1d7b6e449feadd47b41bebe1 100644 (file)
Binary files a/po/zh_CN.gmo and b/po/zh_CN.gmo differ
index 4477a81246b8efc496d31e2b3073b5cb44b5585b..ad8d4848babab958d7347ed5e486d61c46873f4f 100644 (file)
@@ -9,6 +9,7 @@
 # liushuyu <liushuyu011@gmail.com>, 2016.
 # Mingye Wang <arthur200126@gmail.com>, 2015, 2016.
 # Boyuan Yang <073plan@gmail.com>, 2018, 2019, 2020.
+# Wenbin Lv <wenbin816@gmail.com>, 2021.
 #
 # KNOWN DEFECTS (easy fixes, tedious work; sorted by priority):
 #  0. Translation coverage when upstream sends new strings.
@@ -40,16 +41,16 @@ msgstr ""
 "Project-Id-Version: bash 5.1\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2020-11-28 12:51-0500\n"
-"PO-Revision-Date: 2020-12-07 22:28-0500\n"
-"Last-Translator: Boyuan Yang <073plan@gmail.com>\n"
+"PO-Revision-Date: 2021-12-21 21:36+0800\n"
+"Last-Translator: Wenbin Lv <wenbin816@gmail.com>\n"
 "Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
 "Language: zh_CN\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Bugs: Report translation errors to the Language-Team address.\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 2.4.2\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
+"X-Generator: Poedit 3.0.1\n"
 
 #: arrayfunc.c:66
 msgid "bad array subscript"
@@ -106,10 +107,9 @@ msgid "%s: missing colon separator"
 msgstr "%s:缺少冒号分隔符"
 
 #: bashline.c:4555
-#, fuzzy, c-format
-#| msgid "`%s': cannot unbind"
+#, c-format
 msgid "`%s': cannot unbind in command keymap"
-msgstr "“%s”: 无法解除绑定"
+msgstr "“%s”: 无法解除绑定命令键映射"
 
 #: braces.c:327
 #, c-format
@@ -175,20 +175,6 @@ msgid "only meaningful in a `for', `while', or `until' loop"
 msgstr "仅在 `for', `while', 或者`until' 循环中有意义"
 
 #: builtins/caller.def:136
-#, fuzzy
-#| msgid ""
-#| "Return the context of the current subroutine call.\n"
-#| "    \n"
-#| "    Without EXPR, returns \"$line $filename\".  With EXPR, returns\n"
-#| "    \"$line $subroutine $filename\"; this extra information can be used to\n"
-#| "    provide a stack trace.\n"
-#| "    \n"
-#| "    The value of EXPR indicates how many call frames to go back before the\n"
-#| "    current one; the top frame is frame 0.\n"
-#| "    \n"
-#| "    Exit Status:\n"
-#| "    Returns 0 unless the shell is not executing a shell function or EXPR\n"
-#| "    is invalid."
 msgid ""
 "Returns the context of the current subroutine call.\n"
 "    \n"
@@ -199,18 +185,14 @@ msgid ""
 "    The value of EXPR indicates how many call frames to go back before the\n"
 "    current one; the top frame is frame 0."
 msgstr ""
-"返回当前子调用的上下文。\n"
+"返回当前子例程调用的上下文。\n"
 "    \n"
-"    不带有 EXPR 时,返回 \"$line $filename\"。带有 EXPR 时,返回\n"
+"    不带有 <表达式> 时,返回 \"$line $filename\"。带有 <表达式> 时,返回\n"
 "    \"$line $subroutine $filename\";这个额外的信息可以被用于提供\n"
 "    栈追踪。\n"
 "    \n"
-"    EXPR 的值 显示了到当前调用帧需要回去多少个调用帧;顶部帧\n"
-"    是第 0 帧。\n"
-"    \n"
-"    退出状态:\n"
-"    除非 shell 不在执行一个 shell 函数或者 EXPR 无效,否则返回结\n"
-"    果为0。"
+"    <表达式> 表示从当前调用帧需要回去多少个调用帧;顶部帧\n"
+"    是第 0 帧。"
 
 #: builtins/cd.def:327
 msgid "HOME not set"
@@ -468,10 +450,9 @@ msgid "cannot find %s in shared object %s: %s"
 msgstr "无法在共享对象 %2$s 中找到 %1$s: %3$s"
 
 #: builtins/enable.def:388
-#, fuzzy, c-format
-#| msgid "%s: not dynamically loaded"
+#, c-format
 msgid "%s: dynamic builtin already loaded"
-msgstr "%s:æ\9cªä»¥å\8a¨æ\80\81æ\96¹å¼\8få\8a è½½"
+msgstr "%s:å\8a¨æ\80\81å\86\85建已ç»\8få\8a è½½"
 
 #: builtins/enable.def:392
 #, c-format
@@ -589,6 +570,8 @@ msgid ""
 "'\n"
 "\n"
 msgstr ""
+"”\n"
+"\n"
 
 #: builtins/help.def:185
 #, c-format
@@ -2453,7 +2436,7 @@ msgstr "umask [-p] [-S] [模式]"
 
 #: builtins.c:177
 msgid "wait [-fn] [-p var] [id ...]"
-msgstr "wait [-fn] [-p 变量] [编号 ...]"
+msgstr "wait [-fn] [-p 变量] [ID ...]"
 
 #: builtins.c:181
 msgid "wait [pid ...]"
@@ -2540,16 +2523,12 @@ msgid "printf [-v var] format [arguments]"
 msgstr "printf [-v var] 格式 [参数]"
 
 #: builtins.c:231
-#, fuzzy
-#| msgid "complete [-abcdefgjksuv] [-pr] [-DEI] [-o option] [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]"
 msgid "complete [-abcdefgjksuv] [-pr] [-DEI] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]"
-msgstr "complete [-abcdefgjksuv] [-pr] [-DEI] [-o 选项] [-A 动作] [-G 全局模式] [-W 词语列表]  [-F 函数] [-C 命令] [-X 过滤模式] [-P 前缀] [-S 后缀] [名称 ...]"
+msgstr "complete [-abcdefgjksuv] [-pr] [-DEI] [-o 选项] [-A 动作] [-G 全局模式] [-W 词语列表] [-F 函数] [-C 命令] [-X 过滤模式] [-P 前缀] [-S 后缀] [名称 ...]"
 
 #: builtins.c:235
-#, fuzzy
-#| msgid "compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]"
 msgid "compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]"
-msgstr "compgen [-abcdefgjksuv] [-o 选项]  [-A 动作] [-G 全局模式] [-W 词语列表]  [-F 函数] [-C 命令] [-X 过滤模式] [-P 前缀] [-S 后缀] [词语]"
+msgstr "compgen [-abcdefgjksuv] [-o 选项] [-A 动作] [-G 全局模式] [-W 词语列表] [-F 函数] [-C 命令] [-X 过滤模式] [-P 前缀] [-S 后缀] [词语]"
 
 #: builtins.c:239
 msgid "compopt [-o|+o option] [-DEI] [name ...]"
@@ -2749,18 +2728,18 @@ msgid ""
 "    Returns 0 unless the shell is not executing a shell function or EXPR\n"
 "    is invalid."
 msgstr ""
-"返回当前子调用的上下文。\n"
+"返回当前子例程调用的上下文。\n"
 "    \n"
-"    不带有 EXPR 时,返回 \"$line $filename\"。带有 EXPR 时,返回\n"
+"    不带有 <表达式> 时,返回 \"$line $filename\"。带有 <表达式> 时,返回\n"
 "    \"$line $subroutine $filename\";这个额外的信息可以被用于提供\n"
 "    栈追踪。\n"
 "    \n"
-"    EXPR 的值 显示了到当前调用帧需要回去多少个调用帧;顶部帧\n"
+"    <表达式> 表示从当前调用帧需要回去多少个调用帧;顶部帧\n"
 "    是第 0 帧。\n"
 "    \n"
 "    退出状态:\n"
-"    除非 shell 不在执行一个 shell 函数或者 EXPR 无效,否则返回结\n"
-"    果为0。"
+"    除非 shell 不在执行一个 shell 函数或者 <表达式> 无效,否则返回结\n"
+"    果为 0。"
 
 #: builtins.c:387
 msgid ""
@@ -2920,43 +2899,6 @@ msgstr ""
 "    返回 COMMAND 命令的返回状态,或者当找不到 COMMAND 命令时失败。"
 
 #: builtins.c:490
-#, fuzzy
-#| msgid ""
-#| "Set variable values and attributes.\n"
-#| "    \n"
-#| "    Declare variables and give them attributes.  If no NAMEs are given,\n"
-#| "    display the attributes and values of all variables.\n"
-#| "    \n"
-#| "    Options:\n"
-#| "      -f\trestrict action or display to function names and definitions\n"
-#| "      -F\trestrict display to function names only (plus line number and\n"
-#| "    \t\tsource file when debugging)\n"
-#| "      -g\tcreate global variables when used in a shell function; otherwise\n"
-#| "    \t\tignored\n"
-#| "      -p\tdisplay the attributes and value of each NAME\n"
-#| "    \n"
-#| "    Options which set attributes:\n"
-#| "      -a\tto make NAMEs indexed arrays (if supported)\n"
-#| "      -A\tto make NAMEs associative arrays (if supported)\n"
-#| "      -i\tto make NAMEs have the `integer' attribute\n"
-#| "      -l\tto convert the value of each NAME to lower case on assignment\n"
-#| "      -n\tmake NAME a reference to the variable named by its value\n"
-#| "      -r\tto make NAMEs readonly\n"
-#| "      -t\tto make NAMEs have the `trace' attribute\n"
-#| "      -u\tto convert the value of each NAME to upper case on assignment\n"
-#| "      -x\tto make NAMEs export\n"
-#| "    \n"
-#| "    Using `+' instead of `-' turns off the given attribute.\n"
-#| "    \n"
-#| "    Variables with the integer attribute have arithmetic evaluation (see\n"
-#| "    the `let' command) performed when the variable is assigned a value.\n"
-#| "    \n"
-#| "    When used in a function, `declare' makes NAMEs local, as with the `local'\n"
-#| "    command.  The `-g' option suppresses this behavior.\n"
-#| "    \n"
-#| "    Exit Status:\n"
-#| "    Returns success unless an invalid option is supplied or a variable\n"
-#| "    assignment error occurs."
 msgid ""
 "Set variable values and attributes.\n"
 "    \n"
@@ -3005,6 +2947,7 @@ msgstr ""
 "      -f\t限制动作或显示为仅函数名称和定义\n"
 "      -F\t限制仅显示函数名称 (以及调试时显示行号和源文件名)\n"
 "      -g\t当用于 shell 函数内时创建全局变量; 否则忽略\n"
+"      -I\t当创建局部变量时,继承上一个作用域的同名变量的属性和值\n"
 "      -p\t显示每个 NAME 变量的属性和值\n"
 "    \n"
 "    设定属性的选项:\n"
@@ -3221,45 +3164,6 @@ msgstr ""
 "    以命令的状态退出,或者在命令为空的情况下返回成功。"
 
 #: builtins.c:652
-#, fuzzy
-#| msgid ""
-#| "Parse option arguments.\n"
-#| "    \n"
-#| "    Getopts is used by shell procedures to parse positional parameters\n"
-#| "    as options.\n"
-#| "    \n"
-#| "    OPTSTRING contains the option letters to be recognized; if a letter\n"
-#| "    is followed by a colon, the option is expected to have an argument,\n"
-#| "    which should be separated from it by white space.\n"
-#| "    \n"
-#| "    Each time it is invoked, getopts will place the next option in the\n"
-#| "    shell variable $name, initializing name if it does not exist, and\n"
-#| "    the index of the next argument to be processed into the shell\n"
-#| "    variable OPTIND.  OPTIND is initialized to 1 each time the shell or\n"
-#| "    a shell script is invoked.  When an option requires an argument,\n"
-#| "    getopts places that argument into the shell variable OPTARG.\n"
-#| "    \n"
-#| "    getopts reports errors in one of two ways.  If the first character\n"
-#| "    of OPTSTRING is a colon, getopts uses silent error reporting.  In\n"
-#| "    this mode, no error messages are printed.  If an invalid option is\n"
-#| "    seen, getopts places the option character found into OPTARG.  If a\n"
-#| "    required argument is not found, getopts places a ':' into NAME and\n"
-#| "    sets OPTARG to the option character found.  If getopts is not in\n"
-#| "    silent mode, and an invalid option is seen, getopts places '?' into\n"
-#| "    NAME and unsets OPTARG.  If a required argument is not found, a '?'\n"
-#| "    is placed in NAME, OPTARG is unset, and a diagnostic message is\n"
-#| "    printed.\n"
-#| "    \n"
-#| "    If the shell variable OPTERR has the value 0, getopts disables the\n"
-#| "    printing of error messages, even if the first character of\n"
-#| "    OPTSTRING is not a colon.  OPTERR has the value 1 by default.\n"
-#| "    \n"
-#| "    Getopts normally parses the positional parameters ($0 - $9), but if\n"
-#| "    more arguments are given, they are parsed instead.\n"
-#| "    \n"
-#| "    Exit Status:\n"
-#| "    Returns success if an option is found; fails if the end of options is\n"
-#| "    encountered or an error occurs."
 msgid ""
 "Parse option arguments.\n"
 "    \n"
@@ -3301,37 +3205,36 @@ msgid ""
 msgstr ""
 "解析选项参数。\n"
 "    \n"
-"    getopts 被 shell 过程用于解析可定位的参数作为选项。\n"
+"    getopts 可在 shell 过程中使用,用于解析位置参数作为选项。\n"
 "    \n"
 "    \n"
-"    OPTSTRING 字符串包含待识别的选项字母;如果一个字母后面跟\n"
-"    ç\9d\80å\88\86å\8f·ï¼\8cå\88\99该é\80\89项é\9c\80è¦\81ä¸\80个å\8f\82æ\95°ï¼\8cè\80\8c该å\8f\82æ\95°åº\94ç\94¨ç©ºæ ¼ä¸\8eé\80\89项å\88\86开。\n"
+"    <选项字符串> 包含待识别的选项字母;如果一个字母后面跟\n"
+"    ç\9d\80å\86\92å\8f·ï¼\8cå\88\99该é\80\89项é\9c\80è¦\81ä¸\80个å\8f\82æ\95°ï¼\8cå\8f\82æ\95°ä¸\8eé\80\89项ä¹\8bé\97´åº\94å½\93ç\94¨ç©ºæ ¼é\9a\94开。\n"
 "    \n"
 "    \n"
-"    每次启动时,getopts 会将下一个选项放到 shell 变量 $name\n"
-"    中,如果 name 变量不存在则先将其初始化,而下一个待处\n"
-"    理的参数序号放入 shell 变量 OPTIND 中。OPTIND 变量在每\n"
-"    次 shell 或者 shell 脚本启动时都被初始化为1。当一个选项要\n"
-"    求有一个参数时,getopts 将参数放入 shell 变量 OPTARG\n"
-"    中。\n"
+"    每次被调用时,getopts 会将下一个选项放到 shell 变量 $name\n"
+"    中,如果 <名称> 变量不存在则先将其初始化,并将下一个待处\n"
+"    理的参数的序号放入 shell 变量 OPTIND 中。OPTIND 变量在每\n"
+"    次 shell 或者 shell 脚本启动时都被初始化为 1。当一个选项要\n"
+"    求有一个参数时,getopts 将该参数放入 shell 变量 OPTARG 中。\n"
 "    \n"
 "    getopts 有两种报告错误的方法。如果 OPTSTRING 变量的第\n"
 "    一个字符是冒号,getopts 使用沉默错误报告。在这种模式\n"
-"    下,不会打印错误消息。如果到了一个无效的选项,\n"
-"    getopts 将找到的选项字符放至 OPTARG 变量中。如果一个必\n"
-"    须的选项没有找到,getopts 放一个 ':' 到 NAME 变量中并且设\n"
+"    下,不会打印错误消息。如果到了一个无效的选项,\n"
+"    getopts 将找到的选项字符放至 OPTARG 变量中。如果没有找到\n"
+"    必需的参数,getopts 放一个 ':' 到 <名称> 变量中并且设\n"
 "    置 OPTARG 变量为找到的选项字符。如果 getopts 不在沉默模\n"
-"    式中,并且遇到了一个无效的选项,getopts 放置一个 '?' 到 NAME \n"
-"    变量中并且取消设定 OPTARGå\8f\98é\87\8fã\80\82å¦\82æ\9e\9cå¿\85é¡»ç\9a\84é\80\89项没æ\9c\89æ\89¾å\88°ï¼\8c\n"
-"    一个'?'会被放入 NAME变量中,OPTARG 将被取消设定,并且会\n"
+"    式中,并且遇到了一个无效的选项,getopts 放置一个 '?' 到 <名称> \n"
+"    变量中并且取消设定 OPTARG å\8f\98é\87\8fã\80\82å¦\82æ\9e\9c没æ\9c\89æ\89¾å\88°å¿\85é\9c\80ç\9a\84å\8f\82æ\95°ï¼\8c\n"
+"    一个 '?' 会被放入 <名称> 变量中,OPTARG 将被取消设定,并且会\n"
 "    打印一个诊断信息。\n"
 "    \n"
-"    如果 shell 变量 OPTERR 的值为0,getopts 禁用\n"
-"    错误信息的打印,即使 OPTSTRING 变量的第一个字符不是\n"
-"    ä¸ªå\86\92å\8f·ã\80\82OPTERR ç\9a\84é»\98认å\80¼ä¸º1.\n"
+"    如果 shell 变量 OPTERR 的值为 0,getopts 将会禁用\n"
+"    错误信息的打印,即使 OPTSTRING 变量的第一个字符不是\n"
+"    ä¸\80个å\86\92å\8f·ã\80\82OPTERR ç\9a\84é»\98认å\80¼ä¸º 1ã\80\82\n"
 "    \n"
-"    getopts 通常解析可定位的参数($0 - $9),不过如果提供了\n"
-"    æ\9b´å¤\9aç\9a\84å\8f\82æ\95°ï¼\8cå®\83们å\8f\8dè\80\8cä¼\9a被解æ\9e\90。\n"
+"    getopts 通常解析位置参数($0 - $9),不过如果在 <参数> 中\n"
+"    æ\8f\90ä¾\9bäº\86å\8f\82æ\95°ï¼\8cå\88\99转è\80\8cè§£æ\9e\90å®\83们。\n"
 "    \n"
 "    退出状态:\n"
 "    如果一个选项被找到则返回成功;如果遇到了选项的结尾或者\n"
@@ -4545,52 +4448,6 @@ msgstr ""
 "    如果所有的 NAME 命令都找到则返回成功;任何一个找不到则失败。"
 
 #: builtins.c:1431
-#, fuzzy
-#| msgid ""
-#| "Modify shell resource limits.\n"
-#| "    \n"
-#| "    Provides control over the resources available to the shell and processes\n"
-#| "    it creates, on systems that allow such control.\n"
-#| "    \n"
-#| "    Options:\n"
-#| "      -S\tuse the `soft' resource limit\n"
-#| "      -H\tuse the `hard' resource limit\n"
-#| "      -a\tall current limits are reported\n"
-#| "      -b\tthe socket buffer size\n"
-#| "      -c\tthe maximum size of core files created\n"
-#| "      -d\tthe maximum size of a process's data segment\n"
-#| "      -e\tthe maximum scheduling priority (`nice')\n"
-#| "      -f\tthe maximum size of files written by the shell and its children\n"
-#| "      -i\tthe maximum number of pending signals\n"
-#| "      -k\tthe maximum number of kqueues allocated for this process\n"
-#| "      -l\tthe maximum size a process may lock into memory\n"
-#| "      -m\tthe maximum resident set size\n"
-#| "      -n\tthe maximum number of open file descriptors\n"
-#| "      -p\tthe pipe buffer size\n"
-#| "      -q\tthe maximum number of bytes in POSIX message queues\n"
-#| "      -r\tthe maximum real-time scheduling priority\n"
-#| "      -s\tthe maximum stack size\n"
-#| "      -t\tthe maximum amount of cpu time in seconds\n"
-#| "      -u\tthe maximum number of user processes\n"
-#| "      -v\tthe size of virtual memory\n"
-#| "      -x\tthe maximum number of file locks\n"
-#| "      -P\tthe maximum number of pseudoterminals\n"
-#| "      -T\tthe maximum number of threads\n"
-#| "    \n"
-#| "    Not all options are available on all platforms.\n"
-#| "    \n"
-#| "    If LIMIT is given, it is the new value of the specified resource; the\n"
-#| "    special LIMIT values `soft', `hard', and `unlimited' stand for the\n"
-#| "    current soft limit, the current hard limit, and no limit, respectively.\n"
-#| "    Otherwise, the current value of the specified resource is printed.  If\n"
-#| "    no option is given, then -f is assumed.\n"
-#| "    \n"
-#| "    Values are in 1024-byte increments, except for -t, which is in seconds,\n"
-#| "    -p, which is in increments of 512 bytes, and -u, which is an unscaled\n"
-#| "    number of processes.\n"
-#| "    \n"
-#| "    Exit Status:\n"
-#| "    Returns success unless an invalid option is supplied or an error occurs."
 msgid ""
 "Modify shell resource limits.\n"
 "    \n"
@@ -4646,39 +4503,40 @@ msgstr ""
 "    选项:\n"
 "      -S\t使用软 (`soft') 资源限制\n"
 "      -H\t使用硬 (`hard') 资源限制\n"
-"      -a\tæ\89\80æ\9c\89å½\93å\89\8dé\99\90å\88¶é\83½è¢«æ\8a¥å\91\8a\n"
-"      -b\tå¥\97æ\8e¥å­\97ç¼\93å­\98尺寸\n"
-"      -c\t创建的核文件的最大尺寸\n"
-"      -d\t一个进程的数据区的最大尺寸\n"
-"      -e\t最高的调度优先级 (`nice')\n"
-"      -f\t有 shell 及其子进程可以写的最大文件尺寸\n"
-"      -i\t最多的可以挂起的信号数\n"
+"      -a\tæ\8a¥å\91\8aå½\93å\89\8dç\9a\84æ\89\80æ\9c\89é\99\90å\88\n"
+"      -b\tå¥\97æ\8e¥å­\97ç¼\93å\86²å\8cºå¤§å°\8f\n"
+"      -c\t创建的核心文件的最大大小\n"
+"      -d\t一个进程的数据段的最大大小\n"
+"      -e\t调度优先级 (`nice')的最大值\n"
+"      -f\tshell 及其子进程可以写的最大文件大小\n"
+"      -i\t可以挂起的最大信号数量\n"
 "      -k\t分配给此进程的最大 kqueue 数量\n"
-"      -l\tä¸\80个è¿\9bç¨\8bå\8f¯ä»¥é\94\81å®\9aç\9a\84æ\9c\80大å\86\85å­\98尺寸\n"
-"      -m\t最大的内存进驻尺寸\n"
-"      -n\tæ\9c\80å¤\9aç\9a\84æ\89\93å¼\80ç\9a\84æ\96\87ä»¶æ\8f\8f述符个数\n"
-"      -p\t管é\81\93ç¼\93å\86²å\8cºå°ºå¯¸\n"
-"      -q\tPOSIX 息队列的最大字节数\n"
+"      -l\tä¸\80个è¿\9bç¨\8bå\8f¯ä»¥é\94\81å®\9aç\9a\84æ\9c\80大å\86\85å­\98大å°\8f\n"
+"      -m\t驻留集的最大大小\n"
+"      -n\tæ\89\93å¼\80ç\9a\84æ\96\87ä»¶æ\8f\8f述符ç\9a\84æ\9c\80大个数\n"
+"      -p\t管é\81\93ç¼\93å\86²å\8cºå¤§å°\8f\n"
+"      -q\tPOSIX 息队列的最大字节数\n"
 "      -r\t实时调度的最大优先级\n"
-"      -s\tæ\9c\80大æ \88尺寸\n"
-"      -t\t最大的CPU时间,以秒为单位\n"
+"      -s\tæ\9c\80大æ \88大å°\8f\n"
+"      -t\t最大的 CPU 时间,以秒为单位\n"
 "      -u\t最大用户进程数\n"
-"      -v\t虚拟内存尺寸\n"
-"      -x\t最大的文件锁数量\n"
-"      -P\t最大伪终端数量\n"
+"      -v\t虚拟内存大小\n"
+"      -x\t文件锁的最大数量\n"
+"      -P\t伪终端的最大数量\n"
+"      -R\t实时进程阻塞前可运行的最大时间\n"
 "      -T\t最大线程数量\n"
 "    \n"
 "    并非所有选项在所有系统上可用。\n"
 "    \n"
-"    如果提供了 LIMIT 变量,则它为指定资源的新的值;特别的 LIMIT 值为\n"
-"    `soft'、`hard'`unlimited',分别表示当前的软限制,硬限制和无限制。\n"
-"    否则打印指定资源的当前限制值,不带选项则假定为 -f\n"
+"    如果提供了 <限制>,则它将成为指定资源的新的值;特殊的 <限制> 值为\n"
+"    `soft'、`hard' 和 `unlimited',分别表示当前的软限制,硬限制和无限制。\n"
+"    否则,打印指定资源的当前限制值。如果未提供选项,则假定为 -f。\n"
 "    \n"
-"    取值都是 1024 字节为单位,除了 -t 以秒为单位,-p 以 512 字节递增,\n"
-"    -u ä¸ºæ\97 è\8c\83å\9b´的进程数量。\n"
+"    限制值都以 1024 字节为单位,除了 -t 以秒为单位,-p 以 512 字节为单位,\n"
+"    -u ä¸ºæ\9cªç»\8f缩æ\94¾的进程数量。\n"
 "    \n"
 "    退出状态:\n"
-"    返回成功,除非使用了无效的选项或者错误发生。"
+"    返回成功,除非使用了无效的选项或者错误发生。"
 
 #: builtins.c:1482
 msgid ""
@@ -4713,25 +4571,6 @@ msgstr ""
 "    返回成功,除非使用了无效的 MODE 模式或者选项。"
 
 #: builtins.c:1502
-#, fuzzy
-#| msgid ""
-#| "Wait for job completion and return exit status.\n"
-#| "    \n"
-#| "    Waits for each process identified by an ID, which may be a process ID or a\n"
-#| "    job specification, and reports its termination status.  If ID is not\n"
-#| "    given, waits for all currently active child processes, and the return\n"
-#| "    status is zero.  If ID is a job specification, waits for all processes\n"
-#| "    in that job's pipeline.\n"
-#| "    \n"
-#| "    If the -n option is supplied, waits for the next job to terminate and\n"
-#| "    returns its exit status.\n"
-#| "    \n"
-#| "    If the -f option is supplied, and job control is enabled, waits for the\n"
-#| "    specified ID to terminate, instead of waiting for it to change status.\n"
-#| "    \n"
-#| "    Exit Status:\n"
-#| "    Returns the status of the last ID; fails if ID is invalid or an invalid\n"
-#| "    option is given."
 msgid ""
 "Wait for job completion and return exit status.\n"
 "    \n"
@@ -4760,17 +4599,24 @@ msgid ""
 msgstr ""
 "等待任务完成并返回退出状态。\n"
 "    \n"
-"    等待以 ID 编号识别的进程,其中 ID 可以是进程编号或者任务声明,\n"
-"    并报告它的终止状态。如果 ID 没有给出,则等待所有的当前活跃子\n"
-"    进程,并且返回状态为零。如果 ID 是任务声明,等待任务管道中的\n"
+"    等待以 <ID> 识别的进程,其中 <ID> 可以是进程 ID 或者任务声明,\n"
+"    并报告它的终止状态。如果没有指定 <ID> ,则等待当前活跃的所有子\n"
+"    进程,并且返回状态为零。如果 <ID> 是任务声明,则等待该任务管道中的\n"
 "    所有进程。\n"
 "    \n"
-"    若给定了 -n 选项,等待下一个任务完成并返回其状态。\n"
+"    若给定了 -n 选项,从 <ID> 列表中等待一个单一的任务完成,\n"
+"    或者,如果没有提供 <ID>,等待下一个任务完成并返回其退出状态。\n"
 "    \n"
-"    若给定了 -f 选项,且已启用了任务控制,则等待指定的 ID 终止\n"
+"    若给定了 -p 选项, 被返回退出状态的任务的进程 ID 或任务 ID 将被赋值\n"
+"    给选项的参数指定的 <变量>。该变量会首先被取消设定,然后才会进行赋值。\n"
+"    该选项只有和 -n 选项同时使用才有用。\n"
+"    \n"
+"    若给定了 -f 选项,且已启用了任务控制,则等待指定的 <ID> 终止,\n"
 "    而非等待它改变状态。\n"
+"    \n"
 "    退出状态:\n"
-"    返回最后一个 ID 进程的状态;如果使用了无效的 ID 或者选项则失败。"
+"    返回最后一个 <ID> 的状态;如果使用了无效的 <ID> ,或者使用了无效的\n"
+"    选项,或者给定了 -n 选项但 shell 没有尚未等待的子进程,则失败。"
 
 #: builtins.c:1533
 msgid ""
@@ -5071,15 +4917,6 @@ msgstr ""
 "    返回被继续的任务的状态。"
 
 #: builtins.c:1726
-#, fuzzy
-#| msgid ""
-#| "Evaluate arithmetic expression.\n"
-#| "    \n"
-#| "    The EXPRESSION is evaluated according to the rules for arithmetic\n"
-#| "    evaluation.  Equivalent to \"let EXPRESSION\".\n"
-#| "    \n"
-#| "    Exit Status:\n"
-#| "    Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise."
 msgid ""
 "Evaluate arithmetic expression.\n"
 "    \n"
@@ -5089,13 +4926,13 @@ msgid ""
 "    Exit Status:\n"
 "    Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise."
 msgstr ""
-"估值算术表达式。\n"
+"对算术表达式估值。\n"
 "    \n"
-"    表达式按照算术法则进行估值。\n"
-"    等价于 \"let 表达式\".\n"
+"    <表达式> 按照算术法则进行估值。\n"
+"    等价于 \"let <表达式>\"。\n"
 "    \n"
-"    退出状态\n"
-"    如果表达式估值为0则返回 1;否则返回0。"
+"    退出状态\n"
+"    如果 <表达式> 估值为 0 则返回 1;否则返回 0。"
 
 #: builtins.c:1738
 msgid ""
@@ -5470,31 +5307,6 @@ msgstr ""
 "    返回成功,除非使用了无效的选项或者写或赋值错误发生。"
 
 #: builtins.c:1971
-#, fuzzy
-#| msgid ""
-#| "Specify how arguments are to be completed by Readline.\n"
-#| "    \n"
-#| "    For each NAME, specify how arguments are to be completed.  If no options\n"
-#| "    are supplied, existing completion specifications are printed in a way that\n"
-#| "    allows them to be reused as input.\n"
-#| "    \n"
-#| "    Options:\n"
-#| "      -p\tprint existing completion specifications in a reusable format\n"
-#| "      -r\tremove a completion specification for each NAME, or, if no\n"
-#| "    \t\tNAMEs are supplied, all completion specifications\n"
-#| "      -D\tapply the completions and actions as the default for commands\n"
-#| "    \t\twithout any specific completion defined\n"
-#| "      -E\tapply the completions and actions to \"empty\" commands --\n"
-#| "    \t\tcompletion attempted on a blank line\n"
-#| "      -I\tapply the completions and actions to the initial (usually the\n"
-#| "    \t\tcommand) word\n"
-#| "    \n"
-#| "    When completion is attempted, the actions are applied in the order the\n"
-#| "    uppercase-letter options are listed above.  If multiple options are supplied,\n"
-#| "    the -D option takes precedence over -E, and both take precedence over -I.\n"
-#| "    \n"
-#| "    Exit Status:\n"
-#| "    Returns success unless an invalid option is supplied or an error occurs."
 msgid ""
 "Specify how arguments are to be completed by Readline.\n"
 "    \n"
@@ -5522,15 +5334,15 @@ msgid ""
 msgstr ""
 "指定 Readline 如何补全参数。\n"
 "    \n"
-"    声明对于每一个 NAME 名称如何补全参数。如果不带选项,\n"
+"    声明对于每一个 <名称> 如何补全参数。如果不带选项,\n"
 "    现有的补全声明会以可以重用为输入的格式打印出来。\n"
 "    \n"
 "    选项:\n"
-"      -p\t以可重用的格式打印现有的补全声明\n"
-"      -r\t对于每个 NAME 名称删除补全声明,或者如果没有提供 NAME\n"
-"    \t名称,删除所有的补全声明。\n"
-"      -D\t对于没有补全声明定义的命令,设定默认的补全动作\n"
-"      -E\t对于 \"empty\" 命令设定补全动作,—— 对于空行的补全。\n"
+"      -p\t以可重用的格式打印现有的补全声明\n"
+"      -r\t对每一个 <名称> 删除补全声明,或者,如果没有提供 <名称> ,\n"
+"    \t\t删除所有的补全声明\n"
+"      -D\t对äº\8e没æ\9c\89è¡¥å\85¨å£°æ\98\8eå®\9aä¹\89ç\9a\84å\91½ä»¤ï¼\8c设å®\9aé»\98认ç\9a\84è¡¥å\85¨å\92\8cå\8a¨ä½\9c\n"
+"      -E\t对于 \"empty\" 命令设定补全动作——对于空行的补全\n"
 "      -I\t将补全和动作应用在首单词(通常是所给命令)上\n"
 "    \n"
 "    尝试补全时,按照上述大写字母选项的顺序进行动作。\n"
@@ -5538,7 +5350,7 @@ msgstr ""
 "    这两个选项优先级均高于 -I。\n"
 "    \n"
 "    退出状态:\n"
-"    返回成功,除非使用了无效的选项或者错误发生。"
+"    返回成功,除非使用了无效的选项或者错误发生。"
 
 #: builtins.c:2001
 msgid ""
diff --git a/subst.c b/subst.c
index 04fcb4d79df39738c68273194a0dacff519183bf..bf2a8d391a67a54f115373c5b9ae27db914a7862 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -293,7 +293,7 @@ static char *parameter_list_remove_pattern PARAMS((int, char *, int, int));
 #ifdef ARRAY_VARS
 static char *array_remove_pattern PARAMS((SHELL_VAR *, char *, int, int, int));
 #endif
-static char *parameter_brace_remove_pattern PARAMS((char *, char *, arrayind_t, char *, int, int, int));
+static char *parameter_brace_remove_pattern PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
 
 static char *string_var_assignment PARAMS((SHELL_VAR *, char *));
 #if defined (ARRAY_VARS)
@@ -306,7 +306,7 @@ static char *parameter_list_transform PARAMS((int, int, int));
 #if defined ARRAY_VARS
 static char *array_transform PARAMS((int, SHELL_VAR *, int, int));
 #endif
-static char *parameter_brace_transform PARAMS((char *, char *, arrayind_t, char *, int, int, int, int));
+static char *parameter_brace_transform PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int, int));
 static int valid_parameter_transform PARAMS((char *));
 
 static char *process_substitute PARAMS((char *, int));
@@ -322,7 +322,7 @@ static int valid_brace_expansion_word PARAMS((char *, int));
 static int chk_atstar PARAMS((char *, int, int, int *, int *));
 static int chk_arithsub PARAMS((const char *, int));
 
-static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, arrayind_t *));
+static WORD_DESC *parameter_brace_expand_word PARAMS((char *, int, int, int, array_eltstate_t *));
 static char *parameter_brace_find_indir PARAMS((char *, int, int, int));
 static WORD_DESC *parameter_brace_expand_indir PARAMS((char *, int, int, int, int *, int *));
 static WORD_DESC *parameter_brace_expand_rhs PARAMS((char *, char *, int, int, int, int *, int *));
@@ -333,18 +333,18 @@ static intmax_t parameter_brace_expand_length PARAMS((char *));
 
 static char *skiparith PARAMS((char *, int));
 static int verify_substring_values PARAMS((SHELL_VAR *, char *, char *, int, intmax_t *, intmax_t *));
-static int get_var_and_type PARAMS((char *, char *, arrayind_t, int, int, SHELL_VAR **, char **));
+static int get_var_and_type PARAMS((char *, char *, array_eltstate_t *, int, int, SHELL_VAR **, char **));
 static char *mb_substring PARAMS((char *, int, int));
-static char *parameter_brace_substring PARAMS((char *, char *, arrayind_t, char *, int, int, int));
+static char *parameter_brace_substring PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
 
 static int shouldexp_replacement PARAMS((char *));
 
 static char *pos_params_pat_subst PARAMS((char *, char *, char *, int));
 
-static char *parameter_brace_patsub PARAMS((char *, char *, arrayind_t, char *, int, int, int));
+static char *parameter_brace_patsub PARAMS((char *, char *, array_eltstate_t *, char *, int, int, int));
 
 static char *pos_params_casemod PARAMS((char *, char *, int, int));
-static char *parameter_brace_casemod PARAMS((char *, char *, arrayind_t, int, char *, int, int, int));
+static char *parameter_brace_casemod PARAMS((char *, char *, array_eltstate_t *, int, char *, int, int, int));
 
 static WORD_DESC *parameter_brace_expand PARAMS((char *, int *, int, int, int *, int *));
 static WORD_DESC *param_expand PARAMS((char *, int *, int, int *, int *, int *, int *, int));
@@ -4424,10 +4424,8 @@ dequote_string (string)
   char *result, *send;
   DECLARE_MBSTATE;
 
-#if defined (DEBUG)
   if (string[0] == CTLESC && string[1] == 0)
-    internal_inform ("dequote_string: string with bare CTLESC");
-#endif
+    internal_debug ("dequote_string: string with bare CTLESC");
 
   slen = STRLEN (string);
 
@@ -5403,9 +5401,9 @@ array_remove_pattern (var, pattern, patspec, starsub, quoted)
 #endif /* ARRAY_VARS */
 
 static char *
-parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flags)
+parameter_brace_remove_pattern (varname, value, estatep, patstr, rtype, quoted, flags)
      char *varname, *value;
-     arrayind_t ind;
+     array_eltstate_t *estatep;
      char *patstr;
      int rtype, quoted, flags;
 {
@@ -5419,7 +5417,7 @@ parameter_brace_remove_pattern (varname, value, ind, patstr, rtype, quoted, flag
   oname = this_command_name;
   this_command_name = varname;
 
-  vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
+  vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
   if (vtype == -1)
     {
       this_command_name = oname;
@@ -6926,10 +6924,10 @@ chk_atstar (name, quoted, pflags, quoted_dollar_atp, contains_dollar_at)
    the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
    NAME was found inside of a double-quoted expression. */
 static WORD_DESC *
-parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
+parameter_brace_expand_word (name, var_is_special, quoted, pflags, estatep)
      char *name;
      int var_is_special, quoted, pflags;
-     arrayind_t *indp;
+     array_eltstate_t *estatep;
 {
   WORD_DESC *ret;
   char *temp, *tt;
@@ -6942,8 +6940,15 @@ parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
   temp = 0;
   rflags = 0;
 
-  if (indp)
-    *indp = INTMAX_MIN;
+#if defined (ARRAY_VARS)
+  if (estatep)
+    es = *estatep;     /* structure copy */
+  else
+    {
+      init_eltstate (&es);
+      es.ind = INTMAX_MIN;
+    }
+#endif
 
   /* Handle multiple digit arguments, as in ${11}. */  
   if (legal_number (name, &arg_index))
@@ -6972,10 +6977,6 @@ parameter_brace_expand_word (name, var_is_special, quoted, pflags, indp)
   else if (valid_array_reference (name, 0))
     {
 expand_arrayref:
-      init_eltstate (&es);
-      if (indp)
-       es.ind = *indp;
-      
       var = array_variable_part (name, 0, &tt, (int *)0);
       /* These are the cases where word splitting will not be performed */
       if (pflags & PF_ASSIGNRHS)
@@ -7020,11 +7021,13 @@ expand_arrayref:
                    ? quote_string (temp)
                    : quote_escapes (temp);
          rflags |= W_ARRAYIND;
-         if (indp)
-           *indp = es.ind;
+         if (estatep)
+           *estatep = es;      /* structure copy */
        }
       else if (es.subtype == 1 && temp && QUOTED_NULL (temp) && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)))
        rflags |= W_HASQUOTEDNULL;
+      if (estatep == 0)
+       flush_eltstate (&es);
     }
 #endif
   else if (var = find_variable (name))
@@ -7763,9 +7766,9 @@ verify_substring_values (v, value, substr, vtype, e1p, e2p)
    characters in the value are quoted with CTLESC and takes appropriate
    steps.  For convenience, *VALP is set to the dequoted VALUE. */
 static int
-get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
+get_var_and_type (varname, value, estatep, quoted, flags, varp, valp)
      char *varname, *value;
-     arrayind_t ind;
+     array_eltstate_t *estatep;
      int quoted, flags;
      SHELL_VAR **varp;
      char **valp;
@@ -7773,8 +7776,6 @@ get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
   int vtype, want_indir;
   char *temp, *vname;
   SHELL_VAR *v;
-  arrayind_t lind;
-  array_eltstate_t es;
 
   want_indir = *varname == '!' &&
     (legal_variable_starter ((unsigned char)varname[1]) || DIGIT (varname[1])
@@ -7804,10 +7805,10 @@ get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
     {
       v = array_variable_part (vname, 0, &temp, (int *)0);
       /* If we want to signal array_value to use an already-computed index,
-        set LIND to that index */
-      lind = (ind != INTMAX_MIN && (flags & AV_USEIND)) ? ind : 0;
-      init_eltstate (&es);
-      es.ind = lind;
+        the caller will set ESTATEP->IND to that index and pass AV_USEIND in
+        FLAGS. */
+      if (estatep && (flags & AV_USEIND) == 0)
+       estatep->ind = INTMAX_MIN;
 
       if (v && invisible_p (v))
        {
@@ -7828,7 +7829,7 @@ get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
          else
            {
              vtype = VT_ARRAYMEMBER;
-             *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, &es);
+             *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
            }
          *varp = v;
        }
@@ -7845,9 +7846,8 @@ get_var_and_type (varname, value, ind, quoted, flags, varp, valp)
        {
          vtype = VT_ARRAYMEMBER;
          *varp = v;
-         *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, &es);
+         *valp = array_value (vname, Q_DOUBLE_QUOTES, flags, estatep);
        }
-      flush_eltstate (&es);
     }
   else if ((v = find_variable (vname)) && (invisible_p (v) == 0) && (assoc_p (v) || array_p (v)))
     {
@@ -8171,9 +8171,9 @@ valid_parameter_transform (xform)
 }
       
 static char *
-parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, flags)
+parameter_brace_transform (varname, value, estatep, xform, rtype, quoted, pflags, flags)
      char *varname, *value;
-     arrayind_t ind;
+     array_eltstate_t *estatep;
      char *xform;
      int rtype, quoted, pflags, flags;
 {
@@ -8188,7 +8188,7 @@ parameter_brace_transform (varname, value, ind, xform, rtype, quoted, pflags, fl
   oname = this_command_name;
   this_command_name = varname;
 
-  vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
+  vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
   if (vtype == -1)
     {
       this_command_name = oname;
@@ -8304,9 +8304,9 @@ mb_substring (string, s, e)
    VARNAME.  If VARNAME is an array variable, use the array elements. */
 
 static char *
-parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags)
+parameter_brace_substring (varname, value, estatep, substr, quoted, pflags, flags)
      char *varname, *value;
-     arrayind_t ind;
+     array_eltstate_t *estatep;
      char *substr;
      int quoted, pflags, flags;
 {
@@ -8321,7 +8321,7 @@ parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags)
   oname = this_command_name;
   this_command_name = varname;
 
-  vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
+  vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
   if (vtype == -1)
     {
       this_command_name = oname;
@@ -8625,9 +8625,9 @@ pos_params_pat_subst (string, pat, rep, mflags)
    and the string to substitute.  QUOTED is a flags word containing
    the type of quoting currently in effect. */
 static char *
-parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags)
+parameter_brace_patsub (varname, value, estatep, patsub, quoted, pflags, flags)
      char *varname, *value;
-     arrayind_t ind;
+     array_eltstate_t *estatep;
      char *patsub;
      int quoted, pflags, flags;
 {
@@ -8641,7 +8641,7 @@ parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags)
   oname = this_command_name;
   this_command_name = varname;         /* error messages */
 
-  vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
+  vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
   if (vtype == -1)
     {
       this_command_name = oname;
@@ -8871,9 +8871,9 @@ pos_params_modcase (string, pat, modop, mflags)
    to perform.  QUOTED is a flags word containing the type of quoting
    currently in effect. */
 static char *
-parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, pflags, flags)
+parameter_brace_casemod (varname, value, estatep, modspec, patspec, quoted, pflags, flags)
      char *varname, *value;
-     arrayind_t ind;
+     array_eltstate_t *estatep;
      int modspec;
      char *patspec;
      int quoted, pflags, flags;
@@ -8888,7 +8888,7 @@ parameter_brace_casemod (varname, value, ind, modspec, patspec, quoted, pflags,
   oname = this_command_name;
   this_command_name = varname;
 
-  vtype = get_var_and_type (varname, value, ind, quoted, flags, &v, &val);
+  vtype = get_var_and_type (varname, value, estatep, quoted, flags, &v, &val);
   if (vtype == -1)
     {
       this_command_name = oname;
@@ -9065,7 +9065,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
   WORD_DESC *tdesc, *ret;
   int t_index, sindex, c, tflag, modspec, local_pflags, all_element_arrayref;
   intmax_t number;
-  arrayind_t ind;
+  array_eltstate_t es;
 
   temp = temp1 = value = (char *)NULL;
   var_is_set = var_is_null = var_is_special = check_nullness = 0;
@@ -9112,7 +9112,10 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
   ret = 0;
   tflag = 0;
 
-  ind = INTMAX_MIN;
+#if defined (ARRAY_VARS)
+  init_eltstate (&es);
+#endif
+  es.ind = INTMAX_MIN; /* XXX */
 
   /* If the name really consists of a special variable, then make sure
      that we have the entire name.  We don't allow indirect references
@@ -9353,7 +9356,7 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
   else
     {
       local_pflags |= PF_IGNUNBOUND|(pflags&(PF_NOSPLIT2|PF_ASSIGNRHS));
-      tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &ind);
+      tdesc = parameter_brace_expand_word (name, var_is_special, quoted, local_pflags, &es);
     }
 
   if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
@@ -9450,9 +9453,12 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
   /* If this is a substring spec, process it and add the result. */
   if (want_substring)
     {
-      temp1 = parameter_brace_substring (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
+      temp1 = parameter_brace_substring (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
       FREE (value);
       FREE (temp);
+#if defined (ARRAY_VARS)
+      flush_eltstate (&es);
+#endif
 
       if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
         {
@@ -9482,9 +9488,12 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
     }
   else if (want_patsub)
     {
-      temp1 = parameter_brace_patsub (name, temp, ind, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
+      temp1 = parameter_brace_patsub (name, temp, &es, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
       FREE (value);
       FREE (temp);
+#if defined (ARRAY_VARS)
+      flush_eltstate (&es);
+#endif
 
       if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
         {
@@ -9508,9 +9517,12 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
 #if defined (CASEMOD_EXPANSIONS)
   else if (want_casemod)
     {
-      temp1 = parameter_brace_casemod (name, temp, ind, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
+      temp1 = parameter_brace_casemod (name, temp, &es, modspec, value, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
       FREE (value);
       FREE (temp);
+#if defined (ARRAY_VARS)
+      flush_eltstate (&es);
+#endif
 
       if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
         {
@@ -9544,6 +9556,9 @@ bad_substitution:
       FREE (value);
       FREE (temp);
       free (name);
+#if defined (ARRAY_VARS)
+      flush_eltstate (&es);
+#endif
       if (shell_compatibility_level <= 43)
        return &expand_wdesc_error;
       else
@@ -9553,9 +9568,12 @@ bad_substitution:
       break;
 
     case '@':
-      temp1 = parameter_brace_transform (name, temp, ind, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
+      temp1 = parameter_brace_transform (name, temp, &es, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
       free (temp);
       free (value);
+#if defined (ARRAY_VARS)
+      flush_eltstate (&es);
+#endif
 
       if (temp1 == &expand_param_error || temp1 == &expand_param_fatal)
        {
@@ -9583,9 +9601,12 @@ bad_substitution:
          FREE (value);
          break;
        }
-      temp1 = parameter_brace_remove_pattern (name, temp, ind, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
+      temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0);
       free (temp);
       free (value);
+#if defined (ARRAY_VARS)
+      flush_eltstate (&es);
+#endif
 
       ret = alloc_word_desc ();
       ret->word = temp1;
@@ -9652,11 +9673,17 @@ bad_substitution:
              report_error (_("$%s: cannot assign in this way"), name);
              free (name);
              free (value);
+#if defined (ARRAY_VARS)
+             flush_eltstate (&es);
+#endif
              return &expand_wdesc_error;
            }
          else if (c == '?')
            {
              parameter_brace_expand_error (name, value, check_nullness);
+#if defined (ARRAY_VARS)
+             flush_eltstate (&es);
+#endif
              return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
            }
          else if (c != '+')
@@ -9686,6 +9713,9 @@ bad_substitution:
       break;
     }
   free (name);
+#if defined (ARRAY_VARS)
+  flush_eltstate (&es);
+#endif
 
   if (ret == 0)
     {
@@ -10202,7 +10232,7 @@ comsub:
          if (temp && *temp && valid_array_reference (temp, 0))
            {
              chk_atstar (temp, quoted, pflags, quoted_dollar_at_p, contains_dollar_at);
-             tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, (arrayind_t *)NULL);
+             tdesc = parameter_brace_expand_word (temp, SPECIAL_VAR (temp, 0), quoted, pflags, 0);
              if (tdesc == &expand_wdesc_error || tdesc == &expand_wdesc_fatal)
                return (tdesc);
              ret = tdesc;
@@ -10337,8 +10367,8 @@ expand_array_subscript (string, sindex, quoted, flags)
   if (ni >= slen || string[ni] != RBRACK || (ni - si) == 1 ||
       (string[ni+1] != '\0' && (quoted & Q_ARITH) == 0))
     {
-/* let's check and see what fails this check */
-itrace("expand_array_subscript: bad subscript string: `%s'", string+si);
+      /* let's check and see what fails this check */
+      INTERNAL_DEBUG (("expand_array_subscript: bad subscript string: `%s'", string+si));
       ret = (char *)xmalloc (2);       /* badly-formed subscript */
       ret[0] = string[si];
       ret[1] = '\0';
index 0b06381072414283266cf5d055a42ac14b9b6da6..c8bef8dd12533217b1b65fc20d00f3d1cc1b81e7 100755 (executable)
@@ -1,4 +1,4 @@
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
 THIS_SH=$BUILD_DIR/bash
 PATH=$PATH:$BUILD_DIR
 
index f2351a3d13546141b86f3e7ec3af3eda9d3f70d1..1d558228a2bd61a774db862570c798f8c9d2e4cb 100644 (file)
@@ -352,3 +352,34 @@ declare -A var=([two]=$'ab\001cd' [one]=$'\001\001\001\001' )
 declare -A foo=([two]=$'ab\001cd' [one]=$'\001\001\001\001' )
 declare -A foo=([$'\001']=$'ab\001cd' )
 declare -A foo=([$'\001']=$'\001\001\001\001' )
+declare -A A=(["\$(echo Darwin ; echo stderr>&2)"]="darjeeling" [Darwin]="darjeeling" )
+stderr
+darjsharking
+darjsharking
+stderr
+darj
+darj
+stderr
+DARJEELING
+DARJEELING
+stderr
+'darjeeling'
+'darjeeling'
+stderr
+darjeel
+darjeel
+stderr
+10
+10
+stderr
+darjeeling
+darjeeling
+stderr
+set
+set
+stderr
+set
+set
+stderr
+42
+42
index 30e5201d05f73e93e20660fcfefa3f255501661a..5dd90ce522ebff28a4b05212d3c047b0cc41994e 100644 (file)
@@ -256,3 +256,6 @@ ${THIS_SH} ./assoc14.sub
 
 # tests with subscripts and values containing 0x01 (some indexed array tests too)
 ${THIS_SH} ./assoc15.sub
+
+# tests with subscripts being expanded more than one in ${xxx} word expansions
+${THIS_SH} ./assoc16.sub
diff --git a/tests/assoc16.sub b/tests/assoc16.sub
new file mode 100644 (file)
index 0000000..ae8296b
--- /dev/null
@@ -0,0 +1,56 @@
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# bash versions up to and including bash-5.1 expanded these subscripts more
+# than once
+
+declare -A A
+
+A["Darwin"]=darjeeling
+A['$(echo Darwin ; echo stderr>&2)']=darjeeling
+
+declare -p A
+
+echo ${A[$(echo Darwin ; echo stderr>&2)]//eel/shark}
+echo ${A['$(echo Darwin ; echo stderr>&2)']//eel/shark}
+
+echo ${A[$(echo Darwin ; echo stderr>&2)]:0:4}
+echo ${A['$(echo Darwin ; echo stderr>&2)']:0:4}
+
+echo ${A[$(echo Darwin ; echo stderr>&2)]^^}
+echo ${A['$(echo Darwin ; echo stderr>&2)']^^}
+
+echo ${A[$(echo Darwin ; echo stderr>&2)]@Q}
+echo ${A['$(echo Darwin ; echo stderr>&2)']@Q}
+
+echo ${A[$(echo Darwin ; echo stderr>&2)]%ing}
+echo ${A['$(echo Darwin ; echo stderr>&2)']%ing}
+
+echo ${#A[$(echo Darwin ; echo stderr>&2)]}
+echo ${#A['$(echo Darwin ; echo stderr>&2)']}
+
+echo ${A[$(echo Darwin ; echo stderr>&2)]:-value}
+echo ${A['$(echo Darwin ; echo stderr>&2)']:-value}
+
+echo ${A[$(echo Darwin ; echo stderr>&2)]:+set}
+echo ${A['$(echo Darwin ; echo stderr>&2)']:+set}
+
+echo ${A[$(echo Darwin ; echo stderr>&2)]:+set}
+echo ${A['$(echo Darwin ; echo stderr>&2)']:+set}
+
+darjeeling=7*6
+Darwin=7*4
+
+echo $(( ${A[$(echo Darwin ; echo stderr>&2)]} ))
+echo $(( ${A['$(echo Darwin ; echo stderr>&2)']} ))
index 00a30b442e4b4038918880fb618fe0781504b26b..1ec41645cdd1a300f2a7f4734bf8eb412915ee1b 100644 (file)
@@ -13,7 +13,7 @@
 #
 
 # this is a new feature: expanding aliases when initially parsing command
-# substiitutions
+# substitutions
 
 shopt -s expand_aliases
 
index 1f87a4e24bb7384d6e5530270852b5bd87ae79c8..33da5238a2381ffc7ae053777dd162591c08a618 100644 (file)
@@ -120,7 +120,13 @@ argv[3] = <ve>
 5: ${x#$pat}
 6: ${y#$'not'}
 7: ${y#'not'}
+foo bar
+./heredoc7.sub: line 21: after: command not found
+./heredoc7.sub: line 29: warning: here-document at line 29 delimited by end-of-file (wanted `EOF')
+./heredoc7.sub: line 29: foobar: command not found
+./heredoc7.sub: line 29: EOF: command not found
+grep: *.c: No such file or directory
 comsub here-string
-./heredoc.tests: line 152: warning: here-document at line 150 delimited by end-of-file (wanted `EOF')
+./heredoc.tests: line 156: warning: here-document at line 154 delimited by end-of-file (wanted `EOF')
 hi
 there
index 36c005af4195c30ee98a7f2cbbbaefeb3586e66a..d10a7c104cb88dd844180e5442ee5be87471a8fc 100644 (file)
@@ -140,6 +140,10 @@ ${THIS_SH} ./heredoc5.sub
 # test $'...' and $"..." quoted strings in here-documents
 ${THIS_SH} ./heredoc6.sub
 
+# interaction between here-documents and command substitutions
+${THIS_SH} ./heredoc7.sub
+
+
 echo $(
        cat <<< "comsub here-string"
 )
diff --git a/tests/heredoc7.sub b/tests/heredoc7.sub
new file mode 100644 (file)
index 0000000..4119df1
--- /dev/null
@@ -0,0 +1,29 @@
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# should characters outside a command substitution be interpreted as a delimiter
+# for a here-document started inside it?
+echo $(cat << EOF)
+foo
+bar
+EOF
+after
+
+# should characters inside a command substitution be interpreted as a delimiter
+# for a here-document started outside of it?
+
+cat <<EOF && grep $(
+ foobar
+EOF
+echo notthereanywhere) *.c
diff --git a/trap.c b/trap.c
index 1a84aa15710450e5f1d4c4811051c9ab52509162..8c0547559163ef06412dee37b6d9e45f57276628 100644 (file)
--- a/trap.c
+++ b/trap.c
@@ -311,9 +311,7 @@ run_pending_traps ()
 
   if (running_trap > 0)
     {
-#if defined (DEBUG)
-      internal_warning ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap-1);
-#endif
+      internal_debug ("run_pending_traps: recursive invocation while running trap for signal %d", running_trap-1);
 #if defined (SIGWINCH)
       if (running_trap == SIGWINCH+1 && pending_traps[SIGWINCH])
        return;                 /* no recursive SIGWINCH trap invocations */
@@ -475,9 +473,7 @@ trap_handler (sig)
 
   if ((sigmodes[sig] & SIG_TRAPPED) == 0)
     {
-#if defined (DEBUG)
-      internal_warning ("trap_handler: signal %d: signal not trapped", sig);
-#endif
+      internal_debug ("trap_handler: signal %d: signal not trapped", sig);
       SIGRETURN (0);
     }
 
index 47f68c4e708ee27aa7bfb261d90104fa3c13bc34..ec82393d5a8709bc8e2e1e725bfc50030dfb5f23 100644 (file)
@@ -48,6 +48,7 @@
 #include "unwind_prot.h"
 #include "sig.h"
 #include "quit.h"
+#include "bashintl.h"  /* for _() */
 #include "error.h"     /* for internal_warning */
 #include "ocache.h"
 
@@ -282,7 +283,7 @@ unwind_frame_discard_internal (tag, ignore)
     }
 
   if (found == 0)
-    internal_warning ("unwind_frame_discard: %s: frame not found", tag);
+    internal_warning (_("unwind_frame_discard: %s: frame not found"), tag);
 }
 
 /* Restore the value of a variable, based on the contents of SV.
@@ -328,7 +329,7 @@ unwind_frame_run_internal (tag, ignore)
       uwpfree (elt);
     }
   if (tag && found == 0)
-    internal_warning ("unwind_frame_run: %s: frame not found", tag);
+    internal_warning (_("unwind_frame_run: %s: frame not found"), tag);
 }
 
 static void
index dc3f7e68f82f9975a6fc8b7326fa58619d5a243d..802a0510dbabdd228ff074ad148939522ddc9dab 100644 (file)
@@ -2815,7 +2815,7 @@ make_local_array_variable (name, flags)
      scope and discard anything that's invalid. */
   if (localvar_inherit && assoc_p (var))
     {
-      internal_warning ("%s: cannot inherit value from incompatible type", name);
+      internal_warning (_("%s: cannot inherit value from incompatible type"), name);
       VUNSETATTR (var, att_assoc);
       dispose_variable_value (var);
       array = array_create ();
@@ -2871,7 +2871,7 @@ make_local_assoc_variable (name, flags)
      scope and discard anything that's invalid. */
   if (localvar_inherit && array_p (var))
     {
-      internal_warning ("%s: cannot inherit value from incompatible type", name);
+      internal_warning (_("%s: cannot inherit value from incompatible type"), name);
       VUNSETATTR (var, att_array);
       dispose_variable_value (var);
       hash = assoc_create (ASSOC_HASH_BUCKETS);