hello,

The major issue for this update is that upstream started to use
wordexp(3) and some workaround are needed.  (The added patches are
pending upstream.)

The workarounds for wordexp(3) range from manually constructing
strings, to using glob(3) and even rolling wordexp(3) inline stealing
an idea from musl, as other wordexp(3) implementation required either
some helper programs (freebsd) or custom shell flags (glibc/newlib and
bash.)

The behaviour of the program is not changed except that in the `:open'
command: on other systems you should be able to say `:open $(cmd)' or
similar stuff with command substitution, here it only supports
glob(3).

tests from existing users are welcome :)

thoughts/ok?

Index: Makefile
===================================================================
RCS file: /home/cvs/ports/graphics/imv/Makefile,v
retrieving revision 1.6
diff -u -p -r1.6 Makefile
--- Makefile    11 Mar 2022 19:22:33 -0000      1.6
+++ Makefile    12 Jul 2022 10:26:32 -0000
@@ -1,28 +1,48 @@
-GH_ACCOUNT =           eXeC64
-GH_PROJECT =           imv
-GH_TAGNAME =           v2.1.3
-
 COMMENT =              simple image viewer
+
+V =                    4.3.1
+DISTNAME =             imv-v$V
+PKGNAME =              imv-$V
+
 CATEGORIES =           graphics x11
-REVISION =             1
+
+HOMEPAGE =             https://sr.ht/~exec64/imv
 
 # GPLv2+
 PERMIT_PACKAGE =       Yes
 
-WANTLIB += SDL2 SDL2_ttf c fontconfig freeimage pthread
+WANTLIB += GL X11 c cairo freeimage gobject-2.0 heif icuuc inih
+WANTLIB += m nsgif pango-1.0 pangocairo-1.0 pthread rsvg-2 turbojpeg
+WANTLIB += xcb xkbcommon xkbcommon-x11
+
+MASTER_SITES =         https://git.sr.ht/~exec64/imv/archive/
+DISTFILES =            ${DISTNAME}{v$V}${EXTRACT_SUFX}
+
+MODULES =              devel/meson
+
+CFLAGS +=              -D_BSD_SOURCE \
+                       -I${LOCALBASE}/include
+LDFLAGS +=             -L${LOCALBASE}/lib
+
+MODMESON_CONFIGURE_ENV += LDFLAGS="${LDFLAGS}"
+
+BUILD_DEPENDS =                textproc/asciidoc \
+                       devel/cmocka
+
+LIB_DEPENDS =          devel/inih \
+                       devel/pango \
+                       graphics/freeimage \
+                       multimedia/libheif \
+                       textproc/icu4c,-main \
+                       x11/gnome/librsvg \
+                       x11/xkbcommon \
+                       www/netsurf/libnsgif
 
-LIB_DEPENDS =          devel/sdl2 \
-                       devel/sdl2-ttf \
-                       graphics/freeimage
 RUN_DEPENDS =          devel/desktop-file-utils
-TEST_DEPENDS =         devel/cmocka
-
-MAKE_FLAGS +=          V=1 BUILDDIR="${WRKDIR}/build-${ARCH}"
-FAKE_FLAGS +=          $(MAKE_FLAGS) MANPREFIX=${PREFIX}/man PREFIX=${PREFIX}
 
-USE_GMAKE =            Yes
+CONFIGURE_ARGS +=      -Dwindows=x11
 
-ALL_TARGET =           imv
-TEST_TARGET =          check
+post-install:
+       cd ${DESTDIR} && mv etc/imv_config ${PREFIX}/share/examples/
 
 .include <bsd.port.mk>
Index: distinfo
===================================================================
RCS file: /home/cvs/ports/graphics/imv/distinfo,v
retrieving revision 1.2
diff -u -p -r1.2 distinfo
--- distinfo    22 Oct 2016 12:26:46 -0000      1.2
+++ distinfo    12 Jul 2022 08:45:19 -0000
@@ -1,2 +1,2 @@
-SHA256 (imv-2.1.3.tar.gz) = 8Lms18/x0vcwHLXP+yYazk0K8gA9xKKT2aN+cwdJeLc=
-SIZE (imv-2.1.3.tar.gz) = 27664
+SHA256 (imv-v4.3.1.tar.gz) = iNFohQF7dLWU3dagPvIClKbMBT8EzMLh7e9p81FfeZk=
+SIZE (imv-v4.3.1.tar.gz) = 79123
Index: pkg/PLIST
===================================================================
RCS file: /home/cvs/ports/graphics/imv/pkg/PLIST,v
retrieving revision 1.3
diff -u -p -r1.3 PLIST
--- pkg/PLIST   11 Mar 2022 19:22:33 -0000      1.3
+++ pkg/PLIST   12 Jul 2022 09:48:14 -0000
@@ -1,4 +1,12 @@
 @bin bin/imv
