#include "areadlink.h"
#include "file-set.h"
+#include "idx.h"
#include "hash-triple.h"
#include "pathmax.h"
#include "xalloc.h"
{
if (*ht == NULL)
{
- int initial_capacity = 7;
+ idx_t initial_capacity = 7;
*ht = hash_initialize (initial_capacity,
NULL,
triple_hash,
char const *start;
char const *end;
char const *rname_limit;
- ptrdiff_t extra_len = 0;
+ idx_t extra_len = 0;
Hash_table *ht = NULL;
int saved_errno;
bool logical = (can_mode & CAN_NOLINKS) != 0;
int num_links = 0;
- ptrdiff_t prefix_len;
+ idx_t prefix_len;
canonicalize_mode_t can_exist = can_mode & CAN_MODE_MASK;
if (multiple_bits_set (can_exist))
rname = xgetcwd ();
if (!rname)
return NULL;
- ptrdiff_t rnamelen = strlen (rname);
- ptrdiff_t rnamesize = rnamelen; /* Lower bound on size; good enough. */
+ idx_t rnamelen = strlen (rname);
+ idx_t rnamesize = rnamelen; /* Lower bound on size; good enough. */
if (rnamesize < PATH_MAX)
{
rnamesize = PATH_MAX;
/* For UNC file names '\\server\path\to\file', extend the prefix
to include the server: '\\server\'. */
{
- ptrdiff_t i;
+ idx_t i;
for (i = 2; name[i] != '\0' && !ISSLASH (name[i]); )
i++;
if (name[i] != '\0' /* implies ISSLASH (name[i]) */
if (rname_limit - dest <= end - start)
{
- ptrdiff_t dest_offset = dest - rname;
- ptrdiff_t new_size = rname_limit - rname;
+ idx_t dest_offset = dest - rname;
+ idx_t new_size = rname_limit - rname;
if (end - start + 1 > PATH_MAX)
new_size += end - start + 1;
}
}
- ptrdiff_t n = strlen (buf);
- ptrdiff_t len = strlen (end);
+ idx_t n = strlen (buf);
+ idx_t len = strlen (end);
if (!extra_len)
{
if (IS_ABSOLUTE_FILE_NAME (buf))
{
- ptrdiff_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
+ idx_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
if (pfxlen)
memcpy (rname, buf, pfxlen);
--- /dev/null
+/* A type for indices and sizes.
+
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ 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 2, 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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _IDX_H
+#define _IDX_H
+
+/* Get ptrdiff_t. */
+#include <stddef.h>
+
+/* Get PTRDIFF_WIDTH. */
+#include <stdint.h>
+
+/* The type 'idx_t' holds an (array) index or an (object) size.
+ Its implementation is a signed or unsigned integer type, capable of holding
+ the values
+ 0..2^63-1 (on 64-bit platforms) or
+ 0..2^31-1 (on 32-bit platforms).
+
+ Why not use 'size_t' directly?
+
+ * Security: Signed types can be checked for overflow via
+ '-fsanitize=undefined', but unsigned types cannot.
+
+ Why not use 'ptrdiff_t' directly?
+
+ * Maintainability: When reading and modifying code, it helps to know that
+ a certain variable cannot have negative values. For example, when you
+ have a loop
+
+ int n = ...;
+ for (int i = 0; i < n; i++) ...
+
+ or
+
+ ptrdiff_t n = ...;
+ for (ptrdiff_t i = 0; i < n; i++) ...
+
+ you have to ask yourself "what if n < 0?". Whereas in
+
+ idx_t n = ...;
+ for (idx_t i = 0; i < n; i++) ...
+
+ you know that this case cannot happen.
+
+ Similarly, when a programmer writes
+
+ idx_t = ptr2 - ptr1;
+
+ there is an implied assertion that ptr1 and ptr2 point into the same
+ object and that ptr1 <= ptr2.
+
+ * Being future-proof: In the future, range types (integers which are
+ constrained to a certain range of values) may be added to C compilers
+ or to the C standard. Several programming languages (Ada, Haskell,
+ Common Lisp, Pascal) already have range types. Such range types may
+ help producing good code and good warnings. The type 'idx_t'
+ could then be typedef'ed to a range type. */
+
+/* The user can define UNSIGNED_IDX_T, to get a different set of compiler
+ warnings. */
+#if defined UNSIGNED_IDX_T
+# if __clang_version__ >= 11 && 0
+/* It would be tempting to use the clang "extended integer types", which are a
+ special case of range types.
+ <https://clang.llvm.org/docs/LanguageExtensions.html#extended-integer-types>
+ However, these types don't support binary operators with plain integer
+ types (e.g. expressions such as x > 1). */
+typedef unsigned _ExtInt (PTRDIFF_WIDTH - 1) idx_t;
+# else
+/* Use an unsigned type as wide as 'ptrdiff_t'.
+ ISO C does not mandate that 'size_t' and 'ptrdiff_t' have the same size, but
+ it is so an all platforms we have seen since 1990. */
+typedef size_t idx_t;
+# endif
+#else
+/* Use the signed type 'ptrdiff_t' by default. */
+typedef ptrdiff_t idx_t;
+#endif
+
+/* IDX_MAX is the maximum value of an idx_t. */
+#if defined UNSIGNED_IDX_T
+# define IDX_MAX SIZE_MAX
+#else
+# define IDX_MAX PTRDIFF_MAX
+#endif
+
+/* IDX_WIDTH is the number of bits in an idx_t. */
+#define IDX_WIDTH (PTRDIFF_WIDTH - 1)
+
+#endif /* _IDX_H */