findutils-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Findutils-patches] [PATCH 02/19] Fix Savannah bug 22662 (nanoseconds wr


From: James Youngman
Subject: [Findutils-patches] [PATCH 02/19] Fix Savannah bug 22662 (nanoseconds wrongly appended after PM for find -printf %AX)
Date: Fri, 10 Apr 2009 23:52:59 +0100

---
 NEWS        |    3 +
 find/pred.c |  392 +++++++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 265 insertions(+), 130 deletions(-)

diff --git a/NEWS b/NEWS
index 2bd951d..0f7611c 100644
--- a/NEWS
+++ b/NEWS
@@ -271,6 +271,9 @@ This bug has been assigned CVE number CVE-2007-2452.
 
 ** Bug Fixes
 
+#22662: nanoseconds wrongly appended after "PM" for find -printf %AX
+in locale en_US.UTF-8.
+
 #22057: Actually rename the old locate database to the new one
  atomically, instead of just claiming the rename is atomic in a
  comment.
diff --git a/find/pred.c b/find/pred.c
index d758276..5247311 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -6,12 +6,12 @@
    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/>.
 */
@@ -32,6 +32,7 @@
 #include <fcntl.h>
 #include <locale.h>
 #include <openat.h>
+#include <ctype.h>
 #include "xalloc.h"
 #include "dirname.h"
 #include "human.h"
@@ -237,13 +238,13 @@ struct pred_assoc pred_table[] =
 static double ts_difference(struct timespec ts1,
                            struct timespec ts2)
 {
-  double d =  difftime(ts1.tv_sec, ts2.tv_sec) 
+  double d =  difftime(ts1.tv_sec, ts2.tv_sec)
     + (1.0e-9 * (ts1.tv_nsec - ts2.tv_nsec));
   return d;
 }
 
 
-static int 
+static int
 compare_ts(struct timespec ts1,
           struct timespec ts2)
 {
@@ -260,17 +261,17 @@ compare_ts(struct timespec ts1,
 }
 
 /* Predicate processing routines.
- 
+
    PATHNAME is the full pathname of the file being checked.
    *STAT_BUF contains information about PATHNAME.
    *PRED_PTR contains information for applying the predicate.
- 
+
    Return true if the file passes this predicate, false if not. */
 
 
 /* pred_timewindow
  *
- * Returns true if THE_TIME is 
+ * Returns true if THE_TIME is
  * COMP_GT: after the specified time
  * COMP_LT: before the specified time
  * COMP_EQ: after the specified time but by not more than WINDOW seconds.
@@ -282,23 +283,23 @@ pred_timewindow(struct timespec ts, struct predicate 
const *pred_ptr, int window
     {
     case COMP_GT:
       return compare_ts(ts, pred_ptr->args.reftime.ts) > 0;
-      
+
     case COMP_LT:
       return compare_ts(ts, pred_ptr->args.reftime.ts) < 0;
-      
+
     case COMP_EQ:
       {
        /* consider "find . -mtime 0".
-        * 
-        * Here, the origin is exactly 86400 seconds before the start 
-        * of the program (since -daystart was not specified).   This 
-        * function will be called with window=86400 and 
-        * pred_ptr->args.reftime.ts as the origin.  Hence a file 
-        * created the instant the program starts will show a time 
-        * difference (value of delta) of 86400.   Similarly, a file 
-        * created exactly 24h ago would be the newest file which was 
-        * _not_ created today.   So, if delta is 0.0, the file 
-        * was not created today.  If the delta is 86400, the file 
+        *
+        * Here, the origin is exactly 86400 seconds before the start
+        * of the program (since -daystart was not specified).   This
+        * function will be called with window=86400 and
+        * pred_ptr->args.reftime.ts as the origin.  Hence a file
+        * created the instant the program starts will show a time
+        * difference (value of delta) of 86400.   Similarly, a file
+        * created exactly 24h ago would be the newest file which was
+        * _not_ created today.   So, if delta is 0.0, the file
+        * was not created today.  If the delta is 86400, the file
         * was created this instant.
         */
        double delta = ts_difference(ts, pred_ptr->args.reftime.ts);
@@ -350,7 +351,7 @@ pred_closeparen (const char *pathname, struct stat 
*stat_buf, struct predicate *
   (void) &pathname;
   (void) &stat_buf;
   (void) &pred_ptr;
-  
+
   return true;
 }
 
@@ -365,7 +366,7 @@ boolean
 pred_cnewer (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
   (void) pathname;
-  
+
   assert (COMP_GT == pred_ptr->args.reftime.kind);
   return compare_ts(get_stat_ctime(stat_buf), pred_ptr->args.reftime.ts) > 0;
 }
@@ -448,7 +449,7 @@ pred_empty (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_
 {
   (void) pathname;
   (void) pred_ptr;
-  
+
   if (S_ISDIR (stat_buf->st_mode))
     {
       int fd;
@@ -511,8 +512,8 @@ new_impl_pred_exec (int dir_fd, const char *pathname,
   execp->dir_fd = dir_fd;
   if (execp->multiple)
     {
-      /* Push the argument onto the current list. 
-       * The command may or may not be run at this point, 
+      /* Push the argument onto the current list.
+       * The command may or may not be run at this point,
        * depending on the command line length limits.
        */
       bc_push_arg(&execp->ctl,
@@ -523,7 +524,7 @@ new_impl_pred_exec (int dir_fd, const char *pathname,
 
       /* remember that there are pending execdirs. */
       state.execdirs_outstanding = true;
-      
+
       /* POSIX: If the primary expression is punctuated by a plus
        * sign, the primary shall always evaluate as true
        */
@@ -575,7 +576,7 @@ pred_false (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_
   (void) &stat_buf;
   (void) &pred_ptr;
 
-  
+
   return (false);
 }
 
@@ -595,7 +596,7 @@ pred_fprint (const char *pathname, struct stat *stat_buf, 
struct predicate *pred
 {
   (void) &pathname;
   (void) &stat_buf;
-  
+
   print_quoted(pred_ptr->args.printf_vec.stream,
               pred_ptr->args.printf_vec.quote_opts,
               pred_ptr->args.printf_vec.dest_is_tty,
@@ -610,7 +611,7 @@ pred_fprint0 (const char *pathname, struct stat *stat_buf, 
struct predicate *pre
   FILE * fp = pred_ptr->args.printf_vec.stream;
 
   (void) &stat_buf;
-  
+
   fputs (pathname, fp);
   putc (0, fp);
   return true;
@@ -649,7 +650,7 @@ mode_to_filetype(mode_t m)
   return "U";                  /* Unknown */
 }
 
-static double 
+static double
 file_sparseness(const struct stat *p)
 {
 #if defined HAVE_STRUCT_STAT_ST_BLOCKS
@@ -665,7 +666,7 @@ file_sparseness(const struct stat *p)
       double blklen = file_blocksize(p) * (double)p->st_blocks;
       return blklen / p->st_size;
     }
-#else  
+#else
   return 1.0;
 #endif
 }
@@ -728,13 +729,13 @@ do_fprintf(struct format_val *dest,
       /* trusted */
       checked_fwrite(segment->text, 1, segment->text_len, dest);
       break;
-         
+
     case KIND_STOP:            /* Terminate argument and flush output. */
       /* trusted */
       checked_fwrite(segment->text, 1, segment->text_len, dest);
       checked_fflush(dest);
       break;
-         
+
     case KIND_FORMAT:
       switch (segment->format_char[0])
        {
@@ -759,7 +760,7 @@ do_fprintf(struct format_val *dest,
          break;
        case 'D':               /* Device on which file exists (stat.st_dev) */
          /* trusted */
-         checked_fprintf (dest, segment->text, 
+         checked_fprintf (dest, segment->text,
                           human_readable ((uintmax_t) stat_buf->st_dev, hbuf,
                                           human_ceiling, 1, 1));
          break;
@@ -849,7 +850,7 @@ do_fprintf(struct format_val *dest,
          checked_fprintf (dest, segment->text,
                           human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
                                           hbuf, human_ceiling,
-                                          ST_NBLOCKSIZE, 1024)); 
+                                          ST_NBLOCKSIZE, 1024));
          break;
        case 'l':               /* object of symlink */
          /* sanitised */
@@ -919,7 +920,7 @@ do_fprintf(struct format_val *dest,
                         | (m & S_IXOTH ? 00001 : 0))));
          }
          break;
-         
+
        case 'n':               /* number of links */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
@@ -952,25 +953,25 @@ do_fprintf(struct format_val *dest,
            }
          checked_print_quoted (dest, segment->text, cp);
          break;
-         
+
        case 's':               /* size in bytes */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
                   human_readable ((uintmax_t) stat_buf->st_size,
                                   hbuf, human_ceiling, 1, 1));
          break;
-         
+
        case 'S':               /* sparseness */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text, file_sparseness(stat_buf));;
          break;
-         
+
        case 't':               /* mtime in `ctime' format */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
                           ctime_format (get_stat_mtime(stat_buf)));
          break;
-         
+
        case 'u':               /* user name */
          /* trusted */
          /* (well, the actual user is selected by the user on systems
@@ -990,7 +991,7 @@ do_fprintf(struct format_val *dest,
            /* else fallthru */
          }
          /* FALLTHROUGH*/ /* .. to case U */
-         
+
        case 'U':               /* UID number */
          /* UNTRUSTED, probably unexploitable */
          checked_fprintf (dest, segment->text,
@@ -998,8 +999,8 @@ do_fprintf(struct format_val *dest,
                                           human_ceiling, 1, 1));
          break;
 
-         /* %Y: type of file system entry like `ls -l`: 
-          *     (d,-,l,s,p,b,c,n) n=nonexistent(symlink) 
+         /* %Y: type of file system entry like `ls -l`:
+          *     (d,-,l,s,p,b,c,n) n=nonexistent(symlink)
           */
        case 'Y':               /* in case of symlink */
          /* trusted */
@@ -1024,7 +1025,7 @@ do_fprintf(struct format_val *dest,
                        checked_fprintf (dest, segment->text, "L");
                        break;
                      }
-                   else 
+                   else
                      {
                        checked_fprintf (dest, segment->text, "?");
                        error (0, errno, "%s",
@@ -1071,7 +1072,7 @@ pred_fprintf (const char *pathname, struct stat 
*stat_buf, struct predicate *pre
        {
          struct timespec ts;
          int valid = 0;
-         
+
          switch (segment->format_char[0])
            {
            case 'A':
@@ -1097,7 +1098,7 @@ pred_fprintf (const char *pathname, struct stat 
*stat_buf, struct predicate *pre
              assert (0);
              abort ();
            }
-         /* We trust the output of format_date not to contain 
+         /* We trust the output of format_date not to contain
           * nasty characters, though the value of the date
           * is itself untrusted data.
           */
@@ -1131,7 +1132,7 @@ boolean
 pred_fstype (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
   (void) pathname;
-  
+
   if (strcmp (filesystem_type (stat_buf, pathname), pred_ptr->args.str) == 0)
     return true;
   else
@@ -1142,7 +1143,7 @@ boolean
 pred_gid (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
   (void) pathname;
-  
+
   switch (pred_ptr->args.numinfo.kind)
     {
     case COMP_GT:
@@ -1165,7 +1166,7 @@ boolean
 pred_group (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
   (void) pathname;
-  
+
   if (pred_ptr->args.gid == stat_buf->st_gid)
     return (true);
   else
@@ -1180,15 +1181,15 @@ pred_ilname (const char *pathname, struct stat 
*stat_buf, struct predicate *pred
 
 /* Common code between -name, -iname.  PATHNAME is being visited, STR
    is name to compare basename against, and FLAGS are passed to
-   fnmatch.  Recall that 'find / -name /' is one of the few times where a '/' 
-   in the -name must actually find something. */ 
+   fnmatch.  Recall that 'find / -name /' is one of the few times where a '/'
+   in the -name must actually find something. */
 static boolean
 pred_name_common (const char *pathname, const char *str, int flags)
 {
   boolean b;
-  /* We used to use last_component() here, but that would not allow us to 
modify the 
+  /* We used to use last_component() here, but that would not allow us to 
modify the
    * input string, which is const.   We could optimise by duplicating the 
string only
-   * if we need to modify it, and I'll do that if there is a measurable 
+   * if we need to modify it, and I'll do that if there is a measurable
    * performance difference on a machine built after 1990...
    */
   char *base = base_name (pathname);
@@ -1214,7 +1215,7 @@ boolean
 pred_inum (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
   (void) pathname;
-  
+
   switch (pred_ptr->args.numinfo.kind)
     {
     case COMP_GT:
@@ -1237,7 +1238,7 @@ boolean
 pred_ipath (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
   (void) stat_buf;
-  
+
   if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
     return (true);
   return (false);
@@ -1247,7 +1248,7 @@ boolean
 pred_links (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
   (void) pathname;
-  
+
   switch (pred_ptr->args.numinfo.kind)
     {
     case COMP_GT:
@@ -1329,7 +1330,7 @@ boolean
 pred_newer (const char *pathname, struct stat *stat_buf, struct predicate 
*pred_ptr)
 {
   (void) pathname;
-  
+
   assert (COMP_GT == pred_ptr->args.reftime.kind);
   return compare_ts(get_stat_mtime(stat_buf), pred_ptr->args.reftime.ts) > 0;
 }
@@ -1339,9 +1340,9 @@ pred_newerXY (const char *pathname, struct stat 
*stat_buf, struct predicate *pre
 {
   struct timespec ts;
   boolean collected = false;
-  
+
   assert (COMP_GT == pred_ptr->args.reftime.kind);
-  
+
   switch (pred_ptr->args.reftime.xval)
     {
     case XVAL_TIME:
@@ -1352,7 +1353,7 @@ pred_newerXY (const char *pathname, struct stat 
*stat_buf, struct predicate *pre
       ts = get_stat_atime(stat_buf);
       collected = true;
       break;
-      
+
     case XVAL_BIRTHTIME:
       ts = get_stat_birthtime(stat_buf);
       collected = true;
@@ -1364,18 +1365,18 @@ pred_newerXY (const char *pathname, struct stat 
*stat_buf, struct predicate *pre
          return false;
        }
       break;
-      
+
     case XVAL_CTIME:
       ts = get_stat_ctime(stat_buf);
       collected = true;
       break;
-      
+
     case XVAL_MTIME:
       ts = get_stat_mtime(stat_buf);
       collected = true;
       break;
     }
-  
+
   assert (collected);
   return compare_ts(ts, pred_ptr->args.reftime.ts) > 0;
 }
@@ -1385,7 +1386,7 @@ pred_nogroup (const char *pathname, struct stat 
*stat_buf, struct predicate *pre
 {
   (void) pathname;
   (void) pred_ptr;
-  
+
 #ifdef CACHE_IDS
   extern char *gid_unused;
 
@@ -1401,10 +1402,10 @@ pred_nouser (const char *pathname, struct stat 
*stat_buf, struct predicate *pred
 #ifdef CACHE_IDS
   extern char *uid_unused;
 #endif
-  
+
   (void) pathname;
   (void) pred_ptr;
-  
+
 #ifdef CACHE_IDS
   return uid_unused[(unsigned) stat_buf->st_uid];
 #else
@@ -1444,7 +1445,7 @@ pred_okdir (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_
   const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
   if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
     return new_impl_pred_exec (get_current_dirfd(),
-                              state.rel_pathname, stat_buf, pred_ptr, 
+                              state.rel_pathname, stat_buf, pred_ptr,
                               prefix, (prefix ? 2 : 0));
   else
     return false;
@@ -1500,8 +1501,8 @@ pred_perm (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_p
        * evaluate as true if at least all of the bits specified in
        * onum that are also set in the octal mask 07777 are set.
        *
-       * Eric Blake's interpretation is that the mode argument is zero, 
-       
+       * Eric Blake's interpretation is that the mode argument is zero,
+
        */
       if (0 == perm_val)
        return true;            /* Savannah bug 14748; we used to return false 
*/
@@ -1555,7 +1556,7 @@ pred_executable (const char *pathname, struct stat 
*stat_buf, struct predicate *
   (void) pathname;
   (void) stat_buf;
   (void) pred_ptr;
-  
+
   return can_access(X_OK);
 }
 
@@ -1565,7 +1566,7 @@ pred_readable (const char *pathname, struct stat 
*stat_buf, struct predicate *pr
   (void) pathname;
   (void) stat_buf;
   (void) pred_ptr;
-  
+
   return can_access(R_OK);
 }
 
@@ -1575,7 +1576,7 @@ pred_writable (const char *pathname, struct stat 
*stat_buf, struct predicate *pr
   (void) pathname;
   (void) stat_buf;
   (void) pred_ptr;
-  
+
   return can_access(W_OK);
 }
 
@@ -1610,7 +1611,7 @@ pred_prune (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_
     state.stop_at_current_level = true;
 
   /* findutils used to return options.do_dir_first here, so that -prune
-   * returns true only if -depth is not in effect.   But POSIX requires 
+   * returns true only if -depth is not in effect.   But POSIX requires
    * that -prune always evaluate as true.
    */
   return true;
@@ -1623,12 +1624,12 @@ pred_quit (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_p
   (void) stat_buf;
   (void) pred_ptr;
 
-  /* Run any cleanups.  This includes executing any command lines 
+  /* Run any cleanups.  This includes executing any command lines
    * we have partly built but not executed.
    */
   cleanup();
-  
-  /* Since -exec and friends don't leave child processes running in the 
+
+  /* Since -exec and friends don't leave child processes running in the
    * background, there is no need to wait for them here.
    */
   exit(state.exit_status);     /* 0 for success, etc. */
@@ -1685,7 +1686,7 @@ pred_samefile (const char *pathname, struct stat 
*stat_buf, struct predicate *pr
   (void) pathname;
 
   /* We will often still have an fd open on the file under consideration,
-   * but that's just to ensure inode number stability by maintaining 
+   * but that's just to ensure inode number stability by maintaining
    * a reference to it; we don't need the file for anything else.
    */
   return stat_buf->st_ino == pred_ptr->args.samefileid.ino
@@ -1711,12 +1712,12 @@ pred_type (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_p
 
   if (0 == state.type)
     {
-      /* This can sometimes happen with broken NFS servers. 
+      /* This can sometimes happen with broken NFS servers.
        * See Savannah bug #16378.
        */
       return false;
     }
-  
+
   (void) pathname;
 
   if (state.have_stat)
@@ -1811,20 +1812,20 @@ pred_xtype (const char *pathname, struct stat 
*stat_buf, struct predicate *pred_
   int (*ystat) (const char*, struct stat *p);
 
   /* If we would normally stat the link itself, stat the target instead.
-   * If we would normally follow the link, stat the link itself instead. 
+   * If we would normally follow the link, stat the link itself instead.
    */
   if (following_links())
     ystat = optionp_stat;
   else
     ystat = optionl_stat;
-  
+
   set_stat_placeholders(&sbuf);
   if ((*ystat) (state.rel_pathname, &sbuf) != 0)
     {
       if (following_links() && errno == ENOENT)
        {
          /* If we failed to follow the symlink,
-          * fall back on looking at the symlink itself. 
+          * fall back on looking at the symlink itself.
           */
          /* Mimic behavior of ls -lL. */
          return (pred_type (pathname, stat_buf, pred_ptr));
@@ -1836,7 +1837,7 @@ pred_xtype (const char *pathname, struct stat *stat_buf, 
struct predicate *pred_
        }
       return false;
     }
-  /* Now that we have our stat() information, query it in the same 
+  /* Now that we have our stat() information, query it in the same
    * way that -type does.
    */
   return (pred_type (pathname, &sbuf, pred_ptr));
@@ -1868,13 +1869,13 @@ prep_child_for_exec (boolean close_stdin, int dir_fd)
   if (close_stdin)
     {
       const char inputfile[] = "/dev/null";
-      
+
       if (close(0) < 0)
        {
          error(0, errno, _("Cannot close standard input"));
          ok = false;
        }
-      else 
+      else
        {
          if (open(inputfile, O_RDONLY
 #if defined O_LARGEFILE
@@ -1882,7 +1883,7 @@ prep_child_for_exec (boolean close_stdin, int dir_fd)
 #endif
                   ) < 0)
            {
-             /* This is not entirely fatal, since 
+             /* This is not entirely fatal, since
               * executing the child with a closed
               * stdin is almost as good as executing it
               * with its stdin attached to /dev/null.
@@ -1929,15 +1930,15 @@ launch (const struct buildcmd_control *ctl,
       assert (starting_desc >= 0);
       assert (execp->dir_fd == starting_desc);
     }
-  
-       
+
+
   /* Null terminate the arg list.  */
-  bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false); 
-  
+  bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false);
+
   /* Make sure output of command doesn't get mixed with find output. */
   fflush (stdout);
   fflush (stderr);
-  
+
   /* Make sure to listen for the kids.  */
   if (first_time)
     {
@@ -1956,7 +1957,7 @@ launch (const struct buildcmd_control *ctl,
        {
          _exit(1);
        }
-      
+
       execvp (buildstate->cmd_argv[0], buildstate->cmd_argv);
       error (0, errno, "%s",
             safely_quote_err_filename(0, buildstate->cmd_argv[0]));
@@ -1967,7 +1968,7 @@ launch (const struct buildcmd_control *ctl,
   /* In parent; set up for next time. */
   bc_clear_args(ctl, buildstate);
 
-  
+
   while (waitpid (child_pid, &wait_status, 0) == (pid_t) -1)
     {
       if (errno != EINTR)
@@ -1978,23 +1979,23 @@ launch (const struct buildcmd_control *ctl,
          return 0;             /* FAIL */
        }
     }
-  
+
   if (WIFSIGNALED (wait_status))
     {
       error (0, 0, _("%s terminated by signal %d"),
             quotearg_n_style(0, options.err_quoting_style,
                              buildstate->cmd_argv[0]),
             WTERMSIG (wait_status));
-      
+
       if (execp->multiple)
        {
-         /* -exec   \; just returns false if the invoked command fails. 
+         /* -exec   \; just returns false if the invoked command fails.
           * -exec {} + returns true if the invoked command fails, but
           *            sets the program exit status.
           */
          state.exit_status = 1;
        }
-      
+
       return 1;                        /* OK */
     }
 
@@ -2006,7 +2007,7 @@ launch (const struct buildcmd_control *ctl,
     {
       if (execp->multiple)
        {
-         /* -exec   \; just returns false if the invoked command fails. 
+         /* -exec   \; just returns false if the invoked command fails.
           * -exec {} + returns true if the invoked command fails, but
           *            sets the program exit status.
           */
@@ -2014,10 +2015,137 @@ launch (const struct buildcmd_control *ctl,
        }
       return 0;                        /* FAIL */
     }
-  
+
+}
+
+
+static boolean
+scan_for_digit_differences(const char *p, const char *q,
+                          size_t *first, size_t *n)
+{
+  bool ok = true;
+  bool seen = false;
+  size_t i;
+
+  for (i=0; p[i] && q[i]; i++)
+    {
+      if (p[i] != q[i])
+       {
+         if (!isdigit((unsigned char)q[i]) || !isdigit ((unsigned char)q[i]))
+           return false;
+
+         if (!seen)
+           {
+             *first = i;
+             *n = 1;
+           }
+         else
+           {
+             if (*first - i == *n)
+               {
+                 /* Still in the first sequence of differing digits. */
+                 ++*n;
+               }
+             else
+               {
+                 /* More than one differing contiguous character sequence. */
+                 return false;
+               }
+           }
+       }
+    }
+  if (p[i] || q[i])
+    {
+      /* strings are different lengths. */
+      return false;
+    }
+  return true;
 }
 
 
+static char*
+do_time_format (const char *fmt, const struct tm *p, const char *ns, size_t 
ns_size)
+{
+  static char *buf = NULL;
+  static size_t buf_size = 0u;
+  char *timefmt = NULL;
+  boolean done = false;
+  struct tm altered_time;
+
+
+  /* If the format expands to nothing (%p in some locales, for
+   * example), strftime can return 0.  We actually want to distinguish
+   * the error case where the buffer is too short, so we just prepend
+   * an otherwise uninteresting character to prevent the no-output
+   * case.
+   */
+  timefmt = xmalloc (strlen(fmt) + 2u);
+  sprintf (timefmt, "_%s", fmt);
+
+  /* altered_time is a similar time, but in which both
+   * digits of the seconds field are different.
+   */
+  altered_time = *p;
+  if (altered_time.tm_sec >= 11)
+    altered_time.tm_sec -= 11;
+  else
+    altered_time.tm_sec += 11;
+
+  while (!done)
+    {
+      const size_t buf_used = strftime (buf, buf_size, timefmt, p);
+      if (0 != buf_used)
+       {
+         char *altbuf;
+         size_t i, n;
+         size_t final_len = (buf_used
+                             + 1u /* for \0 */
+                             - 1u /* because we don't need the initial 
underscore */
+                             + ns_size);
+         buf = xrealloc (buf, final_len);
+         altbuf = xmalloc (final_len);
+         strftime (altbuf, buf_size, timefmt, &altered_time);
+
+         /* Find the seconds digits; they should be the only changed part.
+          * In theory the result of the two formatting operations could differ 
in
+          * more than just one sequence of decimal digits (for example %X might
+          * in theory return a spelled-out time like "thirty seconds past 
noon").
+          * When that happens, we just avoid inserting the nanoseconds field.
+          */
+         if (scan_for_digit_differences (buf, altbuf, &i, &n)
+             && (2==n) && buf[i+n] && !isdigit((unsigned char)buf[i+n+1]))
+           {
+             const size_t end_of_seconds = i + n;
+
+             /* Move the tail (including the \0).  Note that this
+              * is a move of an overlapping memory block, so we
+              * must use memmove instead of memcpy.  Then insert
+              * the nanoseconds (but not its trailing \0).
+              */
+             memmove (buf+end_of_seconds+ns_size,
+                      buf+end_of_seconds,
+                      buf_used-(end_of_seconds)+1);
+             memcpy (buf+i+n, ns, ns_size);
+           }
+         else
+           {
+             /* No seconds digits.  No need to insert anything. */
+           }
+         /* The first character of buf is the underscore, which we actually
+          * don't want.
+          */
+         free (timefmt);
+         return buf+1;
+       }
+      else
+       {
+         buf = x2nrealloc (buf, &buf_size, 2u);
+       }
+    }
+}
+
+
+
 /* Return a static string formatting the time WHEN according to the
  * strftime format character KIND.
  *
@@ -2038,16 +2166,16 @@ format_date (struct timespec ts, int kind)
    * For example, some systems return junk in the tv_nsec part of
    * st_birthtime.  An example of this is the NetBSD-4.0-RELENG kernel
    * (at Sat Mar 24 18:46:46 2007) running a NetBSD-3.1-RELEASE
-   * runtime and examining files on an msdos filesytem.  So for that 
-   * reason we set NS_BUF_LEN to 32, which is simply "long enough" as 
-   * opposed to "exactly the right size".  Note that the behaviour of 
-   * NetBSD appears to be a result of the use of uninitialised data, 
+   * runtime and examining files on an msdos filesytem.  So for that
+   * reason we set NS_BUF_LEN to 32, which is simply "long enough" as
+   * opposed to "exactly the right size".  Note that the behaviour of
+   * NetBSD appears to be a result of the use of uninitialised data,
    * as it's not 100% reproducible (more like 25%).
    */
   enum {
     NS_BUF_LEN = 32,
     DATE_LEN_PERCENT_APLUS=21  /* length of result of %A+ (it's longer than 
%c)*/
-  };     
+  };
   static char buf[128u+10u + MAX(DATE_LEN_PERCENT_APLUS,
                            MAX (LONGEST_HUMAN_READABLE + 2, 
NS_BUF_LEN+64+200))];
   char ns_buf[NS_BUF_LEN]; /* -.9999999990 (- sign can happen!)*/
@@ -2069,7 +2197,7 @@ format_date (struct timespec ts, int kind)
 
   charsprinted = 0;
   need_ns_suffix = 0;
-  
+
   /* Format the main part of the time. */
   if (kind == '+')
     {
@@ -2105,26 +2233,30 @@ format_date (struct timespec ts, int kind)
        * The reason for discouraging this is that in the future, the
        * granularity may not be nanoseconds.
        */
-      ns_buf[0] = 0;
       charsprinted = snprintf(ns_buf, NS_BUF_LEN, ".%09ld0", (long 
int)ts.tv_nsec);
       assert (charsprinted < NS_BUF_LEN);
     }
+  else
+    {
+      charsprinted = 0;
+      ns_buf[0] = 0;
+    }
 
-  if (kind != '@'
-      && (tm = localtime (&ts.tv_sec))
-      && strftime (buf, sizeof buf, fmt, tm))
+  if (kind != '@')
     {
-      /* For %AS, %CS, %TS, add the fractional part of the seconds
-       * information.
-       */
-      if (need_ns_suffix)
+      tm = localtime (&ts.tv_sec);
+      if (tm)
        {
-         assert ((sizeof buf - strlen(buf)) > strlen(ns_buf));
-         strcat(buf, ns_buf);
+         char *s = do_time_format (fmt, tm, ns_buf, charsprinted);
+         if (s)
+           return s;
        }
-      return buf;
     }
-  else
+
+  /* If we get to here, either the format was %@, or we have fallen back to it
+   * because strftime failed.
+   */
+  if (1)
     {
       uintmax_t w = ts.tv_sec;
       size_t used, len, remaining;
@@ -2150,7 +2282,7 @@ format_date (struct timespec ts, int kind)
          used = (p-buf) + len; /* Offset into buf of current end */
          assert (sizeof buf > used); /* Ensure we can perform subtraction 
safely. */
          remaining = sizeof buf - used - 1u; /* allow space for NUL */
-         
+
          if (strlen(ns_buf) >= remaining)
            {
              error(0, 0,
@@ -2164,11 +2296,11 @@ format_date (struct timespec ts, int kind)
     }
 }
 
-static const char *weekdays[] = 
+static const char *weekdays[] =
   {
     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
   };
-static char * months[] = 
+static char * months[] =
   {
     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
@@ -2182,7 +2314,7 @@ ctime_format (struct timespec ts)
 #define TIME_BUF_LEN 1024u
   static char resultbuf[TIME_BUF_LEN];
   int nout;
-  
+
   ptm = localtime(&ts.tv_sec);
   if (ptm)
     {
@@ -2194,7 +2326,7 @@ ctime_format (struct timespec ts)
       assert (ptm->tm_hour <  24);
       assert (ptm->tm_min  <  60);
       assert (ptm->tm_sec  <= 61); /* allows 2 leap seconds. */
-      
+
       /* wkday mon mday hh:mm:ss.nnnnnnnnn yyyy */
       nout = snprintf(resultbuf, TIME_BUF_LEN,
                      "%3s %3s %2d %02d:%02d:%02d.%010ld %04d",
@@ -2206,7 +2338,7 @@ ctime_format (struct timespec ts)
                      ptm->tm_sec,
                      (long int)ts.tv_nsec,
                      1900 + ptm->tm_year);
-      
+
       assert (nout < TIME_BUF_LEN);
       return resultbuf;
     }
@@ -2327,9 +2459,9 @@ void show_success_rates(const struct predicate *p)
 
 
 #ifdef _NDEBUG
-/* If _NDEBUG is defined, the assertions will do nothing.   Hence 
+/* If _NDEBUG is defined, the assertions will do nothing.   Hence
  * there is no point in having a function body for pred_sanity_check()
- * if that preprocessor macro is defined. 
+ * if that preprocessor macro is defined.
  */
 void
 pred_sanity_check(const struct predicate *predicates)
@@ -2342,7 +2474,7 @@ void
 pred_sanity_check(const struct predicate *predicates)
 {
   const struct predicate *p;
-  
+
   for (p=predicates; p != NULL; p=p->pred_next)
     {
       /* All predicates must do something. */
@@ -2350,17 +2482,17 @@ pred_sanity_check(const struct predicate *predicates)
 
       /* All predicates must have a parser table entry. */
       assert (p->parser_entry != NULL);
-      
-      /* If the parser table tells us that just one predicate function is 
+
+      /* If the parser table tells us that just one predicate function is
        * possible, verify that that is still the one that is in effect.
-       * If the parser has NULL for the predicate function, that means that 
+       * If the parser has NULL for the predicate function, that means that
        * the parse_xxx function fills it in, so we can't check it.
        */
       if (p->parser_entry->pred_func)
        {
          assert (p->parser_entry->pred_func == p->pred_func);
        }
-      
+
       switch (p->parser_entry->type)
        {
          /* Options all take effect during parsing, so there should
@@ -2377,7 +2509,7 @@ pred_sanity_check(const struct predicate *predicates)
          assert (p->parser_entry->type != ARG_OPTION);
          assert (p->parser_entry->type != ARG_POSITIONAL_OPTION);
          break;
-         
+
        case ARG_ACTION:
          assert(p->side_effects); /* actions have side effects. */
          if (!pred_is(p, pred_prune) && !pred_is(p, pred_quit))
-- 
1.5.6.5





reply via email to

[Prev in Thread] Current Thread [Next in Thread]