Skip to content

Commit

Permalink
Emulate struct direntry::d_entry when absent
Browse files Browse the repository at this point in the history
Not all systems have this field, it's not required by POSIX (it
requires bare minimum).

Thanks to Robert Sarkozi.
  • Loading branch information
xaizek committed Jul 7, 2017
1 parent 5a7bf83 commit e9e0499
Show file tree
Hide file tree
Showing 19 changed files with 248 additions and 74 deletions.
3 changes: 2 additions & 1 deletion README
Expand Up @@ -3,7 +3,7 @@ Vifm - vi[m] like file manager

Version: 0.9

This file last updated: 20 June, 2017
This file last updated: 07 July, 2017

Brief Description

Expand Down Expand Up @@ -81,6 +81,7 @@ Package content
| |-- compat/ - implementation of features that are missing on some OSes
| | |
| | |-- curses.c - emulation of some wide functions for OpenBSD
| | |-- dentry.c - emulation of d_entry field of struct direntry
| | |-- getopt.c - part of glibc to have getopt_long() everywhere
| | |-- getopt1.c - getopt.c public interface implementation
| | |-- mntent.c - compatibility file for FreeBSD-like systems
Expand Down
3 changes: 3 additions & 0 deletions build-aux/config.h.in
Expand Up @@ -80,6 +80,9 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H

/* Define to 1 if `d_type' is a member of `struct dirent'. */
#undef HAVE_STRUCT_DIRENT_D_TYPE

