Skip to content

Commit

Permalink
Enable --version-sort on systems without strverscmp()
Browse files Browse the repository at this point in the history
The --version-sort option requires strverscmp(), but this is a glibc
extension that does not exist on OpenBSD and other systems. To enable
--version-sort on those systems, provide an internal implementation of
strverscmp(). The implementation is from the musl C library and is
MIT-licensed.

The build process remains the same: the verscmp flag should be set to 1
only if strverscmp() is available in libc. If verscmp is 0, then the
internal implementation is used.
  • Loading branch information
Tim van der Molen committed Jun 15, 2020
1 parent a624883 commit 5e4c6de
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ indicates that the corresponding feature is enabled by default.
| help | 0 | include help text (refers to the manpage otherwise) |
| inotify | 0 | enable inotify, needed for `--auto-reload` |
| stat64 | 0 | Support CIFS shares from 64bit hosts on 32bit machines |
| verscmp | 1 | Support naturing sorting (`--version-sort`). Requires a GNU-compatible libc exposing `strverscmp` |
| verscmp | 1 | Whether your libc provides `strvercmp()`. If set to 0, feh will use an internal implementation. |
| xinerama | 1 | Support Xinerama/XRandR multiscreen setups |

For example, `make xinerama=0 debug=1` will disable Xinerama support and
Expand Down
5 changes: 1 addition & 4 deletions config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ ifeq (${stat64},1)
endif

ifeq (${verscmp},1)
CFLAGS += -DHAVE_VERSCMP
MAN_VERSCMP = available
else
MAN_VERSCMP = not available
CFLAGS += -DHAVE_STRVERSCMP
endif

ifeq (${xinerama},1)
Expand Down
1 change: 0 additions & 1 deletion man/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ all: ${TARGETS}
-e 's/\$$MAN_DEBUG\$$/${MAN_DEBUG}/' \
-e 's/\$$MAN_EXIF\$$/${MAN_EXIF}/' \
-e 's/\$$MAN_INOTIFY\$$/${MAN_INOTIFY}/' \
-e 's/\$$MAN_VERSCMP\$$/${MAN_VERSCMP}/' \
-e 's/\$$MAN_XINERAMA\$$/${MAN_XINERAMA}/' \
< ${@:.1=.pre} > $@

Expand Down
4 changes: 0 additions & 4 deletions man/feh.pre
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ Compile-time switches in this build:
remote file support: libcurl $MAN_CURL$
.
.It
natural sorting option $MAN_VERSCMP$
.
.It
Xinerama multi-monitor support $MAN_XINERAMA$
.
.It
Expand Down Expand Up @@ -887,7 +884,6 @@ output version information and exit.
.
.It Cm --version-sort
.
.Pq optional feature, $MAN_VERSCMP$ in this build
When combined with
.Cm --sort name , --sort filename ,
or
Expand Down
4 changes: 4 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ ifeq (${exif},1)
exif_nikon.c
endif

ifneq (${verscmp},1)
TARGETS += strverscmp.c
endif

OBJECTS = ${TARGETS:.c=.o}

I_SRCS = ${shell echo *.raw}
Expand Down
5 changes: 4 additions & 1 deletion src/feh.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* strverscmp(3) is a GNU extension. In most supporting C libraries it
* requires _GNU_SOURCE to be defined.
*/
#ifdef HAVE_VERSCMP
#ifdef HAVE_STRVERSCMP
#define _GNU_SOURCE
#endif

Expand Down Expand Up @@ -182,6 +182,9 @@ gib_list *feh_list_jump(gib_list * root, gib_list * l, int direction, int num);
#ifdef HAVE_INOTIFY
void feh_event_handle_inotify(void);
#endif
#ifndef HAVE_STRVERSCMP
int strverscmp(const char *l0, const char *r0);
#endif

/* Imlib stuff */
extern Display *disp;
Expand Down
4 changes: 0 additions & 4 deletions src/filelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,17 +402,13 @@ void feh_file_dirname(char *dst, feh_file * f, int maxlen)
dst[n] = '\0';
}

#ifdef HAVE_VERSCMP
static inline int strcmp_or_strverscmp(const char *s1, const char *s2)
{
if (!opt.version_sort)
return(strcmp(s1, s2));
else
return(strverscmp(s1, s2));
}
#else
#define strcmp_or_strverscmp strcmp
#endif

int feh_cmp_filename(void *file1, void *file2)
{
Expand Down
4 changes: 0 additions & 4 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -943,10 +943,6 @@ static void show_version(void)
"stat64 "
#endif

#ifdef HAVE_VERSCMP
"verscmp "
#endif

#ifdef HAVE_LIBXINERAMA
"xinerama "
#endif
Expand Down
57 changes: 57 additions & 0 deletions src/strverscmp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright © 2005-2020 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#define _GNU_SOURCE
#include <ctype.h>
#include <string.h>

int strverscmp(const char *l0, const char *r0)
{
const unsigned char *l = (const void *)l0;
const unsigned char *r = (const void *)r0;
size_t i, dp, j;
int z = 1;

/* Find maximal matching prefix and track its maximal digit
* suffix and whether those digits are all zeros. */
for (dp=i=0; l[i]==r[i]; i++) {
int c = l[i];
if (!c) return 0;
if (!isdigit(c)) dp=i+1, z=1;
else if (c!='0') z=0;
}

if (l[dp]!='0' && r[dp]!='0') {
/* If we're not looking at a digit sequence that began
* with a zero, longest digit string is greater. */
for (j=i; isdigit(l[j]); j++)
if (!isdigit(r[j])) return 1;
if (isdigit(r[j])) return -1;
} else if (z && dp<i && (isdigit(l[i]) || isdigit(r[i]))) {
/* Otherwise, if common prefix of digit sequence is
* all zeros, digits order less than non-digits. */
return (unsigned char)(l[i]-'0') - (unsigned char)(r[i]-'0');
}

return l[i] - r[i];
}

0 comments on commit 5e4c6de

Please sign in to comment.