xref: /dragonfly/contrib/diffutils/lib/cmpbuf.c (revision 6ea1f93e)
1855caec6SPeter Avalos /* Buffer primitives for comparison operations.
2855caec6SPeter Avalos 
3*6ea1f93eSDaniel Fojt    Copyright (C) 1993, 1995, 1998, 2001-2002, 2006, 2009-2013, 2015-2018 Free
4*6ea1f93eSDaniel Fojt    Software Foundation, Inc.
5855caec6SPeter Avalos 
644b87433SJohn Marino    This program is free software: you can redistribute it and/or modify
7855caec6SPeter Avalos    it under the terms of the GNU General Public License as published by
844b87433SJohn Marino    the Free Software Foundation, either version 3 of the License, or
944b87433SJohn Marino    (at your option) any later version.
10855caec6SPeter Avalos 
11855caec6SPeter Avalos    This program is distributed in the hope that it will be useful,
12855caec6SPeter Avalos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13855caec6SPeter Avalos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14855caec6SPeter Avalos    GNU General Public License for more details.
15855caec6SPeter Avalos 
16855caec6SPeter Avalos    You should have received a copy of the GNU General Public License
1744b87433SJohn Marino    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18855caec6SPeter Avalos 
19855caec6SPeter Avalos #include <config.h>
20855caec6SPeter Avalos 
21855caec6SPeter Avalos #include <errno.h>
22855caec6SPeter Avalos #include <limits.h>
23855caec6SPeter Avalos #include <signal.h>
24855caec6SPeter Avalos #include <unistd.h>
25008e37b6SJohn Marino #include <stdint.h>
26855caec6SPeter Avalos #include <inttypes.h>
27855caec6SPeter Avalos #include <sys/types.h>
28855caec6SPeter Avalos #include "cmpbuf.h"
2944b87433SJohn Marino #include "intprops.h"
30855caec6SPeter Avalos 
31855caec6SPeter Avalos #ifndef SSIZE_MAX
32855caec6SPeter Avalos # define SSIZE_MAX TYPE_MAXIMUM (ssize_t)
33855caec6SPeter Avalos #endif
34855caec6SPeter Avalos 
35855caec6SPeter Avalos #undef MIN
36855caec6SPeter Avalos #define MIN(a, b) ((a) <= (b) ? (a) : (b))
37855caec6SPeter Avalos 
38855caec6SPeter Avalos /* Read NBYTES bytes from descriptor FD into BUF.
39855caec6SPeter Avalos    NBYTES must not be SIZE_MAX.
40855caec6SPeter Avalos    Return the number of characters successfully read.
41855caec6SPeter Avalos    On error, return SIZE_MAX, setting errno.
42855caec6SPeter Avalos    The number returned is always NBYTES unless end-of-file or error.  */
43855caec6SPeter Avalos 
44855caec6SPeter Avalos size_t
block_read(int fd,char * buf,size_t nbytes)45855caec6SPeter Avalos block_read (int fd, char *buf, size_t nbytes)
46855caec6SPeter Avalos {
47855caec6SPeter Avalos   char *bp = buf;
48855caec6SPeter Avalos   char const *buflim = buf + nbytes;
4944b87433SJohn Marino   size_t readlim = MIN (SSIZE_MAX, SIZE_MAX);
50855caec6SPeter Avalos 
51855caec6SPeter Avalos   do
52855caec6SPeter Avalos     {
5344b87433SJohn Marino       size_t bytes_remaining = buflim - bp;
5444b87433SJohn Marino       size_t bytes_to_read = MIN (bytes_remaining, readlim);
55855caec6SPeter Avalos       ssize_t nread = read (fd, bp, bytes_to_read);
56855caec6SPeter Avalos       if (nread <= 0)
57855caec6SPeter Avalos 	{
58855caec6SPeter Avalos 	  if (nread == 0)
59855caec6SPeter Avalos 	    break;
60855caec6SPeter Avalos 
61855caec6SPeter Avalos 	  /* Accommodate Tru64 5.1, which can't read more than INT_MAX
62855caec6SPeter Avalos 	     bytes at a time.  They call that a 64-bit OS?  */
63855caec6SPeter Avalos 	  if (errno == EINVAL && INT_MAX < bytes_to_read)
64855caec6SPeter Avalos 	    {
65855caec6SPeter Avalos 	      readlim = INT_MAX;
66855caec6SPeter Avalos 	      continue;
67855caec6SPeter Avalos 	    }
68855caec6SPeter Avalos 
69855caec6SPeter Avalos 	  /* This is needed for programs that have signal handlers on
70855caec6SPeter Avalos 	     older hosts without SA_RESTART.  It also accommodates
71855caec6SPeter Avalos 	     ancient AIX hosts that set errno to EINTR after uncaught
72855caec6SPeter Avalos 	     SIGCONT.  See <news:1r77ojINN85n@ftp.UU.NET>
73855caec6SPeter Avalos 	     (1993-04-22).  */
74855caec6SPeter Avalos 	  if (! SA_RESTART && errno == EINTR)
75855caec6SPeter Avalos 	    continue;
76855caec6SPeter Avalos 
77855caec6SPeter Avalos 	  return SIZE_MAX;
78855caec6SPeter Avalos 	}
79855caec6SPeter Avalos       bp += nread;
80855caec6SPeter Avalos     }
81855caec6SPeter Avalos   while (bp < buflim);
82855caec6SPeter Avalos 
83855caec6SPeter Avalos   return bp - buf;
84855caec6SPeter Avalos }
85855caec6SPeter Avalos 
86855caec6SPeter Avalos /* Least common multiple of two buffer sizes A and B.  However, if
87855caec6SPeter Avalos    either A or B is zero, or if the multiple is greater than LCM_MAX,
88855caec6SPeter Avalos    return a reasonable buffer size.  */
89855caec6SPeter Avalos 
90855caec6SPeter Avalos size_t
buffer_lcm(size_t a,size_t b,size_t lcm_max)91855caec6SPeter Avalos buffer_lcm (size_t a, size_t b, size_t lcm_max)
92855caec6SPeter Avalos {
93855caec6SPeter Avalos   size_t lcm, m, n, q, r;
94855caec6SPeter Avalos 
95855caec6SPeter Avalos   /* Yield reasonable values if buffer sizes are zero.  */
96855caec6SPeter Avalos   if (!a)
97855caec6SPeter Avalos     return b ? b : 8 * 1024;
98855caec6SPeter Avalos   if (!b)
99855caec6SPeter Avalos     return a;
100855caec6SPeter Avalos 
101855caec6SPeter Avalos   /* n = gcd (a, b) */
102855caec6SPeter Avalos   for (m = a, n = b;  (r = m % n) != 0;  m = n, n = r)
103855caec6SPeter Avalos     continue;
104855caec6SPeter Avalos 
105855caec6SPeter Avalos   /* Yield a if there is an overflow.  */
106855caec6SPeter Avalos   q = a / n;
107855caec6SPeter Avalos   lcm = q * b;
108855caec6SPeter Avalos   return lcm <= lcm_max && lcm / b == q ? lcm : a;
109855caec6SPeter Avalos }
110