/* Define to 1 if `st_mtim' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIM

Expand Down
20 changes: 19 additions & 1 deletion configure
Expand Up @@ -7643,14 +7643,32 @@ else
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default"
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
"
if test "x$ac_cv_member_struct_stat_st_mtim" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_STAT_ST_MTIM 1
_ACEOF
fi
ac_fn_c_check_member "$LINENO" "struct dirent" "d_type" "ac_cv_member_struct_dirent_d_type" "
#include <dirent.h>
"
if test "x$ac_cv_member_struct_dirent_d_type" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_STRUCT_DIRENT_D_TYPE 1
_ACEOF
fi
# Check whether --enable-largefile was given.
Expand Down
9 changes: 8 additions & 1 deletion configure.ac
Expand Up @@ -276,7 +276,14 @@ AC_CHECK_DECL([REG_EXTENDED], [], [AC_MSG_ERROR([REG_EXTENDED not found in regex
AC_CHECK_DECL([REG_ICASE], [], [AC_MSG_ERROR([REG_ICASE not found in regex.h])], [[#include <regex.h>]])
AC_CHECK_DECL([REG_NOMATCH], [], [AC_MSG_ERROR([REG_NOMATCH not found in regex.h])], [[#include <regex.h>]])

AC_CHECK_MEMBERS([struct stat.st_mtim])
AC_CHECK_MEMBERS([struct stat.st_mtim], [], [], [[
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
]])
AC_CHECK_MEMBERS([struct dirent.d_type], [], [], [[
#include <dirent.h>
]])
AC_SYS_LARGEFILE
AC_FUNC_FSEEKO
AC_TYPE_OFF_T
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.am
Expand Up @@ -91,6 +91,7 @@ vifm_SOURCES = \
cfg/info_chars.h \
\
compat/curses.c compat/curses.h \
compat/dtype.c compat/dtype.h \
compat/fs_limits.h \
compat/getopt.c compat/getopt1.c compat/getopt.h compat/getopt_int.h \
compat/mntent.c compat/mntent.h \
Expand Down
58 changes: 31 additions & 27 deletions src/Makefile.in
Expand Up @@ -125,33 +125,33 @@ PROGRAMS = $(bin_PROGRAMS)
am__dirstamp = $(am__leading_dot)dirstamp
am_vifm_OBJECTS = cfg/config.$(OBJEXT) cfg/hist.$(OBJEXT) \
cfg/info.$(OBJEXT) compat/curses.$(OBJEXT) \
compat/getopt.$(OBJEXT) compat/getopt1.$(OBJEXT) \
compat/mntent.$(OBJEXT) compat/os.$(OBJEXT) \
compat/pthread.$(OBJEXT) compat/reallocarray.$(OBJEXT) \
engine/abbrevs.$(OBJEXT) engine/autocmds.$(OBJEXT) \
engine/cmds.$(OBJEXT) engine/completion.$(OBJEXT) \
engine/functions.$(OBJEXT) engine/keys.$(OBJEXT) \
engine/mode.$(OBJEXT) engine/options.$(OBJEXT) \
engine/parsing.$(OBJEXT) engine/text_buffer.$(OBJEXT) \
engine/var.$(OBJEXT) engine/variables.$(OBJEXT) \
int/desktop.$(OBJEXT) int/file_magic.$(OBJEXT) \
int/fuse.$(OBJEXT) int/path_env.$(OBJEXT) \
int/term_title.$(OBJEXT) int/vim.$(OBJEXT) io/ioe.$(OBJEXT) \
io/ioeta.$(OBJEXT) io/iop.$(OBJEXT) io/ior.$(OBJEXT) \
io/private/ioc.$(OBJEXT) io/private/ioe.$(OBJEXT) \
io/private/ioeta.$(OBJEXT) io/private/ionotif.$(OBJEXT) \
io/private/traverser.$(OBJEXT) menus/apropos_menu.$(OBJEXT) \
menus/bmarks_menu.$(OBJEXT) menus/cabbrevs_menu.$(OBJEXT) \
menus/colorscheme_menu.$(OBJEXT) menus/commands_menu.$(OBJEXT) \
menus/dirhistory_menu.$(OBJEXT) menus/dirstack_menu.$(OBJEXT) \
menus/filetypes_menu.$(OBJEXT) menus/find_menu.$(OBJEXT) \
menus/grep_menu.$(OBJEXT) menus/history_menu.$(OBJEXT) \
menus/jobs_menu.$(OBJEXT) menus/locate_menu.$(OBJEXT) \
menus/trash_menu.$(OBJEXT) menus/trashes_menu.$(OBJEXT) \
menus/map_menu.$(OBJEXT) menus/marks_menu.$(OBJEXT) \
menus/menus.$(OBJEXT) menus/registers_menu.$(OBJEXT) \
menus/undolist_menu.$(OBJEXT) menus/users_menu.$(OBJEXT) \
menus/vifm_menu.$(OBJEXT) \
compat/dtype.$(OBJEXT) compat/getopt.$(OBJEXT) \
compat/getopt1.$(OBJEXT) compat/mntent.$(OBJEXT) \
compat/os.$(OBJEXT) compat/pthread.$(OBJEXT) \
compat/reallocarray.$(OBJEXT) engine/abbrevs.$(OBJEXT) \
engine/autocmds.$(OBJEXT) engine/cmds.$(OBJEXT) \
engine/completion.$(OBJEXT) engine/functions.$(OBJEXT) \
engine/keys.$(OBJEXT) engine/mode.$(OBJEXT) \
engine/options.$(OBJEXT) engine/parsing.$(OBJEXT) \
engine/text_buffer.$(OBJEXT) engine/var.$(OBJEXT) \
engine/variables.$(OBJEXT) int/desktop.$(OBJEXT) \
int/file_magic.$(OBJEXT) int/fuse.$(OBJEXT) \
int/path_env.$(OBJEXT) int/term_title.$(OBJEXT) \
int/vim.$(OBJEXT) io/ioe.$(OBJEXT) io/ioeta.$(OBJEXT) \
io/iop.$(OBJEXT) io/ior.$(OBJEXT) io/private/ioc.$(OBJEXT) \
io/private/ioe.$(OBJEXT) io/private/ioeta.$(OBJEXT) \
io/private/ionotif.$(OBJEXT) io/private/traverser.$(OBJEXT) \
menus/apropos_menu.$(OBJEXT) menus/bmarks_menu.$(OBJEXT) \
menus/cabbrevs_menu.$(OBJEXT) menus/colorscheme_menu.$(OBJEXT) \
menus/commands_menu.$(OBJEXT) menus/dirhistory_menu.$(OBJEXT) \
menus/dirstack_menu.$(OBJEXT) menus/filetypes_menu.$(OBJEXT) \
menus/find_menu.$(OBJEXT) menus/grep_menu.$(OBJEXT) \
menus/history_menu.$(OBJEXT) menus/jobs_menu.$(OBJEXT) \
menus/locate_menu.$(OBJEXT) menus/trash_menu.$(OBJEXT) \
menus/trashes_menu.$(OBJEXT) menus/map_menu.$(OBJEXT) \
menus/marks_menu.$(OBJEXT) menus/menus.$(OBJEXT) \
menus/registers_menu.$(OBJEXT) menus/undolist_menu.$(OBJEXT) \
menus/users_menu.$(OBJEXT) menus/vifm_menu.$(OBJEXT) \
modes/dialogs/attr_dialog_nix.$(OBJEXT) \
modes/dialogs/change_dialog.$(OBJEXT) \
modes/dialogs/msg_dialog.$(OBJEXT) \
Expand Down Expand Up @@ -649,6 +649,7 @@ vifm_SOURCES = \
cfg/info_chars.h \
\
compat/curses.c compat/curses.h \
compat/dtype.c compat/dtype.h \
compat/fs_limits.h \
compat/getopt.c compat/getopt1.c compat/getopt.h compat/getopt_int.h \
compat/mntent.c compat/mntent.h \
Expand Down Expand Up @@ -944,6 +945,8 @@ compat/$(DEPDIR)/$(am__dirstamp):
@: > compat/$(DEPDIR)/$(am__dirstamp)
compat/curses.$(OBJEXT): compat/$(am__dirstamp) \
compat/$(DEPDIR)/$(am__dirstamp)
compat/dtype.$(OBJEXT): compat/$(am__dirstamp) \
compat/$(DEPDIR)/$(am__dirstamp)
compat/getopt.$(OBJEXT): compat/$(am__dirstamp) \
compat/$(DEPDIR)/$(am__dirstamp)
compat/getopt1.$(OBJEXT): compat/$(am__dirstamp) \
Expand Down Expand Up @@ -1293,6 +1296,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@cfg/$(DEPDIR)/hist.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@cfg/$(DEPDIR)/info.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/curses.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/dtype.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/getopt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/getopt1.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/mntent.Po@am__quote@
Expand Down
3 changes: 2 additions & 1 deletion src/Makefile.win
Expand Up @@ -40,7 +40,8 @@ DIRS += modes/dialogs/ ui/ utils/
cfg := config.c hist.c info.c
cfg := $(addprefix cfg/, $(cfg))

compat := curses.c getopt.c getopt1.c os.c pthread.c reallocarray.c wcwidth.c
compat := curses.c dtype.c getopt.c getopt1.c os.c pthread.c reallocarray.c
compat += wcwidth.c
compat := $(addprefix compat/, $(compat))

engine := abbrevs.c autocmds.c cmds.c functions.c completion.c keys.c mode.c \
Expand Down
40 changes: 24 additions & 16 deletions src/cmd_completion.c
Expand Up @@ -42,6 +42,7 @@
strrchr() */