+bin/imv-folder
+@bin bin/imv-msg
+@man man/man1/imv-folder.1
+@man man/man1/imv-msg.1
 @man man/man1/imv.1
+@man man/man5/imv.5
+share/applications/imv-folder.desktop
 share/applications/imv.desktop
+share/examples/imv_config
+@sample ${SYSCONFDIR}/imv_config
 @tag update-desktop-database
Index: patches/patch-meson_build
===================================================================
RCS file: patches/patch-meson_build
diff -N patches/patch-meson_build
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-meson_build   6 Aug 2022 08:31:46 -0000
@@ -0,0 +1,19 @@
+don't look out for git
+
+Index: meson.build
+--- meson.build.orig
++++ meson.build
+@@ -8,13 +8,6 @@ project(
+ )
+ 
+ version = '@0@'.format(meson.project_version())
+-prog_git = find_program('git', required: false)
+-if prog_git.found()
+-  git_description = run_command([prog_git.path(), 'describe', '--dirty', 
'--always', '--tags'])
+-  if git_description.returncode() == 0
+-    version = git_description.stdout().strip()
+-  endif
+-endif
+ add_project_arguments('-DIMV_VERSION="@0@"'.format(version), language: 'c')
+ 
+ add_project_arguments('-D_XOPEN_SOURCE=700', language: 'c')
Index: patches/patch-src_imv_c
===================================================================
RCS file: patches/patch-src_imv_c
diff -N patches/patch-src_imv_c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-src_imv_c     6 Aug 2022 08:31:46 -0000
@@ -0,0 +1,252 @@
+work around wordexp
+
+Index: src/imv.c
+--- src/imv.c.orig
++++ src/imv.c
+@@ -1,9 +1,12 @@
+ #include "imv.h"
+ 
++#include <sys/wait.h>
++
+ #include <assert.h>
+ #include <ctype.h>
+ #include <errno.h>
+ #include <getopt.h>
++#include <glob.h>
+ #include <limits.h>
+ #include <pthread.h>
+ #include <stdbool.h>
+@@ -11,7 +14,6 @@
+ #include <stdlib.h>
+ #include <time.h>
+ #include <unistd.h>
+-#include <wordexp.h>
+ 
+ #include "backend.h"
+ #include "binds.h"
+@@ -1363,40 +1365,6 @@ static void render_window(struct imv *imv)
+   imv->cache_invalidated = false;
+ }
+ 
+-static char *get_config_path(void)
+-{
+-  const char *config_paths[] = {
+-    "$imv_config",
+-    "$XDG_CONFIG_HOME/imv/config",
+-    "$HOME/.config/imv/config",
+-    "$HOME/.imv_config",
+-    "$HOME/.imv/config",
+-    "/usr/local/etc/imv_config",
+-    "/etc/imv_config",
+-  };
+-
+-  for (size_t i = 0; i < sizeof(config_paths) / sizeof(char*); ++i) {
+-    wordexp_t word;
+-    if (wordexp(config_paths[i], &word, 0) == 0) {
+-      if (!word.we_wordv[0]) {
+-        wordfree(&word);
+-        continue;
+-      }
+-
+-      char *path = strdup(word.we_wordv[0]);
+-      wordfree(&word);
+-
+-      if (!path || access(path, R_OK) == -1) {
+-        free(path);
+-        continue;
+-      }
+-
+-      return path;
+-    }
+-  }
+-  return NULL;
+-}
+-
+ static bool parse_bool(const char *str)
+ {
+   return (
+@@ -1557,26 +1525,80 @@ static int handle_ini_value(void *user, const char *se
+   return 0;
+ }
+ 
++static int load_config(const char *path, struct imv *imv)
++{
++  int err;
++
++  err = ini_parse(path, handle_ini_value, imv);
++  if (err > 0)
++    imv_log(IMV_ERROR, "Error in config file: %s:%d\n", path, err);
++  return err;
++}
++
+ bool imv_load_config(struct imv *imv)
+ {
+-  char *path = get_config_path();
+-  if (!path) {
+-    /* no config, no problem - we have defaults */
+-    return true;
++  char p[PATH_MAX];
++  char *t;
++  int err;
++
++  if ((t = getenv("imv_config")) != NULL) {
++    err = load_config(t, imv);
++    if (err > 0)
++      return false;
++    if (err == 0)
++      return true;
+   }
+ 
+-  bool result = true;
++  if ((t = getenv("XDG_CONFIG_HOME")) != NULL) {
++    if (snprintf(p, sizeof(p), "%s/imv/config", t) < sizeof(p)) {
++      err = load_config(p, imv);
++      if (err > 0)
++        return false;
++      if (err == 0)
++        return true;
++    }
++  }
+ 
+-  const int err = ini_parse(path, handle_ini_value, imv);
+-  if (err == -1) {
+-    imv_log(IMV_ERROR, "Unable to open config file: %s\n", path);
+-    result = false;
+-  } else if (err > 0) {
+-    imv_log(IMV_ERROR, "Error in config file: %s:%d\n", path, err);
+-    result = false;
++  if ((t = getenv("HOME")) != NULL) {
++    if (snprintf(p, sizeof(p), "%s/.config/imv/config", t) < sizeof(p)) {
++      err = load_config(p, imv);
++      if (err > 0)
++        return false;
++      if (err == 0)
++        return true;
++    }
++
++    if (snprintf(p, sizeof(p), "%s/.imv_config", t) < sizeof(p)) {
++      err = load_config(p, imv);
++      if (err > 0)
++        return false;
++      if (err == 0)
++        return true;
++    }
++
++    if (snprintf(p, sizeof(p), "%s/.imv/config", t) < sizeof(p)) {
++      err = load_config(p, imv);
++      if (err > 0)
++        return false;
++      if (err == 0)
++        return true;
++    }
+   }
+-  free(path);
+-  return result;
++
++  err = load_config("/usr/local/etc/imv_config", imv);
++  if (err > 0)
++    return false;
++  if (err == 0)
++    return true;
++
++  err = load_config("/etc/imv_config", imv);
++  if (err > 0)
++    return false;
++  if (err == 0)
++    return true;
++
++  /* no config, no problem - we have defaults */
++  return true;
+ }
+ 
+ static void command_quit(struct list *args, const char *argstr, void *data)
+@@ -1706,12 +1728,13 @@ static void command_open(struct list *args, const char
+       continue;
+     }
+ 
+-    wordexp_t word;
+-    if (wordexp(args->items[i], &word, 0) == 0) {
+-      for (size_t j = 0; j < word.we_wordc; ++j) {
+-        imv_navigator_add(imv->navigator, word.we_wordv[j], recursive);
++    glob_t g;
++    if (glob(args->items[i], GLOB_BRACE|GLOB_TILDE, NULL, &g) == 0) {
++      char **matches;
++      for (matches = g.gl_pathv; *matches; ++matches) {
++        imv_navigator_add(imv->navigator, *matches, recursive);
+       }
+-      wordfree(&word);
++      globfree(&g);
+     }
+   }
+ }
+@@ -1941,20 +1964,61 @@ static void update_env_vars(struct imv *imv)
+ 
+ static size_t generate_env_text(struct imv *imv, char *buf, size_t buf_len, 
const char *format)
+ {
++  pid_t pid;
++  int status, p[2]; /* read end, write end */
++
++  assert(buf_len > 0);
++
+   update_env_vars(imv);
+ 
+-  size_t len = 0;
+-  wordexp_t word;
+-  if (wordexp(format, &word, 0) == 0) {
+-    for (size_t i = 0; i < word.we_wordc; ++i) {
+-      len += snprintf(buf + len, buf_len - len, "%s ", word.we_wordv[i]);
++  if (pipe(p) == -1)
++    goto err;
++
++  switch (pid = fork()) {
++  case -1:
++    close(p[0]);
++    close(p[1]);
++    goto err;
++  case 0: /* child */
++    close(p[0]);
++    if (dup2(p[1], 1) != -1) {
++      execl("/bin/sh", "sh", "-c", "eval \"printf '%s ' $1\"", "sh",
++        format, (char *)NULL);
+     }
+-    wordfree(&word);
+-  } else {
+-    len += snprintf(buf, buf_len, "error expanding text");
++    _exit(1);
++  default: /* parent */
++    close(p[1]);
++
++    size_t r, siz = buf_len - 1, tot = 0;
++    do {
++      r = read(p[0], buf, siz);
++      if (r == -1) {
++        goto err;
++      } else if (r == 0) {
++        break;
++      }
++      tot += r;
++      buf += r;
++      siz -= r;
++    } while (siz > 0);
++
++    buf[tot] = '\0';
++    while (tot > 0 && isspace((unsigned char)buf[tot-1]))
++      buf[--tot] = '\0';
++
++    close(p[0]);
++
++    pid_t w;
++    do {
++      w = waitpid(pid, &status, 0);
++    } while (w != -1 && errno == EINTR);
++
++    return tot > 0 ? tot-1 : tot; /* don't count the NUL terminator */
+   }
+ 
+-  return len;
++err:
++  snprintf(buf, buf_len, "error expanding text: %s", strerror(errno));
++  return strlen(buf);
+ }
+ 
+ static size_t read_from_stdin(void **buffer)

Reply via email to