diff options
Diffstat (limited to 'gl/lib')
-rw-r--r-- | gl/lib/buffer-lcm.c | 59 | ||||
-rw-r--r-- | gl/lib/buffer-lcm.h | 2 | ||||
-rw-r--r-- | gl/lib/fd-reopen.c | 46 | ||||
-rw-r--r-- | gl/lib/fd-reopen.h | 22 | ||||
-rw-r--r-- | gl/lib/strintcmp.c | 32 | ||||
-rw-r--r-- | gl/lib/strnumcmp-in.h | 244 | ||||
-rw-r--r-- | gl/lib/strnumcmp.c | 31 | ||||
-rw-r--r-- | gl/lib/strnumcmp.h | 2 | ||||
-rw-r--r-- | gl/lib/xfts.c | 65 | ||||
-rw-r--r-- | gl/lib/xfts.h | 10 |
10 files changed, 513 insertions, 0 deletions
diff --git a/gl/lib/buffer-lcm.c b/gl/lib/buffer-lcm.c new file mode 100644 index 000000000..1d22dac7d --- /dev/null +++ b/gl/lib/buffer-lcm.c @@ -0,0 +1,59 @@ +/* buffer-lcm.c - compute a good buffer size for dealing with two files + + Copyright (C) 2002-2012 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 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/>. */ + +/* Written by Paul Eggert. */ + +#include <config.h> +#include "buffer-lcm.h" + +/* Return a buffer size suitable for doing I/O with files whose block + sizes are A and B. However, never return a value greater than + LCM_MAX. */ + +size_t +buffer_lcm (size_t a, size_t b, size_t lcm_max) +{ + size_t size; + + /* Use reasonable values if buffer sizes are zero. */ + if (!a) + size = b ? b : 8 * 1024; + else + { + if (b) + { + /* Return lcm (A, B) if it is in range; otherwise, fall back + on A. */ + + size_t lcm, m, n, q, r; + + /* N = gcd (A, B). */ + for (m = a, n = b; (r = m % n) != 0; m = n, n = r) + continue; + + /* LCM = lcm (A, B), if in range. */ + q = a / n; + lcm = q * b; + if (lcm <= lcm_max && lcm / b == q) + return lcm; + } + + size = a; + } + + return size <= lcm_max ? size : lcm_max; +} diff --git a/gl/lib/buffer-lcm.h b/gl/lib/buffer-lcm.h new file mode 100644 index 000000000..454c65be8 --- /dev/null +++ b/gl/lib/buffer-lcm.h @@ -0,0 +1,2 @@ +#include <stddef.h> +size_t buffer_lcm (size_t, size_t, size_t) _GL_ATTRIBUTE_CONST; diff --git a/gl/lib/fd-reopen.c b/gl/lib/fd-reopen.c new file mode 100644 index 000000000..fd4b92bea --- /dev/null +++ b/gl/lib/fd-reopen.c @@ -0,0 +1,46 @@ +/* Invoke open, but return either a desired file descriptor or -1. + + Copyright (C) 2005-2012 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 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/>. */ + +/* Written by Paul Eggert. */ + +#include <config.h> + +#include "fd-reopen.h" + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +/* Open a file to a particular file descriptor. This is like standard + 'open', except it always returns DESIRED_FD if successful. */ + +int +fd_reopen (int desired_fd, char const *file, int flags, mode_t mode) +{ + int fd = open (file, flags, mode); + + if (fd == desired_fd || fd < 0) + return fd; + else + { + int fd2 = dup2 (fd, desired_fd); + int saved_errno = errno; + close (fd); + errno = saved_errno; + return fd2; + } +} diff --git a/gl/lib/fd-reopen.h b/gl/lib/fd-reopen.h new file mode 100644 index 000000000..b80f09862 --- /dev/null +++ b/gl/lib/fd-reopen.h @@ -0,0 +1,22 @@ +/* Invoke open, but return either a desired file descriptor or -1. + + Copyright (C) 2005-2012 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 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/>. */ + +/* Written by Paul Eggert. */ + +#include <sys/types.h> + +int fd_reopen (int, char const *, int, mode_t); diff --git a/gl/lib/strintcmp.c b/gl/lib/strintcmp.c new file mode 100644 index 000000000..6e4901e22 --- /dev/null +++ b/gl/lib/strintcmp.c @@ -0,0 +1,32 @@ +/* Compare integer strings. + + Copyright (C) 2005-2012 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 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/>. */ + +/* Written by Paul Eggert. */ + +#include <config.h> + +#include "strnumcmp-in.h" + +/* Compare strings A and B as integers without explicitly converting + them to machine numbers, to avoid overflow problems and perhaps + improve performance. */ + +int +strintcmp (char const *a, char const *b) +{ + return numcompare (a, b, -1, -1); +} diff --git a/gl/lib/strnumcmp-in.h b/gl/lib/strnumcmp-in.h new file mode 100644 index 000000000..95ab55fdc --- /dev/null +++ b/gl/lib/strnumcmp-in.h @@ -0,0 +1,244 @@ +/* Compare numeric strings. This is an internal include file. + + Copyright (C) 1988-2012 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 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/>. */ + +/* Written by Mike Haertel. */ + +#ifndef STRNUMCMP_IN_H +# define STRNUMCMP_IN_H 1 + +# include "strnumcmp.h" + +# include <stddef.h> + +# define NEGATION_SIGN '-' +# define NUMERIC_ZERO '0' + +/* ISDIGIT differs from isdigit, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char + or EOF. + - It's typically faster. + POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to + isdigit unless it's important to use the locale's definition + of 'digit' even when the host does not conform to POSIX. */ +# define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9) + + +/* Compare strings A and B containing decimal fractions < 1. + DECIMAL_POINT is the decimal point. Each string + should begin with a decimal point followed immediately by the digits + of the fraction. Strings not of this form are treated as zero. */ + +/* The goal here, is to take two numbers a and b... compare these + in parallel. Instead of converting each, and then comparing the + outcome. Most likely stopping the comparison before the conversion + is complete. The algorithm used, in the old "sort" utility: + + Algorithm: fraccompare + Action : compare two decimal fractions + accepts : char *a, char *b + returns : -1 if a<b, 0 if a=b, 1 if a>b. + implement: + + if *a == decimal_point AND *b == decimal_point + find first character different in a and b. + if both are digits, return the difference *a - *b. + if *a is a digit + skip past zeros + if digit return 1, else 0 + if *b is a digit + skip past zeros + if digit return -1, else 0 + if *a is a decimal_point + skip past decimal_point and zeros + if digit return 1, else 0 + if *b is a decimal_point + skip past decimal_point and zeros + if digit return -1, else 0 + return 0 */ + +static inline int _GL_ATTRIBUTE_PURE +fraccompare (char const *a, char const *b, char decimal_point) +{ + if (*a == decimal_point && *b == decimal_point) + { + while (*++a == *++b) + if (! ISDIGIT (*a)) + return 0; + if (ISDIGIT (*a) && ISDIGIT (*b)) + return *a - *b; + if (ISDIGIT (*a)) + goto a_trailing_nonzero; + if (ISDIGIT (*b)) + goto b_trailing_nonzero; + return 0; + } + else if (*a++ == decimal_point) + { + a_trailing_nonzero: + while (*a == NUMERIC_ZERO) + a++; + return ISDIGIT (*a); + } + else if (*b++ == decimal_point) + { + b_trailing_nonzero: + while (*b == NUMERIC_ZERO) + b++; + return - ISDIGIT (*b); + } + return 0; +} + +/* Compare strings A and B as numbers without explicitly converting + them to machine numbers, to avoid overflow problems and perhaps + improve performance. DECIMAL_POINT is the decimal point and + THOUSANDS_SEP the thousands separator. A DECIMAL_POINT of -1 + causes comparisons to act as if there is no decimal point + character, and likewise for THOUSANDS_SEP. */ + +static inline int _GL_ATTRIBUTE_PURE +numcompare (char const *a, char const *b, + int decimal_point, int thousands_sep) +{ + unsigned char tmpa = *a; + unsigned char tmpb = *b; + int tmp; + size_t log_a; + size_t log_b; + + if (tmpa == NEGATION_SIGN) + { + do + tmpa = *++a; + while (tmpa == NUMERIC_ZERO || tmpa == thousands_sep); + if (tmpb != NEGATION_SIGN) + { + if (tmpa == decimal_point) + do + tmpa = *++a; + while (tmpa == NUMERIC_ZERO); + if (ISDIGIT (tmpa)) + return -1; + while (tmpb == NUMERIC_ZERO || tmpb == thousands_sep) + tmpb = *++b; + if (tmpb == decimal_point) + do + tmpb = *++b; + while (tmpb == NUMERIC_ZERO); + return - ISDIGIT (tmpb); + } + do + tmpb = *++b; + while (tmpb == NUMERIC_ZERO || tmpb == thousands_sep); + + while (tmpa == tmpb && ISDIGIT (tmpa)) + { + do + tmpa = *++a; + while (tmpa == thousands_sep); + do + tmpb = *++b; + while (tmpb == thousands_sep); + } + + if ((tmpa == decimal_point && !ISDIGIT (tmpb)) + || (tmpb == decimal_point && !ISDIGIT (tmpa))) + return fraccompare (b, a, decimal_point); + + tmp = tmpb - tmpa; + + for (log_a = 0; ISDIGIT (tmpa); ++log_a) + do + tmpa = *++a; + while (tmpa == thousands_sep); + + for (log_b = 0; ISDIGIT (tmpb); ++log_b) + do + tmpb = *++b; + while (tmpb == thousands_sep); + + if (log_a != log_b) + return log_a < log_b ? 1 : -1; + + if (!log_a) + return 0; + + return tmp; + } + else if (tmpb == NEGATION_SIGN) + { + do + tmpb = *++b; + while (tmpb == NUMERIC_ZERO || tmpb == thousands_sep); + if (tmpb == decimal_point) + do + tmpb = *++b; + while (tmpb == NUMERIC_ZERO); + if (ISDIGIT (tmpb)) + return 1; + while (tmpa == NUMERIC_ZERO || tmpa == thousands_sep) + tmpa = *++a; + if (tmpa == decimal_point) + do + tmpa = *++a; + while (tmpa == NUMERIC_ZERO); + return ISDIGIT (tmpa); + } + else + { + while (tmpa == NUMERIC_ZERO || tmpa == thousands_sep) + tmpa = *++a; + while (tmpb == NUMERIC_ZERO || tmpb == thousands_sep) + tmpb = *++b; + + while (tmpa == tmpb && ISDIGIT (tmpa)) + { + do + tmpa = *++a; + while (tmpa == thousands_sep); + do + tmpb = *++b; + while (tmpb == thousands_sep); + } + + if ((tmpa == decimal_point && !ISDIGIT (tmpb)) + || (tmpb == decimal_point && !ISDIGIT (tmpa))) + return fraccompare (a, b, decimal_point); + + tmp = tmpa - tmpb; + + for (log_a = 0; ISDIGIT (tmpa); ++log_a) + do + tmpa = *++a; + while (tmpa == thousands_sep); + + for (log_b = 0; ISDIGIT (tmpb); ++log_b) + do + tmpb = *++b; + while (tmpb == thousands_sep); + + if (log_a != log_b) + return log_a < log_b ? -1 : 1; + + if (!log_a) + return 0; + + return tmp; + } +} + +#endif diff --git a/gl/lib/strnumcmp.c b/gl/lib/strnumcmp.c new file mode 100644 index 000000000..115ab598a --- /dev/null +++ b/gl/lib/strnumcmp.c @@ -0,0 +1,31 @@ +/* Compare numeric strings. + + Copyright (C) 2005-2012 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 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/>. */ + +/* Written by Paul Eggert. */ + +#include <config.h> + +#include "strnumcmp-in.h" + +/* Externally-visible name for numcompare. */ + +int _GL_ATTRIBUTE_PURE +strnumcmp (char const *a, char const *b, + int decimal_point, int thousands_sep) +{ + return numcompare (a, b, decimal_point, thousands_sep); +} diff --git a/gl/lib/strnumcmp.h b/gl/lib/strnumcmp.h new file mode 100644 index 000000000..4deef82bd --- /dev/null +++ b/gl/lib/strnumcmp.h @@ -0,0 +1,2 @@ +int strintcmp (char const *, char const *) _GL_ATTRIBUTE_PURE; +int strnumcmp (char const *, char const *, int, int); diff --git a/gl/lib/xfts.c b/gl/lib/xfts.c new file mode 100644 index 000000000..b19200e20 --- /dev/null +++ b/gl/lib/xfts.c @@ -0,0 +1,65 @@ +/* xfts.c -- a wrapper for fts_open + + Copyright (C) 2003-2012 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 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/>. */ + +/* Written by Jim Meyering. */ + +#include <config.h> + +#include <stdbool.h> +#include <stdlib.h> +#include <errno.h> +#include <assert.h> + +#include "xalloc.h" +#include "xfts.h" + +/* Fail with a proper diagnostic if fts_open fails. */ + +FTS * +xfts_open (char * const *argv, int options, + int (*compar) (const FTSENT **, const FTSENT **)) +{ + FTS *fts = fts_open (argv, options | FTS_CWDFD, compar); + if (fts == NULL) + { + /* This can fail in two ways: out of memory or with errno==EINVAL, + which indicates it was called with invalid bit_flags. */ + assert (errno != EINVAL); + xalloc_die (); + } + + return fts; +} + +/* When fts_read returns FTS_DC to indicate a directory cycle, + it may or may not indicate a real problem. When a program like + chgrp performs a recursive traversal that requires traversing + symbolic links, it is *not* a problem. However, when invoked + with "-P -R", it deserves a warning. The fts_options member + records the options that control this aspect of fts's behavior, + so test that. */ +bool +cycle_warning_required (FTS const *fts, FTSENT const *ent) +{ +#define ISSET(Fts,Opt) ((Fts)->fts_options & (Opt)) + /* When dereferencing no symlinks, or when dereferencing only + those listed on the command line and we're not processing + a command-line argument, then a cycle is a serious problem. */ + return ((ISSET (fts, FTS_PHYSICAL) && !ISSET (fts, FTS_COMFOLLOW)) + || (ISSET (fts, FTS_PHYSICAL) && ISSET (fts, FTS_COMFOLLOW) + && ent->fts_level != FTS_ROOTLEVEL)); +} diff --git a/gl/lib/xfts.h b/gl/lib/xfts.h new file mode 100644 index 000000000..f903f4804 --- /dev/null +++ b/gl/lib/xfts.h @@ -0,0 +1,10 @@ +#include <stdbool.h> +#include "fts_.h" + +FTS * +xfts_open (char * const *, int options, + int (*) (const FTSENT **, const FTSENT **)); + +bool +cycle_warning_required (FTS const *fts, FTSENT const *ent) + _GL_ATTRIBUTE_PURE; |