diff options
| author | stkhan <personal@slickd.xyz> | 2022-05-13 18:15:43 +0000 |
|---|---|---|
| committer | stkhan <personal@slickd.xyz> | 2022-05-13 18:15:43 +0000 |
| commit | 2e81fbdf15168a5b6df291b7062d120156a5ce45 (patch) | |
| tree | 57de36552c6f46e43d8520ccf65acb80ef5f6c29 | |
| parent | 7a93f153bf5e088ab6e2da6fcc0518744cfd54af (diff) | |
Removed dwm scripts, sfm, , added scroll, and added dark theme to surf
41 files changed, 1056 insertions, 4784 deletions
@@ -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
+[25T[0;0H[?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[25;0H
\ 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** - -[](https://lgtm.com/projects/g/afify/sfm/context:cpp) -[](https://ci.appveyor.com/project/afify/sfm) -[](https://frontend.code-inspector.com/public/project/19656/sfm/dashboard) -[](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, <); - return strftime(result, MAX_DTF, dtfmt, <); -} - -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, >imeout); -#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 Binary files differdeleted file mode 100644 index c7b1f8e..0000000 --- a/sfm-0.4/sfm.png +++ /dev/null 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[] = ">"; |