From fd9fcf741e6660a1344dafd33956fcdc64fdc643 Mon Sep 17 00:00:00 2001 From: Anna Arad <4895022+annagrram@users.noreply.github.com> Date: Fri, 27 Dec 2019 19:02:20 +0100 Subject: Get nnn compile and run on Haiku (#403) * Add support for Haiku OS * Adjust DISTFILES and dist rule in haiku --- Makefile | 4 +- VERSION.mk | 1 + misc/haiku/Makefile | 117 +++++++++++++++++++++++++++++++++++++++++++ misc/haiku/haiku_interop.h | 14 ++++++ misc/haiku/nm.cpp | 83 ++++++++++++++++++++++++++++++ misc/haiku/nnn-master.recipe | 52 +++++++++++++++++++ src/nnn.c | 51 +++++++++++++++++-- 7 files changed, 317 insertions(+), 5 deletions(-) create mode 100644 VERSION.mk create mode 100644 misc/haiku/Makefile create mode 100644 misc/haiku/haiku_interop.h create mode 100644 misc/haiku/nm.cpp create mode 100644 misc/haiku/nnn-master.recipe diff --git a/Makefile b/Makefile index 51dee97..6afeec2 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION = 2.8.1 +include VERSION.mk PREFIX ?= /usr/local MANPREFIX ?= $(PREFIX)/share/man @@ -57,7 +57,7 @@ CFLAGS += $(CFLAGS_CURSES) LDLIBS += $(LDLIBS_CURSES) -DISTFILES = src nnn.1 Makefile README.md LICENSE +DISTFILES = src nnn.1 Makefile README.md LICENSE VERSION.mk SRC = src/nnn.c HEADERS = src/nnn.h BIN = nnn diff --git a/VERSION.mk b/VERSION.mk new file mode 100644 index 0000000..b387df4 --- /dev/null +++ b/VERSION.mk @@ -0,0 +1 @@ +VERSION = 2.8.1 diff --git a/misc/haiku/Makefile b/misc/haiku/Makefile new file mode 100644 index 0000000..6fd576d --- /dev/null +++ b/misc/haiku/Makefile @@ -0,0 +1,117 @@ +include VERSION.mk + +PREFIX ?= /boot/system/non-packaged +MANPREFIX ?= /boot/system/non-packaged/documentation/man +STRIP ?= strip +PKG_CONFIG ?= pkg-config +INSTALL ?= install +CP ?= cp + +CFLAGS_OPTIMIZATION ?= -O3 + +O_DEBUG := 0 +O_NORL := 0 # no readline support +O_NOLOC := 0 # no locale support + +# convert targets to flags for backwards compatibility +ifneq ($(filter debug,$(MAKECMDGOALS)),) + O_DEBUG := 1 +endif +ifneq ($(filter norl,$(MAKECMDGOALS)),) + O_NORL := 1 +endif +ifneq ($(filter noloc,$(MAKECMDGOALS)),) + O_NORL := 1 + O_NOLOC := 1 +endif + +ifeq ($(O_DEBUG),1) + CPPFLAGS += -DDBGMODE + CFLAGS += -g + LDLIBS += -lrt +endif + +ifeq ($(O_NORL),1) + CPPFLAGS += -DNORL +else + LDLIBS += -lreadline +endif + +ifeq ($(O_NOLOC),1) + CPPFLAGS += -DNOLOCALE +endif + +ifeq ($(shell $(PKG_CONFIG) ncursesw && echo 1),1) + CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncursesw) + LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs ncursesw) +else ifeq ($(shell $(PKG_CONFIG) ncurses && echo 1),1) + CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncurses) + LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs ncurses) +else + LDLIBS_CURSES ?= -lncurses +endif + +ifeq ($(shell uname -s), Haiku) + LDLIBS_HAIKU ?= -lstdc++ -lbe + SRC_HAIKU ?= misc/haiku/nm.cpp + OBJS_HAIKU ?= misc/haiku/nm.o +endif + +CFLAGS += -Wall -Wextra +CFLAGS += $(CFLAGS_OPTIMIZATION) +CFLAGS += $(CFLAGS_CURSES) + +LDLIBS += $(LDLIBS_CURSES) $(LDLIBS_HAIKU) + +DISTFILES = src nnn.1 Makefile README.md LICENSE VERSION.mk +SRC = src/nnn.c +HEADERS = src/nnn.h +BIN = nnn +OBJS := nnn.o $(OBJS_HAIKU) + +all: $(BIN) + +ifeq ($(shell uname -s), Haiku) +$(OBJS_HAIKU): $(SRC_HAIKU) + $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< +endif + +nnn.o: $(SRC) $(HEADERS) + $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< + +$(BIN): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +# targets for backwards compatibility +debug: $(BIN) +norl: $(BIN) +noloc: $(BIN) + +install: all + $(INSTALL) -m 0755 -d $(DESTDIR)$(PREFIX)/bin + $(INSTALL) -m 0755 $(BIN) $(DESTDIR)$(PREFIX)/bin + $(INSTALL) -m 0755 -d $(DESTDIR)$(MANPREFIX)/man1 + $(INSTALL) -m 0644 $(BIN).1 $(DESTDIR)$(MANPREFIX)/man1 + +uninstall: + $(RM) $(DESTDIR)$(PREFIX)/bin/$(BIN) + $(RM) $(DESTDIR)$(MANPREFIX)/man1/$(BIN).1 + +strip: $(BIN) + $(STRIP) $^ + +dist: + mkdir -p nnn-$(VERSION) + $(CP) -r $(DISTFILES) nnn-$(VERSION) + mkdir -p nnn-$(VERSION)/misc + $(CP) -r misc/haiku nnn-$(VERSION)/misc + tar -cf nnn-$(VERSION).tar nnn-$(VERSION) + gzip nnn-$(VERSION).tar + $(RM) -r nnn-$(VERSION) + +clean: + $(RM) -f $(BIN) $(OBJS) nnn-$(VERSION).tar.gz + +skip: ; + +.PHONY: all debug install uninstall strip dist clean diff --git a/misc/haiku/haiku_interop.h b/misc/haiku/haiku_interop.h new file mode 100644 index 0000000..b422412 --- /dev/null +++ b/misc/haiku/haiku_interop.h @@ -0,0 +1,14 @@ +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct haiku_nm_t *haiku_nm_h; +haiku_nm_h haiku_init_nm(); +void haiku_close_nm(haiku_nm_h hnd); +int haiku_watch_dir(haiku_nm_h hnd, const char *path); +int haiku_stop_watch(haiku_nm_h hnd); +int haiku_is_update_needed(haiku_nm_h hnd); + +#ifdef __cplusplus +} +#endif diff --git a/misc/haiku/nm.cpp b/misc/haiku/nm.cpp new file mode 100644 index 0000000..ede1d37 --- /dev/null +++ b/misc/haiku/nm.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +#include "haiku_interop.h" + +filter_result dir_mon_flt(BMessage *message, BHandler **hnd, BMessageFilter *fltr) { + (void) hnd; + (void) fltr; + + if (message->what == B_NODE_MONITOR) { + int32 val; + message->FindInt32("opcode", &val); + + switch (val) { + case B_ENTRY_CREATED: + case B_ENTRY_MOVED: + case B_ENTRY_REMOVED: + return B_DISPATCH_MESSAGE; + } + } + + return B_SKIP_MESSAGE; +} + +class DirectoryListener : public BLooper { +public: + bool recv_reset() { + Lock(); + bool val = _ev_on; + _ev_on = false; + Unlock(); + + return val; + } +private: + void MessageReceived(BMessage * message) override { + Lock(); + _ev_on = true; + Unlock(); + BLooper::MessageReceived(message); + } + + bool _ev_on = false; +}; + +struct haiku_nm_t { + haiku_nm_t() { + dl = new DirectoryListener(); + flt = new BMessageFilter(B_PROGRAMMED_DELIVERY, B_LOCAL_SOURCE, dir_mon_flt); + dl->AddCommonFilter(flt); + dl->Run(); + } + + DirectoryListener *dl; + BMessageFilter *flt; + node_ref nr; +}; + +haiku_nm_h haiku_init_nm() { + return new haiku_nm_t(); +} + +void haiku_close_nm(haiku_nm_h hnd) { + delete hnd->flt; + // This is the way of deleting a BLooper + hnd->dl->PostMessage(B_QUIT_REQUESTED); + delete hnd; +} +int haiku_watch_dir(haiku_nm_h hnd, const char *path) { + BDirectory dir(path); + dir.GetNodeRef(&(hnd->nr)); + + return watch_node(&(hnd->nr), B_WATCH_DIRECTORY, nullptr, hnd->dl); +} +int haiku_stop_watch(haiku_nm_h hnd) { + return watch_node(&(hnd->nr), B_STOP_WATCHING, nullptr, hnd->dl); +} + +int haiku_is_update_needed(haiku_nm_h hnd) { + return hnd->dl->recv_reset(); +} diff --git a/misc/haiku/nnn-master.recipe b/misc/haiku/nnn-master.recipe new file mode 100644 index 0000000..7e2e463 --- /dev/null +++ b/misc/haiku/nnn-master.recipe @@ -0,0 +1,52 @@ +SUMMARY="The missing terminal file manager for X" +DESCRIPTION=" +nnn is a full-featured terminal file manager. It's tiny and nearly 0-config with an incredible performance. + +nnn is also a du analyzer, an app launcher, a batch renamer and a file picker. The plugin repository has tons of plugins and documentation to extend the capabilities further. You can plug new functionality and play with a custom keybind instantly. There's an independent (neo)vim plugin. + +It runs smoothly on the Raspberry Pi, Termux on Android, Linux, macOS, BSD, Cygwin, WSL and works seamlessly with DEs and GUI utilities. + +Visit the Wiki for concepts, program usage, how-tos and troubleshooting. +" +HOMEPAGE="https://github.com/jarun/nnn" +COPYRIGHT="2016-2019 Arun Prakash Jana" +LICENSE="BSD (2-clause)" +REVISION="1" +SOURCE_URI="git://github.com/jarun/nnn.git" + +ARCHITECTURES="x86 x86_64" + +PROVIDES=" + nnn = $portVersion + cmd:nnn = $portVersion + " +REQUIRES=" + haiku + lib:libncurses + lib:libreadline + " + +BUILD_REQUIRES=" + haiku_devel + pkgconfig + devel:libncurses + devel:libreadline + " + +BUILD_PREREQUIRES=" + cmd:make + cmd:gcc + cmd:g++ + cmd:ld + cmd:install +" + +BUILD() +{ + make -f misc/haiku/Makefile +} + +INSTALL() +{ + make -f misc/haiku/Makefile PREFIX=$prefix MANPREFIX=$manDir install +} diff --git a/src/nnn.c b/src/nnn.c index 46d8bf5..574c7d7 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -49,6 +49,9 @@ #include #include #define BSD_KQUEUE +#elif defined(__HAIKU__) +#include "../misc/haiku/haiku_interop.h" +#define HAIKU_NM #else #include #endif @@ -570,6 +573,9 @@ static struct kevent events_to_monitor[NUM_EVENT_FDS]; static uint KQUEUE_FFLAGS = NOTE_DELETE | NOTE_EXTEND | NOTE_LINK | NOTE_RENAME | NOTE_REVOKE | NOTE_WRITE; static struct timespec gtimeout; +#elif defined(HAIKU_NM) +static bool haiku_nm_active = FALSE; +static haiku_nm_h haiku_hnd = NULL; #endif /* Function macros */ @@ -1892,6 +1898,8 @@ static int nextsel(int presel) struct kevent event_data[NUM_EVENT_SLOTS]; memset((void *)event_data, 0x0, sizeof(struct kevent) * NUM_EVENT_SLOTS); +#elif defined(HAIKU_NM) +// TODO: Do some Haiku declarations #endif if (c == 0 || c == MSGWAIT) { @@ -1947,6 +1955,9 @@ static int nextsel(int presel) && kevent(kq, events_to_monitor, NUM_EVENT_SLOTS, event_data, NUM_EVENT_FDS, >imeout) > 0) c = CONTROL('L'); +#elif defined(HAIKU_NM) + if (!cfg.selmode && !cfg.blkorder && haiku_nm_active && idle & 1 && haiku_is_update_needed(haiku_hnd)) + c = CONTROL('L'); #endif } else idle = 0; @@ -3250,12 +3261,25 @@ static bool xmktree(char* path, bool dir) /* Create folder from path to '\0' inserted at p */ if (mkdir(path, 0777) == -1 && errno != EEXIST) { +#ifdef __HAIKU__ + // XDG_CONFIG_HOME contains a directory + // that is read-only, but the full path + // is writeable. + // Try to continue and see what happens. + // TODO: Find a more robust solution. + if (errno == B_READ_ONLY_DEVICE) { + goto next; + } +#endif DPRINTF_S("mkdir1!"); DPRINTF_S(strerror(errno)); *slash = '/'; return FALSE; } +#ifdef __HAIKU__ +next: +#endif /* Restore path */ *slash = '/'; ++p; @@ -3774,7 +3798,7 @@ static int dentfill(char *path, struct entry **dents) if (!dp) goto exit; -#ifdef __sun +#if defined(__sun) || defined(__HAIKU__) flags = AT_SYMLINK_NOFOLLOW; /* no d_type */ #else if (cfg.blkorder || dp->d_type == DT_UNKNOWN) { @@ -3878,7 +3902,7 @@ static int dentfill(char *path, struct entry **dents) /* Copy other fields */ dentp->t = cfg.mtime ? sb.st_mtime : sb.st_atime; -#ifndef __sun +#if !(defined(__sun) || defined(__HAIKU__)) if (!flags && dp->d_type == DT_LNK) { /* Do not add sizes for links */ dentp->mode = (sb.st_mode & ~S_IFMT) | S_IFLNK; @@ -3926,7 +3950,7 @@ static int dentfill(char *path, struct entry **dents) if (S_ISDIR(sb.st_mode)) dentp->flags |= DIR_OR_LINK_TO_DIR; -#ifndef __sun /* no d_type */ +#if !(defined(__sun) || defined(__HAIKU__)) /* no d_type */ } else if (dp->d_type == DT_DIR || (dp->d_type == DT_LNK && S_ISDIR(sb.st_mode))) { dentp->flags |= DIR_OR_LINK_TO_DIR; #endif @@ -4321,6 +4345,12 @@ begin: event_fd = -1; dir_changed = FALSE; } +#elif defined(HAIKU_NM) + if ((presel == FILTER || dir_changed) && haiku_hnd != NULL) { + haiku_stop_watch(haiku_hnd); + haiku_nm_active = FALSE; + dir_changed = FALSE; + } #endif /* Can fail when permissions change while browsing. @@ -4352,6 +4382,8 @@ begin: EV_SET(&events_to_monitor[0], event_fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, KQUEUE_FFLAGS, 0, path); } +#elif defined(HAIKU_NM) + haiku_nm_active = haiku_watch_dir(haiku_hnd, path) == _SUCCESS; #endif while (1) { @@ -4726,6 +4758,11 @@ nochange: close(event_fd); event_fd = -1; } +#elif defined(HAIKU_NM) + if (haiku_nm_active) { + haiku_stop_watch(haiku_hnd); + haiku_nm_active = FALSE; + } #endif presel = filterentries(path, lastname); @@ -5852,6 +5889,12 @@ int main(int argc, char *argv[]) xerror(); return _FAILURE; } +#elif defined(HAIKU_NM) + haiku_hnd = haiku_init_nm(); + if (!haiku_hnd) { + xerror(); + return _FAILURE; + } #endif /* Set nnn nesting level */ @@ -5950,6 +5993,8 @@ int main(int argc, char *argv[]) if (event_fd >= 0) close(event_fd); close(kq); +#elif defined(HAIKU_NM) + haiku_close_nm(haiku_hnd); #endif return _SUCCESS; -- cgit v1.2.3-70-g09d2