#include "cfg/config.h"
#include "compat/dtype.h"
#include "compat/fs_limits.h"
#include "compat/os.h"
#include "engine/abbrevs.h"
Expand Down Expand Up @@ -92,9 +93,9 @@ static void complete_from_string_list(const char str[], const char *items[][2],
static void complete_command_name(const char beginning[]);
static void filename_completion_in_dir(const char *path, const char *str,
CompletionType type);
static void filename_completion_internal(DIR *dir, const char filename[],
CompletionType type);
static int is_dirent_targets_exec(const struct dirent *d);
static void filename_completion_internal(DIR *dir, const char dir_path[],
const char filename[], CompletionType type);
static int is_dirent_targets_exec(const struct dirent *d, const char path[]);
#ifdef _WIN32
static void complete_with_shared(const char *server, const char *file);
#endif
Expand Down Expand Up @@ -967,7 +968,7 @@ filename_completion(const char str[], CompletionType type,
}
else
{
filename_completion_internal(dir, filename, type);
filename_completion_internal(dir, dirname, filename, type);
(void)vifm_chdir(flist_get_dir(curr_view));
}

Expand All @@ -984,28 +985,34 @@ filename_completion(const char str[], CompletionType type,

/* The file completion core of filename_completion(). */
static void
filename_completion_internal(DIR *dir, const char filename[],
CompletionType type)
filename_completion_internal(DIR *dir, const char dir_path[],
const char filename[], CompletionType type)
{
struct dirent *d;

size_t filename_len = strlen(filename);
while((d = os_readdir(dir)) != NULL)
{
char full_path[PATH_MAX + 1];
int is_dir, is_exec;

if(filename[0] == '\0' && d->d_name[0] == '.')
continue;
if(!file_matches(d->d_name, filename, filename_len))
continue;

if(type == CT_DIRONLY && !is_dirent_targets_dir(d))
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, d->d_name);
is_dir = is_dirent_targets_dir(full_path, d);
is_exec = is_dirent_targets_exec(d, full_path);

if(type == CT_DIRONLY && !is_dir)
continue;
else if(type == CT_EXECONLY && !is_dirent_targets_exec(d))
else if(type == CT_EXECONLY && !is_exec)
continue;
else if(type == CT_DIREXEC && !is_dirent_targets_dir(d) &&
!is_dirent_targets_exec(d))
else if(type == CT_DIREXEC && !is_dir && !is_exec)
continue;

if(is_dirent_targets_dir(d) && type != CT_ALL_WOS)
if(is_dir && type != CT_ALL_WOS)
{
vle_compl_put_path_match(format_str("%s/", d->d_name));
}
Expand All @@ -1025,16 +1032,17 @@ filename_completion_internal(DIR *dir, const char filename[],
/* Uses dentry to check file type. Returns non-zero for directories,
* otherwise zero is returned. Symbolic links are dereferenced. */
static int
is_dirent_targets_exec(const struct dirent *d)
is_dirent_targets_exec(const struct dirent *d, const char path[])
{
#ifndef _WIN32
if(d->d_type == DT_DIR)
const unsigned char type = get_dirent_type(d, path);
if(type == DT_DIR)
return 0;
if(d->d_type == DT_LNK && get_symlink_type(d->d_name) != SLT_UNKNOWN)
if(type == DT_LNK && get_symlink_type(path) != SLT_UNKNOWN)
return 0;
return os_access(d->d_name, X_OK) == 0;
return os_access(path, X_OK) == 0;
#else
return is_win_executable(d->d_name);
return is_win_executable(path);
#endif
}

Expand Down
63 changes: 63 additions & 0 deletions src/compat/dtype.c
@@ -0,0 +1,63 @@
/* vifm
* Copyright (C) 2016 xaizek.
*
* 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 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

#include "dtype.h"
#include <dirent.h> /* dirent */

#if !defined(HAVE_STRUCT_DIRENT_D_TYPE) || !HAVE_STRUCT_DIRENT_D_TYPE

#include "os.h"

unsigned char
get_dirent_type(const struct dirent *dentry, const char path[])
{
struct stat st;

if(os_lstat(path, &st) != 0 || st.st_ino == 0)
{
return DT_UNKNOWN;
}

switch(st.st_mode & S_IFMT)
{
case S_IFBLK: return DT_BLK;
case S_IFCHR: return DT_CHR;
case S_IFDIR: return DT_DIR;
case S_IFIFO: return DT_FIFO;
case S_IFREG: return DT_REG;
#ifndef _WIN32
case S_IFLNK: return DT_LNK;
case S_IFSOCK: return DT_SOCK;
#endif

default: return DT_UNKNOWN;
}
}

#else

unsigned char
get_dirent_type(const struct dirent *dentry, const char path[])
{
return dentry->d_type;
}

#endif

/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
/* vim: set cinoptions+=t0 : */
50 changes: 50 additions & 0 deletions src/compat/dtype.h
@@ -0,0 +1,50 @@
/* vifm
* Copyright (C) 2016 xaizek.
*
* 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 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

#ifndef VIFM__COMPAT__DTYPE_H__
#define VIFM__COMPAT__DTYPE_H__

#if !defined(HAVE_STRUCT_DIRENT_D_TYPE) || !HAVE_STRUCT_DIRENT_D_TYPE

/* Declaration of entry types that match those defined by POSIX. */
enum
{
DT_BLK,
DT_CHR,
DT_DIR,
DT_FIFO,
DT_REG,
#ifndef _WIN32
DT_LNK,
DT_SOCK,
#endif
DT_UNKNOWN
};

#endif

struct dirent;

/* Retrieves entry type. Either directly from dirent or by running lstat() on
* the path. Returns the type. */
unsigned char get_dirent_type(const struct dirent *dentry, const char path[]);

#endif // VIFM__COMPAT__DTYPE_H__

/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
/* vim: set cinoptions+=t0 : */

0 comments on commit e9e0499

Please sign in to comment.