(root)/
diffutils-3.10/
lib/
cmpbuf.c
       1  /* Buffer primitives for comparison operations.
       2  
       3     Copyright (C) 1993, 1995, 1998, 2001-2002, 2006, 2009-2013, 2015-2023 Free
       4     Software Foundation, Inc.
       5  
       6     This program is free software: you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation, either version 3 of the License, or
       9     (at your option) any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      18  
      19  #include <config.h>
      20  
      21  #include <errno.h>
      22  #include <limits.h>
      23  #include <signal.h>
      24  #include <unistd.h>
      25  #include <stdint.h>
      26  #include <inttypes.h>
      27  #include <sys/types.h>
      28  #include "cmpbuf.h"
      29  #include "intprops.h"
      30  
      31  #ifndef SSIZE_MAX
      32  # define SSIZE_MAX TYPE_MAXIMUM (ssize_t)
      33  #endif
      34  
      35  #undef MIN
      36  #define MIN(a, b) ((a) <= (b) ? (a) : (b))
      37  
      38  /* Read NBYTES bytes from descriptor FD into BUF.
      39     NBYTES must not be SIZE_MAX.
      40     Return the number of characters successfully read.
      41     On error, return SIZE_MAX, setting errno.
      42     The number returned is always NBYTES unless end-of-file or error.  */
      43  
      44  size_t
      45  block_read (int fd, char *buf, size_t nbytes)
      46  {
      47    char *bp = buf;
      48    char const *buflim = buf + nbytes;
      49    size_t readlim = MIN (SSIZE_MAX, SIZE_MAX);
      50  
      51    do
      52      {
      53        size_t bytes_remaining = buflim - bp;
      54        size_t bytes_to_read = MIN (bytes_remaining, readlim);
      55        ssize_t nread = read (fd, bp, bytes_to_read);
      56        if (nread <= 0)
      57          {
      58            if (nread == 0)
      59              break;
      60  
      61            /* Accommodate Tru64 5.1, which can't read more than INT_MAX
      62               bytes at a time.  They call that a 64-bit OS?  */
      63            if (errno == EINVAL && INT_MAX < bytes_to_read)
      64              {
      65                readlim = INT_MAX;
      66                continue;
      67              }
      68  
      69            /* This is needed for programs that have signal handlers on
      70               older hosts without SA_RESTART.  It also accommodates
      71               ancient AIX hosts that set errno to EINTR after uncaught
      72               SIGCONT.  See <news:1r77ojINN85n@ftp.UU.NET>
      73               (1993-04-22).  */
      74            if (! SA_RESTART && errno == EINTR)
      75              continue;
      76  
      77            return SIZE_MAX;
      78          }
      79        bp += nread;
      80      }
      81    while (bp < buflim);
      82  
      83    return bp - buf;
      84  }
      85  
      86  /* Least common multiple of two buffer sizes A and B.  However, if
      87     either A or B is zero, or if the multiple is greater than LCM_MAX,
      88     return a reasonable buffer size.  */
      89  
      90  size_t
      91  buffer_lcm (size_t a, size_t b, size_t lcm_max)
      92  {
      93    size_t lcm, m, n, q, r;
      94  
      95    /* Yield reasonable values if buffer sizes are zero.  */
      96    if (!a)
      97      return b ? b : 8 * 1024;
      98    if (!b)
      99      return a;
     100  
     101    /* n = gcd (a, b) */
     102    for (m = a, n = b;  (r = m % n) != 0;  m = n, n = r)
     103      continue;
     104  
     105    /* Yield a if there is an overflow.  */
     106    q = a / n;
     107    return !INT_MULTIPLY_WRAPV (q, b, &lcm) && lcm <= lcm_max ? lcm : a;
     108  }