summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstkhan <personal@slickd.xyz>2022-05-13 18:15:43 +0000
committerstkhan <personal@slickd.xyz>2022-05-13 18:15:43 +0000
commit2e81fbdf15168a5b6df291b7062d120156a5ce45 (patch)
tree57de36552c6f46e43d8520ccf65acb80ef5f6c29
parent7a93f153bf5e088ab6e2da6fcc0518744cfd54af (diff)
Removed dwm scripts, sfm, , added scroll, and added dark theme to surf
-rw-r--r--Makefile13
-rw-r--r--dwm-6.3/Makefile1
-rwxr-xr-xdwm-6.3/scripts/dmenuunicode18
-rwxr-xr-xdwm-6.3/scripts/dwm-goto14
-rwxr-xr-xdwm-6.3/scripts/dwm-mute4
-rwxr-xr-xdwm-6.3/scripts/dwm-search14
-rwxr-xr-xdwm-6.3/scripts/dwm-vol_down3
-rwxr-xr-xdwm-6.3/scripts/dwm-vol_up3
-rwxr-xr-xdwm-6.3/scripts/passmenu35
-rwxr-xr-xdwm-6.3/scripts/power8
-rw-r--r--scripts/Makefile7
-rwxr-xr-xscripts/get_weather5
-rw-r--r--scripts/ip.c32
-rw-r--r--scroll-0.1/Makefile45
-rw-r--r--scroll-0.1/README34
-rw-r--r--scroll-0.1/TODO3
-rw-r--r--scroll-0.1/config.def.h16
-rw-r--r--scroll-0.1/config.h16
-rw-r--r--scroll-0.1/config.mk12
-rw-r--r--scroll-0.1/ptty.c156
-rw-r--r--scroll-0.1/scroll.168
-rw-r--r--scroll-0.1/scroll.c594
-rw-r--r--scroll-0.1/up.log74
-rwxr-xr-xscroll-0.1/up.sh15
-rw-r--r--sfm-0.4/LICENSE19
-rw-r--r--sfm-0.4/Makefile51
-rw-r--r--sfm-0.4/README.md78
-rw-r--r--sfm-0.4/config.def.h163
-rw-r--r--sfm-0.4/config.h163
-rw-r--r--sfm-0.4/config.mk14
-rw-r--r--sfm-0.4/sfm.1147
-rw-r--r--sfm-0.4/sfm.c2033
-rw-r--r--sfm-0.4/sfm.pngbin745 -> 0 bytes
-rw-r--r--sfm-0.4/termbox.c1509
-rw-r--r--sfm-0.4/termbox.h317
-rw-r--r--sfm-0.4/utf8.c78
-rw-r--r--sfm-0.4/util.c44
-rw-r--r--sfm-0.4/util.h17
-rw-r--r--surf/style/default.css15
m---------sxiv0
-rw-r--r--tabbed/config.h2
41 files changed, 1056 insertions, 4784 deletions
diff --git a/Makefile b/Makefile
index ccc6413..80a4b22 100644
--- a/Makefile
+++ b/Makefile
@@ -7,19 +7,19 @@ help:
@echo ""
@echo " c, clean: cleans dir"
@echo " cleanp: really cleans dir"
- @echo " config: sets a theme for sarc"
+ @echo " cfg,config: sets a theme for sarc"
@echo " install: installs build"
@echo
@echo "running with no args will just build it"
config:
rm -rf .config
@./scripts/set_theme.sh
+ @echo "Run make to compile sarc"
sarc: clean
./scripts/cp.sh
make -C $(DWM)
make -C $(ST)
make -C $(DMENU)
- make -C $(SFM)
make -C surf
make -C dwmblocks
make -C nsxiv
@@ -28,27 +28,27 @@ sarc: clean
make -C sent
make -C wmname
rm -rf colors.h
- gcc -o scripts/gip scripts/ip.c
c: clean
+cfg: config
install:
make install -C $(DWM)
make install -C $(ST)
make install -C $(DMENU)
- make install -C $(SFM)
make install -C surf
make install -C dwmblocks
make install -C nsxiv
make install -C tabbed
- make install -C scripts
make install -C farbfeld
make install -C sent
make install -C wmname
install scripts/sarc.sh /usr/local/bin
+ install scripts/fehbg /usr/local/bin
+ @echo
+ @echo "Finished! Run make install to install"
clean:
make clean -C dwm-6.3
make clean -C st-0.8.4
make clean -C dmenu-5.0
- make clean -C $(SFM)
make clean -C surf
make clean -C nsxiv
make clean -C tabbed
@@ -56,6 +56,7 @@ clean:
make clean -C farbfeld
make clean -C sent
make clean -C wmname
+ make clean -C scroll-0.1
rm -rf scripts/gip colors.h
cleanp: clean
rm -rf .config
diff --git a/dwm-6.3/Makefile b/dwm-6.3/Makefile
index 5ac0a5e..3009009 100644
--- a/dwm-6.3/Makefile
+++ b/dwm-6.3/Makefile
@@ -43,7 +43,6 @@ install: all
mkdir -p ${DESTDIR}${MANPREFIX}/man1
sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
- cp scripts/* $(PREFIX)/bin
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
${DESTDIR}${MANPREFIX}/man1/dwm.1
diff --git a/dwm-6.3/scripts/dmenuunicode b/dwm-6.3/scripts/dmenuunicode
deleted file mode 100755
index 7d9a4ea..0000000
--- a/dwm-6.3/scripts/dmenuunicode
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-
-# The famous "get a menu of emojis to copy" script.
-
-# Get user selection via dmenu from emoji file.
-chosen=$(cut -d ';' -f1 ~/.local/share/larbs/emoji | dmenu -i -l 30 | sed "s/ .*//")
-
-# Exit if none chosen.
-[ -z "$chosen" ] && exit
-
-# If you run this command with an argument, it will automatically insert the
-# character. Otherwise, show a message that the emoji has been copied.
-if [ -n "$1" ]; then
- xdotool type "$chosen"
-else
- printf "$chosen" | xclip -selection clipboard
- notify-send "'$chosen' copied to clipboard." &
-fi
diff --git a/dwm-6.3/scripts/dwm-goto b/dwm-6.3/scripts/dwm-goto
deleted file mode 100755
index f297b25..0000000
--- a/dwm-6.3/scripts/dwm-goto
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-
-URL=$(cat ~/.config/surf/history.txt | sed 's/^[^ *]* //' | sort -u | dmenu -p "Enter a URL: ")
-POSTURL=$(echo $URL | sed 's/-e//; s/reddit.com/old.reddit.com/')
-CMD="firejail --noprofile --hosts-file=~/.config/surf/ads.txt tabbed -dn tabbed-surf -r 2 surf -e '' $POSTURL"
-
-echo $POSTURL
-if [[ -z "$URL" ]]; then
- exit
-else
- # saves url to history
- echo $URL >> ~/.config/surf/history.txt
- $CMD
-fi
diff --git a/dwm-6.3/scripts/dwm-mute b/dwm-6.3/scripts/dwm-mute
deleted file mode 100755
index 5a23e63..0000000
--- a/dwm-6.3/scripts/dwm-mute
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-pamixer -t
-dunstify "Toggled mute" &
diff --git a/dwm-6.3/scripts/dwm-search b/dwm-6.3/scripts/dwm-search
deleted file mode 100755
index ff49fc7..0000000
--- a/dwm-6.3/scripts/dwm-search
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-
-QUERY=$(tac ~/.config/surf/search.txt | sort -u | dmenu -l 20 -p "Search DuckDuckGo: ")
-SEARCH=$(echo $QUERY | sed 's/ /+/g; s/-e//')
-URL="duckduckgo.com/?q=$SEARCH"
-CMD="firejail --noprofile --hosts-file=~/.config/surf/ads.txt tabbed -dn tabbed-surf -r 2 surf -e '' $URL"
-
-if [[ -z "$SEARCH" ]]; then
- exit
-else
- # saves search to history
- echo $QUERY | sed 's/-e//' >> ~/.config/surf/search.txt
- $CMD
-fi
diff --git a/dwm-6.3/scripts/dwm-vol_down b/dwm-6.3/scripts/dwm-vol_down
deleted file mode 100755
index 8ecec15..0000000
--- a/dwm-6.3/scripts/dwm-vol_down
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-pamixer --allow-boost -d 5
diff --git a/dwm-6.3/scripts/dwm-vol_up b/dwm-6.3/scripts/dwm-vol_up
deleted file mode 100755
index 4e11111..0000000
--- a/dwm-6.3/scripts/dwm-vol_up
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-pamixer --allow-boost -i 5
diff --git a/dwm-6.3/scripts/passmenu b/dwm-6.3/scripts/passmenu
deleted file mode 100755
index 76d92ab..0000000
--- a/dwm-6.3/scripts/passmenu
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env bash
-
-shopt -s nullglob globstar
-
-typeit=0
-if [[ $1 == "--type" ]]; then
- typeit=1
- shift
-fi
-
-if [[ -n $WAYLAND_DISPLAY ]]; then
- dmenu=dmenu-wl
- xdotool="ydotool type --file -"
-elif [[ -n $DISPLAY ]]; then
- dmenu=dmenu
- xdotool="xdotool type --clearmodifiers --file -"
-else
- echo "Error: No Wayland or X11 display detected" >&2
- exit 1
-fi
-
-prefix=${PASSWORD_STORE_DIR-~/.password-store}
-password_files=( "$prefix"/**/*.gpg )
-password_files=( "${password_files[@]#"$prefix"/}" )
-password_files=( "${password_files[@]%.gpg}" )
-
-password=$(printf '%s\n' "${password_files[@]}" | "$dmenu" "$@")
-
-[[ -n $password ]] || exit
-
-if [[ $typeit -eq 0 ]]; then
- pass show -c "$password" 2>/dev/null
-else
- pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | $xdotool
-fi
diff --git a/dwm-6.3/scripts/power b/dwm-6.3/scripts/power
deleted file mode 100755
index d376fa9..0000000
--- a/dwm-6.3/scripts/power
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-# A dmenu wrapper script for system functions.
-
-case "$(printf "🔃 reboot\n🖥️shutdown\n" | dmenu -i -p 'Power: ')" in
- '🔃 reboot') sudo reboot ;;
- '🖥️shutdown') sudo poweroff ;;
- *) exit 1 ;;
-esac
diff --git a/scripts/Makefile b/scripts/Makefile
deleted file mode 100644
index 1b32df7..0000000
--- a/scripts/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-include ../config.mk
-
-install:
- gcc -o gip ip.c
- cp get_weather fehbg gip $(PREFIX)/bin
-clean:
- rm $(PREFIX)/bin/{gip, , fehbg, get_weather}
diff --git a/scripts/get_weather b/scripts/get_weather
deleted file mode 100755
index 1b3767b..0000000
--- a/scripts/get_weather
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-echo "Date: $(date)" >> ~/.cache/weather_report
-curl wttr.in > ~/.cache/weather_report
-st less -Srf ~/.cache/weather_report
diff --git a/scripts/ip.c b/scripts/ip.c
deleted file mode 100644
index 3276696..0000000
--- a/scripts/ip.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h> /* for strncpy */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <arpa/inet.h>
-
-int
-main()
-{
- int fd;
- struct ifreq ifr;
-
- fd = socket(AF_INET, SOCK_DGRAM, 0);
-
- /* I want to get an IPv4 IP address */
- ifr.ifr_addr.sa_family = AF_INET;
- strncpy(ifr.ifr_name, "wlan0", IFNAMSIZ-1);
-
- ioctl(fd, SIOCGIFADDR, &ifr);
-
- close(fd);
-
- /* display result */
- printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
-
- return 0;
-}
diff --git a/scroll-0.1/Makefile b/scroll-0.1/Makefile
new file mode 100644
index 0000000..cacccd2
--- /dev/null
+++ b/scroll-0.1/Makefile
@@ -0,0 +1,45 @@
+.POSIX:
+
+include config.mk
+
+all: scroll
+
+config.h:
+ cp config.def.h config.h
+
+scroll: scroll.c config.h
+
+install: scroll
+ mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1
+ cp -f scroll $(DESTDIR)$(BINDIR)
+ cp -f scroll.1 $(DESTDIR)$(MANDIR)/man1
+
+uninstall:
+ rm -f $(DESTDIR)$(BINDIR)/scroll $(DESTDIR)$(MANDIR)/man1/scroll.1
+
+test: scroll ptty
+ # check usage
+ if ./ptty ./scroll -h; then exit 1; fi
+ # check exit passthrough of child
+ if ! ./ptty ./scroll true; then exit 1; fi
+ if ./ptty ./scroll false; then exit 1; fi
+ ./up.sh
+
+clean:
+ rm -f scroll ptty
+
+distclean: clean
+ rm -f config.h scroll-$(VERSION).tar.gz
+
+dist: clean
+ mkdir -p scroll-$(VERSION)
+ cp -R README scroll.1 TODO Makefile config.mk config.def.h \
+ ptty.c scroll.c up.sh up.log \
+ scroll-$(VERSION)
+ tar -cf - scroll-$(VERSION) | gzip > scroll-$(VERSION).tar.gz
+ rm -rf scroll-$(VERSION)
+
+.c:
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< -lutil
+
+.PHONY: all install test clean distclean dist
diff --git a/scroll-0.1/README b/scroll-0.1/README
new file mode 100644
index 0000000..7ddb949
--- /dev/null
+++ b/scroll-0.1/README
@@ -0,0 +1,34 @@
+This program provides a scroll back buffer for a terminal like st(1). It
+should run on any Unix-like system.
+
+At the moment it is in an experimental state. Its not recommended for
+productive use.
+
+The initial version of this program is from Roberto E. Vargas Caballero:
+ https://lists.suckless.org/dev/1703/31256.html
+
+What is the state of scroll?
+
+The project is faced with some hard facts, that our original plan is not doable
+as we thought in the fist place:
+
+ 1. [crtl]+[e] is used in emacs mode (default) on the shell to jump to the end
+ of the line. But, its also used so signal a scroll down mouse event from
+ terminal emulators to the shell an other programs.
+
+ - A workaround is to use vi mode in the shell.
+ - Or to give up mouse support (default behavior)
+
+ 2. scroll could not handle backward cursor jumps and editing of old lines
+ properly. We just handle current line editing and switching between
+ alternative screens (curses mode). For a proper end user experience we
+ would need to write complete new a terminal emulator like screen or tmux.
+
+What is the performance impact of scroll?
+
+ indirect OpenBSD
+-------------------------------
+ 0x 7.53 s
+ 1x 10.10 s
+ 2x 12.00 s
+ 3x 13.73 s
diff --git a/scroll-0.1/TODO b/scroll-0.1/TODO
new file mode 100644
index 0000000..84ffd33
--- /dev/null
+++ b/scroll-0.1/TODO
@@ -0,0 +1,3 @@
+ * strlen function which is aware of unicode
+ * handle wrapping lines in scrolling line count correctly
+ * hotkey to dump buffer to file (like screen hardcopy)
diff --git a/scroll-0.1/config.def.h b/scroll-0.1/config.def.h
new file mode 100644
index 0000000..536db70
--- /dev/null
+++ b/scroll-0.1/config.def.h
@@ -0,0 +1,16 @@
+/*
+ * Define ESC sequences to use for scroll events.
+ * Use "cat -v" to figure out favorite key combination.
+ *
+ * lines is the number of lines scrolled up or down.
+ * If lines is negative, it's the fraction of the terminal size.
+ */
+
+struct rule rules[] = {
+ /* sequence event lines */
+ {"\033[5;2~", SCROLL_UP, -1}, /* [Shift] + [PageUP] */
+ {"\033[6;2~", SCROLL_DOWN, -1}, /* [Shift] + [PageDown] */
+ /* mouse binding shadows ^E and ^Y, so it's disabled by default */
+ //{"\031", SCROLL_UP, 1}, /* mouse wheel up */
+ //{"\005", SCROLL_DOWN, 1}, /* mouse wheel Down */
+};
diff --git a/scroll-0.1/config.h b/scroll-0.1/config.h
new file mode 100644
index 0000000..536db70
--- /dev/null
+++ b/scroll-0.1/config.h
@@ -0,0 +1,16 @@
+/*
+ * Define ESC sequences to use for scroll events.
+ * Use "cat -v" to figure out favorite key combination.
+ *
+ * lines is the number of lines scrolled up or down.
+ * If lines is negative, it's the fraction of the terminal size.
+ */
+
+struct rule rules[] = {
+ /* sequence event lines */
+ {"\033[5;2~", SCROLL_UP, -1}, /* [Shift] + [PageUP] */
+ {"\033[6;2~", SCROLL_DOWN, -1}, /* [Shift] + [PageDown] */
+ /* mouse binding shadows ^E and ^Y, so it's disabled by default */
+ //{"\031", SCROLL_UP, 1}, /* mouse wheel up */
+ //{"\005", SCROLL_DOWN, 1}, /* mouse wheel Down */
+};
diff --git a/scroll-0.1/config.mk b/scroll-0.1/config.mk
new file mode 100644
index 0000000..5676b85
--- /dev/null
+++ b/scroll-0.1/config.mk
@@ -0,0 +1,12 @@
+# scroll version
+VERSION = 0.1
+
+# paths
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+MANDIR = $(PREFIX)/share/man
+
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_DEFAULT_SOURCE
+# if your system is not POSIX, add -std=c99 to CFLAGS
+CFLAGS = -Os
+LDFLAGS = -s
diff --git a/scroll-0.1/ptty.c b/scroll-0.1/ptty.c
new file mode 100644
index 0000000..bbbb99f
--- /dev/null
+++ b/scroll-0.1/ptty.c
@@ -0,0 +1,156 @@
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#if defined(__linux)
+ #include <pty.h>
+#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+ #include <util.h>
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+ #include <libutil.h>
+#endif
+
+void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ } else {
+ fputc('\n', stderr);
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+void
+usage(void)
+{
+ fputs("ptty [-C] [-c cols] [-r rows] cmd\n", stderr);
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct winsize ws = {.ws_row = 25, .ws_col = 80, 0, 0};
+ int ch;
+ bool closeflag = false;
+
+ while ((ch = getopt(argc, argv, "c:r:Ch")) != -1) {
+ switch (ch) {
+ case 'c': /* cols */
+ ws.ws_col = strtoimax(optarg, NULL, 10);
+ if (errno != 0)
+ die("strtoimax: %s", optarg);
+ break;
+ case 'r': /* lines */
+ ws.ws_row = strtoimax(optarg, NULL, 10);
+ if (errno != 0)
+ die("strtoimax: %s", optarg);
+ break;
+ case 'C':
+ closeflag = true;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ int mfd;
+ pid_t child = forkpty(&mfd, NULL, NULL, &ws);
+ switch (child) {
+ case -1:
+ die("forkpty");
+ case 0: /* child */
+ execvp(argv[0], argv);
+ die("exec");
+ }
+
+ /* parent */
+
+ if (closeflag && close(mfd) == -1)
+ die("close:");
+
+ int pfds = 2;
+ struct pollfd pfd[2] = {
+ { STDIN_FILENO, POLLIN, 0},
+ { mfd, POLLIN, 0}
+ };
+
+ for (;;) {
+ char buf[BUFSIZ];
+ ssize_t n;
+ int r;
+
+ if ((r = poll(pfd, pfds, -1)) == -1)
+ die("poll:");
+
+ if (pfd[0].revents & POLLIN) {
+ if ((n = read(STDIN_FILENO, buf, sizeof buf)) == -1)
+ die("read:");
+ if (n == 0) {
+ pfd[0].fd = -1;
+ if (close(mfd) == -1)
+ die("close:");
+ break;
+ }
+ if (write(mfd, buf, n) == -1)
+ die("write:");
+ }
+
+ if (pfd[1].revents & POLLIN) {
+ if ((n = read(mfd, buf, sizeof(buf)-1)) == -1)
+ die("read:");
+
+ if (n == 0) break;
+
+ buf[n] = '\0';
+
+ /* handle cursor position request */
+ if (strcmp("\033[6n", buf) == 0) {
+ dprintf(mfd, "\033[25;1R");
+ continue;
+ }
+
+ if (write(STDOUT_FILENO, buf, n) == -1)
+ die("write:");
+ }
+
+ if (pfd[0].revents & POLLHUP) {
+ pfd[0].fd = -1;
+ if (close(mfd) == -1)
+ die("close:");
+ break;
+ }
+ if (pfd[1].revents & POLLHUP)
+ break;
+ }
+
+ int status;
+ if (waitpid(child, &status, 0) != child)
+ die("waitpid:");
+
+ return WEXITSTATUS(status);
+}
diff --git a/scroll-0.1/scroll.1 b/scroll-0.1/scroll.1
new file mode 100644
index 0000000..b5524ab
--- /dev/null
+++ b/scroll-0.1/scroll.1
@@ -0,0 +1,68 @@
+.\"
+.\" Copyright (c) 2020 Jan Klemkow <j.klemkow@wemelug.de>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd April 9, 2020
+.Dt SCROLL 1
+.Os
+.Sh NAME
+.Nm scroll
+.Nd scrollback buffer
+.Sh SYNOPSIS
+.Nm
+.Op Fl Mh
+.Op Fl m Ar size
+.Op program Op arg ...
+.Sh DESCRIPTION
+The
+.Nm
+utility saves output lines from the child
+.Ar program
+to use them for scrollback.
+If
+.Ar program
+is not set,
+.Nm
+starts the users default shell.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl h
+Shows usage of
+.Nm .
+.It Fl M
+Set memory limit used for scrollbackbuffer to maximum.
+.It Fl m Ar size
+Set memory limit used for scrollbackbuffer to
+.Ar size .
+.El
+.Sh EXIT STATUS
+.Nm
+exits with the status code of its the child
+.Ar program .
+.Sh EXAMPLES
+.Nm st
+.Fl e
+.Nm scroll
+.Nm /bin/sh
+.Sh SEE ALSO
+.Xr screen 1 ,
+.Xr st 1 ,
+.Xr tmux 1
+.Sh AUTHORS
+.Nm
+was written by
+.An Jan Klemkow Aq Mt j.klemkow@wemelug.de
+and
+.An Jochen Sprickerhof Aq Mt git@jochen.sprickerhof.de .
diff --git a/scroll-0.1/scroll.c b/scroll-0.1/scroll.c
new file mode 100644
index 0000000..8f66d54
--- /dev/null
+++ b/scroll-0.1/scroll.c
@@ -0,0 +1,594 @@
+/*
+ * Based on an example code from Roberto E. Vargas Caballero.
+ *
+ * See LICENSE file for copyright and license details.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#if defined(__linux)
+ #include <pty.h>
+#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+ #include <util.h>
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+ #include <libutil.h>
+#endif
+
+#define LENGTH(X) (sizeof (X) / sizeof ((X)[0]))
+
+const char *argv0;
+
+TAILQ_HEAD(tailhead, line) head;
+
+struct line {
+ TAILQ_ENTRY(line) entries;
+ size_t size;
+ size_t len;
+ char *buf;
+} *bottom;
+
+pid_t child;
+int mfd;
+struct termios dfl;
+struct winsize ws;
+static bool altscreen = false; /* is alternative screen active */
+static bool doredraw = false; /* redraw upon sigwinch */
+
+struct rule {
+ const char *seq;
+ enum {SCROLL_UP, SCROLL_DOWN} event;
+ short lines;
+};
+
+#include "config.h"
+
+void
+die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ } else {
+ fputc('\n', stderr);
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+void
+sigwinch(int sig)
+{
+ assert(sig == SIGWINCH);
+
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1)
+ die("ioctl:");
+ if (ioctl(mfd, TIOCSWINSZ, &ws) == -1) {
+ if (errno == EBADF) /* child already exited */
+ return;
+ die("ioctl:");
+ }
+ kill(-child, SIGWINCH);
+ doredraw = true;
+}
+
+void
+reset(void)
+{
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &dfl) == -1)
+ die("tcsetattr:");
+}
+
+/* error avoiding remalloc */
+void *
+earealloc(void *ptr, size_t size)
+{
+ void *mem;
+
+ while ((mem = realloc(ptr, size)) == NULL) {
+ struct line *line = TAILQ_LAST(&head, tailhead);
+
+ if (line == NULL)
+ die("realloc:");
+
+ TAILQ_REMOVE(&head, line, entries);
+ free(line->buf);
+ free(line);
+ }
+
+ return mem;
+}
+
+/* Count string length w/o ansi esc sequences. */
+size_t
+strelen(const char *buf, size_t size)
+{
+ enum {CHAR, BREK, ESC} state = CHAR;
+ size_t len = 0;
+
+ for (size_t i = 0; i < size; i++) {
+ char c = buf[i];
+
+ switch (state) {
+ case CHAR:
+ if (c == '\033')
+ state = BREK;
+ else
+ len++;
+ break;
+ case BREK:
+ if (c == '[') {
+ state = ESC;
+ } else {
+ state = CHAR;
+ len++;
+ }
+ break;
+ case ESC:
+ if (c >= 64 && c <= 126)
+ state = CHAR;
+ break;
+ }
+ }
+
+ return len;
+}
+
+/* detect alternative screen switching and clear screen */
+bool
+skipesc(char c)
+{
+ static enum {CHAR, BREK, ESC} state = CHAR;
+ static char buf[BUFSIZ];
+ static size_t i = 0;
+
+ switch (state) {
+ case CHAR:
+ if (c == '\033')
+ state = BREK;
+ break;
+ case BREK:
+ if (c == '[')
+ state = ESC;
+ else
+ state = CHAR;
+ break;
+ case ESC:
+ buf[i++] = c;
+ if (i == sizeof buf) {
+ /* TODO: find a better way to handle this situation */
+ state = CHAR;
+ i = 0;
+ } else if (c >= 64 && c <= 126) {
+ state = CHAR;
+ buf[i] = '\0';
+ i = 0;
+
+ /* esc seq. enable alternative screen */
+ if (strcmp(buf, "?1049h") == 0 ||
+ strcmp(buf, "?1047h") == 0 ||
+ strcmp(buf, "?47h" ) == 0)
+ altscreen = true;
+
+ /* esc seq. disable alternative screen */
+ if (strcmp(buf, "?1049l") == 0 ||
+ strcmp(buf, "?1047l") == 0 ||
+ strcmp(buf, "?47l" ) == 0)
+ altscreen = false;
+
+ /* don't save cursor move or clear screen */
+ /* esc sequences to log */
+ switch (c) {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'H':
+ case 'J':
+ case 'K':
+ case 'f':
+ return true;
+ }
+ }
+ break;
+ }
+
+ return altscreen;
+}
+
+void
+getcursorposition(int *x, int *y)
+{
+ char input[BUFSIZ];
+ ssize_t n;
+
+ if (write(STDOUT_FILENO, "\033[6n", 4) == -1)
+ die("requesting cursor position");
+
+ do {
+ if ((n = read(STDIN_FILENO, input, sizeof(input)-1)) == -1)
+ die("reading cursor position");
+ input[n] = '\0';
+ } while (sscanf(input, "\033[%d;%dR", y, x) != 2);
+
+ if (*x <= 0 || *y <= 0)
+ die("invalid cursor position: x=%d y=%d", *x, *y);
+}
+
+void
+addline(char *buf, size_t size)
+{
+ struct line *line = earealloc(NULL, sizeof *line);
+
+ line->size = size;
+ line->len = strelen(buf, size);
+ line->buf = earealloc(NULL, size);
+ memcpy(line->buf, buf, size);
+
+ TAILQ_INSERT_HEAD(&head, line, entries);
+}
+
+void
+redraw()
+{
+ int rows = 0, x, y;
+
+ if (bottom == NULL)
+ return;
+
+ getcursorposition(&x, &y);
+
+ if (y < ws.ws_row-1)
+ y--;
+
+ /* wind back bottom pointer by shown history */
+ for (; bottom != NULL && TAILQ_NEXT(bottom, entries) != NULL &&
+ rows < y - 1; rows++)
+ bottom = TAILQ_NEXT(bottom, entries);
+
+ /* clear screen */
+ dprintf(STDOUT_FILENO, "\033[2J");
+ /* set cursor position to upper left corner */
+ write(STDOUT_FILENO, "\033[0;0H", 6);
+
+ /* remove newline of first line as we are at 0,0 already */
+ if (bottom->size > 0 && bottom->buf[0] == '\n')
+ write(STDOUT_FILENO, bottom->buf + 1, bottom->size - 1);
+ else
+ write(STDOUT_FILENO, bottom->buf, bottom->size);
+
+ for (rows = ws.ws_row; rows > 0 &&
+ TAILQ_PREV(bottom, tailhead, entries) != NULL; rows--) {
+ bottom = TAILQ_PREV(bottom, tailhead, entries);
+ write(STDOUT_FILENO, bottom->buf, bottom->size);
+ }
+
+ if (bottom == TAILQ_FIRST(&head)) {
+ /* add new line in front of the shell prompt */
+ write(STDOUT_FILENO, "\n", 1);
+ write(STDOUT_FILENO, "\033[?25h", 6); /* show cursor */
+ } else
+ bottom = TAILQ_NEXT(bottom, entries);
+}
+
+void
+scrollup(int n)
+{
+ int rows = 2, x, y, extra = 0;
+ struct line *scrollend = bottom;
+
+ if (bottom == NULL)
+ return;
+
+ getcursorposition(&x, &y);
+
+ if (n < 0) /* scroll by fraction of ws.ws_row, but at least one line */
+ n = ws.ws_row > (-n) ? ws.ws_row / (-n) : 1;
+
+ /* wind back scrollend pointer by the current screen */
+ while (rows < y && TAILQ_NEXT(scrollend, entries) != NULL) {
+ scrollend = TAILQ_NEXT(scrollend, entries);
+ rows += (scrollend->len - 1) / ws.ws_col + 1;
+ }
+
+ if (rows <= 0)
+ return;
+
+ /* wind back scrollend pointer n lines */
+ for (rows = 0; rows + extra < n &&
+ TAILQ_NEXT(scrollend, entries) != NULL; rows++) {
+ scrollend = TAILQ_NEXT(scrollend, entries);
+ extra += (scrollend->len - 1) / ws.ws_col;
+ }
+
+ /* move the text in terminal rows lines down */
+ dprintf(STDOUT_FILENO, "\033[%dT", n);
+ /* set cursor position to upper left corner */
+ write(STDOUT_FILENO, "\033[0;0H", 6);
+ /* hide cursor */
+ write(STDOUT_FILENO, "\033[?25l", 6);
+
+ /* remove newline of first line as we are at 0,0 already */
+ if (scrollend->size > 0 && scrollend->buf[0] == '\n')
+ write(STDOUT_FILENO, scrollend->buf + 1, scrollend->size - 1);
+ else
+ write(STDOUT_FILENO, scrollend->buf, scrollend->size);
+ if (y + n >= ws.ws_row)
+ bottom = TAILQ_NEXT(bottom, entries);
+
+ /* print rows lines and move bottom forward to the new screen bottom */
+ for (; rows > 1; rows--) {
+ scrollend = TAILQ_PREV(scrollend, tailhead, entries);
+ if (y + n >= ws.ws_row)
+ bottom = TAILQ_NEXT(bottom, entries);
+ write(STDOUT_FILENO, scrollend->buf, scrollend->size);
+ }
+ /* move cursor from line n to the old bottom position */
+ if (y + n < ws.ws_row) {
+ dprintf(STDOUT_FILENO, "\033[%d;%dH", y + n, x);
+ write(STDOUT_FILENO, "\033[?25h", 6); /* show cursor */
+ } else
+ dprintf(STDOUT_FILENO, "\033[%d;0H", ws.ws_row);
+}
+
+void
+scrolldown(char *buf, size_t size, int n)
+{
+ if (bottom == NULL || bottom == TAILQ_FIRST(&head))
+ return;
+
+ if (n < 0) /* scroll by fraction of ws.ws_row, but at least one line */
+ n = ws.ws_row > (-n) ? ws.ws_row / (-n) : 1;
+
+ bottom = TAILQ_PREV(bottom, tailhead, entries);
+ /* print n lines */
+ while (n > 0 && bottom != NULL && bottom != TAILQ_FIRST(&head)) {
+ bottom = TAILQ_PREV(bottom, tailhead, entries);
+ write(STDOUT_FILENO, bottom->buf, bottom->size);
+ n -= (bottom->len - 1) / ws.ws_col + 1;
+ }
+ if (n > 0 && bottom == TAILQ_FIRST(&head)) {
+ write(STDOUT_FILENO, "\033[?25h", 6); /* show cursor */
+ write(STDOUT_FILENO, buf, size);
+ } else if (bottom != NULL)
+ bottom = TAILQ_NEXT(bottom, entries);
+}
+
+void
+jumpdown(char *buf, size_t size)
+{
+ int rows = ws.ws_row;
+
+ /* wind back by one page starting from the latest line */
+ bottom = TAILQ_FIRST(&head);
+ for (; TAILQ_NEXT(bottom, entries) != NULL && rows > 0; rows--)
+ bottom = TAILQ_NEXT(bottom, entries);
+
+ scrolldown(buf, size, ws.ws_row);
+}
+
+void
+usage(void) {
+ die("usage: %s [-Mvh] [-m mem] [program]", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ struct rlimit rlimit;
+
+ argv0 = argv[0];
+
+ if (getrlimit(RLIMIT_DATA, &rlimit) == -1)
+ die("getrlimit");
+
+ const char *optstring = "Mm:vh";
+ while ((ch = getopt(argc, argv, optstring)) != -1) {
+ switch (ch) {
+ case 'M':
+ rlimit.rlim_cur = rlimit.rlim_max;
+ break;
+ case 'm':
+ rlimit.rlim_cur = strtoull(optarg, NULL, 0);
+ if (errno != 0)
+ die("strtoull: %s", optarg);
+ break;
+ case 'v':
+ die("%s " VERSION, argv0);
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ TAILQ_INIT(&head);
+
+ if (isatty(STDIN_FILENO) == 0 || isatty(STDOUT_FILENO) == 0)
+ die("parent it not a tty");
+
+ /* save terminal settings for resetting after exit */
+ if (tcgetattr(STDIN_FILENO, &dfl) == -1)
+ die("tcgetattr:");
+ if (atexit(reset))
+ die("atexit:");
+
+ /* get window size of the terminal */
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1)
+ die("ioctl:");
+
+ child = forkpty(&mfd, NULL, &dfl, &ws);
+ if (child == -1)
+ die("forkpty:");
+ if (child == 0) { /* child */
+ if (argc >= 1) {
+ execvp(argv[0], argv);
+ } else {
+ struct passwd *passwd = getpwuid(getuid());
+ if (passwd == NULL)
+ die("getpwid:");
+ execlp(passwd->pw_shell, passwd->pw_shell, NULL);
+ }
+
+ perror("execvp");
+ _exit(127);
+ }
+
+ /* set maximum memory size for scrollback buffer */
+ if (setrlimit(RLIMIT_DATA, &rlimit) == -1)
+ die("setrlimit:");
+
+#ifdef __OpenBSD__
+ if (pledge("stdio tty proc", NULL) == -1)
+ die("pledge:");
+#endif
+
+ if (signal(SIGWINCH, sigwinch) == SIG_ERR)
+ die("signal:");
+
+ struct termios new = dfl;
+ cfmakeraw(&new);
+ new.c_cc[VMIN ] = 1; /* return read if at least one byte in buffer */
+ new.c_cc[VTIME] = 0; /* no polling time for read from terminal */
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &new) == -1)
+ die("tcsetattr:");
+
+ size_t size = BUFSIZ, len = 0, pos = 0;
+ char *buf = calloc(size, sizeof *buf);
+ if (buf == NULL)
+ die("calloc:");
+
+ struct pollfd pfd[2] = {
+ {STDIN_FILENO, POLLIN, 0},
+ {mfd, POLLIN, 0}
+ };
+
+ for (;;) {
+ char input[BUFSIZ];
+
+ if (poll(pfd, LENGTH(pfd), -1) == -1 && errno != EINTR)
+ die("poll:");
+
+ if (doredraw) {
+ redraw();
+ doredraw = false;
+ }
+
+ if (pfd[0].revents & POLLHUP || pfd[1].revents & POLLHUP)
+ break;
+
+ if (pfd[0].revents & POLLIN) {
+ ssize_t n = read(STDIN_FILENO, input, sizeof(input)-1);
+
+ if (n == -1 && errno != EINTR)
+ die("read:");
+ if (n == 0)
+ break;
+
+ input[n] = '\0';
+
+ if (altscreen)
+ goto noevent;
+
+ for (size_t i = 0; i < LENGTH(rules); i++) {
+ if (strncmp(rules[i].seq, input,
+ strlen(rules[i].seq)) == 0) {
+ if (rules[i].event == SCROLL_UP)
+ scrollup(rules[i].lines);
+ if (rules[i].event == SCROLL_DOWN)
+ scrolldown(buf, len,
+ rules[i].lines);
+ goto out;
+ }
+ }
+ noevent:
+ if (write(mfd, input, n) == -1)
+ die("write:");
+
+ if (bottom != TAILQ_FIRST(&head))
+ jumpdown(buf, len);
+ }
+ out:
+ if (pfd[1].revents & POLLIN) {
+ ssize_t n = read(mfd, input, sizeof(input)-1);
+
+ if (n == -1 && errno != EINTR)
+ die("read:");
+ if (n == 0) /* on exit of child we continue here */
+ continue; /* let signal handler catch SIGCHLD */
+
+ input[n] = '\0';
+
+ /* don't print child output while scrolling */
+ if (bottom == TAILQ_FIRST(&head))
+ if (write(STDOUT_FILENO, input, n) == -1)
+ die("write:");
+
+ /* iterate over the input buffer */
+ for (char *c = input; n-- > 0; c++) {
+ /* don't save alternative screen and */
+ /* clear screen esc sequences to scrollback */
+ if (skipesc(*c))
+ continue;
+
+ if (*c == '\n') {
+ addline(buf, len);
+ /* only advance bottom if scroll is */
+ /* at the end of the scroll back */
+ if (bottom == NULL ||
+ TAILQ_PREV(bottom, tailhead,
+ entries) == TAILQ_FIRST(&head))
+ bottom = TAILQ_FIRST(&head);
+
+ memset(buf, 0, size);
+ len = pos = 0;
+ buf[pos++] = '\r';
+ } else if (*c == '\r') {
+ pos = 0;
+ continue;
+ }
+ buf[pos++] = *c;
+ if (pos > len)
+ len = pos;
+ if (len == size) {
+ size *= 2;
+ buf = earealloc(buf, size);
+ }
+ }
+ }
+ }
+
+ if (close(mfd) == -1)
+ die("close:");
+
+ int status;
+ if (waitpid(child, &status, 0) == -1)
+ die("waitpid:");
+
+ return WEXITSTATUS(status);
+}
diff --git a/scroll-0.1/up.log b/scroll-0.1/up.log
new file mode 100644
index 0000000..5f40226
--- /dev/null
+++ b/scroll-0.1/up.log
@@ -0,0 +1,74 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+[?25l1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25 \ No newline at end of file
diff --git a/scroll-0.1/up.sh b/scroll-0.1/up.sh
new file mode 100755
index 0000000..fa28a80
--- /dev/null
+++ b/scroll-0.1/up.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -eu
+export POSIXLY_CORRECT=1
+
+i=1
+while test "$i" -lt 50; do
+ echo "$i"
+ i=$((i + 1))
+done > tmp.log
+
+(sleep 1; printf '\033[5;2~'; sleep 1; ) \
+ | ./ptty ./scroll tail -fn 50 tmp.log > out.log
+
+cmp out.log up.log
diff --git a/sfm-0.4/LICENSE b/sfm-0.4/LICENSE
deleted file mode 100644
index 342ffaa..0000000
--- a/sfm-0.4/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-ISC License
-
-© 2020-2021 Hassan Afify <hassan at afify dot dev>
-© 2020 Mohamed Afify <mohamed at afify dot dev>
-© 2021 Nikolay Korotkiy <sikmir@gmail.com>
-© 2021 David Kalliecharan <david@david.science>
-© 2021 Tdukv <tdukv@protonmail.com>
-
-Permission to use, copy, modify, and distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/sfm-0.4/Makefile b/sfm-0.4/Makefile
deleted file mode 100644
index dae243f..0000000
--- a/sfm-0.4/Makefile
+++ /dev/null
@@ -1,51 +0,0 @@
-# sfm - simple file manager
-# See LICENSE file for copyright and license details.
-
-include config.mk
-
-SRC = sfm.c util.c termbox.c utf8.c
-OBJ = ${SRC:.c=.o}
-
-all: options sfm
-
-options:
- @echo sfm build options:
- @echo "CFLAGS = ${CFLAGS}"
- @echo "LDFLAGS = ${LDFLAGS}"
- @echo "CC = ${CC}"
-
-.c.o:
- ${CC} -c ${CFLAGS} $<
-
-${OBJ}: config.h config.mk
-
-config.h:
- cp config.def.h $@
-
-sfm: ${OBJ}
- ${CC} ${LDFLAGS} -o $@ ${OBJ}
-
-clean:
- rm -f sfm ${OBJ} sfm-${VERSION}.tar.gz
-
-dist: clean
- mkdir -p sfm-${VERSION}
- cp -R LICENSE Makefile README.md config.def.h config.mk\
- sfm.1 sfm.png termbox.h util.h ${SRC} sfm-${VERSION}
- tar -cf sfm-${VERSION}.tar sfm-${VERSION}
- gzip sfm-${VERSION}.tar
- rm -rf sfm-${VERSION}
-
-install: sfm
- mkdir -p ${DESTDIR}${PREFIX}/bin
- cp -f sfm ${DESTDIR}${PREFIX}/bin
- chmod 755 ${DESTDIR}${PREFIX}/bin/sfm
- mkdir -p ${DESTDIR}${MANPREFIX}/man1
- sed "s/VERSION/${VERSION}/g" < sfm.1 > ${DESTDIR}${MANPREFIX}/man1/sfm.1
- chmod 644 ${DESTDIR}${MANPREFIX}/man1/sfm.1
-
-uninstall:
- rm -f ${DESTDIR}${PREFIX}/bin/sfm\
- ${DESTDIR}${MANPREFIX}/man1/sfm.1
-
-.PHONY: all options clean dist install uninstall
diff --git a/sfm-0.4/README.md b/sfm-0.4/README.md
deleted file mode 100644
index 81eb044..0000000
--- a/sfm-0.4/README.md
+++ /dev/null
@@ -1,78 +0,0 @@
-<img src="https://afify.dev/img/sfm.png" alt="sfm logo"/>
-
-**simple file manager**
-
-[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/afify/sfm.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/afify/sfm/context:cpp)
-[![Build status](https://ci.appveyor.com/api/projects/status/goq88ahjyvtjrui2?svg=true)](https://ci.appveyor.com/project/afify/sfm)
-[![code-inspector](https://www.code-inspector.com/project/19656/score/svg)](https://frontend.code-inspector.com/public/project/19656/sfm/dashboard)
-[![code-inspector](https://www.code-inspector.com/project/19656/status/svg)](https://frontend.code-inspector.com/public/project/19656/sfm/dashboard)
-
-Description
-------------
-sfm is a simple file manager for unix-like systems.
-* pthreads(7) to read events, no timers.
-* BSD kqueue(2) - kernel event notification mechanism.
-* Linux inotify(7) - monitoring filesystem events.
-* dual pane.
-* bookmarks.
-* open files by extension.
-* bottom statusbar.
-* vim-like key bindings.
-* filter.
-* no dependencies.
-* c99 static linking.
-* based on [termbox](https://github.com/nsf/termbox).
-* Inspired by [vifm](https://vifm.info/) and [noice](https://git.2f30.org/noice/).
-* Follows the suckless [philosophy](https://suckless.org/philosophy/).
-
-Patches
--------
-[sfm-patches](https://github.com/afify/sfm-patches)
-
-Performance
-------------
-```sh
-$ perf stat -r 10 sfm
-```
-
-Options
--------
-```sh
-$ sfm [-v]
-$ man sfm
-```
-<img src="https://afify.dev/img/sfm_sc.png" alt="sfm screenshot" width="800"/>
-
-Installation
-------------
-**current**
-```sh
-git clone git://git.afify.dev/sfm
-cd sfm/
-make
-make install
-```
-**latest release**
-```sh
-[ "$(uname)" = "Linux" ] && shacmd="sha256sum" grepf="--color=never"|| shacmd="sha256"
-latest=$(curl -s https://git.afify.dev/sfm/tags.xml | grep $grepf -m 1 -o "\[v.*\]" | tr -d '[]')
-tgz="https://git.afify.dev/sfm/releases/sfm-${latest}.tar.gz"
-sha="${tgz}.sha256"
-wget "${tgz}"
-wget "${sha}"
-${shacmd} -c "sfm-${latest}.tar.gz.sha256" && \
-tar -xzf "sfm-${latest}.tar.gz" && cd "sfm-${latest}" && \
-make
-make install
-```
-
-Run
----
-```sh
-$ sfm
-```
-
-Configuration
--------------
-The configuration of sfm is done by creating a custom config.h
-and (re)compiling the source code. This keeps it fast, secure and simple.
diff --git a/sfm-0.4/config.def.h b/sfm-0.4/config.def.h
deleted file mode 100644
index 067411e..0000000
--- a/sfm-0.4/config.def.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/* See LICENSE file for copyright and license details.*/
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-/* colors fg, bg */
-static const Cpair cdir = { 31, 0 };
-static const Cpair cfile = { 243, 0 };
-static const Cpair clnk = { 96, 0 };
-static const Cpair cblk = { 95, 0 };
-static const Cpair cchr = { 94, 0 };
-static const Cpair cifo = { 93, 0 };
-static const Cpair csock = { 92, 0 };
-static const Cpair cexec = { 91, 0 };
-static const Cpair cother = { 90, 0 };
-
-static const Cpair cframe = { 233, 233 };
-static const Cpair cpanell = { 166, 233 };
-static const Cpair cpanelr = { 5, 233 };
-static const Cpair cerr = { 124, 0 };
-static const Cpair cprompt = { 33, 0 };
-static const Cpair csearch = { 255, 0 };
-static const Cpair cstatus = { 243, 0 };
-
-/* commands */
-#if defined(__linux__)
-#define CHFLAG "chattr"
-#else
-#define CHFLAG "chflags"
-#endif
-static const char *rm_cmd[] = { "rm", "-rf" }; /* delete */
-static const char *cp_cmd[] = { "cp", "-r" }; /* copy */
-static const char *chown_cmd[] = { "chown", "-R" }; /* change file owner and group */
-static const char *chmod_cmd[] = { "chmod" }; /* change file mode bits */
-static const char *chflags_cmd[] = { CHFLAG }; /* change file flags */
-static const char *mv_cmd[] = { "mv" }; /* move */
-static const char delconf[] = "yes";
-
-static const size_t rm_cmd_len = LEN(rm_cmd);
-static const size_t cp_cmd_len = LEN(cp_cmd);
-static const size_t chown_cmd_len = LEN(chown_cmd);
-static const size_t chmod_cmd_len = LEN(chmod_cmd);
-static const size_t chflags_cmd_len = LEN(chflags_cmd);
-static const size_t mv_cmd_len = LEN(mv_cmd);
-static const size_t delconf_len = LEN(delconf);
-
-/* bookmarks */
-static const char root[] = "/";
-
-/* software */
-static const char *mpv[] = { "mpv", "--fullscreen" };
-static const char *sxiv[] = { "sxiv" };
-static const char *mupdf[] = { "mupdf", "-I" };
-static const char *libreoffice[] = { "libreoffice" };
-static const char *gimp[] = { "gimp" };
-static const char *r2[] = { "r2", "-c", "vv" };
-
-/* extensions*/
-static const char *images[] = { "bmp", "jpg", "jpeg", "png", "gif", "xpm" };
-static const char *pdf[] = { "epub", "pdf" };
-static const char *arts[] = { "xcf" };
-static const char *obj[] = { "o", "a", "so" };
-static const char *videos[] = { "avi", "flv", "wav", "webm", "wma", "wmv",
- "m2v", "m4a", "m4v", "mkv", "mov", "mp3",
- "mp4", "mpeg", "mpg" };
-static const char *documents[] = { "odt", "doc", "docx", "xls", "xlsx", "odp",
- "ods", "pptx", "odg" };
-
-static Rule rules[] = {
- {videos, LEN(videos), mpv, LEN(mpv) },
- {images, LEN(images), sxiv, LEN(sxiv) },
- {pdf, LEN(pdf), mupdf, LEN(mupdf) },
- {documents, LEN(documents), libreoffice, LEN(libreoffice) },
- {arts, LEN(arts), gimp, LEN(gimp) },
- {obj, LEN(obj), r2, LEN(r2) },
-};
-
-/* normal keys */
-static Key nkeys[] = {
- /* keyval function arg */
- { {.ch = 'j'}, mv_ver, {.i = -1} },
- { {.key = TB_KEY_ARROW_DOWN}, mv_ver, {.i = -1} },
- { {.ch = 'k'}, mv_ver, {.i = +1} },
- { {.key = TB_KEY_ARROW_UP}, mv_ver, {.i = +1} },
- { {.key = TB_KEY_CTRL_U}, mv_ver, {.i = +3} },
- { {.key = TB_KEY_CTRL_D}, mv_ver, {.i = -3} },
- { {.ch = 'l'}, mvfwd, {.i = 0} },
- { {.key = TB_KEY_ARROW_RIGHT}, mvfwd, {.i = 0} },
- { {.ch = 'h'}, mvbk, {.i = 0} },
- { {.key = TB_KEY_ARROW_LEFT}, mvbk, {.i = 0} },
- { {.ch = 'g'}, mvtop, {.i = 0} },
- { {.ch = 'G'}, mvbtm, {.i = 0} },
- { {.ch = 'n'}, crnf, {0} },
- { {.ch = 'N'}, crnd, {0} },
- { {.ch = 'd'}, delent, {0} },
- { {.ch = 'D'}, dupl, {0} },
- { {.ch = 'x'}, calcdir, {0} },
- { {.ch = '/'}, start_filter, {0} },
- { {.ch = 'q'}, quit, {0} },
- { {.ch = 'v'}, start_vmode, {0} },
- { {.ch = 'y'}, yank, {0} },
- { {.ch = 'p'}, paste, {0} },
- { {.ch = 'P'}, selmv, {0} },
- { {.ch = 'c'}, start_change, {0} },
- { {.ch = 'b'}, opnsh, {0} },
- { {.key = TB_KEY_SPACE}, switch_pane, {0} },
- { {.key = TB_KEY_CTRL_R}, refresh, {0} },
- { {.ch = '\\'}, bkmrk, {.v = root} },
- { {.ch = '.'}, toggle_df, {0} },
-};
-
-/* change keys */
-static Key ckeys[] = {
- /* keyval function arg */
- { {.ch = 'w'}, rname, {0} },
- { {.ch = 'o'}, chngo, {0} },
- { {.ch = 'm'}, chngm, {0} },
- { {.ch = 'f'}, chngf, {0} },
- { {.ch = 'q'}, exit_change, {0} },
- { {.ch = 'c'}, exit_change, {0} },
- { {.key = TB_KEY_ESC}, exit_change, {0} },
-};
-
-/* visual keys */
-static Key vkeys[] = {
- /* keyval function arg */
- { {.ch = 'j'}, seldwn, {.i = -1} },
- { {.key = TB_KEY_ARROW_DOWN}, seldwn, {.i = -1} },
- { {.ch = 'k'}, selup, {.i = +1} },
- { {.key = TB_KEY_ARROW_UP}, selup, {.i = +1} },
- { {.ch = 'a'}, selall, {0} },
- { {.ch = 'y'}, selynk, {0} },
- { {.ch = 'd'}, seldel, {.v = delconf} },
- { {.ch = 'q'}, exit_vmode, {0} },
- { {.ch = 'v'}, exit_vmode, {0} },
- { {.key = TB_KEY_ESC}, exit_vmode, {0} },
-};
-
-static const size_t nkeyslen = LEN(nkeys);
-static const size_t vkeyslen = LEN(vkeys);
-static const size_t ckeyslen = LEN(ckeys);
-
-/* permissions */
-static const mode_t ndir_perm = S_IRWXU;
-static const mode_t nf_perm = S_IRUSR | S_IWUSR;
-
-/* dotfiles */
-static int show_dotfiles = 1;
-
-/* statusbar */
-static const char dtfmt[] = "%F %R"; /* date time format */
-
-/* unicode chars */
-#define u_hl 0x2500 /* ─ */
-#define u_vl 0x2502 /* │ */
-#define u_cnw 0x250C /* ┌ */
-#define u_cne 0x2510 /* ┐ */
-#define u_csw 0x2514 /* └ */
-#define u_cse 0x2518 /* ┘ */
-#define u_mn 0x252C /* ┬ */
-#define u_ms 0x2534 /* ┴ */
-
-#endif /* CONFIG_H */
diff --git a/sfm-0.4/config.h b/sfm-0.4/config.h
deleted file mode 100644
index 939b0c9..0000000
--- a/sfm-0.4/config.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/* See LICENSE file for copyright and license details.*/
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-/* colors fg, bg */
-static const Cpair cdir = { 31, 0 };
-static const Cpair cfile = { 243, 0 };
-static const Cpair clnk = { 96, 0 };
-static const Cpair cblk = { 95, 0 };
-static const Cpair cchr = { 94, 0 };
-static const Cpair cifo = { 93, 0 };
-static const Cpair csock = { 92, 0 };
-static const Cpair cexec = { 91, 0 };
-static const Cpair cother = { 90, 0 };
-
-static const Cpair cframe = { 233, 233 };
-static const Cpair cpanell = { 166, 233 };
-static const Cpair cpanelr = { 5, 233 };
-static const Cpair cerr = { 124, 0 };
-static const Cpair cprompt = { 33, 0 };
-static const Cpair csearch = { 255, 0 };
-static const Cpair cstatus = { 243, 0 };
-
-/* commands */
-#if defined(__linux__)
-#define CHFLAG "chattr"
-#else
-#define CHFLAG "chflags"
-#endif
-static const char *rm_cmd[] = { "rm", "-rf" }; /* delete */
-static const char *cp_cmd[] = { "cp", "-r" }; /* copy */
-static const char *chown_cmd[] = { "chown", "-R" }; /* change file owner and group */
-static const char *chmod_cmd[] = { "chmod" }; /* change file mode bits */
-static const char *chflags_cmd[] = { CHFLAG }; /* change file flags */
-static const char *mv_cmd[] = { "mv" }; /* move */
-static const char delconf[] = "yes";
-
-static const size_t rm_cmd_len = LEN(rm_cmd);
-static const size_t cp_cmd_len = LEN(cp_cmd);
-static const size_t chown_cmd_len = LEN(chown_cmd);
-static const size_t chmod_cmd_len = LEN(chmod_cmd);
-static const size_t chflags_cmd_len = LEN(chflags_cmd);
-static const size_t mv_cmd_len = LEN(mv_cmd);
-static const size_t delconf_len = LEN(delconf);
-
-/* bookmarks */
-static const char root[] = "/";
-
-/* software */
-static const char *mpv[] = { "mpv", "--fullscreen" };
-static const char *sxiv[] = { "nsxiv" };
-static const char *mupdf[] = { "mupdf", "-I" };
-static const char *libreoffice[] = { "libreoffice" };
-static const char *gimp[] = { "gimp" };
-static const char *r2[] = { "r2", "-c", "vv" };
-
-/* extensions*/
-static const char *images[] = { "bmp", "jpg", "jpeg", "png", "gif", "xpm" };
-static const char *pdf[] = { "epub", "pdf" };
-static const char *arts[] = { "xcf" };
-static const char *obj[] = { "o", "a", "so" };
-static const char *videos[] = { "avi", "flv", "wav", "webm", "wma", "wmv",
- "m2v", "m4a", "m4v", "mkv", "mov", "mp3",
- "mp4", "mpeg", "mpg" };
-static const char *documents[] = { "odt", "doc", "docx", "xls", "xlsx", "odp",
- "ods", "pptx", "odg" };
-
-static Rule rules[] = {
- {videos, LEN(videos), mpv, LEN(mpv) },
- {images, LEN(images), sxiv, LEN(sxiv) },
- {pdf, LEN(pdf), mupdf, LEN(mupdf) },
- {documents, LEN(documents), libreoffice, LEN(libreoffice) },
- {arts, LEN(arts), gimp, LEN(gimp) },
- {obj, LEN(obj), r2, LEN(r2) },
-};
-
-/* normal keys */
-static Key nkeys[] = {
- /* keyval function arg */
- { {.ch = 'j'}, mv_ver, {.i = -1} },
- { {.key = TB_KEY_ARROW_DOWN}, mv_ver, {.i = -1} },
- { {.ch = 'k'}, mv_ver, {.i = +1} },
- { {.key = TB_KEY_ARROW_UP}, mv_ver, {.i = +1} },
- { {.key = TB_KEY_CTRL_U}, mv_ver, {.i = +3} },
- { {.key = TB_KEY_CTRL_D}, mv_ver, {.i = -3} },
- { {.ch = 'l'}, mvfwd, {.i = 0} },
- { {.key = TB_KEY_ARROW_RIGHT}, mvfwd, {.i = 0} },
- { {.ch = 'h'}, mvbk, {.i = 0} },
- { {.key = TB_KEY_ARROW_LEFT}, mvbk, {.i = 0} },
- { {.ch = 'g'}, mvtop, {.i = 0} },
- { {.ch = 'G'}, mvbtm, {.i = 0} },
- { {.ch = 'n'}, crnf, {0} },
- { {.ch = 'N'}, crnd, {0} },
- { {.ch = 'd'}, delent, {0} },
- { {.ch = 'D'}, dupl, {0} },
- { {.ch = 'x'}, calcdir, {0} },
- { {.ch = '/'}, start_filter, {0} },
- { {.ch = 'q'}, quit, {0} },
- { {.ch = 'v'}, start_vmode, {0} },
- { {.ch = 'y'}, yank, {0} },
- { {.ch = 'p'}, paste, {0} },
- { {.ch = 'P'}, selmv, {0} },
- { {.ch = 'c'}, start_change, {0} },
- { {.ch = 'b'}, opnsh, {0} },
- { {.key = TB_KEY_SPACE}, switch_pane, {0} },
- { {.key = TB_KEY_CTRL_R}, refresh, {0} },
- { {.ch = '\\'}, bkmrk, {.v = root} },
- { {.ch = '.'}, toggle_df, {0} },
-};
-
-/* change keys */
-static Key ckeys[] = {
- /* keyval function arg */
- { {.ch = 'w'}, rname, {0} },
- { {.ch = 'o'}, chngo, {0} },
- { {.ch = 'm'}, chngm, {0} },
- { {.ch = 'f'}, chngf, {0} },
- { {.ch = 'q'}, exit_change, {0} },
- { {.ch = 'c'}, exit_change, {0} },
- { {.key = TB_KEY_ESC}, exit_change, {0} },
-};
-
-/* visual keys */
-static Key vkeys[] = {
- /* keyval function arg */
- { {.ch = 'j'}, seldwn, {.i = -1} },
- { {.key = TB_KEY_ARROW_DOWN}, seldwn, {.i = -1} },
- { {.ch = 'k'}, selup, {.i = +1} },
- { {.key = TB_KEY_ARROW_UP}, selup, {.i = +1} },
- { {.ch = 'a'}, selall, {0} },
- { {.ch = 'y'}, selynk, {0} },
- { {.ch = 'd'}, seldel, {.v = delconf} },
- { {.ch = 'q'}, exit_vmode, {0} },
- { {.ch = 'v'}, exit_vmode, {0} },
- { {.key = TB_KEY_ESC}, exit_vmode, {0} },
-};
-
-static const size_t nkeyslen = LEN(nkeys);
-static const size_t vkeyslen = LEN(vkeys);
-static const size_t ckeyslen = LEN(ckeys);
-
-/* permissions */
-static const mode_t ndir_perm = S_IRWXU;
-static const mode_t nf_perm = S_IRUSR | S_IWUSR;
-
-/* dotfiles */
-static int show_dotfiles = 1;
-
-/* statusbar */
-static const char dtfmt[] = "%F %R"; /* date time format */
-
-/* unicode chars */
-#define u_hl 0x2500 /* ─ */
-#define u_vl 0x2502 /* │ */
-#define u_cnw 0x250C /* ┌ */
-#define u_cne 0x2510 /* ┐ */
-#define u_csw 0x2514 /* └ */
-#define u_cse 0x2518 /* ┘ */
-#define u_mn 0x252C /* ┬ */
-#define u_ms 0x2534 /* ┴ */
-
-#endif /* CONFIG_H */
diff --git a/sfm-0.4/config.mk b/sfm-0.4/config.mk
deleted file mode 100644
index 5732f77..0000000
--- a/sfm-0.4/config.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-# sfm version
-VERSION = 0.4
-
-# paths
-PREFIX = /usr/local
-MANPREFIX = ${PREFIX}/share/man
-
-# flags
-CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\"
-CFLAGS = -std=c99 -pedantic -Wextra -Wall -Wno-unused-parameter -Os ${CPPFLAGS}
-LDFLAGS = -pthread -s
-
-# compiler and linker
-CC = cc
diff --git a/sfm-0.4/sfm.1 b/sfm-0.4/sfm.1
deleted file mode 100644
index 788acdf..0000000
--- a/sfm-0.4/sfm.1
+++ /dev/null
@@ -1,147 +0,0 @@
-.TH sfm 1 sfm\-VERSION
-.SH NAME
-sfm \- simple file manager
-.SH SYNOPSIS
-.B sfm
-.RB [ \-v ]
-.SH DESCRIPTION
-sfm is a simple file manager for unix-like systems based on termbox.
-dual panes, bottom statusbar, bookmarks, open files by extention, vim-like key bindings as default configuration. cwd is left pane dir.
-.P
-.SH OPTIONS
-.TP
-.B \-v
-print version.
-.SH USAGE
-.SS Normal Mode
-.TP
-.B q
-quit
-.TP
-.B h
-back
-.TP
-.B j
-down
-.TP
-.B k
-up
-.TP
-.B l
-open dir | file
-.TP
-.B g
-top
-.TP
-.B G
-bottom
-.TP
-.B ctrl+u
-scroll up
-.TP
-.B ctrl+d
-scroll down
-.TP
-.B n
-create new file if not exists
-.TP
-.B N
-create new directory if not exists
-.TP
-.B d
-delete file | directory recursively
-.TP
-.B D
-duplicate file | directory recursively
-.TP
-.B y
-yank
-.TP
-.B p
-paste
-.TP
-.B P
-move
-.TP
-.B b
-spawn a shell in the current directory
-.TP
-.B c
-start change
-.TP
-.B cw
-rename
-.TP
-.B co
-change owner and group (chown)
-.TP
-.B cm
-change mode (chmod)
-.TP
-.B cf
-change flags (chflags | chattr)
-.TP
-.B cc
-exit change
-.TP
-.B cq
-exit change
-.TP
-.B .
-toggle dotfiles
-.TP
-.B v
-start visual mode
-.TP
-.B /
-start filter
-.TP
-.B ENTER
-find filter
-.TP
-.B ESC
-exit filter
-.TP
-.B SPACE
-switch pane
-.TP
-.B ctrl+r
-refresh panes
-.SS Visual Mode
-.TP
-.B j
-select down
-.TP
-.B k
-select up
-.TP
-.B d
-delete selection
-.TP
-.B v
-exit visual mode
-.TP
-.B q
-exit visual mode
-.TP
-.B ESC
-exit visual mode | change
-.SH CUSTOMIZATION
-sfm is customized by creating a custom
-.IR config.h
-and (re)compiling the source
-code. This keeps it fast, secure and simple.
-.SH ENVIRONMENT
-.TP
-.B EDITOR
-open unconfigured file extention. vi(1) if not set.
-.TP
-.B HOME
-right pane default directory. / if not set.
-.TP
-.B SHELL
-shell spawned with the 'b' key. /bin/sh if not set.
-.SH AUTHORS
-See the LICENSE file for the authors.
-.SH LICENSE
-See the LICENSE file for the terms of redistribution.
diff --git a/sfm-0.4/sfm.c b/sfm-0.4/sfm.c
deleted file mode 100644
index 3a69586..0000000
--- a/sfm-0.4/sfm.c
+++ /dev/null
@@ -1,2033 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-
-#if defined(__linux__)
-#define _GNU_SOURCE
-#elif defined(__APPLE__)
-#define _DARWIN_C_SOURCE
-#elif defined(__FreeBSD__)
-#define __BSD_VISIBLE 1
-#endif
-#include <sys/types.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#if defined(__linux__)
-#include <sys/inotify.h>
-#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
- defined(__APPLE__)
-#include <sys/event.h>
-#endif
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <libgen.h>
-#include <pthread.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "termbox.h"
-#include "util.h"
-
-/* macros */
-#define MAX_P 4096
-#define MAX_N 255
-#define MAX_USRI 32
-#define MAX_EXT 4
-#define MAX_STATUS 255
-#define MAX_LINE 4096
-#define MAX_USRN 32
-#define MAX_GRPN 32
-#define MAX_DTF 32
-#define CURSOR(x) (x)->direntr[(x)->hdir - 1]
-
-/* typedef */
-typedef struct {
- char name[MAX_N];
- gid_t group;
- mode_t mode;
- off_t size;
- time_t dt;
- uid_t user;
-} Entry;
-
-typedef struct {
- uint16_t fg;
- uint16_t bg;
-} Cpair;
-
-typedef struct {
- int pane_id;
- char dirn[MAX_P]; // dir name cwd
- char *filter;
- Entry *direntr; // dir entries
- int dirc; // dir entries sum
- int hdir; // highlighted dir
- int x_srt;
- int x_end;
- int firstrow;
- int parent_firstrow;
- int parent_row; // FIX
- Cpair dircol;
- int inotify_wd;
- int event_fd;
-} Pane;
-
-typedef struct {
- const char **ext;
- size_t exlen;
- const void *v;
- size_t vlen;
-} Rule;
-
-typedef union {
- uint16_t key; /* one of the TB_KEY_* constants */
- uint32_t ch; /* unicode character */
-} Evkey;
-
-typedef union {
- int i;
- const void *v;
-} Arg;
-
-typedef struct {
- const Evkey evkey;
- void (*func)(const Arg *);
- const Arg arg;
-} Key;
-
-/* function declarations */
-static void print_tb(const char *, int, int, uint16_t, uint16_t);
-static void printf_tb(int, int, Cpair, const char *, ...);
-static void print_status(Cpair, const char *, ...);
-static void print_xstatus(char, int);
-static void print_error(char *);
-static void print_prompt(char *);
-static void print_info(Pane *, char *);
-static void print_row(Pane *, size_t, Cpair);
-static void clear(int, int, int, uint16_t);
-static void clear_status(void);
-static void clear_pane(Pane *);
-static void add_hi(Pane *, size_t);
-static void rm_hi(Pane *, size_t);
-static int check_dir(char *);
-static int sort_name(const void *const, const void *const);
-static void get_dirp(char *);
-static char *get_ext(char *);
-static int get_fdt(char *, time_t);
-static char *get_fgrp(gid_t);
-static char *get_fperm(mode_t);
-static char *get_fsize(off_t);
-static char *get_fullpath(char *, char *);
-static char *get_fusr(uid_t);
-static void get_dirsize(char *, off_t *);
-static void get_hicol(Cpair *, mode_t);
-static void delent(const Arg *arg);
-static void calcdir(const Arg *arg);
-static void crnd(const Arg *arg);
-static void crnf(const Arg *arg);
-static void mv_ver(const Arg *arg);
-static void mvbk(const Arg *arg);
-static void mvbtm(const Arg *arg);
-static void mvfwd(const Arg *arg);
-static void mvtop(const Arg *arg);
-static void bkmrk(const Arg *arg);
-static int get_usrinput(char *, size_t, const char *, ...);
-static int frules(char *);
-static int spawn(const void *, size_t, const void *, size_t, char *, int);
-static int opnf(char *);
-static int fsev_init(void);
-static int addwatch(Pane *);
-static int read_events(void);
-static void rmwatch(Pane *);
-static void fsev_shdn(void);
-static void toggle_df(const Arg *arg);
-static void start_filter(const Arg *arg);
-static void start_vmode(const Arg *arg);
-static void exit_vmode(const Arg *arg);
-static void start_change(const Arg *arg);
-static void exit_change(const Arg *arg);
-static void selup(const Arg *arg);
-static void seldwn(const Arg *arg);
-static void selall(const Arg *arg);
-static void selref(void);
-static void selynk(const Arg *arg);
-static void selcalc(void);
-static void paste(const Arg *arg);
-static void selmv(const Arg *arg);
-static void seldel(const Arg *arg);
-static void init_files(void);
-static void free_files(void);
-static void yank(const Arg *arg);
-static void rname(const Arg *arg);
-static void chngo(const Arg *arg);
-static void chngm(const Arg *arg);
-static void chngf(const Arg *arg);
-static void dupl(const Arg *arg);
-static void switch_pane(const Arg *arg);
-static void quit(const Arg *arg);
-static void grabkeys(struct tb_event *, Key *, size_t);
-static void *read_th(void *arg);
-static void start_ev(void);
-static void refresh_pane(Pane *);
-static void set_direntr(Pane *, struct dirent *, DIR *, char *);
-static int listdir(Pane *);
-static void t_resize(void);
-static void get_shell(void);
-static void opnsh(const Arg *arg);
-static void set_panes(void);
-static void draw_frame(void);
-static void refresh(const Arg *arg);
-static void start(void);
-
-/* global variables */
-static pthread_t fsev_thread;
-static Pane panes[2];
-static Pane *cpane;
-static int pane_idx;
-static char *editor[2];
-static char fed[] = "vi";
-static char *shell[2];
-static char sh[] = "/bin/sh";
-static int theight, twidth, hwidth, scrheight;
-static int *sel_indexes;
-static size_t sel_len = 0;
-static char **sel_files;
-static int cont_vmode = 0;
-static int cont_change = 0;
-static pid_t fork_pid = 0, main_pid;
-#if defined(_SYS_INOTIFY_H)
-#define READEVSZ 16
-static int inotify_fd;
-#elif defined(_SYS_EVENT_H_)
-#define READEVSZ 0
-static int kq;
-struct kevent evlist[2]; /* events we want to monitor */
-struct kevent chlist[2]; /* events that were triggered */
-static struct timespec gtimeout;
-#endif
-#if defined(__linux__) || defined(__FreeBSD__)
-#define OFF_T "%ld"
-#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
-#define OFF_T "%lld"
-#endif
-enum { Left, Right }; /* panes */
-enum { Wait, DontWait }; /* spawn forks */
-
-/* configuration, allows nested code to access above variables */
-#include "config.h"
-
-/* function implementations */
-static void
-print_tb(const char *str, int x, int y, uint16_t fg, uint16_t bg)
-{
- while (*str != '\0') {
- uint32_t uni = 0;
- str += tb_utf8_char_to_unicode(&uni, str);
- tb_change_cell(x, y, uni, fg, bg);
- x++;
- }
-}
-
-static void
-printf_tb(int x, int y, Cpair col, const char *fmt, ...)
-{
- char buf[MAX_LINE];
- va_list vl;
- va_start(vl, fmt);
- (void)vsnprintf(buf, MAX_LINE, fmt, vl);
- va_end(vl);
- print_tb(buf, x, y, col.fg, col.bg);
-}
-
-static void
-print_status(Cpair col, const char *fmt, ...)
-{
- char buf[MAX_STATUS];
- va_list vl;
- va_start(vl, fmt);
- (void)vsnprintf(buf, MAX_STATUS, fmt, vl);
- va_end(vl);
- clear_status();
- print_tb(buf, 1, theight - 1, col.fg, col.bg);
-}
-
-static void
-print_xstatus(char c, int x)
-{
- uint32_t uni = 0;
- (void)tb_utf8_char_to_unicode(&uni, &c);
- tb_change_cell(x, theight - 1, uni, cstatus.fg, cstatus.bg);
-}
-
-static void
-print_error(char *errmsg)
-{
- print_status(cerr, errmsg);
-}
-
-static void
-print_prompt(char *prompt)
-{
- print_status(cprompt, prompt);
-}
-
-static void
-print_info(Pane *pane, char *dirsize)
-{
- char *sz, *ur, *gr, *dt, *prm;
-
- dt = ecalloc(MAX_DTF, sizeof(char));
-
- prm = get_fperm(CURSOR(pane).mode);
- ur = get_fusr(CURSOR(pane).user);
- gr = get_fgrp(CURSOR(pane).group);
-
- if (get_fdt(dt, CURSOR(pane).dt) < 0)
- *dt = '\0';
-
- if (S_ISREG(CURSOR(pane).mode)) {
- sz = get_fsize(CURSOR(pane).size);
- } else {
- if (dirsize == NULL) {
- sz = ecalloc(1, sizeof(char));
- *sz = '\0';
- } else {
- sz = dirsize;
- }
- }
-
- print_status(cstatus, "%02d/%02d %s %s:%s %s %s", pane->hdir,
- pane->dirc, prm, ur, gr, dt, sz);
-
- free(prm);
- free(ur);
- free(gr);
- free(dt);
- free(sz);
-}
-
-static void
-print_row(Pane *pane, size_t entpos, Cpair col)
-{
- int x, y;
- char *full_str, *rez_pth;
- char lnk_full[MAX_N];
-
- full_str = basename(pane->direntr[entpos].name);
- x = pane->x_srt;
- y = entpos - pane->firstrow + 1;
-
- if (S_ISLNK(pane->direntr[entpos].mode) != 0) {
- rez_pth = ecalloc(MAX_P, sizeof(char));
- if (realpath(pane->direntr[entpos].name, rez_pth) != NULL) {
- snprintf(
- lnk_full, MAX_N, "%s -> %s", full_str, rez_pth);
- full_str = lnk_full;
- }
- free(rez_pth);
- }
-
- printf_tb(x, y, col, "%*.*s", ~hwidth, hwidth, full_str);
-}
-
-static void
-clear(int sx, int ex, int y, uint16_t bg)
-{
- /* clear line from to */
- /* x = line number vertical */
- /* y = column number horizontal */
- int i;
- for (i = sx; i < ex; i++) {
- tb_change_cell(i, y, 0x0000, TB_DEFAULT, bg);
- }
-}
-
-static void
-clear_status(void)
-{
- clear(1, twidth - 1, theight - 1, cstatus.bg);
-}
-
-static void
-clear_pane(Pane *pane)
-{
- int i, y;
- y = 0, i = 0;
-
- while (i < scrheight) {
- clear(pane->x_srt, pane->x_end, y, TB_DEFAULT);
- i++;
- y++;
- }
-
- /* draw top line */
- for (y = pane->x_srt; y < pane->x_end; ++y) {
- tb_change_cell(y, 0, u_hl, cframe.fg, cframe.bg);
- }
-}
-
-static void
-add_hi(Pane *pane, size_t entpos)
-{
- Cpair col;
- get_hicol(&col, pane->direntr[entpos].mode);
- col.fg |= TB_REVERSE | TB_BOLD;
- col.bg |= TB_REVERSE;
- print_row(pane, entpos, col);
-}
-
-static void
-rm_hi(Pane *pane, size_t entpos)
-{
- Cpair col;
- get_hicol(&col, pane->direntr[entpos].mode);
- print_row(pane, entpos, col);
-}
-
-static int
-check_dir(char *path)
-{
- DIR *dir;
- dir = opendir(path);
-
- if (dir == NULL) {
- if (errno == ENOTDIR) {
- return 1;
- } else {
- return -1;
- }
- }
-
- if (closedir(dir) < 0)
- return -1;
-
- return 0;
-}
-
-static int
-sort_name(const void *const A, const void *const B)
-{
- int result;
- mode_t data1 = (*(Entry *)A).mode;
- mode_t data2 = (*(Entry *)B).mode;
-
- if (data1 < data2) {
- return -1;
- } else if (data1 == data2) {
- result = strncmp((*(Entry *)A).name, (*(Entry *)B).name, MAX_N);
- return result;
- } else {
- return 1;
- }
-}
-
-static void
-get_dirp(char *cdir)
-{
- int counter, len, i;
-
- counter = 0;
- len = strnlen(cdir, MAX_P);
- if (len == 1)
- return;
-
- for (i = len - 1; i > 1; i--) {
- if (cdir[i] == '/')
- break;
- else
- counter++;
- }
-
- cdir[len - counter - 1] = '\0';
-}
-
-static char *
-get_ext(char *str)
-{
- char *ext;
- char dot;
- size_t counter, len, i;
-
- dot = '.';
- counter = 0;
- len = strnlen(str, MAX_N);
-
- for (i = len - 1; i > 0; i--) {
- if (str[i] == dot) {
- break;
- } else {
- counter++;
- }
- }
-
- ext = ecalloc(MAX_EXT + 1, sizeof(char));
- strncpy(ext, &str[len - counter], MAX_EXT);
- ext[MAX_EXT] = '\0';
- return ext;
-}
-
-static int
-get_fdt(char *result, time_t status)
-{
- struct tm lt;
- localtime_r(&status, &lt);
- return strftime(result, MAX_DTF, dtfmt, &lt);
-}
-
-static char *
-get_fgrp(gid_t status)
-{
- char *result;
- struct group *gr;
-
- result = ecalloc(MAX_GRPN, sizeof(char));
- gr = getgrgid(status);
- if (gr == NULL)
- (void)snprintf(result, MAX_GRPN, "%u", status);
- else
- strncpy(result, gr->gr_name, MAX_GRPN);
-
- result[MAX_GRPN - 1] = '\0';
- return result;
-}
-
-static char *
-get_fperm(mode_t mode)
-{
- char *buf;
- size_t i;
-
- const char chars[] = "rwxrwxrwx";
- buf = ecalloc(11, sizeof(char));
-
- if (S_ISDIR(mode))
- buf[0] = 'd';
- else if (S_ISREG(mode))
- buf[0] = '-';
- else if (S_ISLNK(mode))
- buf[0] = 'l';
- else if (S_ISBLK(mode))
- buf[0] = 'b';
- else if (S_ISCHR(mode))
- buf[0] = 'c';
- else if (S_ISFIFO(mode))
- buf[0] = 'p';
- else if (S_ISSOCK(mode))
- buf[0] = 's';
- else
- buf[0] = '?';
-
- for (i = 1; i < 10; i++) {
- buf[i] = (mode & (1 << (9 - i))) ? chars[i - 1] : '-';
- }
- buf[10] = '\0';
-
- return buf;
-}
-
-static char *
-get_fsize(off_t size)
-{
- char *result; /* need to be freed */
- char unit;
- int result_len;
- int counter;
-
- counter = 0;
- result_len = 6; /* 9999X/0 */
- result = ecalloc(result_len, sizeof(char));
-
- while (size >= 1000) {
- size /= 1024;
- ++counter;
- }
-
- switch (counter) {
- case 0:
- unit = 'B';
- break;
- case 1:
- unit = 'K';
- break;
- case 2:
- unit = 'M';
- break;
- case 3:
- unit = 'G';
- break;
- case 4:
- unit = 'T';
- break;
- default:
- unit = '?';
- }
-
- if (snprintf(result, result_len, OFF_T "%c", size, unit) < 0)
- strncat(result, "???", result_len);
-
- return result;
-}
-
-static char *
-get_fullpath(char *first, char *second)
-{
- char *full_path;
-
- full_path = ecalloc(MAX_P, sizeof(char));
-
- if (strncmp(first, "/", MAX_P) == 0)
- (void)snprintf(full_path, MAX_P, "/%s", second);
- else
- (void)snprintf(full_path, MAX_P, "%s/%s", first, second);
-
- return full_path;
-}
-
-static char *
-get_fusr(uid_t status)
-{
- char *result;
- struct passwd *pw;
-
- result = ecalloc(MAX_USRN, sizeof(char));
- pw = getpwuid(status);
- if (pw == NULL)
- (void)snprintf(result, MAX_USRN, "%u", status);
- else
- strncpy(result, pw->pw_name, MAX_USRN);
-
- result[MAX_USRN - 1] = '\0';
- return result;
-}
-
-static void
-get_dirsize(char *fullpath, off_t *fullsize)
-{
- DIR *dir;
- char *ent_full;
- mode_t mode;
- struct dirent *entry;
- struct stat status;
-
- dir = opendir(fullpath);
- if (dir == NULL) {
- return;
- }
-
- while ((entry = readdir(dir)) != 0) {
- if ((strncmp(entry->d_name, ".", 2) == 0 ||
- strncmp(entry->d_name, "..", 3) == 0))
- continue;
-
- ent_full = get_fullpath(fullpath, entry->d_name);
- if (lstat(ent_full, &status) == 0) {
- mode = status.st_mode;
- if (S_ISDIR(mode)) {
- get_dirsize(ent_full, fullsize);
- free(ent_full);
- } else {
- *fullsize += status.st_size;
- free(ent_full);
- }
- }
- }
-
- closedir(dir);
- clear_status();
-}
-
-static void
-get_hicol(Cpair *col, mode_t mode)
-{
- switch (mode & S_IFMT) {
- case S_IFREG:
- *col = cfile;
- if ((S_IXUSR | S_IXGRP | S_IXOTH) & mode)
- *col = cexec;
- break;
- case S_IFDIR:
- *col = cdir;
- break;
- case S_IFLNK:
- *col = clnk;
- break;
- case S_IFBLK:
- *col = cblk;
- break;
- case S_IFCHR:
- *col = cchr;
- break;
- case S_IFIFO:
- *col = cifo;
- break;
- case S_IFSOCK:
- *col = csock;
- break;
- default:
- *col = cother;
- break;
- }
-}
-
-static void
-delent(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- char *inp_conf;
-
- inp_conf = ecalloc(delconf_len, sizeof(char));
- if ((get_usrinput(inp_conf, delconf_len, "delete files(s) (%s) ?",
- delconf) < 0) ||
- (strncmp(inp_conf, delconf, delconf_len) != 0)) {
- free(inp_conf);
- return; /* canceled by user or wrong inp_conf */
- }
- free(inp_conf);
-
- char *tmp[1];
- tmp[0] = CURSOR(cpane).name;
- if (spawn(rm_cmd, rm_cmd_len, tmp, 1, NULL, DontWait) < 0) {
- print_error(strerror(errno));
- return;
- }
-}
-
-static void
-calcdir(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- if (!S_ISDIR(CURSOR(cpane).mode))
- return;
-
- off_t *fullsize;
- char *csize;
-
- fullsize = ecalloc(1, sizeof(off_t));
- get_dirsize(CURSOR(cpane).name, fullsize);
- csize = get_fsize(*fullsize);
-
- CURSOR(cpane).size = *fullsize;
- print_info(cpane, csize);
- free(fullsize);
-}
-
-static void
-crnd(const Arg *arg)
-{
- char *user_input, *path;
-
- user_input = ecalloc(MAX_USRI, sizeof(char));
- if (get_usrinput(user_input, MAX_USRI, "new dir") < 0) {
- free(user_input);
- return;
- }
-
- path = ecalloc(MAX_P, sizeof(char));
- if (snprintf(path, MAX_P, "%s/%s", cpane->dirn, user_input) < 0) {
- free(user_input);
- free(path);
- return;
- }
-
- PERROR(mkdir(path, ndir_perm) < 0);
-
- free(user_input);
- free(path);
-}
-
-static void
-crnf(const Arg *arg)
-{
- char *user_input, *path;
- int rf;
-
- user_input = ecalloc(MAX_USRI, sizeof(char));
- if (get_usrinput(user_input, MAX_USRI, "new file") < 0) {
- free(user_input);
- return;
- }
-
- path = ecalloc(MAX_P, sizeof(char));
- if (snprintf(path, MAX_P, "%s/%s", cpane->dirn, user_input) < 0) {
- free(user_input);
- free(path);
- return;
- }
-
- rf = open(path, O_CREAT | O_EXCL, nf_perm);
-
- if (rf < 0)
- print_error(strerror(errno));
- else if (close(rf) < 0)
- print_error(strerror(errno));
-
- free(user_input);
- free(path);
-}
-static void
-mv_ver(const Arg *arg)
-{
-
- if (cpane->dirc < 1)
- return;
- if (cpane->hdir - arg->i < 1) /* first line */
- return;
-
- if (cpane->hdir - arg->i > cpane->dirc) /* last line */
- return;
-
- if (cpane->firstrow > 0 && arg->i > 0 &&
- cpane->hdir <= (cpane->firstrow + arg->i)) { /* scroll up */
- cpane->firstrow = cpane->firstrow - arg->i;
- rm_hi(cpane, cpane->hdir - 1);
- cpane->hdir = cpane->hdir - arg->i;
- refresh_pane(cpane);
- add_hi(cpane, cpane->hdir - 1);
- return;
- }
-
- if (cpane->hdir - cpane->firstrow >= scrheight + arg->i &&
- arg->i < 0) { /* scroll down */
- cpane->firstrow = cpane->firstrow - arg->i;
- rm_hi(cpane, cpane->hdir - 1);
- cpane->hdir = cpane->hdir - arg->i;
- refresh_pane(cpane);
- add_hi(cpane, cpane->hdir - 1);
- return;
- }
-
- rm_hi(cpane, cpane->hdir - 1);
- cpane->hdir = cpane->hdir - arg->i;
- add_hi(cpane, cpane->hdir - 1);
- print_info(cpane, NULL);
-}
-
-static void
-mvbk(const Arg *arg)
-{
- if (cpane->dirn[0] == '/' && cpane->dirn[1] == '\0') { /* cwd = / */
- return;
- }
-
- get_dirp(cpane->dirn);
- if (check_dir(cpane->dirn) < 0) {
- print_error(strerror(errno));
- return;
- }
-
- cpane->firstrow = cpane->parent_firstrow;
- cpane->hdir = cpane->parent_row;
- PERROR(listdir(cpane) < 0);
- cpane->parent_firstrow = 0;
- cpane->parent_row = 1;
-}
-
-static void
-mvbtm(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- if (cpane->dirc > scrheight) {
- rm_hi(cpane, cpane->hdir - 1);
- cpane->hdir = cpane->dirc;
- cpane->firstrow = cpane->dirc - scrheight + 1;
- refresh_pane(cpane);
- add_hi(cpane, cpane->hdir - 1);
- } else {
- rm_hi(cpane, cpane->hdir - 1);
- cpane->hdir = cpane->dirc;
- add_hi(cpane, cpane->hdir - 1);
- }
- print_info(cpane, NULL);
-}
-
-static void
-mvfwd(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- int s;
-
- switch (check_dir(CURSOR(cpane).name)) {
- case 0:
- strncpy(cpane->dirn, CURSOR(cpane).name, MAX_P);
- cpane->parent_row = cpane->hdir;
- cpane->parent_firstrow = cpane->firstrow;
- cpane->hdir = 1;
- cpane->firstrow = 0;
- PERROR(listdir(cpane) < 0);
- break;
- case 1: /* not a directory open file */
- tb_shutdown();
- s = opnf(CURSOR(cpane).name);
- if (tb_init() != 0)
- die("tb_init");
- t_resize();
- if (s < 0)
- print_error("process failed non-zero exit");
- break;
- case -1: /* failed to open directory */
- print_error(strerror(errno));
- }
-}
-
-static void
-mvtop(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- if (cpane->dirc > scrheight) {
- rm_hi(cpane, cpane->hdir - 1);
- cpane->hdir = 1;
- cpane->firstrow = 0;
- refresh_pane(cpane);
- add_hi(cpane, cpane->hdir - 1);
- } else {
- rm_hi(cpane, cpane->hdir - 1);
- cpane->hdir = 1;
- add_hi(cpane, cpane->hdir - 1);
- print_info(cpane, NULL);
- }
-}
-
-static void
-bkmrk(const Arg *arg)
-{
- if (check_dir((char *)arg->v) != 0) {
- print_error(strerror(errno));
- return;
- }
-
- strncpy(cpane->dirn, (char *)arg->v, MAX_P);
- cpane->firstrow = 0;
- cpane->parent_row = 1;
- cpane->hdir = 1;
- PERROR(listdir(cpane) < 0);
-}
-
-static int
-get_usrinput(char *result, size_t max_chars, const char *fmt, ...)
-{
- char msg[MAX_N];
- size_t i, cpos, startat;
- struct tb_event fev;
- va_list vl;
-
- i = 0;
- cpos = 1;
-
- va_start(vl, fmt);
- startat = vsnprintf(msg, MAX_N, fmt, vl) + 1;
- va_end(vl);
-
- clear_status();
- print_tb(msg, 1, theight - 1, cprompt.fg, cprompt.bg);
- tb_set_cursor(startat + 1, theight - 1);
- tb_present();
-
- while (tb_poll_event(&fev) != 0) {
- switch (fev.type) {
- case TB_EVENT_KEY:
- if (fev.key == TB_KEY_ESC) {
- tb_set_cursor(-1, -1);
- clear_status();
- return -1;
- }
-
- if (fev.key == TB_KEY_BACKSPACE ||
- fev.key == TB_KEY_BACKSPACE2) {
- if (BETWEEN(cpos, 2, max_chars)) {
- result[i - 1] = '\0';
- cpos--;
- i--;
- print_xstatus(' ', startat + cpos);
- tb_set_cursor(
- startat + cpos, theight - 1);
- }
-
- } else if (fev.key == TB_KEY_ENTER) {
- tb_set_cursor(-1, -1);
- result[cpos - 1] = '\0';
- return 0;
-
- } else if (fev.key) { /* disable other TB_KEY_* */
- break;
-
- } else {
- if (cpos < max_chars) {
- print_xstatus(
- (char)fev.ch, (startat + cpos));
- result[i] = (char)fev.ch;
- tb_set_cursor((startat + cpos + 1),
- theight - 1);
- cpos++;
- i++;
- }
- }
-
- tb_present();
- break;
-
- case TB_EVENT_RESIZE:
- t_resize();
- clear_status();
- print_tb(msg, 1, theight - 1, cprompt.fg, cprompt.bg);
- print_tb(result, startat + 1, theight - 1, cstatus.fg,
- cstatus.bg);
- tb_present();
- break;
-
- default:
- return -1;
- }
- }
-
- return -1;
-}
-
-static int
-frules(char *ex)
-{
- size_t c, d;
-
- for (c = 0; c < LEN(rules); c++)
- for (d = 0; d < rules[c].exlen; d++)
- if (strncmp(rules[c].ext[d], ex, MAX_EXT) == 0)
- return c;
- return -1;
-}
-
-static int
-spawn(const void *com_argv, size_t com_argc, const void *f_argv, size_t f_argc,
- char *fn, int waiting)
-{
- int ws;
- size_t argc;
- pid_t r;
-
- argc = com_argc + f_argc + 2;
- char *argv[argc];
-
- memcpy(argv, com_argv, com_argc * sizeof(char *)); /* command */
- memcpy(&argv[com_argc], f_argv, f_argc * sizeof(char *)); /* files */
-
- argv[argc - 2] = fn;
- argv[argc - 1] = NULL;
-
- fork_pid = fork();
- switch (fork_pid) {
- case -1:
- return -1;
- case 0:
- execvp(argv[0], argv);
- exit(EXIT_SUCCESS);
- default:
- if (waiting == Wait) {
- while ((r = waitpid(fork_pid, &ws, 0)) == -1 &&
- errno == EINTR)
- continue;
- if (r == -1)
- return -1;
- if ((WIFEXITED(ws) != 0) && (WEXITSTATUS(ws) != 0))
- return -1;
- }
- }
- fork_pid = 0; /* enable th_handler() */
- return 0;
-}
-
-static int
-opnf(char *fn)
-{
- char *ex;
- int c;
-
- ex = get_ext(fn);
- c = frules(ex);
- free(ex);
-
- if (c < 0) /* extension not found open in editor */
- return spawn(editor, 1, NULL, 0, fn, Wait);
- else
- return spawn(
- (char **)rules[c].v, rules[c].vlen, NULL, 0, fn, Wait);
-}
-
-static void
-opnsh(const Arg *arg)
-{
- int s;
-
- tb_shutdown();
- chdir(cpane->dirn);
- s = spawn(shell, 1, NULL, 0, NULL, Wait);
- if (tb_init() != 0)
- die("tb_init");
- t_resize();
- if (s < 0)
- print_error("process failed non-zero exit");
-}
-
-static int
-fsev_init(void)
-{
-#if defined(_SYS_INOTIFY_H)
- inotify_fd = inotify_init();
- if (inotify_fd < 0)
- return -1;
-#elif defined(_SYS_EVENT_H_)
- gtimeout.tv_sec = 1;
- kq = kqueue();
- if (kq < 0)
- return -1;
-#endif
- return 0;
-}
-
-static int
-addwatch(Pane *pane)
-{
-#if defined(_SYS_INOTIFY_H)
- return pane->inotify_wd = inotify_add_watch(inotify_fd, pane->dirn,
- IN_MODIFY | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE |
- IN_ATTRIB | IN_DELETE | IN_DELETE_SELF |
- IN_MOVE_SELF);
-#elif defined(_SYS_EVENT_H_)
- pane->event_fd = open(pane->dirn, O_RDONLY);
- if (pane->event_fd < 0)
- return pane->event_fd;
- EV_SET(&evlist[pane->pane_id], pane->event_fd, EVFILT_VNODE,
- EV_ADD | EV_CLEAR,
- NOTE_DELETE | NOTE_EXTEND | NOTE_LINK | NOTE_RENAME |
- NOTE_ATTRIB | NOTE_REVOKE | NOTE_WRITE,
- 0, NULL);
- return 0;
-#endif
-}
-
-static int
-read_events(void)
-{
-#if defined(_SYS_INOTIFY_H)
- char *p;
- ssize_t r;
- struct inotify_event *event;
- const size_t events = 32;
- const size_t evbuflen =
- events * (sizeof(struct inotify_event) + MAX_N + 1);
- char buf[evbuflen];
-
- if (cpane->inotify_wd < 0)
- return -1;
- r = read(inotify_fd, buf, evbuflen);
- if (r <= 0)
- return r;
-
- for (p = buf; p < buf + r;) {
- event = (struct inotify_event *)p;
- if (!event->wd)
- break;
- if (event->mask) {
- return r;
- }
-
- p += sizeof(struct inotify_event) + event->len;
- }
-#elif defined(_SYS_EVENT_H_)
- return kevent(kq, evlist, 2, chlist, 2, &gtimeout);
-#endif
- return -1;
-}
-
-static void
-rmwatch(Pane *pane)
-{
-#if defined(_SYS_INOTIFY_H)
- if (pane->inotify_wd >= 0)
- inotify_rm_watch(inotify_fd, pane->inotify_wd);
-#elif defined(_SYS_EVENT_H_)
- close(pane->event_fd);
-#endif
-}
-
-static void
-fsev_shdn(void)
-{
- pthread_cancel(fsev_thread);
-#if defined(__linux__)
- pthread_join(fsev_thread, NULL);
-#endif
- rmwatch(&panes[Left]);
- rmwatch(&panes[Right]);
-#if defined(_SYS_INOTIFY_H)
- close(inotify_fd);
-#elif defined(_SYS_EVENT_H_)
- close(kq);
-#endif
-}
-
-static void
-toggle_df(const Arg *arg)
-{
- show_dotfiles = !show_dotfiles;
- PERROR(listdir(&panes[Left]));
- PERROR(listdir(&panes[Right]));
- tb_present();
-}
-
-static void
-start_filter(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- char *user_input;
- user_input = ecalloc(MAX_USRI, sizeof(char));
- if (get_usrinput(user_input, MAX_USRI, "filter") < 0) {
- free(user_input);
- return;
- }
- cpane->filter = user_input;
- if (listdir(cpane) < 0)
- print_error("no match");
- cpane->filter = NULL;
- free(user_input);
-}
-
-static void
-start_vmode(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- struct tb_event fev;
- if (sel_indexes != NULL) {
- free(sel_indexes);
- sel_indexes = NULL;
- }
-
- sel_indexes = ecalloc(cpane->dirc, sizeof(size_t));
- sel_indexes[0] = cpane->hdir;
- cont_vmode = 0;
- print_prompt("-- VISUAL --");
- tb_present();
- while (tb_poll_event(&fev) != 0) {
- switch (fev.type) {
- case TB_EVENT_KEY:
- grabkeys(&fev, vkeys, vkeyslen);
- if (cont_vmode == -1)
- return;
- tb_present();
- break;
- }
- }
-}
-
-static void
-exit_vmode(const Arg *arg)
-{
- refresh_pane(cpane);
- add_hi(cpane, cpane->hdir - 1);
- cont_vmode = -1;
-}
-
-static void
-start_change(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- struct tb_event fev;
-
- cont_change = 0;
- print_prompt("c [womf]");
- tb_present();
- while (tb_poll_event(&fev) != 0) {
- switch (fev.type) {
- case TB_EVENT_KEY:
- grabkeys(&fev, ckeys, ckeyslen);
- if (cont_change == -1)
- return;
- tb_present();
- break;
- }
- }
-}
-
-static void
-exit_change(const Arg *arg)
-{
- cont_change = -1;
- print_info(cpane, NULL);
-}
-
-static void
-selup(const Arg *arg)
-{
- mv_ver(arg);
- print_prompt("-- VISUAL --");
- int index = abs(cpane->hdir - sel_indexes[0]);
-
- if (cpane->hdir < sel_indexes[0]) {
- sel_indexes[index] = cpane->hdir;
- add_hi(cpane, sel_indexes[index]);
- } else if (index < cpane->dirc) {
- sel_indexes[index + 1] = 0;
- }
- if (cpane->dirc >= scrheight ||
- cpane->hdir <= 1) { /* rehighlight all if scrolling */
- selref();
- }
-}
-
-static void
-seldwn(const Arg *arg)
-{
- mv_ver(arg);
- print_prompt("-- VISUAL --");
- int index = abs(cpane->hdir - sel_indexes[0]);
-
- if (cpane->hdir > sel_indexes[0]) {
- sel_indexes[index] = cpane->hdir;
- add_hi(cpane, sel_indexes[index] - 2);
- } else {
- sel_indexes[index + 1] = 0;
- }
- if (cpane->dirc >= scrheight ||
- cpane->hdir >= cpane->dirc) { /* rehighlight all if scrolling */
- selref();
- }
-}
-
-static void
-selall(const Arg *arg)
-{
- int i;
- for (i = 0; i < cpane->dirc; i++) {
- sel_indexes[i] = i + 1;
- }
- selref();
-}
-
-static void
-selref(void)
-{
- int i;
- for (i = 0; i < cpane->dirc; i++) {
- if (sel_indexes[i] < (scrheight + cpane->firstrow) &&
- sel_indexes[i] >
- cpane->firstrow) { /* checks if in the frame of the directories */
- add_hi(cpane, sel_indexes[i] - 1);
- }
- }
-}
-
-static void
-selcalc(void)
-{
- int j;
- sel_len = 0;
-
- for (j = 0; j < cpane->dirc; j++) { /* calculate used selection size */
- if (sel_indexes[j] != 0)
- sel_len++;
- else
- break;
- }
-}
-
-static void
-free_files(void)
-{
- size_t i;
-
- if (sel_files != NULL) {
- for (i = 0; i < sel_len; i++) {
- free(sel_files[i]);
- sel_files[i] = NULL;
- }
- free(sel_files);
- sel_files = NULL;
- }
-}
-
-static void
-init_files(void)
-{
- size_t i;
- free_files();
-
- selcalc();
- sel_files = ecalloc(sel_len, sizeof(char *));
-
- for (i = 0; i < sel_len; i++) {
- sel_files[i] = ecalloc(MAX_P, sizeof(char));
- strncpy(sel_files[i], cpane->direntr[sel_indexes[i] - 1].name,
- MAX_P);
- }
-}
-
-static void
-selynk(const Arg *arg)
-{
- init_files();
- refresh_pane(cpane);
- add_hi(cpane, cpane->hdir - 1);
- print_status(cprompt, "%zu files are yanked", sel_len);
- cont_vmode = -1;
-}
-
-static void
-seldel(const Arg *arg)
-{
- char *inp_conf;
-
- inp_conf = ecalloc(delconf_len, sizeof(char));
- if ((get_usrinput(inp_conf, delconf_len, "delete files(s) (%s) ?",
- delconf) < 0) ||
- (strncmp(inp_conf, delconf, delconf_len) != 0)) {
- free(inp_conf);
- return; /* canceled by user or wrong inp_conf */
- }
- free(inp_conf);
-
- init_files();
-
- if (spawn(rm_cmd, rm_cmd_len, sel_files, sel_len, NULL, DontWait) < 0)
- print_error(strerror(errno));
- else
- print_status(cprompt, "%zu files are deleted", sel_len);
-
- free_files();
- cont_vmode = -1;
-}
-
-static void
-paste(const Arg *arg)
-{
- if (sel_files == NULL) {
- print_error("nothing to paste");
- return;
- }
-
- if (spawn(cp_cmd, cp_cmd_len, sel_files, sel_len, cpane->dirn,
- DontWait) < 0)
- print_error(strerror(errno));
- else
- print_status(cprompt, "%zu files are copied", sel_len);
-
- free_files();
-}
-
-static void
-selmv(const Arg *arg)
-{
- if (sel_files == NULL) {
- print_error("nothing to move");
- return;
- }
-
- if (spawn(mv_cmd, mv_cmd_len, sel_files, sel_len, cpane->dirn,
- DontWait) < 0)
- print_error(strerror(errno));
- else
- print_status(cprompt, "%zu files are moved", sel_len);
-
- free_files();
-}
-
-static void
-rname(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- char new_name[MAX_P];
- char *input_name;
-
- input_name = ecalloc(MAX_N, sizeof(char));
-
- if (get_usrinput(input_name, MAX_N, "rename: %s",
- basename(CURSOR(cpane).name)) < 0) {
- exit_change(0);
- free(input_name);
- return;
- }
-
- if (snprintf(new_name, MAX_P, "%s/%s", cpane->dirn, input_name) < 0) {
- free(input_name);
- print_error(strerror(errno));
- return;
- }
-
- char *rename_cmd[] = { "mv", CURSOR(cpane).name, new_name };
- PERROR(spawn(rename_cmd, 3, NULL, 0, NULL, DontWait) < 0);
-
- free(input_name);
- exit_change(0);
-}
-
-static void
-chngo(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- char *input_og;
- char *tmp[1];
-
- input_og = ecalloc(MAX_N, sizeof(char));
-
- if (get_usrinput(input_og, MAX_N, "OWNER:GROUP %s",
- basename(CURSOR(cpane).name)) < 0) {
- exit_change(0);
- free(input_og);
- return;
- }
-
- tmp[0] = input_og;
- if (spawn(chown_cmd, chown_cmd_len, tmp, 1, CURSOR(cpane).name,
- DontWait) < 0) {
- print_error(strerror(errno));
- return;
- }
-
- free(input_og);
- exit_change(0);
-}
-
-static void
-chngm(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- char *input_og;
- char *tmp[1];
-
- input_og = ecalloc(MAX_N, sizeof(char));
-
- if (get_usrinput(input_og, MAX_N, "chmod %s",
- basename(CURSOR(cpane).name)) < 0) {
- exit_change(0);
- free(input_og);
- return;
- }
-
- tmp[0] = input_og;
- if (spawn(chmod_cmd, chmod_cmd_len, tmp, 1, CURSOR(cpane).name,
- DontWait) < 0) {
- print_error(strerror(errno));
- return;
- }
-
- free(input_og);
- exit_change(0);
-}
-
-static void
-chngf(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- char *input_og;
- char *tmp[1];
-
- input_og = ecalloc(MAX_N, sizeof(char));
-
- if (get_usrinput(input_og, MAX_N, CHFLAG " %s",
- basename(CURSOR(cpane).name)) < 0) {
- exit_change(0);
- free(input_og);
- return;
- }
-
- tmp[0] = input_og;
- if (spawn(chflags_cmd, chflags_cmd_len, tmp, 1, CURSOR(cpane).name,
- DontWait) < 0) {
- print_error(strerror(errno));
- return;
- }
-
- free(input_og);
- exit_change(0);
-}
-
-static void
-dupl(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
- char new_name[MAX_P];
- char *input_name;
-
- input_name = ecalloc(MAX_N, sizeof(char));
-
- if (get_usrinput(input_name, MAX_N, "new name: %s",
- basename(CURSOR(cpane).name)) < 0) {
- free(input_name);
- return;
- }
-
- if (snprintf(new_name, MAX_P, "%s/%s", cpane->dirn, input_name) < 0) {
- free(input_name);
- print_error(strerror(errno));
- return;
- }
-
- char *tmp[1];
- tmp[0] = CURSOR(cpane).name;
- if (spawn(cp_cmd, cp_cmd_len, tmp, 1, new_name, DontWait) < 0) {
- print_error(strerror(errno));
- return;
- }
-
- free(input_name);
-}
-
-static void
-yank(const Arg *arg)
-{
- if (cpane->dirc < 1)
- return;
-
- free_files();
- sel_len = 1;
- sel_files = ecalloc(sel_len, sizeof(char *));
- sel_files[0] = ecalloc(MAX_P, sizeof(char));
- strncpy(sel_files[0], CURSOR(cpane).name, MAX_P);
- print_status(cprompt, "1 file is yanked", sel_len);
-}
-
-static void
-switch_pane(const Arg *arg)
-{
- if (cpane->dirc > 0)
- rm_hi(cpane, cpane->hdir - 1);
- cpane = &panes[pane_idx ^= 1];
- if (cpane->dirc > 0) {
- add_hi(cpane, cpane->hdir - 1);
- print_info(cpane, NULL);
- } else {
- clear_status();
- }
-}
-
-static void
-quit(const Arg *arg)
-{
- if (cont_vmode == -1) { /* check if selection was allocated */
- free(sel_indexes);
- if (sel_files != NULL)
- free_files();
- }
- free(panes[Left].direntr);
- free(panes[Right].direntr);
- fsev_shdn();
- tb_shutdown();
- exit(EXIT_SUCCESS);
-}
-
-static void
-grabkeys(struct tb_event *event, Key *key, size_t max_keys)
-{
- size_t i;
-
- for (i = 0; i < max_keys; i++) {
- if (event->ch != 0) {
- if (event->ch == key[i].evkey.ch) {
- key[i].func(&key[i].arg);
- return;
- }
- } else if (event->key != 0) {
- if (event->key == key[i].evkey.key) {
- key[i].func(&key[i].arg);
- return;
- }
- }
- }
-}
-
-void *
-read_th(void *arg)
-{
- struct timespec tim;
- tim.tv_sec = 0;
- tim.tv_nsec = 5000000L; /* 0.005 sec */
-
- while (1)
- if (read_events() > READEVSZ) {
- kill(main_pid, SIGUSR1);
- nanosleep(&tim, NULL);
- }
- return arg;
-}
-
-static void
-start_ev(void)
-{
- struct tb_event ev;
-
- while (tb_poll_event(&ev) != 0) {
- switch (ev.type) {
- case TB_EVENT_KEY:
- grabkeys(&ev, nkeys, nkeyslen);
- tb_present();
- break;
- case TB_EVENT_RESIZE:
- t_resize();
- break;
- default:
- break;
- }
- }
- tb_shutdown();
-}
-
-static void
-refresh_pane(Pane *pane)
-{
- size_t y, dyn_max, start_from;
- hwidth = (twidth / 2) - 4;
- Cpair col;
-
- y = 1;
- start_from = pane->firstrow;
- dyn_max = MIN(pane->dirc, (scrheight - 1) + pane->firstrow);
-
- /* print each entry in directory */
- while (start_from < dyn_max) {
- get_hicol(&col, pane->direntr[start_from].mode);
- print_row(pane, start_from, col);
- start_from++;
- y++;
- }
-
- if (pane->dirc > 0)
- print_info(pane, NULL);
- else
- clear_status();
-
- /* print current directory title */
- pane->dircol.fg |= TB_BOLD;
- printf_tb(pane->x_srt, 0, pane->dircol, " %.*s", hwidth, pane->dirn);
-}
-
-static void
-set_direntr(Pane *pane, struct dirent *entry, DIR *dir, char *filter)
-{
- int i;
- char *tmpfull;
- struct stat status;
-
-#define ADD_ENTRY \
- tmpfull = get_fullpath(pane->dirn, entry->d_name); \
- strncpy(pane->direntr[i].name, tmpfull, MAX_N); \
- if (lstat(tmpfull, &status) == 0) { \
- pane->direntr[i].size = status.st_size; \
- pane->direntr[i].mode = status.st_mode; \
- pane->direntr[i].group = status.st_gid; \
- pane->direntr[i].user = status.st_uid; \
- pane->direntr[i].dt = status.st_mtime; \
- } \
- i++; \
- free(tmpfull);
-
- i = 0;
- pane->direntr =
- erealloc(pane->direntr, (10 + pane->dirc) * sizeof(Entry));
- while ((entry = readdir(dir)) != 0) {
- if (show_dotfiles == 1) {
- if (entry->d_name[0] == '.' &&
- (entry->d_name[1] == '\0' ||
- entry->d_name[1] == '.'))
- continue;
- } else {
- if (entry->d_name[0] == '.')
- continue;
- }
-
- if (filter == NULL) {
- ADD_ENTRY
- } else if (filter != NULL) {
- if (strcasestr(entry->d_name, filter) != NULL) {
- ADD_ENTRY
- }
- }
- }
-
- pane->dirc = i;
-}
-
-static int
-listdir(Pane *pane)
-{
- DIR *dir;
- struct dirent *entry;
- int filtercount = 0;
- size_t oldc = pane->dirc;
-
- pane->dirc = 0;
-
- dir = opendir(pane->dirn);
- if (dir == NULL)
- return -1;
-
- /* get content and filter sum */
- while ((entry = readdir(dir)) != 0) {
- if (pane->filter != NULL) {
- if (strcasestr(entry->d_name, pane->filter) != NULL)
- filtercount++;
- } else { /* no filter */
- pane->dirc++;
- }
- }
-
- if (pane->filter == NULL) {
- clear_pane(pane);
- pane->dirc -= 2;
- }
-
- if (pane->filter != NULL) {
- if (filtercount > 0) {
- pane->dirc = filtercount;
- clear_pane(pane);
- pane->hdir = 1;
- } else if (filtercount == 0) {
- if (closedir(dir) < 0)
- return -1;
- pane->dirc = oldc;
- return -1;
- }
- }
-
- /* print current directory title */
- pane->dircol.fg |= TB_BOLD;
- printf_tb(pane->x_srt, 0, pane->dircol, " %.*s", hwidth, pane->dirn);
-
- if (pane->filter == NULL) /* dont't watch when filtering */
- if (addwatch(pane) < 0)
- print_error("can't add watch");
-
- /* empty directory */
- if (pane->dirc == 0) {
- clear_status();
- if (closedir(dir) < 0)
- return -1;
- return 0;
- }
-
- rewinddir(dir); /* reset position */
- set_direntr(
- pane, entry, dir, pane->filter); /* create array of entries */
- qsort(pane->direntr, pane->dirc, sizeof(Entry), sort_name);
- refresh_pane(pane);
-
- if (pane->hdir > pane->dirc)
- pane->hdir = pane->dirc;
-
- if (pane == cpane && pane->dirc > 0)
- add_hi(pane, pane->hdir - 1);
-
- if (closedir(dir) < 0)
- return -1;
- return 0;
-}
-
-static void
-t_resize(void)
-{
- tb_clear();
- draw_frame();
- panes[Left].x_end = (twidth / 2) - 1;
- panes[Right].x_end = twidth - 1;
- panes[Right].x_srt = (twidth / 2) + 2;
- refresh_pane(&panes[Left]);
- refresh_pane(&panes[Right]);
- if (cpane->dirc > 0)
- add_hi(cpane, cpane->hdir - 1);
- tb_present();
-}
-
-static void
-get_editor(void)
-{
- editor[0] = getenv("EDITOR");
- editor[1] = NULL;
-
- if (editor[0] == NULL)
- editor[0] = fed;
-}
-
-static void
-get_shell(void)
-{
- shell[0] = getenv("SHELL");
- shell[1] = NULL;
-
- if (shell[0] == NULL)
- shell[0] = sh;
-}
-
-static void
-set_panes(void)
-{
- char *home;
- char cwd[MAX_P];
-
- home = getenv("HOME");
- if (home == NULL)
- home = "/";
- if ((getcwd(cwd, sizeof(cwd)) == NULL))
- strncpy(cwd, home, MAX_P);
-
- pane_idx = Left; /* cursor pane */
- cpane = &panes[pane_idx];
-
- panes[Left].pane_id = 0;
- panes[Left].x_srt = 2;
- panes[Left].x_end = (twidth / 2) - 1;
- panes[Left].dircol = cpanell;
- panes[Left].firstrow = 0;
- panes[Left].direntr = ecalloc(0, sizeof(Entry));
- strncpy(panes[Left].dirn, cwd, MAX_P);
- panes[Left].hdir = 1;
- panes[Left].inotify_wd = -1;
- panes[Left].parent_row = 1;
-
- panes[Right].pane_id = 1;
- panes[Right].x_srt = (twidth / 2) + 2;
- panes[Right].x_end = twidth - 1;
- panes[Right].dircol = cpanelr;
- panes[Right].firstrow = 0;
- panes[Right].direntr = ecalloc(0, sizeof(Entry));
- strncpy(panes[Right].dirn, home, MAX_P);
- panes[Right].hdir = 1;
- panes[Right].inotify_wd = -1;
- panes[Right].parent_row = 1;
-}
-
-static void
-draw_frame(void)
-{
- int i;
- theight = tb_height();
- twidth = tb_width();
- hwidth = (twidth / 2) - 4;
- scrheight = theight - 2;
-
- /* 2 horizontal lines */
- for (i = 1; i < twidth - 1; ++i) {
- tb_change_cell(i, 0, u_hl, cframe.fg, cframe.bg);
- tb_change_cell(i, theight - 2, u_hl, cframe.fg, cframe.bg);
- }
-
- /* 4 vertical lines */
- for (i = 1; i < theight - 1; ++i) {
- tb_change_cell(0, i, u_vl, cframe.fg, cframe.bg);
- tb_change_cell(
- (twidth - 1) / 2, i - 1, u_vl, cframe.fg, cframe.bg);
- tb_change_cell(((twidth - 1) / 2) + 1, i - 1, u_vl, cframe.fg,
- cframe.bg);
- tb_change_cell(twidth - 1, i, u_vl, cframe.fg, cframe.bg);
- }
-
- /* 4 corners */
- tb_change_cell(0, 0, u_cnw, cframe.fg, cframe.bg);
- tb_change_cell(twidth - 1, 0, u_cne, cframe.fg, cframe.bg);
- tb_change_cell(0, theight - 2, u_csw, cframe.fg, cframe.bg);
- tb_change_cell(twidth - 1, theight - 2, u_cse, cframe.fg, cframe.bg);
-
- /* 2 middel top and bottom */
- tb_change_cell((twidth - 1) / 2, 0, u_mn, cframe.fg, cframe.bg);
- tb_change_cell(
- (twidth - 1) / 2, theight - 2, u_ms, cframe.fg, cframe.bg);
-}
-
-void
-th_handler(int num)
-{
- if (fork_pid > 0) /* while forking don't listdir() */
- return;
- (void)num;
- PERROR(listdir(&panes[Left]));
- PERROR(listdir(&panes[Right]));
- tb_present();
-}
-
-static int
-start_signal(void)
-{
- struct sigaction sa;
-
- main_pid = getpid();
- sa.sa_handler = th_handler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- return sigaction(SIGUSR1, &sa, NULL);
-}
-
-static void
-refresh(const Arg *arg)
-{
- kill(main_pid, SIGWINCH);
-}
-
-static void
-start(void)
-{
- switch (tb_init()) {
- case TB_EFAILED_TO_OPEN_TTY:
- die("TB_EFAILED_TO_OPEN_TTY");
- break;
- case TB_EUNSUPPORTED_TERMINAL:
- die("TB_EUNSUPPORTED_TERMINAL");
- break;
- case TB_EPIPE_TRAP_ERROR:
- die("TB_EUNSUPPORTED_TERMINAL");
- break;
- case 0:
- break;
- default:
- die("UNKNOWN FAILURE");
- }
-
- if (tb_select_output_mode(TB_OUTPUT_256) != TB_OUTPUT_256)
- if (tb_select_output_mode(TB_OUTPUT_NORMAL) != TB_OUTPUT_NORMAL)
- die("output error");
- draw_frame();
- set_panes();
- get_editor();
- get_shell();
- PERROR(start_signal() < 0);
- PERROR(fsev_init() < 0);
- PERROR(listdir(&panes[Left]) < 0);
- PERROR(listdir(&panes[Right]) < 0);
- tb_present();
-
- pthread_create(&fsev_thread, NULL, read_th, NULL);
- start_ev();
-}
-
-int
-main(int argc, char *argv[])
-{
-#if defined(__OpenBSD__)
- if (pledge("cpath exec getpw proc rpath stdio tmppath tty wpath",
- NULL) == -1)
- die("pledge");
-#endif /* __OpenBSD__ */
- if (argc == 1)
- start();
- else if (argc == 2 && strncmp("-v", argv[1], 2) == 0)
- die("sfm-" VERSION);
- else
- die("usage: sfm [-v]");
- return 0;
-}
diff --git a/sfm-0.4/sfm.png b/sfm-0.4/sfm.png
deleted file mode 100644
index c7b1f8e..0000000
--- a/sfm-0.4/sfm.png
+++ /dev/null
Binary files differ
diff --git a/sfm-0.4/termbox.c b/sfm-0.4/termbox.c
deleted file mode 100644
index 1c7bfdd..0000000
--- a/sfm-0.4/termbox.c
+++ /dev/null
@@ -1,1509 +0,0 @@
-#if defined(__linux__)
-#define _GNU_SOURCE
-#elif defined(__APPLE__)
-#define _DARWIN_C_SOURCE
-#elif defined(__FreeBSD__)
-#define __BSD_VISIBLE 1
-#endif
-#include "termbox.h"
-
-#include <sys/ioctl.h>
-#include <sys/select.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <wchar.h>
-
-#define ENTER_MOUSE_SEQ "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h"
-#define EXIT_MOUSE_SEQ "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"
-#define EUNSUPPORTED_TERM -1
-#define TI_MAGIC 0432
-#define TI_ALT_MAGIC 542
-#define TI_HEADER_LENGTH 12
-#define TB_KEYS_NUM 22
-#define CELL(buf, x, y) (buf)->cells[(y) * (buf)->width + (x)]
-#define IS_CURSOR_HIDDEN(cx, cy) (cx == -1 || cy == -1)
-#define LAST_COORD_INIT -1
-#define WRITE_LITERAL(X) bytebuffer_append(&output_buffer, (X), sizeof(X) - 1)
-#define WRITE_INT(X) \
- bytebuffer_append(&output_buffer, buf, convertnum((X), buf))
-
-struct cellbuf {
- int width;
- int height;
- struct tb_cell *cells;
-};
-
-struct bytebuffer {
- char *buf;
- int len;
- int cap;
-};
-
-enum {
- T_ENTER_CA,
- T_EXIT_CA,
- T_SHOW_CURSOR,
- T_HIDE_CURSOR,
- T_CLEAR_SCREEN,
- T_SGR0,
- T_UNDERLINE,
- T_BOLD,
- T_BLINK,
- T_REVERSE,
- T_ENTER_KEYPAD,
- T_EXIT_KEYPAD,
- T_ENTER_MOUSE,
- T_EXIT_MOUSE,
- T_FUNCS_NUM,
-};
-
-static int init_term_builtin(void);
-static char *read_file(const char *file);
-static char *terminfo_try_path(const char *path, const char *term);
-static char *load_terminfo(void);
-static const char *terminfo_copy_string(char *data, int str, int table);
-static int init_term(void);
-static void shutdown_term(void);
-static bool starts_with(const char *s1, int len, const char *s2);
-static int parse_mouse_event(struct tb_event *event, const char *buf, int len);
-static int parse_escape_seq(struct tb_event *event, const char *buf, int len);
-static int convertnum(uint32_t num, char *buf);
-static void write_cursor(int x, int y);
-static void write_sgr(uint16_t fg, uint16_t bg);
-static void cellbuf_init(struct cellbuf *buf, int width, int height);
-static void cellbuf_resize(struct cellbuf *buf, int width, int height);
-static void cellbuf_clear(struct cellbuf *buf);
-static void cellbuf_free(struct cellbuf *buf);
-static void get_term_size(int *w, int *h);
-static void update_term_size(void);
-static void send_attr(uint16_t fg, uint16_t bg);
-static void send_char(int x, int y, uint32_t c);
-static void send_clear(void);
-static void sigwinch_handler(int xxx);
-static void update_size(void);
-static int read_up_to(int n);
-static int wait_fill_event(struct tb_event *event, struct timeval *timeout);
-static void bytebuffer_reserve(struct bytebuffer *b, int cap);
-static void bytebuffer_init(struct bytebuffer *b, int cap);
-static void bytebuffer_free(struct bytebuffer *b);
-static void bytebuffer_clear(struct bytebuffer *b);
-static void bytebuffer_append(struct bytebuffer *b, const char *data, int len);
-static void bytebuffer_puts(struct bytebuffer *b, const char *str);
-static void bytebuffer_resize(struct bytebuffer *b, int len);
-static void bytebuffer_flush(struct bytebuffer *b, int fd);
-static void bytebuffer_truncate(struct bytebuffer *b, int n);
-
-static struct termios orig_tios;
-static struct cellbuf back_buffer;
-static struct cellbuf front_buffer;
-static struct bytebuffer output_buffer;
-static struct bytebuffer input_buffer;
-static int termw = -1;
-static int termh = -1;
-static int inputmode = TB_INPUT_ESC;
-static int outputmode = TB_OUTPUT_NORMAL;
-static int inout;
-static int winch_fds[2];
-static int lastx = LAST_COORD_INIT;
-static int lasty = LAST_COORD_INIT;
-static int cursor_x = -1;
-static int cursor_y = -1;
-static uint16_t background = TB_DEFAULT;
-static uint16_t foreground = TB_DEFAULT;
-/* may happen in a different thread */
-static volatile int buffer_size_change_request;
-// rxvt-256color
-static const char *rxvt_256color_keys[] = { "\033[11~", "\033[12~", "\033[13~",
- "\033[14~", "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~",
- "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[7~",
- "\033[8~", "\033[5~", "\033[6~", "\033[A", "\033[B", "\033[D", "\033[C",
- 0 };
-static const char *rxvt_256color_funcs[] = {
- "\0337\033[?47h",
- "\033[2J\033[?47l\0338",
- "\033[?25h",
- "\033[?25l",
- "\033[H\033[2J",
- "\033[m",
- "\033[4m",
- "\033[1m",
- "\033[5m",
- "\033[7m",
- "\033=",
- "\033>",
- ENTER_MOUSE_SEQ,
- EXIT_MOUSE_SEQ,
-};
-// Eterm
-static const char *eterm_keys[] = { "\033[11~", "\033[12~", "\033[13~",
- "\033[14~", "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~",
- "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[7~",
- "\033[8~", "\033[5~", "\033[6~", "\033[A", "\033[B", "\033[D", "\033[C",
- 0 };
-static const char *eterm_funcs[] = {
- "\0337\033[?47h",
- "\033[2J\033[?47l\0338",
- "\033[?25h",
- "\033[?25l",
- "\033[H\033[2J",
- "\033[m",
- "\033[4m",
- "\033[1m",
- "\033[5m",
- "\033[7m",
- "",
- "",
- "",
- "",
-};
-// screen
-static const char *screen_keys[] = { "\033OP", "\033OQ", "\033OR", "\033OS",
- "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~",
- "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[1~", "\033[4~",
- "\033[5~", "\033[6~", "\033OA", "\033OB", "\033OD", "\033OC", 0 };
-static const char *screen_funcs[] = {
- "\033[?1049h",
- "\033[?1049l",
- "\033[34h\033[?25h",
- "\033[?25l",
- "\033[H\033[J",
- "\033[m",
- "\033[4m",
- "\033[1m",
- "\033[5m",
- "\033[7m",
- "\033[?1h\033=",
- "\033[?1l\033>",
- ENTER_MOUSE_SEQ,
- EXIT_MOUSE_SEQ,
-};
-// rxvt-unicode
-static const char *rxvt_unicode_keys[] = { "\033[11~", "\033[12~", "\033[13~",
- "\033[14~", "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~",
- "\033[21~", "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[7~",
- "\033[8~", "\033[5~", "\033[6~", "\033[A", "\033[B", "\033[D", "\033[C",
- 0 };
-static const char *rxvt_unicode_funcs[] = {
- "\033[?1049h",
- "\033[r\033[?1049l",
- "\033[?25h",
- "\033[?25l",
- "\033[H\033[2J",
- "\033[m\033(B",
- "\033[4m",
- "\033[1m",
- "\033[5m",
- "\033[7m",
- "\033=",
- "\033>",
- ENTER_MOUSE_SEQ,
- EXIT_MOUSE_SEQ,
-};
-// linux
-static const char *linux_keys[] = { "\033[[A", "\033[[B", "\033[[C", "\033[[D",
- "\033[[E", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~",
- "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033[1~", "\033[4~",
- "\033[5~", "\033[6~", "\033[A", "\033[B", "\033[D", "\033[C", 0 };
-static const char *linux_funcs[] = {
- "",
- "",
- "\033[?25h\033[?0c",
- "\033[?25l\033[?1c",
- "\033[H\033[J",
- "\033[0;10m",
- "\033[4m",
- "\033[1m",
- "\033[5m",
- "\033[7m",
- "",
- "",
- "",
- "",
-};
-// xterm
-static const char *xterm_keys[] = { "\033OP", "\033OQ", "\033OR", "\033OS",
- "\033[15~", "\033[17~", "\033[18~", "\033[19~", "\033[20~", "\033[21~",
- "\033[23~", "\033[24~", "\033[2~", "\033[3~", "\033OH", "\033OF",
- "\033[5~", "\033[6~", "\033OA", "\033OB", "\033OD", "\033OC", 0 };
-static const char *xterm_funcs[] = {
- "\033[?1049h",
- "\033[?1049l",
- "\033[?12l\033[?25h",
- "\033[?25l",
- "\033[H\033[2J",
- "\033(B\033[m",
- "\033[4m",
- "\033[1m",
- "\033[5m",
- "\033[7m",
- "\033[?1h\033=",
- "\033[?1l\033>",
- ENTER_MOUSE_SEQ,
- EXIT_MOUSE_SEQ,
-};
-static struct term {
- const char *name;
- const char **keys;
- const char **funcs;
-} terms[] = {
- { "rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs },
- { "Eterm", eterm_keys, eterm_funcs },
- { "screen", screen_keys, screen_funcs },
- { "rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs },
- { "linux", linux_keys, linux_funcs },
- { "xterm", xterm_keys, xterm_funcs },
- { 0, 0, 0 },
-};
-static bool init_from_terminfo = false;
-static const char **keys;
-static const char **funcs;
-
-static int
-try_compatible(const char *term, const char *name, const char **tkeys,
- const char **tfuncs)
-{
- if (strstr(term, name)) {
- keys = tkeys;
- funcs = tfuncs;
- return 0;
- }
-
- return EUNSUPPORTED_TERM;
-}
-
-static int
-init_term_builtin(void)
-{
- int i;
- const char *term = getenv("TERM");
-
- if (term) {
- for (i = 0; terms[i].name; i++) {
- if (!strcmp(terms[i].name, term)) {
- keys = terms[i].keys;
- funcs = terms[i].funcs;
- return 0;
- }
- }
-
- /* let's do some heuristic, maybe it's a compatible terminal */
- if (try_compatible(term, "xterm", xterm_keys, xterm_funcs) == 0)
- return 0;
- if (try_compatible(term, "rxvt", rxvt_unicode_keys,
- rxvt_unicode_funcs) == 0)
- return 0;
- if (try_compatible(term, "linux", linux_keys, linux_funcs) == 0)
- return 0;
- if (try_compatible(term, "Eterm", eterm_keys, eterm_funcs) == 0)
- return 0;
- if (try_compatible(term, "screen", screen_keys, screen_funcs) ==
- 0)
- return 0;
- if (try_compatible(term, "tmux", screen_keys, screen_funcs) ==
- 0)
- return 0;
- /* let's assume that 'cygwin' is xterm compatible */
- if (try_compatible(term, "cygwin", xterm_keys, xterm_funcs) ==
- 0)
- return 0;
- }
-
- return EUNSUPPORTED_TERM;
-}
-
-//----------------------------------------------------------------------
-// terminfo
-//----------------------------------------------------------------------
-
-static char *
-read_file(const char *file)
-{
- FILE *f = fopen(file, "rb");
- if (!f)
- return 0;
-
- struct stat st;
- if (fstat(fileno(f), &st) != 0) {
- fclose(f);
- return 0;
- }
-
- char *data = malloc(st.st_size);
- if (!data) {
- fclose(f);
- return 0;
- }
-
- if (fread(data, 1, st.st_size, f) != (size_t)st.st_size) {
- fclose(f);
- free(data);
- return 0;
- }
-
- fclose(f);
- return data;
-}
-
-static char *
-terminfo_try_path(const char *path, const char *term)
-{
- char tmp[4096];
- snprintf(tmp, sizeof(tmp), "%s/%c/%s", path, term[0], term);
- tmp[sizeof(tmp) - 1] = '\0';
- char *data = read_file(tmp);
- if (data) {
- return data;
- }
-
- // fallback to darwin specific dirs structure
- snprintf(tmp, sizeof(tmp), "%s/%x/%s", path, term[0], term);
- tmp[sizeof(tmp) - 1] = '\0';
- return read_file(tmp);
-}
-
-static char *
-load_terminfo(void)
-{
- char tmp[4096];
- const char *term = getenv("TERM");
- if (!term) {
- return 0;
- }
-
- // if TERMINFO is set, no other directory should be searched
- const char *terminfo = getenv("TERMINFO");
- if (terminfo) {
- return terminfo_try_path(terminfo, term);
- }
-
- // next, consider ~/.terminfo
- const char *home = getenv("HOME");
- if (home) {
- snprintf(tmp, sizeof(tmp), "%s/.terminfo", home);
- tmp[sizeof(tmp) - 1] = '\0';
- char *data = terminfo_try_path(tmp, term);
- if (data)
- return data;
- }
-
- // next, TERMINFO_DIRS
- const char *dirs = getenv("TERMINFO_DIRS");
- if (dirs) {
- snprintf(tmp, sizeof(tmp), "%s", dirs);
- tmp[sizeof(tmp) - 1] = '\0';
- char *dir = strtok(tmp, ":");
- while (dir) {
- const char *cdir = dir;
- if (strcmp(cdir, "") == 0) {
- cdir = "/usr/share/terminfo";
- }
- char *data = terminfo_try_path(cdir, term);
- if (data)
- return data;
- dir = strtok(0, ":");
- }
- }
-
- // fallback to /usr/share/terminfo
- return terminfo_try_path("/usr/share/terminfo", term);
-}
-
-static const char *
-terminfo_copy_string(char *data, int str, int table)
-{
- const int16_t off = *(int16_t *)(data + str);
- const char *src = data + table + off;
- int len = strlen(src);
- char *dst = malloc(len + 1);
- strcpy(dst, src);
- return dst;
-}
-
-static const int16_t ti_funcs[] = {
- 28,
- 40,
- 16,
- 13,
- 5,
- 39,
- 36,
- 27,
- 26,
- 34,
- 89,
- 88,
-};
-
-static const int16_t ti_keys[] = {
- 66,
- 68 /* apparently not a typo; 67 is F10 for whatever reason */,
- 69,
- 70,
- 71,
- 72,
- 73,
- 74,
- 75,
- 67,
- 216,
- 217,
- 77,
- 59,
- 76,
- 164,
- 82,
- 81,
- 87,
- 61,
- 79,
- 83,
-};
-
-static int
-init_term(void)
-{
- int i;
- char *data = load_terminfo();
- if (!data) {
- init_from_terminfo = false;
- return init_term_builtin();
- }
-
- int16_t *header = (int16_t *)data;
-
- const int number_sec_len = header[0] == TI_ALT_MAGIC ? 4 : 2;
-
- if ((header[1] + header[2]) % 2) {
- // old quirk to align everything on word boundaries
- header[2] += 1;
- }
-
- const int str_offset = TI_HEADER_LENGTH + header[1] + header[2] +
- number_sec_len * header[3];
- const int table_offset = str_offset + 2 * header[4];
-
- keys = malloc(sizeof(const char *) * (TB_KEYS_NUM + 1));
- for (i = 0; i < TB_KEYS_NUM; i++) {
- keys[i] = terminfo_copy_string(
- data, str_offset + 2 * ti_keys[i], table_offset);
- }
- keys[TB_KEYS_NUM] = 0;
-
- funcs = malloc(sizeof(const char *) * T_FUNCS_NUM);
- // the last two entries are reserved for mouse. because the table offset is
- // not there, the two entries have to fill in manually
- for (i = 0; i < T_FUNCS_NUM - 2; i++) {
- funcs[i] = terminfo_copy_string(
- data, str_offset + 2 * ti_funcs[i], table_offset);
- }
-
- funcs[T_FUNCS_NUM - 2] = ENTER_MOUSE_SEQ;
- funcs[T_FUNCS_NUM - 1] = EXIT_MOUSE_SEQ;
-
- init_from_terminfo = true;
- free(data);
- return 0;
-}
-
-static void
-shutdown_term(void)
-{
- if (init_from_terminfo) {
- int i;
- for (i = 0; i < TB_KEYS_NUM; i++) {
- free((void *)keys[i]);
- }
- // the last two entries are reserved for mouse. because the table offset
- // is not there, the two entries have to fill in manually and do not
- // need to be freed.
- for (i = 0; i < T_FUNCS_NUM - 2; i++) {
- free((void *)funcs[i]);
- }
- free(keys);
- free(funcs);
- }
-}
-
-// if s1 starts with s2 returns true, else false
-// len is the length of s1
-// s2 should be null-terminated
-static bool
-starts_with(const char *s1, int len, const char *s2)
-{
- int n = 0;
- while (*s2 && n < len) {
- if (*s1++ != *s2++)
- return false;
- n++;
- }
- return *s2 == 0;
-}
-
-static int
-parse_mouse_event(struct tb_event *event, const char *buf, int len)
-{
- if (len >= 6 && starts_with(buf, len, "\033[M")) {
- // X10 mouse encoding, the simplest one
- // \033 [ M Cb Cx Cy
- int b = buf[3] - 32;
- switch (b & 3) {
- case 0:
- if ((b & 64) != 0)
- event->key = TB_KEY_MOUSE_WHEEL_UP;
- else
- event->key = TB_KEY_MOUSE_LEFT;
- break;
- case 1:
- if ((b & 64) != 0)
- event->key = TB_KEY_MOUSE_WHEEL_DOWN;
- else
- event->key = TB_KEY_MOUSE_MIDDLE;
- break;
- case 2:
- event->key = TB_KEY_MOUSE_RIGHT;
- break;
- case 3:
- event->key = TB_KEY_MOUSE_RELEASE;
- break;
- default:
- return -6;
- }
- event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default
- if ((b & 32) != 0)
- event->mod |= TB_MOD_MOTION;
-
- // the coord is 1,1 for upper left
- event->x = (uint8_t)buf[4] - 1 - 32;
- event->y = (uint8_t)buf[5] - 1 - 32;
-
- return 6;
- } else if (starts_with(buf, len, "\033[<") ||
- starts_with(buf, len, "\033[")) {
- // xterm 1006 extended mode or urxvt 1015 extended mode
- // xterm: \033 [ < Cb ; Cx ; Cy (M or m)
- // urxvt: \033 [ Cb ; Cx ; Cy M
- int i, mi = -1, starti = -1;
- int isM, isU, s1 = -1, s2 = -1;
- int n1 = 0, n2 = 0, n3 = 0;
-
- for (i = 0; i < len; i++) {
- // We search the first (s1) and the last (s2) ';'
- if (buf[i] == ';') {
- if (s1 == -1)
- s1 = i;
- s2 = i;
- }
-
- // We search for the first 'm' or 'M'
- if ((buf[i] == 'm' || buf[i] == 'M') && mi == -1) {
- mi = i;
- break;
- }
- }
- if (mi == -1)
- return 0;
-
- // whether it's a capital M or not
- isM = (buf[mi] == 'M');
-
- if (buf[2] == '<') {
- isU = 0;
- starti = 3;
- } else {
- isU = 1;
- starti = 2;
- }
-
- if (s1 == -1 || s2 == -1 || s1 == s2)
- return 0;
-
- n1 = strtoul(&buf[starti], NULL, 10);
- n2 = strtoul(&buf[s1 + 1], NULL, 10);
- n3 = strtoul(&buf[s2 + 1], NULL, 10);
-
- if (isU)
- n1 -= 32;
-
- switch (n1 & 3) {
- case 0:
- if ((n1 & 64) != 0) {
- event->key = TB_KEY_MOUSE_WHEEL_UP;
- } else {
- event->key = TB_KEY_MOUSE_LEFT;
- }
- break;
- case 1:
- if ((n1 & 64) != 0) {
- event->key = TB_KEY_MOUSE_WHEEL_DOWN;
- } else {
- event->key = TB_KEY_MOUSE_MIDDLE;
- }
- break;
- case 2:
- event->key = TB_KEY_MOUSE_RIGHT;
- break;
- case 3:
- event->key = TB_KEY_MOUSE_RELEASE;
- break;
- default:
- return mi + 1;
- }
-
- if (!isM) {
- // on xterm mouse release is signaled by lowercase m
- event->key = TB_KEY_MOUSE_RELEASE;
- }
-
- event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default
- if ((n1 & 32) != 0)
- event->mod |= TB_MOD_MOTION;
-
- event->x = (uint8_t)n2 - 1;
- event->y = (uint8_t)n3 - 1;
-
- return mi + 1;
- }
-
- return 0;
-}
-
-// convert escape sequence to event, and return consumed bytes on success
-// (failure == 0)
-static int
-parse_escape_seq(struct tb_event *event, const char *buf, int len)
-{
- int mouse_parsed = parse_mouse_event(event, buf, len);
-
- if (mouse_parsed != 0)
- return mouse_parsed;
-
- // it's pretty simple here, find 'starts_with' match and return
- // success, else return failure
- int i;
- for (i = 0; keys[i]; i++) {
- if (starts_with(buf, len, keys[i])) {
- event->ch = 0;
- event->key = 0xFFFF - i;
- return strlen(keys[i]);
- }
- }
- return 0;
-}
-
-static bool
-extract_event(struct tb_event *event, struct bytebuffer *inbuf, int in)
-{
- const char *buf = inbuf->buf;
- const int len = inbuf->len;
- if (len == 0)
- return false;
-
- if (buf[0] == '\033') {
- int n = parse_escape_seq(event, buf, len);
- if (n != 0) {
- bool success = true;
- if (n < 0) {
- success = false;
- n = -n;
- }
- bytebuffer_truncate(inbuf, n);
- return success;
- } else {
- // it's not escape sequence, then it's ALT or ESC,
- // check inputmode
- if (in & TB_INPUT_ESC) {
- // if we're in escape mode, fill ESC event, pop
- // buffer, return success
- event->ch = 0;
- event->key = TB_KEY_ESC;
- event->mod = 0;
- bytebuffer_truncate(inbuf, 1);
- return true;
- } else if (in & TB_INPUT_ALT) {
- // if we're in alt mode, set ALT modifier to
- // event and redo parsing
- event->mod = TB_MOD_ALT;
- bytebuffer_truncate(inbuf, 1);
- return extract_event(event, inbuf, in);
- }
- assert(!"never got here");
- }
- }
-
- // if we're here, this is not an escape sequence and not an alt sequence
- // so, it's a FUNCTIONAL KEY or a UNICODE character
-
- // first of all check if it's a functional key
- if ((unsigned char)buf[0] <= TB_KEY_SPACE ||
- (unsigned char)buf[0] == TB_KEY_BACKSPACE2) {
- // fill event, pop buffer, return success */
- event->ch = 0;
- event->key = (uint16_t)buf[0];
- bytebuffer_truncate(inbuf, 1);
- return true;
- }
-
- // feh... we got utf8 here
-
- // check if there is all bytes
- if (len >= tb_utf8_char_length(buf[0])) {
- /* everything ok, fill event, pop buffer, return success */
- tb_utf8_char_to_unicode(&event->ch, buf);
- event->key = 0;
- bytebuffer_truncate(inbuf, tb_utf8_char_length(buf[0]));
- return true;
- }
-
- // event isn't recognized, perhaps there is not enough bytes in utf8
- // sequence
- return false;
-}
-
-/* -------------------------------------------------------- */
-
-int
-tb_init_fd(int inout_)
-{
- inout = inout_;
- if (inout == -1) {
- return TB_EFAILED_TO_OPEN_TTY;
- }
-
- if (init_term() < 0) {
- close(inout);
- return TB_EUNSUPPORTED_TERMINAL;
- }
-
- if (pipe(winch_fds) < 0) {
- close(inout);
- return TB_EPIPE_TRAP_ERROR;
- }
-
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = sigwinch_handler;
- sa.sa_flags = 0;
- sigaction(SIGWINCH, &sa, 0);
-
- tcgetattr(inout, &orig_tios);
-
- struct termios tios;
- memcpy(&tios, &orig_tios, sizeof(tios));
-
- tios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR |
- ICRNL | IXON);
- tios.c_oflag &= ~OPOST;
- tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
- tios.c_cflag &= ~(CSIZE | PARENB);
- tios.c_cflag |= CS8;
- tios.c_cc[VMIN] = 0;
- tios.c_cc[VTIME] = 0;
- tcsetattr(inout, TCSAFLUSH, &tios);
-
- bytebuffer_init(&input_buffer, 128);
- bytebuffer_init(&output_buffer, 32 * 1024);
-
- bytebuffer_puts(&output_buffer, funcs[T_ENTER_CA]);
- bytebuffer_puts(&output_buffer, funcs[T_ENTER_KEYPAD]);
- bytebuffer_puts(&output_buffer, funcs[T_HIDE_CURSOR]);
- send_clear();
-
- update_term_size();
- cellbuf_init(&back_buffer, termw, termh);
- cellbuf_init(&front_buffer, termw, termh);
- cellbuf_clear(&back_buffer);
- cellbuf_clear(&front_buffer);
-
- return 0;
-}
-
-int
-tb_init_file(const char *name)
-{
- return tb_init_fd(open(name, O_RDWR));
-}
-
-int
-tb_init(void)
-{
- return tb_init_file("/dev/tty");
-}
-
-void
-tb_shutdown(void)
-{
- if (termw == -1) {
- fputs("tb_shutdown() should not be called twice.", stderr);
- abort();
- }
-
- bytebuffer_puts(&output_buffer, funcs[T_SHOW_CURSOR]);
- bytebuffer_puts(&output_buffer, funcs[T_SGR0]);
- bytebuffer_puts(&output_buffer, funcs[T_CLEAR_SCREEN]);
- bytebuffer_puts(&output_buffer, funcs[T_EXIT_CA]);
- bytebuffer_puts(&output_buffer, funcs[T_EXIT_KEYPAD]);
- bytebuffer_puts(&output_buffer, funcs[T_EXIT_MOUSE]);
- bytebuffer_flush(&output_buffer, inout);
- tcsetattr(inout, TCSAFLUSH, &orig_tios);
-
- shutdown_term();
- close(inout);
- close(winch_fds[0]);
- close(winch_fds[1]);
-
- cellbuf_free(&back_buffer);
- cellbuf_free(&front_buffer);
- bytebuffer_free(&output_buffer);
- bytebuffer_free(&input_buffer);
- termw = termh = -1;
-}
-
-void
-tb_present(void)
-{
- int x, y, w, i;
- struct tb_cell *back, *front;
-
- /* invalidate cursor position */
- lastx = LAST_COORD_INIT;
- lasty = LAST_COORD_INIT;
-
- if (buffer_size_change_request) {
- update_size();
- buffer_size_change_request = 0;
- }
-
- for (y = 0; y < front_buffer.height; ++y) {
- for (x = 0; x < front_buffer.width;) {
- back = &CELL(&back_buffer, x, y);
- front = &CELL(&front_buffer, x, y);
- w = wcwidth(back->ch);
- if (w < 1)
- w = 1;
- if (memcmp(back, front, sizeof(struct tb_cell)) == 0) {
- x += w;
- continue;
- }
- memcpy(front, back, sizeof(struct tb_cell));
- send_attr(back->fg, back->bg);
- if (w > 1 && x >= front_buffer.width - (w - 1)) {
- // Not enough room for wide ch, so send spaces
- for (i = x; i < front_buffer.width; ++i) {
- send_char(i, y, ' ');
- }
- } else {
- send_char(x, y, back->ch);
- for (i = 1; i < w; ++i) {
- front = &CELL(&front_buffer, x + i, y);
- front->ch = 0;
- front->fg = back->fg;
- front->bg = back->bg;
- }
- }
- x += w;
- }
- }
- if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y))
- write_cursor(cursor_x, cursor_y);
- bytebuffer_flush(&output_buffer, inout);
-}
-
-void
-tb_set_cursor(int cx, int cy)
-{
- if (IS_CURSOR_HIDDEN(cursor_x, cursor_y) && !IS_CURSOR_HIDDEN(cx, cy))
- bytebuffer_puts(&output_buffer, funcs[T_SHOW_CURSOR]);
-
- if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y) && IS_CURSOR_HIDDEN(cx, cy))
- bytebuffer_puts(&output_buffer, funcs[T_HIDE_CURSOR]);
-
- cursor_x = cx;
- cursor_y = cy;
- if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y))
- write_cursor(cursor_x, cursor_y);
-}
-
-void
-tb_put_cell(int x, int y, const struct tb_cell *cell)
-{
- if ((unsigned)x >= (unsigned)back_buffer.width)
- return;
- if ((unsigned)y >= (unsigned)back_buffer.height)
- return;
- CELL(&back_buffer, x, y) = *cell;
-}
-
-void
-tb_change_cell(int x, int y, uint32_t ch, uint16_t fg, uint16_t bg)
-{
- struct tb_cell c = { ch, fg, bg };
- tb_put_cell(x, y, &c);
-}
-
-void
-tb_blit(int x, int y, int w, int h, const struct tb_cell *cells)
-{
- if (x + w < 0 || x >= back_buffer.width)
- return;
- if (y + h < 0 || y >= back_buffer.height)
- return;
- int xo = 0, yo = 0, ww = w, hh = h;
- if (x < 0) {
- xo = -x;
- ww -= xo;
- x = 0;
- }
- if (y < 0) {
- yo = -y;
- hh -= yo;
- y = 0;
- }
- if (ww > back_buffer.width - x)
- ww = back_buffer.width - x;
- if (hh > back_buffer.height - y)
- hh = back_buffer.height - y;
-
- int sy;
- struct tb_cell *dst = &CELL(&back_buffer, x, y);
- const struct tb_cell *src = cells + yo * w + xo;
- size_t size = sizeof(struct tb_cell) * ww;
-
- for (sy = 0; sy < hh; ++sy) {
- memcpy(dst, src, size);
- dst += back_buffer.width;
- src += w;
- }
-}
-
-struct tb_cell *
-tb_cell_buffer(void)
-{
- return back_buffer.cells;
-}
-
-int
-tb_poll_event(struct tb_event *event)
-{
- return wait_fill_event(event, 0);
-}
-
-int
-tb_peek_event(struct tb_event *event, int timeout)
-{
- struct timeval tv;
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
- return wait_fill_event(event, &tv);
-}
-
-int
-tb_width(void)
-{
- return termw;
-}
-
-int
-tb_height(void)
-{
- return termh;
-}
-
-void
-tb_clear(void)
-{
- if (buffer_size_change_request) {
- update_size();
- buffer_size_change_request = 0;
- }
- cellbuf_clear(&back_buffer);
-}
-
-int
-tb_select_input_mode(int mode)
-{
- if (mode) {
- if ((mode & (TB_INPUT_ESC | TB_INPUT_ALT)) == 0)
- mode |= TB_INPUT_ESC;
-
- /* technically termbox can handle that, but let's be nice and show here
- what mode is actually used */
- if ((mode & (TB_INPUT_ESC | TB_INPUT_ALT)) ==
- (TB_INPUT_ESC | TB_INPUT_ALT))
- mode &= ~TB_INPUT_ALT;
-
- inputmode = mode;
- if (mode & TB_INPUT_MOUSE) {
- bytebuffer_puts(&output_buffer, funcs[T_ENTER_MOUSE]);
- bytebuffer_flush(&output_buffer, inout);
- } else {
- bytebuffer_puts(&output_buffer, funcs[T_EXIT_MOUSE]);
- bytebuffer_flush(&output_buffer, inout);
- }
- }
- return inputmode;
-}
-
-int
-tb_select_output_mode(int mode)
-{
- if (mode)
- outputmode = mode;
- return outputmode;
-}
-
-void
-tb_set_clear_attributes(uint16_t fg, uint16_t bg)
-{
- foreground = fg;
- background = bg;
-}
-
-/* -------------------------------------------------------- */
-
-static int
-convertnum(uint32_t num, char *buf)
-{
- int i, l = 0;
- int ch;
- do {
- buf[l++] = '0' + (num % 10);
- num /= 10;
- } while (num);
- for (i = 0; i < l / 2; i++) {
- ch = buf[i];
- buf[i] = buf[l - 1 - i];
- buf[l - 1 - i] = ch;
- }
- return l;
-}
-
-static void
-write_cursor(int x, int y)
-{
- char buf[32];
- WRITE_LITERAL("\033[");
- WRITE_INT(y + 1);
- WRITE_LITERAL(";");
- WRITE_INT(x + 1);
- WRITE_LITERAL("H");
-}
-
-static void
-write_sgr(uint16_t fg, uint16_t bg)
-{
- char buf[32];
-
- if (fg == TB_DEFAULT && bg == TB_DEFAULT)
- return;
-
- switch (outputmode) {
- case TB_OUTPUT_256:
- case TB_OUTPUT_216:
- case TB_OUTPUT_GRAYSCALE:
- WRITE_LITERAL("\033[");
- if (fg != TB_DEFAULT) {
- WRITE_LITERAL("38;5;");
- WRITE_INT(fg);
- if (bg != TB_DEFAULT) {
- WRITE_LITERAL(";");
- }
- }
- if (bg != TB_DEFAULT) {
- WRITE_LITERAL("48;5;");
- WRITE_INT(bg);
- }
- WRITE_LITERAL("m");
- break;
- case TB_OUTPUT_NORMAL:
- default:
- WRITE_LITERAL("\033[");
- if (fg != TB_DEFAULT) {
- WRITE_LITERAL("3");
- WRITE_INT(fg - 1);
- if (bg != TB_DEFAULT) {
- WRITE_LITERAL(";");
- }
- }
- if (bg != TB_DEFAULT) {
- WRITE_LITERAL("4");
- WRITE_INT(bg - 1);
- }
- WRITE_LITERAL("m");
- break;
- }
-}
-
-static void
-cellbuf_init(struct cellbuf *buf, int width, int height)
-{
- buf->cells = (struct tb_cell *)malloc(
- sizeof(struct tb_cell) * width * height);
- assert(buf->cells);
- buf->width = width;
- buf->height = height;
-}
-
-static void
-cellbuf_resize(struct cellbuf *buf, int width, int height)
-{
- if (buf->width == width && buf->height == height)
- return;
-
- int oldw = buf->width;
- int oldh = buf->height;
- struct tb_cell *oldcells = buf->cells;
-
- cellbuf_init(buf, width, height);
- cellbuf_clear(buf);
-
- int minw = (width < oldw) ? width : oldw;
- int minh = (height < oldh) ? height : oldh;
- int i;
-
- for (i = 0; i < minh; ++i) {
- struct tb_cell *csrc = oldcells + (i * oldw);
- struct tb_cell *cdst = buf->cells + (i * width);
- memcpy(cdst, csrc, sizeof(struct tb_cell) * minw);
- }
-
- free(oldcells);
-}
-
-static void
-cellbuf_clear(struct cellbuf *buf)
-{
- int i;
- int ncells = buf->width * buf->height;
-
- for (i = 0; i < ncells; ++i) {
- buf->cells[i].ch = ' ';
- buf->cells[i].fg = foreground;
- buf->cells[i].bg = background;
- }
-}
-
-static void
-cellbuf_free(struct cellbuf *buf)
-{
- free(buf->cells);
-}
-
-static void
-get_term_size(int *w, int *h)
-{
- struct winsize sz;
- memset(&sz, 0, sizeof(sz));
-
- ioctl(inout, TIOCGWINSZ, &sz);
-
- *w = sz.ws_col > 0 ? sz.ws_col : 80;
- *h = sz.ws_row > 0 ? sz.ws_row : 24;
-}
-
-static void
-update_term_size(void)
-{
- struct winsize sz;
- memset(&sz, 0, sizeof(sz));
-
- ioctl(inout, TIOCGWINSZ, &sz);
-
- termw = sz.ws_col > 0 ? sz.ws_col : 80;
- termh = sz.ws_row > 0 ? sz.ws_row : 24;
-}
-
-static void
-send_attr(uint16_t fg, uint16_t bg)
-{
-#define LAST_ATTR_INIT 0xFFFF
- static uint16_t lastfg = LAST_ATTR_INIT, lastbg = LAST_ATTR_INIT;
- if (fg != lastfg || bg != lastbg) {
- bytebuffer_puts(&output_buffer, funcs[T_SGR0]);
-
- uint16_t fgcol;
- uint16_t bgcol;
-
- switch (outputmode) {
- case TB_OUTPUT_256:
- fgcol = fg & 0xFF;
- bgcol = bg & 0xFF;
- break;
-
- case TB_OUTPUT_216:
- fgcol = fg & 0xFF;
- if (fgcol > 215)
- fgcol = 7;
- bgcol = bg & 0xFF;
- if (bgcol > 215)
- bgcol = 0;
- fgcol += 0x10;
- bgcol += 0x10;
- break;
-
- case TB_OUTPUT_GRAYSCALE:
- fgcol = fg & 0xFF;
- if (fgcol > 23)
- fgcol = 23;
- bgcol = bg & 0xFF;
- if (bgcol > 23)
- bgcol = 0;
- fgcol += 0xe8;
- bgcol += 0xe8;
- break;
-
- case TB_OUTPUT_NORMAL:
- default:
- fgcol = fg & 0x0F;
- bgcol = bg & 0x0F;
- }
-
- if (fg & TB_BOLD)
- bytebuffer_puts(&output_buffer, funcs[T_BOLD]);
- if (bg & TB_BOLD)
- bytebuffer_puts(&output_buffer, funcs[T_BLINK]);
- if (fg & TB_UNDERLINE)
- bytebuffer_puts(&output_buffer, funcs[T_UNDERLINE]);
- if ((fg & TB_REVERSE) || (bg & TB_REVERSE))
- bytebuffer_puts(&output_buffer, funcs[T_REVERSE]);
-
- write_sgr(fgcol, bgcol);
-
- lastfg = fg;
- lastbg = bg;
- }
-}
-
-static void
-send_char(int x, int y, uint32_t c)
-{
- char buf[7];
- int bw = tb_utf8_unicode_to_char(buf, c);
- if (x - 1 != lastx || y != lasty)
- write_cursor(x, y);
- lastx = x;
- lasty = y;
- if (!c)
- buf[0] = ' '; // replace 0 with whitespace
- bytebuffer_append(&output_buffer, buf, bw);
-}
-
-static void
-send_clear(void)
-{
- send_attr(foreground, background);
- bytebuffer_puts(&output_buffer, funcs[T_CLEAR_SCREEN]);
- if (!IS_CURSOR_HIDDEN(cursor_x, cursor_y))
- write_cursor(cursor_x, cursor_y);
- bytebuffer_flush(&output_buffer, inout);
-
- /* we need to invalidate cursor position too and these two vars are
- * used only for simple cursor positioning optimization, cursor
- * actually may be in the correct place, but we simply discard
- * optimization once and it gives us simple solution for the case when
- * cursor moved */
- lastx = LAST_COORD_INIT;
- lasty = LAST_COORD_INIT;
-}
-
-static void
-sigwinch_handler(int xxx)
-{
- (void)xxx;
- const int zzz = 1;
- write(winch_fds[1], &zzz, sizeof(int));
-}
-
-static void
-update_size(void)
-{
- update_term_size();
- cellbuf_resize(&back_buffer, termw, termh);
- cellbuf_resize(&front_buffer, termw, termh);
- cellbuf_clear(&front_buffer);
- send_clear();
-}
-
-static int
-read_up_to(int n)
-{
- assert(n > 0);
- const int prevlen = input_buffer.len;
- bytebuffer_resize(&input_buffer, prevlen + n);
-
- int read_n = 0;
- while (read_n <= n) {
- ssize_t r = 0;
- if (read_n < n) {
- r = read(inout, input_buffer.buf + prevlen + read_n,
- n - read_n);
- }
-#ifdef __CYGWIN__
- // While linux man for tty says when VMIN == 0 && VTIME == 0, read
- // should return 0 when there is nothing to read, cygwin's read returns
- // -1. Not sure why and if it's correct to ignore it, but let's pretend
- // it's zero.
- if (r < 0)
- r = 0;
-#endif
- if (r < 0) {
- // EAGAIN / EWOULDBLOCK shouldn't occur here
- assert(errno != EAGAIN && errno != EWOULDBLOCK);
- return -1;
- } else if (r > 0) {
- read_n += r;
- } else {
- bytebuffer_resize(&input_buffer, prevlen + read_n);
- return read_n;
- }
- }
- assert(!"unreachable");
- return 0;
-}
-
-static int
-wait_fill_event(struct tb_event *event, struct timeval *timeout)
-{
- // ;-)
-#define ENOUGH_DATA_FOR_PARSING 64
- fd_set events;
- memset(event, 0, sizeof(struct tb_event));
-
- // try to extract event from input buffer, return on success
- event->type = TB_EVENT_KEY;
- if (extract_event(event, &input_buffer, inputmode))
- return event->type;
-
- // it looks like input buffer is incomplete, let's try the short path,
- // but first make sure there is enough space
- int n = read_up_to(ENOUGH_DATA_FOR_PARSING);
- if (n < 0)
- return -1;
- if (n > 0 && extract_event(event, &input_buffer, inputmode))
- return event->type;
-
- // n == 0, or not enough data, let's go to select
- while (1) {
- FD_ZERO(&events);
- FD_SET(inout, &events);
- FD_SET(winch_fds[0], &events);
- int maxfd = (winch_fds[0] > inout) ? winch_fds[0] : inout;
- int result = select(maxfd + 1, &events, 0, 0, timeout);
- if (!result)
- return 0;
-
- if (FD_ISSET(inout, &events)) {
- event->type = TB_EVENT_KEY;
- n = read_up_to(ENOUGH_DATA_FOR_PARSING);
- if (n < 0)
- return -1;
-
- if (n == 0)
- continue;
-
- if (extract_event(event, &input_buffer, inputmode))
- return event->type;
- }
- if (FD_ISSET(winch_fds[0], &events)) {
- event->type = TB_EVENT_RESIZE;
- int zzz = 0;
- read(winch_fds[0], &zzz, sizeof(int));
- buffer_size_change_request = 1;
- get_term_size(&event->w, &event->h);
- return TB_EVENT_RESIZE;
- }
- }
-}
-
-static void
-bytebuffer_reserve(struct bytebuffer *b, int cap)
-{
- if (b->cap >= cap) {
- return;
- }
-
- // prefer doubling capacity
- if (b->cap * 2 >= cap) {
- cap = b->cap * 2;
- }
-
- char *newbuf = realloc(b->buf, cap);
- b->buf = newbuf;
- b->cap = cap;
-}
-
-static void
-bytebuffer_init(struct bytebuffer *b, int cap)
-{
- b->cap = 0;
- b->len = 0;
- b->buf = 0;
-
- if (cap > 0) {
- b->cap = cap;
- b->buf = malloc(cap); // just assume malloc works always
- }
-}
-
-static void
-bytebuffer_free(struct bytebuffer *b)
-{
- if (b->buf)
- free(b->buf);
-}
-
-static void
-bytebuffer_clear(struct bytebuffer *b)
-{
- b->len = 0;
-}
-
-static void
-bytebuffer_append(struct bytebuffer *b, const char *data, int len)
-{
- bytebuffer_reserve(b, b->len + len);
- memcpy(b->buf + b->len, data, len);
- b->len += len;
-}
-
-static void
-bytebuffer_puts(struct bytebuffer *b, const char *str)
-{
- bytebuffer_append(b, str, strlen(str));
-}
-
-static void
-bytebuffer_resize(struct bytebuffer *b, int len)
-{
- bytebuffer_reserve(b, len);
- b->len = len;
-}
-
-static void
-bytebuffer_flush(struct bytebuffer *b, int fd)
-{
- write(fd, b->buf, b->len);
- bytebuffer_clear(b);
-}
-
-static void
-bytebuffer_truncate(struct bytebuffer *b, int n)
-{
- if (n <= 0)
- return;
- if (n > b->len)
- n = b->len;
- const int nmove = b->len - n;
- memmove(b->buf, b->buf + n, nmove);
- b->len -= n;
-}
diff --git a/sfm-0.4/termbox.h b/sfm-0.4/termbox.h
deleted file mode 100644
index 7f6e775..0000000
--- a/sfm-0.4/termbox.h
+++ /dev/null
@@ -1,317 +0,0 @@
-#ifndef TERMBOX_H
-#define TERMBOX_H
-
-#include <stdint.h>
-
-/* Key constants. See also struct tb_event's key field.
- *
- * These are a safe subset of terminfo keys, which exist on all popular
- * terminals. Termbox uses only them to stay truly portable.
- */
-#define TB_KEY_F1 (0xFFFF-0)
-#define TB_KEY_F2 (0xFFFF-1)
-#define TB_KEY_F3 (0xFFFF-2)
-#define TB_KEY_F4 (0xFFFF-3)
-#define TB_KEY_F5 (0xFFFF-4)
-#define TB_KEY_F6 (0xFFFF-5)
-#define TB_KEY_F7 (0xFFFF-6)
-#define TB_KEY_F8 (0xFFFF-7)
-#define TB_KEY_F9 (0xFFFF-8)
-#define TB_KEY_F10 (0xFFFF-9)
-#define TB_KEY_F11 (0xFFFF-10)
-#define TB_KEY_F12 (0xFFFF-11)
-#define TB_KEY_INSERT (0xFFFF-12)
-#define TB_KEY_DELETE (0xFFFF-13)
-#define TB_KEY_HOME (0xFFFF-14)
-#define TB_KEY_END (0xFFFF-15)
-#define TB_KEY_PGUP (0xFFFF-16)
-#define TB_KEY_PGDN (0xFFFF-17)
-#define TB_KEY_ARROW_UP (0xFFFF-18)
-#define TB_KEY_ARROW_DOWN (0xFFFF-19)
-#define TB_KEY_ARROW_LEFT (0xFFFF-20)
-#define TB_KEY_ARROW_RIGHT (0xFFFF-21)
-#define TB_KEY_MOUSE_LEFT (0xFFFF-22)
-#define TB_KEY_MOUSE_RIGHT (0xFFFF-23)
-#define TB_KEY_MOUSE_MIDDLE (0xFFFF-24)
-#define TB_KEY_MOUSE_RELEASE (0xFFFF-25)
-#define TB_KEY_MOUSE_WHEEL_UP (0xFFFF-26)
-#define TB_KEY_MOUSE_WHEEL_DOWN (0xFFFF-27)
-
-/* These are all ASCII code points below SPACE character and a BACKSPACE key. */
-#define TB_KEY_CTRL_TILDE 0x00
-#define TB_KEY_CTRL_2 0x00 /* clash with 'CTRL_TILDE' */
-#define TB_KEY_CTRL_A 0x01
-#define TB_KEY_CTRL_B 0x02
-#define TB_KEY_CTRL_C 0x03
-#define TB_KEY_CTRL_D 0x04
-#define TB_KEY_CTRL_E 0x05
-#define TB_KEY_CTRL_F 0x06
-#define TB_KEY_CTRL_G 0x07
-#define TB_KEY_BACKSPACE 0x08
-#define TB_KEY_CTRL_H 0x08 /* clash with 'CTRL_BACKSPACE' */
-#define TB_KEY_TAB 0x09
-#define TB_KEY_CTRL_I 0x09 /* clash with 'TAB' */
-#define TB_KEY_CTRL_J 0x0A
-#define TB_KEY_CTRL_K 0x0B
-#define TB_KEY_CTRL_L 0x0C
-#define TB_KEY_ENTER 0x0D
-#define TB_KEY_CTRL_M 0x0D /* clash with 'ENTER' */
-#define TB_KEY_CTRL_N 0x0E
-#define TB_KEY_CTRL_O 0x0F
-#define TB_KEY_CTRL_P 0x10
-#define TB_KEY_CTRL_Q 0x11
-#define TB_KEY_CTRL_R 0x12
-#define TB_KEY_CTRL_S 0x13
-#define TB_KEY_CTRL_T 0x14
-#define TB_KEY_CTRL_U 0x15
-#define TB_KEY_CTRL_V 0x16
-#define TB_KEY_CTRL_W 0x17
-#define TB_KEY_CTRL_X 0x18
-#define TB_KEY_CTRL_Y 0x19
-#define TB_KEY_CTRL_Z 0x1A
-#define TB_KEY_ESC 0x1B
-#define TB_KEY_CTRL_LSQ_BRACKET 0x1B /* clash with 'ESC' */
-#define TB_KEY_CTRL_3 0x1B /* clash with 'ESC' */
-#define TB_KEY_CTRL_4 0x1C
-#define TB_KEY_CTRL_BACKSLASH 0x1C /* clash with 'CTRL_4' */
-#define TB_KEY_CTRL_5 0x1D
-#define TB_KEY_CTRL_RSQ_BRACKET 0x1D /* clash with 'CTRL_5' */
-#define TB_KEY_CTRL_6 0x1E
-#define TB_KEY_CTRL_7 0x1F
-#define TB_KEY_CTRL_SLASH 0x1F /* clash with 'CTRL_7' */
-#define TB_KEY_CTRL_UNDERSCORE 0x1F /* clash with 'CTRL_7' */
-#define TB_KEY_SPACE 0x20
-#define TB_KEY_BACKSPACE2 0x7F
-#define TB_KEY_CTRL_8 0x7F /* clash with 'BACKSPACE2' */
-
-/* These are non-existing ones.
- *
- * #define TB_KEY_CTRL_1 clash with '1'
- * #define TB_KEY_CTRL_9 clash with '9'
- * #define TB_KEY_CTRL_0 clash with '0'
- */
-
-/*
- * Alt modifier constant, see tb_event.mod field and tb_select_input_mode function.
- * Mouse-motion modifier
- */
-#define TB_MOD_ALT 0x01
-#define TB_MOD_MOTION 0x02
-
-/* Colors (see struct tb_cell's fg and bg fields). */
-#define TB_DEFAULT 0x00
-#define TB_BLACK 0x01
-#define TB_RED 0x02
-#define TB_GREEN 0x03
-#define TB_YELLOW 0x04
-#define TB_BLUE 0x05
-#define TB_MAGENTA 0x06
-#define TB_CYAN 0x07
-#define TB_WHITE 0x08
-
-// #define TB_GREY 0x09
-// #define TB_RED_B 0x0A
-// #define TB_GREEN_B 0x0B
-// #define TB_YELLOW_B 0x0C
-// #define TB_BLUE_B 0x0D
-// #define TB_MAGENTA_B 0x0E
-// #define TB_CYAN_B 0x0F
-// #define TB_GREY_B 0x10
-
-/* Attributes, it is possible to use multiple attributes by combining them
- * using bitwise OR ('|'). Although, colors cannot be combined. But you can
- * combine attributes and a single color. See also struct tb_cell's fg and bg
- * fields.
- */
-#define TB_BOLD 0x0100
-#define TB_UNDERLINE 0x0200
-#define TB_REVERSE 0x0400
-
-/* A cell, single conceptual entity on the terminal screen. The terminal screen
- * is basically a 2d array of cells. It has the following fields:
- * - 'ch' is a unicode character
- * - 'fg' foreground color and attributes
- * - 'bg' background color and attributes
- */
-struct tb_cell {
- uint32_t ch;
- uint16_t fg;
- uint16_t bg;
-};
-
-#define TB_EVENT_KEY 1
-#define TB_EVENT_RESIZE 2
-#define TB_EVENT_MOUSE 3
-
-/* An event, single interaction from the user. The 'mod' and 'ch' fields are
- * valid if 'type' is TB_EVENT_KEY. The 'w' and 'h' fields are valid if 'type'
- * is TB_EVENT_RESIZE. The 'x' and 'y' fields are valid if 'type' is
- * TB_EVENT_MOUSE. The 'key' field is valid if 'type' is either TB_EVENT_KEY
- * or TB_EVENT_MOUSE. The fields 'key' and 'ch' are mutually exclusive; only
- * one of them can be non-zero at a time.
- */
-struct tb_event {
- uint8_t type;
- uint8_t mod; /* modifiers to either 'key' or 'ch' below */
- uint16_t key; /* one of the TB_KEY_* constants */
- uint32_t ch; /* unicode character */
- int32_t w;
- int32_t h;
- int32_t x;
- int32_t y;
-};
-
-/* Error codes returned by tb_init(). All of them are self-explanatory, except
- * the pipe trap error. Termbox uses unix pipes in order to deliver a message
- * from a signal handler (SIGWINCH) to the main event reading loop. Honestly in
- * most cases you should just check the returned code as < 0.
- */
-#define TB_EUNSUPPORTED_TERMINAL -1
-#define TB_EFAILED_TO_OPEN_TTY -2
-#define TB_EPIPE_TRAP_ERROR -3
-
-/* Initializes the termbox library. This function should be called before any
- * other functions. Function tb_init is same as tb_init_file("/dev/tty").
- * After successful initialization, the library must be
- * finalized using the tb_shutdown() function.
- */
-int tb_init(void);
-int tb_init_file(const char* name);
-int tb_init_fd(int inout);
-void tb_shutdown(void);
-
-/* Returns the size of the internal back buffer (which is the same as
- * terminal's window size in characters). The internal buffer can be resized
- * after tb_clear() or tb_present() function calls. Both dimensions have an
- * unspecified negative value when called before tb_init() or after
- * tb_shutdown().
- */
-int tb_width(void);
-int tb_height(void);
-
-/* Clears the internal back buffer using TB_DEFAULT color or the
- * color/attributes set by tb_set_clear_attributes() function.
- */
-void tb_clear(void);
-void tb_set_clear_attributes(uint16_t fg, uint16_t bg);
-
-/* Synchronizes the internal back buffer with the terminal. */
-void tb_present(void);
-
-#define TB_HIDE_CURSOR -1
-
-/* Sets the position of the cursor. Upper-left character is (0, 0). If you pass
- * TB_HIDE_CURSOR as both coordinates, then the cursor will be hidden. Cursor
- * is hidden by default.
- */
-void tb_set_cursor(int cx, int cy);
-
-/* Changes cell's parameters in the internal back buffer at the specified
- * position.
- */
-void tb_put_cell(int x, int y, const struct tb_cell *cell);
-void tb_change_cell(int x, int y, uint32_t ch, uint16_t fg, uint16_t bg);
-
-/* Copies the buffer from 'cells' at the specified position, assuming the
- * buffer is a two-dimensional array of size ('w' x 'h'), represented as a
- * one-dimensional buffer containing lines of cells starting from the top.
- *
- * (DEPRECATED: use tb_cell_buffer() instead and copy memory on your own)
- */
-void tb_blit(int x, int y, int w, int h, const struct tb_cell *cells);
-
-/* Returns a pointer to internal cell back buffer. You can get its dimensions
- * using tb_width() and tb_height() functions. The pointer stays valid as long
- * as no tb_clear() and tb_present() calls are made. The buffer is
- * one-dimensional buffer containing lines of cells starting from the top.
- */
-struct tb_cell *tb_cell_buffer(void);
-
-#define TB_INPUT_CURRENT 0 /* 000 */
-#define TB_INPUT_ESC 1 /* 001 */
-#define TB_INPUT_ALT 2 /* 010 */
-#define TB_INPUT_MOUSE 4 /* 100 */
-
-/* Sets the termbox input mode. Termbox has two input modes:
- * 1. Esc input mode.
- * When ESC sequence is in the buffer and it doesn't match any known
- * ESC sequence => ESC means TB_KEY_ESC.
- * 2. Alt input mode.
- * When ESC sequence is in the buffer and it doesn't match any known
- * sequence => ESC enables TB_MOD_ALT modifier for the next keyboard event.
- *
- * You can also apply TB_INPUT_MOUSE via bitwise OR operation to either of the
- * modes (e.g. TB_INPUT_ESC | TB_INPUT_MOUSE). If none of the main two modes
- * were set, but the mouse mode was, TB_INPUT_ESC mode is used. If for some
- * reason you've decided to use (TB_INPUT_ESC | TB_INPUT_ALT) combination, it
- * will behave as if only TB_INPUT_ESC was selected.
- *
- * If 'mode' is TB_INPUT_CURRENT, it returns the current input mode.
- *
- * Default termbox input mode is TB_INPUT_ESC.
- */
-int tb_select_input_mode(int mode);
-
-#define TB_OUTPUT_CURRENT 0
-#define TB_OUTPUT_NORMAL 1
-#define TB_OUTPUT_256 2
-#define TB_OUTPUT_216 3
-#define TB_OUTPUT_GRAYSCALE 4
-
-/* Sets the termbox output mode. Termbox has three output options:
- * 1. TB_OUTPUT_NORMAL => [1..8]
- * This mode provides 8 different colors:
- * black, red, green, yellow, blue, magenta, cyan, white
- * Shortcut: TB_BLACK, TB_RED, ...
- * Attributes: TB_BOLD, TB_UNDERLINE, TB_REVERSE
- *
- * Example usage:
- * tb_change_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED);
- *
- * 2. TB_OUTPUT_256 => [0..256]
- * In this mode you can leverage the 256 terminal mode:
- * 0x00 - 0x07: the 8 colors as in TB_OUTPUT_NORMAL
- * 0x08 - 0x0f: TB_* | TB_BOLD
- * 0x10 - 0xe7: 216 different colors
- * 0xe8 - 0xff: 24 different shades of grey
- *
- * Example usage:
- * tb_change_cell(x, y, '@', 184, 240);
- * tb_change_cell(x, y, '@', 0xb8, 0xf0);
- *
- * 3. TB_OUTPUT_216 => [0..216]
- * This mode supports the 3rd range of the 256 mode only.
- * But you don't need to provide an offset.
- *
- * 4. TB_OUTPUT_GRAYSCALE => [0..23]
- * This mode supports the 4th range of the 256 mode only.
- * But you dont need to provide an offset.
- *
- * Execute build/src/demo/output to see its impact on your terminal.
- *
- * If 'mode' is TB_OUTPUT_CURRENT, it returns the current output mode.
- *
- * Default termbox output mode is TB_OUTPUT_NORMAL.
- */
-int tb_select_output_mode(int mode);
-
-/* Wait for an event up to 'timeout' milliseconds and fill the 'event'
- * structure with it, when the event is available. Returns the type of the
- * event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case
- * there were no event during 'timeout' period.
- */
-int tb_peek_event(struct tb_event *event, int timeout);
-
-/* Wait for an event forever and fill the 'event' structure with it, when the
- * event is available. Returns the type of the event (one of TB_EVENT_*
- * constants) or -1 if there was an error.
- */
-int tb_poll_event(struct tb_event *event);
-
-/* Utility utf8 functions. */
-#define TB_EOF -1
-int tb_utf8_char_length(char c);
-int tb_utf8_char_to_unicode(uint32_t *out, const char *c);
-int tb_utf8_unicode_to_char(char *out, uint32_t c);
-
-#endif /* TERMBOX_H */
diff --git a/sfm-0.4/utf8.c b/sfm-0.4/utf8.c
deleted file mode 100644
index a8fbc35..0000000
--- a/sfm-0.4/utf8.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "termbox.h"
-
-static const unsigned char utf8_length[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
- 5, 6, 6, 1, 1 };
-
-static const unsigned char utf8_mask[6] = { 0x7F, 0x1F, 0x0F, 0x07, 0x03,
- 0x01 };
-
-int
-tb_utf8_char_length(char c)
-{
- return utf8_length[(unsigned char)c];
-}
-
-int
-tb_utf8_char_to_unicode(uint32_t *out, const char *c)
-{
- if (*c == 0)
- return TB_EOF;
-
- int i;
- unsigned char len = tb_utf8_char_length(*c);
- unsigned char mask = utf8_mask[len - 1];
- uint32_t result = c[0] & mask;
- for (i = 1; i < len; ++i) {
- result <<= 6;
- result |= c[i] & 0x3f;
- }
-
- *out = result;
- return (int)len;
-}
-
-int
-tb_utf8_unicode_to_char(char *out, uint32_t c)
-{
- int len = 0;
- int first;
- int i;
-
- if (c < 0x80) {
- first = 0;
- len = 1;
- } else if (c < 0x800) {
- first = 0xc0;
- len = 2;
- } else if (c < 0x10000) {
- first = 0xe0;
- len = 3;
- } else if (c < 0x200000) {
- first = 0xf0;
- len = 4;
- } else if (c < 0x4000000) {
- first = 0xf8;
- len = 5;
- } else {
- first = 0xfc;
- len = 6;
- }
-
- for (i = len - 1; i > 0; --i) {
- out[i] = (c & 0x3f) | 0x80;
- c >>= 6;
- }
- out[0] = c | first;
-
- return len;
-}
diff --git a/sfm-0.4/util.c b/sfm-0.4/util.c
deleted file mode 100644
index 4aca4e0..0000000
--- a/sfm-0.4/util.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "util.h"
-
-void *
-ecalloc(size_t nmemb, size_t size)
-{
- void *p;
- p = calloc(nmemb, size);
- FAIL_IF(p == NULL, "calloc");
- return p;
-}
-
-void *
-erealloc(void *p, size_t len)
-{
- if ((p = realloc(p, len)) == NULL)
- die("realloc: %s\n", strerror(errno));
- return p;
-}
-
-void
-die(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- if (fmt[0] != '\0' && fmt[strlen(fmt)-1] == ':') {
- (void)fputc(' ', stderr);
- perror(NULL);
- } else {
- (void)fputc('\n', stderr);
- }
-
- exit(EXIT_FAILURE);
-}
diff --git a/sfm-0.4/util.h b/sfm-0.4/util.h
deleted file mode 100644
index 2ade6d5..0000000
--- a/sfm-0.4/util.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-
-#ifndef UTIL_H
-#define UTIL_H
-
-#define MAX(A, B) ((A) > (B) ? (A) : (B))
-#define MIN(A, B) ((A) < (B) ? (A) : (B))
-#define LEN(A) (sizeof(A)/sizeof(A[0]))
-#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
-#define FAIL_IF(EXP, MSG) {if(EXP){fprintf(stderr, "[\033[31mFAILED %d\033[0m] %s\n", __LINE__, MSG);exit(EXIT_FAILURE);}}
-#define PERROR(EXP) {if(EXP){print_error(strerror(errno));}};
-
-void *ecalloc(size_t, size_t);
-void *erealloc(void*, size_t);
-void die(const char *fmt, ...);
-
-#endif /* UTIL_H */
diff --git a/surf/style/default.css b/surf/style/default.css
new file mode 100644
index 0000000..5cd091b
--- /dev/null
+++ b/surf/style/default.css
@@ -0,0 +1,15 @@
+*,div,pre,textarea,body,input,td,tr,p {
+ background-color: #202020 !important;
+ background-image: none !important;
+ color: #bbbbbb !important;
+}
+h1,h2,h3,h4 {
+ background-color: #202020 !important;
+ color: #b8ddea !important;
+}
+img {
+ opacity: .5;
+}
+img:hover {
+ opacity: 1;
+}
diff --git a/sxiv b/sxiv
deleted file mode 160000
-Subproject 2cac112dde5ffb2162f4ace7977e602878b8387
diff --git a/tabbed/config.h b/tabbed/config.h
index e9e9833..c0b980e 100644
--- a/tabbed/config.h
+++ b/tabbed/config.h
@@ -5,7 +5,7 @@
static const char font[] = "Source Code Pro:size=9";
static const char* normbgcolor = "#222222";
static const char* normfgcolor = "#cccccc";
-static const char* selbgcolor = "#555555";
+static const char* selbgcolor = "#080466";
static const char* selfgcolor = "#ffffff";
static const char before[] = "<";
static const char after[] = ">";