commit e32611cbf2489deac5a965ab21a77b11ffb94632
parent fa3342980e41e35331659a098c9cc5d688dcd301
Author: Dimitris Zervas <dzervas@dzervas.gr>
Date: Thu, 24 Jul 2014 00:10:55 +0300
Applied Evil_Bob's patch
Diffstat:
LICENSE | | | 3 | ++- |
Makefile | | | 64 | +++++++++++++++++++++++++++++++++++++--------------------------- |
arg.h | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
config.def.h | | | 3 | ++- |
config.h | | | 455 | ------------------------------------------------------------------------------- |
config.mk | | | 3 | +-- |
sandy.c | | | 517 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
7 files changed, 403 insertions(+), 703 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -1,8 +1,9 @@
MIT/X Consortium License
-© 2011 Rafael Garcia <rafael.garcia.gallego@gmail.com>
+© 2014 Rafael Garcia <rafael.garcia.gallego@gmail.com>
Raquel Garcia <raquel.garcia.bautista@gmail.com>
Dimitris Zervas <dzervas@dzervas.gr>
+ Hiltjo Posthuma <hiltjo@codemadness.org>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
diff --git a/Makefile b/Makefile
@@ -3,58 +3,68 @@
include config.mk
+.POSIX:
+.SUFFIXES: .c .o
+
+HDR = arg.h
+
SRC = sandy.c
-OBJ = ${SRC:.c=.o}
+
+OBJ = $(SRC:.c=.o)
all: options sandy
options:
@echo sandy build options:
- @echo "CFLAGS = ${CFLAGS}"
- @echo "LDFLAGS = ${LDFLAGS}"
- @echo "CC = ${CC}"
+ @echo "CFLAGS = $(CFLAGS)"
+ @echo "LDFLAGS = $(LDFLAGS)"
+ @echo "CC = $(CC)"
+
+$(OBJ): config.h config.mk
+
+.o:
+ @echo LD $@
+ @$(LD) -o $@ $< $(LDFLAGS)
.c.o:
@echo CC $<
- @${CC} -c ${CFLAGS} $<
-
-${OBJ}: config.h config.mk
+ @$(CC) -c -o $@ $< $(CFLAGS)
config.h:
@echo creating $@ from config.def.h
@cp config.def.h $@
-sandy: ${OBJ}
+sandy: $(OBJ)
@echo CC -o $@
- @${CC} -o $@ sandy.o ${LDFLAGS}
+ @$(CC) -o $@ $(OBJ) $(LDFLAGS)
clean:
@echo cleaning
- @rm -f sandy ${OBJ} sandy-${VERSION}.tar.gz
+ @rm -f sandy $(OBJ) sandy-$(VERSION).tar.gz
dist: clean
@echo creating dist tarball
- @mkdir -p sandy-${VERSION}
+ @mkdir -p sandy-$(VERSION)
@cp -R LICENSE Makefile config.mk config.def.h \
- README TODO sandy.1 ${SRC} sandy-${VERSION}
- @tar -cf sandy-${VERSION}.tar sandy-${VERSION}
- @gzip sandy-${VERSION}.tar
- @rm -rf sandy-${VERSION}
+ README TODO sandy.1 $(HDR) $(SRC) sandy-$(VERSION)
+ @tar -cf sandy-$(VERSION).tar sandy-$(VERSION)
+ @gzip sandy-$(VERSION).tar
+ @rm -rf sandy-$(VERSION)
install: all
- @echo installing executable file to ${DESTDIR}${PREFIX}/bin
- @mkdir -p ${DESTDIR}${PREFIX}/bin
- @cp -f sandy ${DESTDIR}${PREFIX}/bin
- @chmod 755 ${DESTDIR}${PREFIX}/bin/sandy
- @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
- @mkdir -p ${DESTDIR}${MANPREFIX}/man1
- @sed "s/VERSION/${VERSION}/g" < sandy.1 > ${DESTDIR}${MANPREFIX}/man1/sandy.1
- @chmod 644 ${DESTDIR}${MANPREFIX}/man1/sandy.1
+ @echo installing executable file to $(DESTDIR)$(PREFIX)/bin
+ @mkdir -p $(DESTDIR)$(PREFIX)/bin
+ @cp -f sandy $(DESTDIR)$(PREFIX)/bin
+ @chmod 755 $(DESTDIR)$(PREFIX)/bin/sandy
+ @echo installing manual page to $(DESTDIR)$(MANPREFIX)/man1
+ @mkdir -p $(DESTDIR)$(MANPREFIX)/man1
+ @sed "s/VERSION/$(VERSION)/g" < sandy.1 > $(DESTDIR)$(MANPREFIX)/man1/sandy.1
+ @chmod 644 $(DESTDIR)$(MANPREFIX)/man1/sandy.1
uninstall:
- @echo removing executable file from ${DESTDIR}${PREFIX}/bin
- @rm -f ${DESTDIR}${PREFIX}/bin/sandy
- @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
- @rm -f ${DESTDIR}${MANPREFIX}/man1/sandy.1
+ @echo removing executable file from $(DESTDIR)$(PREFIX)/bin
+ @rm -f $(DESTDIR)$(PREFIX)/bin/sandy
+ @echo removing manual page from $(DESTDIR)$(MANPREFIX)/man1
+ @rm -f $(DESTDIR)$(MANPREFIX)/man1/sandy.1
.PHONY: all options clean dist install uninstall
diff --git a/arg.h b/arg.h
@@ -0,0 +1,61 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#ifndef ARG_H__
+#define ARG_H__
+
+extern char *argv0;
+
+/* use main(int argc, char *argv[]) */
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
+ argv[0] && argv[0][1]\
+ && argv[0][0] == '-';\
+ argc--, argv++) {\
+ char argc_;\
+ char **argv_;\
+ int brk_;\
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\
+ argv++;\
+ argc--;\
+ break;\
+ }\
+ for (brk_ = 0, argv[0]++, argv_ = argv;\
+ argv[0][0] && !brk_;\
+ argv[0]++) {\
+ if (argv_ != argv)\
+ break;\
+ argc_ = argv[0][0];\
+ switch (argc_)
+
+/* Handles obsolete -NUM syntax */
+#define ARGNUM case '0':\
+ case '1':\
+ case '2':\
+ case '3':\
+ case '4':\
+ case '5':\
+ case '6':\
+ case '7':\
+ case '8':\
+ case '9'
+
+#define ARGEND }\
+ }
+
+#define ARGC() argc_
+
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ ((x), abort(), (char *)0) :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
+ (char *)0 :\
+ (brk_ = 1, (argv[0][1] != '\0')?\
+ (&argv[0][1]) :\
+ (argc--, argv++, argv[0])))
+
+#endif
diff --git a/config.def.h b/config.def.h
@@ -240,7 +240,8 @@ static const Key commkeys[] = { /* Command mode keys here */
{ .keyv.c = { 'X' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
{ .keyv.c = { 'X' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } },
/* TODO: won't work since Arg is a union */
-{ .keyv.c = { 'y' }, { t_rw, 0, 0, 0 }, f_pipero, { .m = m_sentence, .v = TOCLIP } },
+/*{ .keyv.c = { 'y' }, { t_rw, 0, 0, 0 }, f_pipero, { .m = m_sentence, .v = TOCLIP } },*/
+{ .keyv.c = { 'y' }, { t_rw, 0, 0, 0 }, f_pipero, { .v = TOCLIP } },
{ .keyv.c = { ';' }, { 0, 0, 0, 0 }, f_spawn, CMD_P },
{ .keyv.c = { ':' }, { 0, 0, 0, 0 }, f_spawn, CMD_P },
{ .keyv.c = { '\'' }, { 0, 0, 0, 0 }, f_move, { .m = m_tomark } },
diff --git a/config.h b/config.h
@@ -1,455 +0,0 @@
-/* A simplified way to customize */
-#define USE_TERM_STATUS 1
-#define BOTTOM_TITLE 0
-#define HILIGHT_CURRENT 1
-#define HILIGHT_SYNTAX 1
-#define SHOW_NONPRINT 0
-#define HANDLE_MOUSE 1
-#define VIM_BINDINGS 1
-
-/* Things unlikely to be changed, yet still in the config.h file */
-static const bool isutf8 = TRUE;
-static const char fifobase[] = "/tmp/sandyfifo.";
-static int tabstop = 8; /* Not const, as it may be changed via param */
-/* static const char systempath[] = "/etc/sandy"; */
-/* static const char userpath[] = ".sandy"; */ /* Relative to $HOME */
-
-#if SHOW_NONPRINT /* TODO: show newline character too (as $) */
-static const char tabstr[3] = { (char)0xC2, (char)0xBB, 0x00 }; /* Double right arrow */
-static const char spcstr[3] = { (char)0xC2, (char)0xB7, 0x00 }; /* Middle dot */
-static const char nlstr[2] = { '$', 0x00 }; /* '$' is tradition for EOL */
-#else
-static const char tabstr[2] = { ' ', 0 };
-static const char spcstr[2] = { ' ', 0 };
-static const char nlstr[1] = { 0 };
-#endif
-
-/* Helper config functions, not used in main code */
-static void f_pipeai(const Arg*);
-static void f_pipeline(const Arg*);
-static void f_pipenull(const Arg*);
-
-/* Args to f_spawn */
-#define PROMPT(prompt, default, cmd) { .v = (const char *[]){ "/bin/sh", "-c", \
- "dmenu -v >/dev/null 2>&1 || DISPLAY=\"\";"\
- "if [ -n \"$DISPLAY\" ]; then arg=\"`echo \\\"" default "\\\" | dmenu $DMENU_OPTS -p '" prompt "'`\";" \
- "else if slmenu -v >/dev/null 2>&1; then arg=\"`echo \\\"" default "\\\" | slmenu -t -p '" prompt "'`\";" \
- "else printf \"\033[0;0H\033[7m"prompt"\033[K\033[0m \" >&2; read -r arg; fi; fi &&" \
- "echo " cmd "\"$arg\" > ${SANDY_FIFO}", NULL } }
-
-#define FIND PROMPT("Find:", "${SANDY_FIND}", "/")
-#define FINDBW PROMPT("Find (back):", "${SANDY_FIND}", "?")
-#define PIPE PROMPT("Pipe:", "${SANDY_PIPE}", "!")
-#define SAVEAS PROMPT("Save as:", "${SANDY_FILE}", "w")
-#define REPLACE PROMPT("Replace:", "", "!echo -n ")
-#define SED PROMPT("Sed:", "", "!sed ")
-#define CMD_P PROMPT("Command:", "/\n?\nw\nq\n!\nsyntax\noffset\nicase\nro\nai\ndump", "")
-
-/* Args to f_pipe and friends, simple examples are inlined instead */
-#define TOCLIP "tee /tmp/.sandy.clipboard.$USER | xsel -ib 2>/dev/null"
-#define FROMCLIP "xsel -ob 2>/dev/null || cat /tmp/.sandy.clipboard.$USER"
-#define TOSEL "tee /tmp/.sandy.selection.$USER | xsel -i 2>/dev/null"
-#define FROMSEL "xsel -o 2>/dev/null || cat /tmp/.sandy.selection.$USER"
-#define AUTOINDENT "awk 'BEGIN{ l=\"\\n\" }; \
- { if(match($0, \"^[\t ]+[^\t ]\")) l=substr($0, RSTART, RLENGTH-1); \
- else l=\"\"; \
- if(FNR==NR && $0 ~ /^[\t ]+$/) print \"\"; \
- else print }; \
- END{ ORS=\"\"; print l }' 2>/dev/null"
-#define CAPITALIZE "awk 'BEGIN{ ORS=\"\" }; \
- { for ( i=1; i <= NF; i++) { $i=tolower($i) ; sub(\".\", substr(toupper($i),1,1) , $i) } \
- if(FNR==NF) print $0; \
- else print $0\"\\n\" }' 2>/dev/null"
-
-/* Hooks are launched from the main code */
-#define HOOK_SAVE_NO_FILE f_spawn (&(const Arg)SAVEAS)
-#undef HOOK_DELETE_ALL /* This affects every delete */
-#undef HOOK_SELECT_ALL /* This affects every selection */
-
-/* Key-bindings and stuff */
-/* WARNING: use CONTROL(ch) ONLY with '@', (caps)A-Z, '[', '\', ']', '^', '_' or '?' */
-/* otherwise it may not mean what you think. See man 7 ascii for more info */
-#define CONTROL(ch) {(ch ^ 0x40)}
-#define META(ch) { 0x1B, ch }
-
-static const Key curskeys[] = { /* Plain keys here, no CONTROL or META */
-/* keyv.i, tests, func, arg */
-{ .keyv.i = KEY_BACKSPACE, { t_rw, t_ins,0, 0 }, f_delete, { .m = m_prevchar } },
-{ .keyv.i = KEY_BACKSPACE, { 0, 0, 0, 0 }, f_move, { .m = m_prevchar } },
-{ .keyv.i = KEY_DC, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
-{ .keyv.i = KEY_DC, { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } },
-{ .keyv.i = KEY_SDC, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
-{ .keyv.i = KEY_SDC, { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } },
-{ .keyv.i = KEY_IC, { t_sel, 0, 0, 0 }, f_pipero, { .v = TOCLIP } },
-{ .keyv.i = KEY_SIC, { t_rw, 0, 0, 0 }, f_pipenull, { .v = FROMCLIP } },
-{ .keyv.i = KEY_HOME, { t_ai, 0, 0, 0 }, f_move, { .m = m_smartbol } },
-{ .keyv.i = KEY_HOME, { 0, 0, 0, 0 }, f_move, { .m = m_bol } },
-{ .keyv.i = KEY_END, { 0, 0, 0, 0 }, f_move, { .m = m_eol } },
-{ .keyv.i = KEY_SHOME, { 0, 0, 0, 0 }, f_move, { .m = m_bof } },
-{ .keyv.i = KEY_SEND, { 0, 0, 0, 0 }, f_move, { .m = m_eof } },
-{ .keyv.i = KEY_PPAGE, { 0, 0, 0, 0 }, f_move, { .m = m_prevscr } },
-{ .keyv.i = KEY_NPAGE, { 0, 0, 0, 0 }, f_move, { .m = m_nextscr } },
-{ .keyv.i = KEY_UP, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevline } },
-{ .keyv.i = KEY_UP, { 0, 0, 0, 0 }, f_move, { .m = m_prevline } },
-{ .keyv.i = KEY_DOWN, { t_sent,0, 0, 0 }, f_adjective, { .m = m_nextline } },
-{ .keyv.i = KEY_DOWN, { 0, 0, 0, 0 }, f_move, { .m = m_nextline } },
-{ .keyv.i = KEY_LEFT, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevchar } },
-{ .keyv.i = KEY_LEFT, { 0, 0, 0, 0 }, f_move, { .m = m_prevchar } },
-{ .keyv.i = KEY_RIGHT, { t_sent,0, 0, 0 }, f_adjective, { .m = m_nextchar } },
-{ .keyv.i = KEY_RIGHT, { 0, 0, 0, 0 }, f_move, { .m = m_nextchar } },
-{ .keyv.i = KEY_SLEFT, { 0, 0, 0, 0 }, f_move, { .m = m_prevword } },
-{ .keyv.i = KEY_SRIGHT, { 0, 0, 0, 0 }, f_move, { .m = m_nextword } },
-};
-
-static const Key stdkeys[] = {
-/* keyv.c, test, func, arg */
-{ .keyv.c = CONTROL('@'), { 0, 0, 0, 0 }, f_move, { .m = m_tomark } },
-{ .keyv.c = META(' '), { 0, 0, 0, 0 }, f_mark, { 0 } },
-{ .keyv.c = META('`'), { 0, 0, 0, 0 }, f_mark, { 0 } },
-{ .keyv.c = CONTROL('A'), { t_ai, 0, 0, 0 }, f_move, { .m = m_smartbol } },
-{ .keyv.c = CONTROL('A'), { 0, 0, 0, 0 }, f_move, { .m = m_bol } },
-{ .keyv.c = CONTROL('B'), { 0, 0, 0, 0 }, f_move, { .m = m_prevchar } },
-{ .keyv.c = META('b'), { 0, 0, 0, 0 }, f_move, { .m = m_prevword } },
-{ .keyv.c = CONTROL('C'), { t_warn,t_mod,0, 0 }, f_toggle, { .i = S_Running } },
-{ .keyv.c = CONTROL('C'), { t_mod, 0, 0, 0 }, f_toggle, { .i = S_Warned } },
-{ .keyv.c = CONTROL('C'), { 0, 0, 0, 0 }, f_toggle, { .i = S_Running } },
-{ .keyv.c = META('c'), { t_sel, t_rw, 0, 0 }, f_pipe, { .v = CAPITALIZE } },
-{ .keyv.c = CONTROL('D'), { t_sel, t_rw, 0, 0 }, f_pipe, { .v = TOCLIP } },
-{ .keyv.c = CONTROL('D'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } },
-{ .keyv.c = META('d'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextword } },
-{ .keyv.c = CONTROL('E'), { 0, 0, 0, 0 }, f_move, { .m = m_eol } },
-{ .keyv.c = CONTROL('F'), { 0, 0, 0, 0 }, f_move, { .m = m_nextchar } },
-{ .keyv.c = META('f'), { 0, 0, 0, 0 }, f_move, { .m = m_nextword } },
-{ .keyv.c = CONTROL('G'), { t_sel, 0, 0, 0 }, f_select, { .m = m_stay } },
-{ .keyv.c = CONTROL('H'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } },
-{ .keyv.c = CONTROL('I'), { t_rw, t_ins,0, 0 }, f_insert, { .v = "\t" } },
-{ .keyv.c = CONTROL('J'), { t_rw, t_ai, 0, 0 }, f_pipeai, { .v = AUTOINDENT } },
-{ .keyv.c = CONTROL('J'), { t_rw, t_ins,0, 0 }, f_insert, { .v = "\n" } },
-{ .keyv.c = CONTROL('J'), { 0, 0, 0, 0 }, f_move, { .m = m_nextline } },
-{ .keyv.c = CONTROL('K'), { t_eol, t_rw, 0, 0 }, f_delete, { .m = m_nextchar } },
-{ .keyv.c = CONTROL('K'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_eol } },
-{ .keyv.c = CONTROL('L'), { 0, 0, 0, 0 }, f_center, { 0 } },
-{ .keyv.c = META('l'), { t_sel, t_rw, 0, 0 }, f_pipe, { .v = "tr [A-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ] [a-zàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ]" } }, /* Lowercase */
-{ .keyv.c = CONTROL('M'), { t_rw, t_ai, 0, 0 }, f_pipeai, { .v = AUTOINDENT } } ,
-{ .keyv.c = CONTROL('M'), { t_rw, t_ins,0, 0 }, f_insert, { .v = "\n" } },
-{ .keyv.c = CONTROL('M'), { 0, 0, 0, 0 }, f_move, { .m = m_nextline } },
-{ .keyv.c = CONTROL('N'), { 0, 0, 0, 0 }, f_move, { .m = m_nextline } },
-{ .keyv.c = CONTROL('O'), { t_sel, 0, 0, 0 }, f_select, { .m = m_tosel } }, /* Swap fsel and fcur */
-{ .keyv.c = CONTROL('P'), { 0, 0, 0, 0 }, f_move, { .m = m_prevline } },
-{ .keyv.c = CONTROL('Q'), { t_rw, 0, 0, 0 }, f_toggle, { .i = S_InsEsc } },
-{ .keyv.c = CONTROL('R'), { t_redo,t_rw, 0, 0 }, f_undo, { .i = -1 } },
-{ .keyv.c = META('r'), { 0, 0, 0, 0 }, f_findbw, { 0 } },
-{ .keyv.c = CONTROL('S'), { t_sel, 0, 0, 0 }, f_findfw, { 0 } },
-{ .keyv.c = CONTROL('S'), { 0, 0, 0, 0 }, f_spawn, FIND },
-{ .keyv.c = META('s'), { 0, 0, 0, 0 }, f_findfw, { 0 } },
-{ .keyv.c = CONTROL('T'), { 0, 0, 0, 0 }, f_pipero , { .v = TOCLIP } },
-{ .keyv.c = CONTROL('U'), { t_bol, t_rw, 0, 0 }, f_delete, { .m = m_prevchar } },
-{ .keyv.c = CONTROL('U'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_bol } },
-{ .keyv.c = META('u'), { t_sel, t_rw, 0, 0 }, f_pipe, { .v = "tr [a-zàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ] [A-ZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ] | sed 's/ß/SS/g'" } }, /* Uppercase */
-{ .keyv.c = CONTROL('V'), { 0, 0, 0, 0 }, f_move, { .m = m_prevscr } },
-{ .keyv.c = META('v'), { 0, 0, 0, 0 }, f_move, { .m = m_nextscr } },
-{ .keyv.c = CONTROL('W'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevword } },
-{ .keyv.c = CONTROL('X'), { t_mod, t_rw, 0, 0 }, f_save, { 0 } },
-{ .keyv.c = CONTROL('X'), { 0, 0, 0, 0 }, f_toggle, { .i = S_Running } },
-{ .keyv.c = META('x'), { 0, 0, 0, 0 }, f_spawn, CMD_P },
-{ .keyv.c = CONTROL('Y'), { t_rw, 0, 0, 0 }, f_pipenull, { .v = FROMCLIP } },
-{ .keyv.c = CONTROL('Z'), { 0, 0, 0, 0 }, f_suspend, { 0 } },
-{ .keyv.c = CONTROL('['), { t_vis, 0, 0, 0 }, f_toggle, { .i = S_Visual } },
-#if VIM_BINDINGS
-{ .keyv.c = CONTROL('['), { t_ins, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-#else
-{ .keyv.c = CONTROL('['), { 0, 0, 0, 0 }, f_spawn, CMD_P },
-#endif
-{ .keyv.c = CONTROL('\\'),{ t_rw, 0, 0, 0 }, f_spawn, PIPE },
-{ .keyv.c = META('\\'), { t_rw, 0, 0, 0 }, f_spawn, SED },
-{ .keyv.c = CONTROL(']'), { 0, 0, 0, 0 }, f_extsel, { .i = ExtDefault } },
-{ .keyv.c = CONTROL('^'), { t_redo,t_rw, 0, 0 }, f_undo, { .i = -1 } },
-{ .keyv.c = CONTROL('^'), { t_rw, 0, 0, 0 }, f_repeat, { 0 } },
-{ .keyv.c = META('6'), { t_rw, 0, 0, 0 }, f_pipeline, { .v = "tr '\n' ' '" } }, /* Join lines */
-{ .keyv.c = META('5'), { t_sel, t_rw, 0, 0 }, f_spawn, REPLACE },
-{ .keyv.c = CONTROL('?'), { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } },
-{ .keyv.c = META(','), { 0, 0, 0, 0 }, f_move, { .m = m_bof } },
-{ .keyv.c = META('.'), { 0, 0, 0, 0 }, f_move, { .m = m_eof } },
-};
-
-#if VIM_BINDINGS
-/* TODO: add better paste support (if whole line was yanked, append above,
- * not where you are) */
-static const Key commkeys[] = { /* Command mode keys here */
-/* keyv.c, tests, func, arg */
-{ .keyv.c = { '$' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_eol } },
-{ .keyv.c = { '$' }, { 0, 0, 0, 0 }, f_move, { .m = m_eol } },
-{ .keyv.c = { '^' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_bol } },
-{ .keyv.c = { '^' }, { 0, 0, 0, 0 }, f_move, { .m = m_bol } },
-{ .keyv.c = { 'A' }, { 0, 0, 0, 0 }, f_move, { .m = m_eol } },
-{ .keyv.c = { 'A' }, { 0, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'a' }, { t_eol, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'a' }, { 0, 0, 0, 0 }, f_move, { .m = m_nextchar } },
-{ .keyv.c = { 'a' }, { 0, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'b' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevword } },
-{ .keyv.c = { 'b' }, { 0, 0, 0, 0 }, f_move, { .m = m_prevword } },
-{ .keyv.c = { 'c' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_sentence } },
-{ .keyv.c = { 'c' }, { t_rw, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'C' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_eol } },
-{ .keyv.c = { 'C' }, { t_rw, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'd' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
-{ .keyv.c = { 'd' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_sentence } },
-/*{ .keyv.c = { 'd' }, { t_rw, 0, 0, 0 }, f_pipe, { .m = m_sentence, .v = TOCLIP } }, */
-{ .keyv.c = { 'D' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_eol } },
-{ .keyv.c = { 'g' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_bof } },
-{ .keyv.c = { 'g' }, { 0, 0, 0, 0 }, f_move, { .m = m_bof } },
-{ .keyv.c = { 'G' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_eof } },
-{ .keyv.c = { 'G' }, { 0, 0, 0, 0 }, f_move, { .m = m_eof } },
-{ .keyv.c = { 'h' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevchar } },
-{ .keyv.c = { 'h' }, { 0, 0, 0, 0 }, f_move, { .m = m_prevchar } },
-{ .keyv.c = { 'i' }, { 0, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'j' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_nextline } },
-{ .keyv.c = { 'j' }, { 0, 0, 0, 0 }, f_move, { .m = m_nextline } },
-{ .keyv.c = { 'k' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_prevline } },
-{ .keyv.c = { 'k' }, { 0, 0, 0, 0 }, f_move, { .m = m_prevline } },
-{ .keyv.c = { 'l' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_nextchar } },
-{ .keyv.c = { 'l' }, { 0, 0, 0, 0 }, f_move, { .m = m_nextchar } },
-{ .keyv.c = { 'm' }, { 0, 0, 0, 0 }, f_mark, { .i = 0 } },
-{ .keyv.c = { 'n' }, { 0, 0, 0, 0 }, f_findfw, { .i = 0 } },
-{ .keyv.c = { 'N' }, { 0, 0, 0, 0 }, f_findbw, { .i = 0 } },
-{ .keyv.c = { 'o' }, { t_rw, t_ai, 0, 0 }, f_move, { .m = m_eol } },
-{ .keyv.c = { 'o' }, { t_rw, t_ai, 0, 0 }, f_pipeai, { .v = AUTOINDENT } },
-{ .keyv.c = { 'o' }, { t_rw, t_ai, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'o' }, { t_rw, 0, 0, 0 }, f_move, { .m = m_eol } },
-{ .keyv.c = { 'o' }, { t_rw, 0, 0, 0 }, f_insert, { .v = "\n" } },
-{ .keyv.c = { 'o' }, { t_rw, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'O' }, { t_rw, t_ai, 0, 0 }, f_move, { .m = m_bol } },
-{ .keyv.c = { 'O' }, { t_rw, t_ai, 0, 0 }, f_pipeai, { .v = AUTOINDENT } },
-{ .keyv.c = { 'O' }, { t_rw, t_ai, 0, 0 }, f_move, { .m = m_prevline } },
-{ .keyv.c = { 'O' }, { t_rw, t_ai, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'O' }, { t_rw, 0, 0, 0 }, f_move, { .m = m_bol } },
-{ .keyv.c = { 'O' }, { t_rw, 0, 0, 0 }, f_insert, { .v = "\n" } },
-{ .keyv.c = { 'O' }, { t_rw, 0, 0, 0 }, f_move, { .m = m_prevline } },
-{ .keyv.c = { 'O' }, { t_rw, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'p' }, { t_rw, 0, 0, 0 }, f_pipenull, { .v = FROMCLIP } },
-{ .keyv.c = { 's' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
-{ .keyv.c = { 's' }, { t_sel, t_rw, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 's' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } },
-{ .keyv.c = { 's' }, { t_rw, 0, 0, 0 }, f_toggle, { .i = S_Command } },
-{ .keyv.c = { 'u' }, { t_undo,t_rw, 0, 0 }, f_undo, { .i = 1 } },
-{ .keyv.c = { 'v' }, { 0, 0, 0, 0 }, f_toggle, { .i = S_Visual } },
-{ .keyv.c = { 'w' }, { t_sent,0, 0, 0 }, f_adjective, { .m = m_nextword } },
-{ .keyv.c = { 'w' }, { 0, 0, 0, 0 }, f_move, { .m = m_nextword } },
-{ .keyv.c = { 'x' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
-{ .keyv.c = { 'x' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_nextchar } },
-{ .keyv.c = { 'X' }, { t_sel, t_rw, 0, 0 }, f_delete, { .m = m_tosel } },
-{ .keyv.c = { 'X' }, { t_rw, 0, 0, 0 }, f_delete, { .m = m_prevchar } },
-/* TODO: won't work since Arg is a union */
-{ .keyv.c = { 'y' }, { t_rw, 0, 0, 0 }, f_pipero, { .m = m_sentence, .v = TOCLIP } },
-{ .keyv.c = { ';' }, { 0, 0, 0, 0 }, f_spawn, CMD_P },
-{ .keyv.c = { ':' }, { 0, 0, 0, 0 }, f_spawn, CMD_P },
-{ .keyv.c = { '\'' }, { 0, 0, 0, 0 }, f_move, { .m = m_tomark } },
-{ .keyv.c = { '.' }, { t_rw, 0, 0, 0 }, f_repeat, { 0 } },
-{ .keyv.c = { '/' }, { 0, 0, 0, 0 }, f_spawn, FIND },
-{ .keyv.c = { ' ' }, { 0, 0, 0, 0 }, f_move, { .m = m_nextchar } },
-/* TODO: Keybindings left:
- * e/E go to the end of the word (adj) (?)
- * r replace char (verb)
- * t/T do until char (adj)
- * i do inside (adj) (ex. diw deletes current word)
- * </> ident
- */
-};
-#endif
-
-#if HANDLE_MOUSE
-/*Mouse clicks */
-static const Click clks[] = {
-/* mouse mask, fcur / fsel, tests, func, arg */
-{BUTTON1_CLICKED, { TRUE , TRUE }, { 0, 0, 0 }, 0, { 0 } },
-{BUTTON3_CLICKED, { TRUE , FALSE }, { t_sel, 0, 0 }, f_pipero, { .v = TOSEL } },
-{BUTTON2_CLICKED, { FALSE, FALSE }, { t_rw, 0, 0 }, f_pipenull, { .v = FROMSEL } },
-/*{BUTTON4_CLICKED, { FALSE, FALSE }, { 0, 0, 0 }, f_move, { .m = m_prevscr } },*/
-/*{BUTTON5_CLICKED, { FALSE, FALSE }, { 0, 0, 0 }, f_move, { .m = m_nextscr } },*/
-/* ^^ NCurses is a sad old library.... it does not include button 5 nor
- * cursor movement in its mouse declaration by default */
-{BUTTON1_DOUBLE_CLICKED, { TRUE , TRUE }, { 0, 0, 0 }, f_extsel, { .i = ExtWord } },
-{BUTTON1_TRIPLE_CLICKED, { TRUE , TRUE }, { 0, 0, 0 }, f_extsel, { .i = ExtLines } },
-};
-#endif /* HANDLE_MOUSE */
-
-/* Commands read at the fifo */
-static const Command cmds[] = { /* REMEMBER: if(arg == 0) arg.v=regex_match */
-/* regex, tests, func arg */
-{"^([0-9]+)$", { 0, 0, 0 }, f_line , { 0 } },
-{"^/(.*)$", { 0, 0, 0 }, f_findfw, { 0 } },
-{"^\\?(.*)$", { 0, 0, 0 }, f_findbw, { 0 } },
-{"^![ \t]*(.*)$", { t_rw, 0, 0 }, f_pipe, { 0 } },
-{"^![ /t]*(.*)$", { 0, 0, 0 }, f_pipero, { 0 } },
-{"^w[ \t]*(.*)$", { t_mod, t_rw, 0 }, f_save, { 0 } },
-{"^syntax (.*)$", { 0, 0, 0 }, f_syntax, { 0 } },
-{"^offset (.*)$", { 0, 0, 0 }, f_offset, { 0 } },
-{"^icase$", { 0, 0, 0 }, f_toggle, { .i = S_CaseIns } },
-{"^ro$", { 0, 0, 0 }, f_toggle, { .i = S_Readonly } },
-{"^ai$", { 0, 0, 0 }, f_toggle, { .i = S_AutoIndent } },
-{"^dump$", { 0, 0, 0 }, f_toggle, { .i = S_DumpStdout } },
-{"^q$", { t_mod, 0, 0 }, f_toggle, { .i = S_Warned } },
-{"^q$", { 0, 0, 0 }, f_toggle, { .i = S_Running } },
-{"^q!$", { 0, 0, 0 }, f_toggle, { .i = S_Running } },
-};
-
-/* Syntax color definition */
-#define B "\\b"
-/* #define B "^| |\t|\\(|\\)|\\[|\\]|\\{|\\}|\\||$" -- Use this if \b is not in your libc's regex implementation */
-
-static const Syntax syntaxes[] = {
-#if HILIGHT_SYNTAX
-{"c", "\\.([ch](pp|xx)?|cc)$", {
- /* HiRed */ "$^",
- /* HiGreen */ B"(for|if|while|do|else|case|default|switch|try|throw|catch|operator|new|delete)"B,
- /* LoGreen */ B"(float|double|bool|char|int|short|long|sizeof|enum|void|static|const|struct|union|typedef|extern|(un)?signed|inline|((s?size)|((u_?)?int(8|16|32|64|ptr)))_t|class|namespace|template|public|protected|private|typename|this|friend|virtual|using|mutable|volatile|register|explicit)"B,
- /* HiMag */ B"(goto|continue|break|return)"B,
- /* LoMag */ "(^#(define|include(_next)?|(un|ifn?)def|endif|el(if|se)|if|warning|error|pragma))|"B"[A-Z_][0-9A-Z_]+"B"",
- /* HiBlue */ "(\\(|\\)|\\{|\\}|\\[|\\])",
- /* LoRed */ "(\"(\\\\.|[^\"])*\")",
- /* LoBlue */ "(//.*|/\\*([^*]|\\*[^/])*\\*/|/\\*([^*]|\\*[^/])*$|^([^/]|/[^*])*\\*/)",
- } },
-
-{"sh", "\\.sh$", {
- /* HiRed */ "$^",
- /* HiGreen */ "^[0-9A-Z_]+\\(\\)",
- /* LoGreen */ B"(case|do|done|elif|else|esac|exit|fi|for|function|if|in|local|read|return|select|shift|then|time|until|while)"B,
- /* HiMag */ "$^",
- /* LoMag */ "\"(\\\\.|[^\"])*\"",
- /* HiBlue */ "(\\{|\\}|\\(|\\)|\\;|\\]|\\[|`|\\\\|\\$|<|>|!|=|&|\\|)",
- /* LoRed */ "\\$\\{?[0-9A-Z_!@#$*?-]+\\}?",
- /* LoBlue */ "#.*$",
- } },
-
-{"makefile", "(Makefile[^/]*|\\.mk)$", {
- /* HiRed */ "$^",
- /* HiGreen */ "$^",
- /* LoGreen */ "\\$+[{(][a-zA-Z0-9_-]+[})]",
- /* HiMag */ B"(if|ifeq|else|endif)"B,
- /* LoMag */ "$^",
- /* HiBlue */ "^[^ ]+:",
- /* LoRed */ "[:=]",
- /* LoBlue */ "#.*$",
- } },
-
-{"man", "\\.[1-9]x?$", {
- /* HiRed */ "\\.(BR?|I[PR]?).*$",
- /* HiGreen */ "$^",
- /* LoGreen */ "\\.(S|T)H.*$",
- /* HiMag */ "\\.(br|DS|RS|RE|PD)",
- /* LoMag */ "(\\.(S|T)H|\\.TP)",
- /* HiBlue */ "\\.(BR?|I[PR]?|PP)",
- /* LoRed */ "$^",
- /* LoBlue */ "\\\\f[BIPR]",
- } },
-
-{"vala", "\\.(vapi|vala)$", {
- /* HiRed */ B"[A-Z_][0-9A-Z_]+"B,
- /* HiGreen */ B"(for|if|while|do|else|case|default|switch|get|set|value|out|ref|enum)"B,
- /* LoGreen */ B"(uint|uint8|uint16|uint32|uint64|bool|byte|ssize_t|size_t|char|double|string|float|int|long|short|this|base|transient|void|true|false|null|unowned|owned)"B,
- /* HiMag */ B"(try|catch|throw|finally|continue|break|return|new|sizeof|signal|delegate)"B,
- /* LoMag */ B"(abstract|class|final|implements|import|instanceof|interface|using|private|public|static|strictfp|super|throws)"B,
- /* HiBlue */ "(\\(|\\)|\\{|\\}|\\[|\\])",
- /* LoRed */ "\"(\\\\.|[^\"])*\"",
- /* LoBlue */ "(//.*|/\\*([^*]|\\*[^/])*\\*/|/\\*([^*]|\\*[^/])*$|^([^/]|/[^*])*\\*/)",
- } },
-{"java", "\\.java$", {
- /* HiRed */ B"[A-Z_][0-9A-Z_]+"B,
- /* HiGreen */ B"(for|if|while|do|else|case|default|switch)"B,
- /* LoGreen */ B"(boolean|byte|char|double|float|int|long|short|transient|void|true|false|null)"B,
- /* HiMag */ B"(try|catch|throw|finally|continue|break|return|new)"B,
- /* LoMag */ B"(abstract|class|extends|final|implements|import|instanceof|interface|native|package|private|protected|public|static|strictfp|this|super|synchronized|throws|volatile)"B,
- /* HiBlue */ "(\\(|\\)|\\{|\\}|\\[|\\])",
- /* LoRed */ "\"(\\\\.|[^\"])*\"",
- /* LoBlue */ "(//.*|/\\*([^*]|\\*[^/])*\\*/|/\\*([^*]|\\*[^/])*$|^([^/]|/[^*])*\\*/)",
- } },
-{"ruby", "\\.rb$", {
- /* HiRed */ "(\\$|@|@@)?"B"[A-Z]+[0-9A-Z_a-z]*",
- /* HiGreen */ B"(__FILE__|__LINE__|BEGIN|END|alias|and|begin|break|case|class|def|defined\?|do|else|elsif|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield)"B,
- /* LoGreen */ "([ ]|^):[0-9A-Z_]+"B,
- /* HiMag */ "(/([^/]|(\\/))*/[iomx]*|%r\\{([^}]|(\\}))*\\}[iomx]*)",
- /* LoMag */ "(`[^`]*`|%x\\{[^}]*\\})",
- /* HiBlue */ "(\"([^\"]|(\\\\\"))*\"|%[QW]?\\{[^}]*\\}|%[QW]?\\([^)]*\\)|%[QW]?<[^>]*>|%[QW]?\\[[^]]*\\]|%[QW]?\\$[^$]*\\$|%[QW]?\\^[^^]*\\^|%[QW]?![^!]*!|\'([^\']|(\\\\\'))*\'|%[qw]\\{[^}]*\\}|%[qw]\\([^)]*\\)|%[qw]<[^>]*>|%[qw]\\[[^]]*\\]|%[qw]\\$[^$]*\\$|%[qw]\\^[^^]*\\^|%[qw]![^!]*!)",
- /* LoRed */ "#\\{[^}]*\\}",
- /* LoBlue */ "(#[^{].*$|#$)",
- } },
-#else /* HILIGHT_SYNTAX */
-{"", "\0", { "\0", "\0", "\0", "\0", "\0", "\0", "\0", "\0" } }
-#endif /* HILIGHT_SYNTAX */
-};
-
-/* Colors */
-static const short fgcolors[LastFG] = {
- [DefFG] = -1,
- [CurFG] = (HILIGHT_CURRENT?COLOR_BLACK : -1),
- [SelFG] = COLOR_BLACK,
- [SpcFG] = COLOR_WHITE,
- [CtrlFG] = COLOR_RED,
- [Syn0FG] = COLOR_RED,
- [Syn1FG] = COLOR_GREEN,
- [Syn2FG] = COLOR_GREEN,
- [Syn3FG] = COLOR_MAGENTA,
- [Syn4FG] = COLOR_MAGENTA,
- [Syn5FG] = COLOR_BLUE,
- [Syn6FG] = COLOR_RED,
- [Syn7FG] = COLOR_BLUE,
-};
-
-static const int colorattrs[LastFG] = {
- [DefFG] = 0,
- [CurFG] = 0,
- [SelFG] = 0,
- [SpcFG] = A_DIM,
- [CtrlFG] = A_DIM,
- [Syn0FG] = A_BOLD,
- [Syn1FG] = A_BOLD,
- [Syn2FG] = 0,
- [Syn3FG] = A_BOLD,
- [Syn4FG] = 0,
- [Syn5FG] = A_BOLD,
- [Syn6FG] = 0,
- [Syn7FG] = 0,
-};
-
-static const int bwattrs[LastFG] = {
- [DefFG] = 0,
- [CurFG] = 0,
- [SelFG] = A_REVERSE,
- [SpcFG] = A_DIM,
- [CtrlFG] = A_DIM,
- [Syn0FG] = A_BOLD,
- [Syn1FG] = A_BOLD,
- [Syn2FG] = A_BOLD,
- [Syn3FG] = A_BOLD,
- [Syn4FG] = A_BOLD,
- [Syn5FG] = A_BOLD,
- [Syn6FG] = A_BOLD,
- [Syn7FG] = A_BOLD,
-};
-
-static const short bgcolors[LastBG] = {
- [DefBG] = -1,
- [CurBG] = (HILIGHT_CURRENT ? COLOR_CYAN : -1),
- [SelBG] = COLOR_YELLOW,
-};
-
-/* Helper config functions implementation */
-void /* Pipe selection from bol, then select last line only, special for autoindenting */
-f_pipeai(const Arg *arg) {
- i_sortpos(&fsel, &fcur);
- fsel.o = 0;
- f_pipe(arg);
- fsel = fcur;
-}
-
-void /* Pipe full lines including the selection */
-f_pipeline(const Arg *arg) {
- f_extsel(&(const Arg){ .i = ExtLines });
- f_pipe(arg);
-}
-
-void /* Pipe empty text */
-f_pipenull(const Arg *arg) {
- fsel = fcur;
- f_pipe(arg);
-}
diff --git a/config.mk b/config.mk
@@ -15,7 +15,7 @@ LIBS = -L/usr/lib -lc -lncurses
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L
#CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
#LDFLAGS = -s ${LIBS}
-CFLAGS = -ggdb -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
+CFLAGS = -ggdb -std=c99 -pedantic -Wall -Wextra -pedantic -O0 ${INCS} ${CPPFLAGS}
LDFLAGS = ${LIBS}
# Solaris
@@ -24,4 +24,3 @@ LDFLAGS = ${LIBS}
# compiler and linker
CC = cc
-
diff --git a/sandy.c b/sandy.c
@@ -16,8 +16,10 @@
#include <sys/wait.h>
#include <limits.h>
-#define LENGTH(x) ((int)(sizeof (x) / sizeof *(x)))
+#include "arg.h"
+
#define LINSIZ 128
+#define LEN(x) (sizeof (x) / sizeof *(x))
#define UTF8LEN(ch) ((unsigned char)ch>=0xFC ? 6 : \
((unsigned char)ch>=0xF8 ? 5 : \
((unsigned char)ch>=0xF0 ? 4 : \
@@ -170,9 +172,9 @@ static regex_t *find_res[2]; /* Compiled regex for search term */
static int sel_re = 0; /* Index to the above, we keep 2 REs so regexec does not segfault */
static int ch; /* Used to store input */
static char c[7]; /* Used to store input */
-static char *fifopath = NULL; /* Path to command fifo */
+static char fifopath[PATH_MAX]; /* Path to command fifo */
static char *filename = NULL; /* Path to file loade on buffer */
-static char *title = NULL; /* Screen title */
+static char title[BUFSIZ]; /* Screen title */
static char *tmptitle = NULL; /* Screen title, temporary */
static char *tsl_str = NULL; /* String to print to status line */
static char *fsl_str = NULL; /* String to come back from status line */
@@ -192,6 +194,11 @@ static Arg varg; /* Arguments of the verb (some will be ove
static int vi; /* Helping var to store place of verb in key chain */
static int multiply = 1; /* Times to replay a command */
+/* allocate memory or die. */
+static void *ecalloc(size_t, size_t);
+static void *erealloc(void *, size_t);
+static char *estrdup(const char *);
+
/* Functions */
/* f_* functions can be linked to an action or keybinding */
static void f_adjective(const Arg *);
@@ -224,10 +231,10 @@ static void i_advpos(Filepos * pos, int o);
static void i_calcvlen(Line * l);
static void i_cleanup(int);
static bool i_deltext(Filepos, Filepos);
-static void i_die(char *str);
+static void i_die(const char *str);
static void i_dirtyrange(Line *, Line *);
static bool i_dotests(bool(*const a[])(void));
-static void i_dokeys(const Key[], int);
+static void i_dokeys(const Key[], unsigned int);
static void i_edit(void);
static void i_find(bool);
static char *i_gettext(Filepos, Filepos);
@@ -241,7 +248,7 @@ static void i_readfifo(void);
static void i_readfile(char *);
static void i_resize(void);
static Filepos i_scrtofpos(int, int);
-static bool i_setfindterm(char *);
+static bool i_setfindterm(const char *);
static void i_setup(void);
static void i_sigwinch(int);
static void i_sigcont(int);
@@ -288,9 +295,43 @@ static Filepos m_tosel(Filepos);
#include "config.h"
/* Some extra stuff that depends on config.h */
-static regex_t *cmd_res[LENGTH(cmds)];
-static regex_t *syntax_file_res[LENGTH(syntaxes)];
-static regex_t *syntax_res[LENGTH(syntaxes)][SYN_COLORS];
+static regex_t *cmd_res[LEN(cmds)];
+static regex_t *syntax_file_res[LEN(syntaxes)];
+static regex_t *syntax_res[LEN(syntaxes)][SYN_COLORS];
+
+char *argv0;
+
+static void *
+ecalloc(size_t nmemb, size_t size) {
+ void *p;
+
+ p = calloc(nmemb, size);
+ if(p == NULL)
+ i_die("Can't calloc.\n");
+ return p;
+}
+
+static void *
+erealloc(void *ptr, size_t size) {
+ void *p;
+
+ p = realloc(ptr, size);
+ if(p == NULL) {
+ free(ptr);
+ i_die("Can't realloc.\n");
+ }
+ return p;
+}
+
+static char *
+estrdup(const char *s) {
+ char *p;
+
+ p = strdup(s);
+ if(p == NULL)
+ i_die("Can't strdup.\n");
+ return p;
+}
/* F_* FUNCTIONS
* Can be linked to an action or keybinding. Always return void and take
@@ -310,9 +351,12 @@ f_adjective(const Arg * arg) {
i_multiply(verb, varg);
}
-/* Make cursor line the one in the middle of the screen if possible, refresh screen */
+/* Make cursor line the one in the middle of the screen if possible,
+ * refresh screen */
void
f_center(const Arg * arg) {
+ (void) arg;
+
int i = LINESABS / 2;
scrline = fcur.l;
@@ -333,6 +377,7 @@ f_delete(const Arg * arg) {
i_sortpos(&pos0, &pos1);
s = i_gettext(pos0, pos1);
i_addundo(FALSE, pos0, pos1, s);
+ free(s);
if(i_deltext(pos0, pos1))
fcur = pos0;
else
@@ -356,10 +401,12 @@ f_extsel(const Arg * arg) {
fcur = m_nextword(fcur);
break;
case ExtLines:
- fsel.o = 0, fcur.o = fcur.l->len;
+ fsel.o = 0;
+ fcur.o = fcur.l->len;
break;
case ExtAll:
- fsel.l = fstline, fcur.l = lstline;
+ fsel.l = fstline;
+ fcur.l = lstline;
f_extsel(&(const Arg) { .i = ExtLines });
break;
case ExtDefault:
@@ -394,16 +441,15 @@ f_insert(const Arg * arg) {
newcur = i_addtext((char *) arg->v, fcur);
- if((statusflags & S_GroupUndo) && undos && (undos->flags & UndoIns)
- && fcur.o == undos->endo && undos->endl == i_lineno(fcur.l)
- && ((char *) arg->v)[0] != '\n')
+ if((statusflags & S_GroupUndo) && undos && (undos->flags & UndoIns) &&
+ fcur.o == undos->endo && undos->endl == i_lineno(fcur.l) &&
+ ((char *) arg->v)[0] != '\n') {
i_addtoundo(newcur, arg->v);
- else {
- i_addundo(TRUE, fcur, newcur, strdup((char *) arg->v));
+ } else {
+ i_addundo(TRUE, fcur, newcur, (char *) arg->v);
if(fcur.l != newcur.l)
fsel = newcur;
}
-
fcur = fsel = newcur;
statusflags |= (S_Modified | S_GroupUndo);
lastaction = LastInsert;
@@ -414,7 +460,9 @@ void
f_line(const Arg * arg) {
long int l;
- l = atoi(arg->v); /* TODO: strtol */
+ l = atoi(arg->v);
+ if(!l)
+ l = 1;
fcur.l = i_lineat(l);
if(fcur.o > fcur.l->len)
fcur.o = fcur.l->len;
@@ -424,6 +472,8 @@ f_line(const Arg * arg) {
/* Set mark at current position */
void
f_mark(const Arg * arg) {
+ (void) arg;
+
fmrk = fcur;
}
@@ -438,13 +488,14 @@ f_move(const Arg * arg) {
/* Got to atoi(arg->v) position in the current line */
void
f_offset(const Arg * arg) {
- fcur.o = atoi(arg->v); /* TODO: strtol */
+ fcur.o = atoi(arg->v);
if(fcur.o > fcur.l->len)
fcur.o = fcur.l->len;
FIXNEXT(fcur);
}
-/* Pipe selection through arg->v external command. Your responsibility: call only if t_rw() */
+/* Pipe selection through arg->v external command. Your responsibility:
+ * call only if t_rw() */
void
f_pipe(const Arg * arg) {
i_pipetext(arg->v);
@@ -452,9 +503,12 @@ f_pipe(const Arg * arg) {
lastaction = LastPipe;
}
-/* Pipe selection through arg->v external command but do not update text on screen */
+/* Pipe selection through arg->v external command but do not update text
+ * on screen */
void
f_pipero(const Arg * arg) {
+ (void) arg;
+
long oldsf = statusflags;
statusflags |= S_Readonly;
@@ -466,6 +520,8 @@ f_pipero(const Arg * arg) {
/* Repeat the last action. Your responsibility: call only if t_rw() */
void
f_repeat(const Arg * arg) {
+ (void) arg;
+
i_sortpos(&fsel, &fcur);
switch (lastaction) {
case LastDelete:
@@ -494,7 +550,7 @@ f_save(const Arg * arg) {
if(arg && arg->v && *((char *) arg->v)) {
statusflags &= ~S_DumpStdout;
free(filename);
- filename = strdup((char *) arg->v);
+ filename = estrdup((char *) arg->v);
setenv(envs[EnvFile], filename, 1);
} else if(filename == NULL && !(statusflags & S_DumpStdout)) {
unsetenv(envs[EnvFile]);
@@ -546,6 +602,8 @@ f_spawn(const Arg * arg) {
void
f_suspend(const Arg * arg) {
+ (void) arg;
+
endwin();
signal(SIGCONT, i_sigcont);
raise(SIGSTOP);
@@ -554,11 +612,12 @@ f_suspend(const Arg * arg) {
/* Set syntax with name arg->v */
void
f_syntax(const Arg * arg) {
- int i, j;
+ unsigned int i, j;
statusflags |= S_DirtyScr;
- for(i = 0; i < LENGTH(syntaxes); i++)
- if((arg && arg->v) ? !strcmp(arg->v, syntaxes[i].name)
+ for(i = 0; i < LEN(syntaxes); i++)
+ if((arg && arg->v)
+ ? !strcmp(arg->v, syntaxes[i].name)
: !regexec(syntax_file_res[i], filename, 0, NULL, 0)) {
for(j = 0; j < SYN_COLORS; j++) {
if((syntx >= 0) && syntax_res[syntx][j])
@@ -597,7 +656,8 @@ f_toggle(const Arg * arg) {
}
}
-/* Undo last action if arg->i >=0, redo otherwise. Your responsibility: call only if t_undo() / t_redo() */
+/* Undo last action if arg->i >=0, redo otherwise. Your responsibility:
+ * call only if t_undo() / t_redo() */
void
f_undo(const Arg * arg) {
Filepos start, end;
@@ -647,14 +707,14 @@ void
i_addtoundo(Filepos newend, const char *s) {
size_t oldsiz, newsiz;
+ if(!undos)
+ return;
oldsiz = strlen(undos->str);
newsiz = strlen(s);
undos->endl = i_lineno(newend.l);
undos->endo = newend.o;
- if((undos->str = (char *) realloc(undos->str, 1 + oldsiz + newsiz)) == NULL)
- i_die("Can't malloc.\n");
-
+ undos->str = (char *) erealloc(undos->str, 1 + oldsiz + newsiz);
strncat(undos->str, s, newsiz);
}
@@ -665,7 +725,7 @@ i_addundo(bool ins, Filepos start, Filepos end, char *s) {
if(!s || !*s)
return;
- if(statusflags & S_GroupUndo) {
+ if(undos && (statusflags & S_GroupUndo)) {
end.l = i_lineat((undos->endl - undos->startl) + i_lineno(end.l));
i_addtoundo(end, s);
return;
@@ -674,15 +734,14 @@ i_addundo(bool ins, Filepos start, Filepos end, char *s) {
/* Once you make a change, the old redos go away */
if(redos)
i_killundos(&redos);
- if((u = (Undo *) calloc(1, sizeof(Undo))) == NULL)
- i_die("Can't malloc.\n");
+ u = (Undo *) ecalloc(1, sizeof(Undo));
u->flags = (ins ? UndoIns : 0);
u->startl = i_lineno(start.l);
u->endl = i_lineno(end.l);
u->starto = start.o;
u->endo = end.o;
- u->str = s;
+ u->str = estrdup(s);
u->prev = undos;
undos = u;
}
@@ -699,10 +758,8 @@ i_addtext(char *buf, Filepos pos) {
for(c = buf[0]; c != '\0'; c = buf[++i]) {
/* newline / line feed */
if(c == '\n' || c == '\r') {
- if(((lnew = (Line *) malloc(sizeof(Line))) == NULL)
- || ((lnew->c = calloc(1, LINSIZ)) == NULL))
- i_die("Can't malloc.\n");
- lnew->c[0] = '\0';
+ lnew = (Line *)ecalloc(1, sizeof(Line));
+ lnew->c = ecalloc(1, LINSIZ);
lnew->dirty = l->dirty = TRUE;
lnew->len = lnew->vlen = 0;
lnew->mul = 1;
@@ -726,9 +783,8 @@ i_addtext(char *buf, Filepos pos) {
o = il = 0;
} else {
/* Regular char */
- /* TODO: handle realloc error */
if(2 + (l->len) >= LINSIZ * (l->mul))
- l->c = (char *) realloc(l->c, LINSIZ * (++(l->mul)));
+ l->c = (char *) erealloc(l->c, LINSIZ * (++(l->mul)));
memmove(l->c + il + o + 1, l->c + il + o,
(1 + l->len - (il + o)));
l->c[il + o] = c;
@@ -777,22 +833,21 @@ i_calcvlen(Line * l) {
/* Cleanup and exit */
void
i_cleanup(int sig) {
- int i;
+ unsigned int i;
i_killundos(&undos);
i_killundos(&redos);
close(fifofd);
unlink(fifopath);
- free(fifopath);
free(filename);
- free(title);
- for(i = 0; i < LENGTH(cmds); i++)
+ for(i = 0; i < LEN(cmds); i++)
regfree(cmd_res[i]);
- for(i = 0; i < LENGTH(syntaxes); i++)
+ for(i = 0; i < LEN(syntaxes); i++)
regfree(syntax_file_res[i]);
- if(syntx >= 0)
+ if(syntx >= 0) {
for(i = 0; i < SYN_COLORS; i++)
regfree(syntax_res[syntx][i]);
+ }
regfree(find_res[0]);
regfree(find_res[1]);
endwin();
@@ -801,7 +856,7 @@ i_cleanup(int sig) {
/* Quit less gracefully */
void
-i_die(char *str) {
+i_die(const char *str) {
reset_shell_mode();
fputs(str, stderr);
exit(EXIT_FAILURE);
@@ -878,23 +933,23 @@ i_dotests(bool(*const a[])(void)) {
int i;
for(i = 0; a[i]; i++) {
- if(!(a[i]()))
+ if(!a[i]())
return FALSE;
}
return TRUE;
}
void
-i_dokeys(const Key bindings[], int length_bindings) {
- int index, i, j;
+i_dokeys(const Key bindings[], unsigned int length_bindings) {
+ unsigned int index, i, j;
for(index = 0; index < length_bindings; index++) {
- if(((bindings[index].keyv.c
- && memcmp(c, bindings[index].keyv.c,
- sizeof bindings[index].keyv.c) == 0)
- || (bindings[index].keyv.i
- && ch == bindings[index].keyv.i))
- && i_dotests(bindings[index].test)) {
+ if(((bindings[index].keyv.c &&
+ memcmp(c, bindings[index].keyv.c,
+ sizeof bindings[index].keyv.c) == 0) ||
+ (bindings[index].keyv.i && ch == bindings[index].keyv.i)) &&
+ i_dotests(bindings[index].test)) {
+
if(bindings[index].func != f_insert)
statusflags &= ~(S_GroupUndo);
@@ -942,11 +997,11 @@ i_dokeys(const Key bindings[], int length_bindings) {
(bindings[i + 1].keyv.i &&
bindings[i + 1].keyv.i == bindings[index].keyv.i)) {
- for(j = 0; j < LENGTH(bindings[i].test); j++) {
+ for(j = 0; j < LEN(bindings[i].test); j++) {
if(bindings[i].test[j] != bindings[i + 1].test[j])
break;
}
- if(j == LENGTH(bindings[i].test))
+ if(j == LEN(bindings[i].test))
continue;
}
}
@@ -985,8 +1040,8 @@ i_edit(void) {
FD_SET(0, &fds);
FD_SET(fifofd, &fds);
signal(SIGWINCH, i_sigwinch);
- if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) == -1
- && errno == EINTR) {
+ if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) == -1 &&
+ errno == EINTR) {
signal(SIGWINCH, SIG_IGN);
continue;
}
@@ -1008,7 +1063,7 @@ i_edit(void) {
i_mouse();
else
#endif /* HANDLE_MOUSE */
- i_dokeys(curskeys, LENGTH(curskeys));
+ i_dokeys(curskeys, LEN(curskeys));
continue;
}
@@ -1028,18 +1083,16 @@ i_edit(void) {
}
if(!(statusflags & S_InsEsc) && ISCTRL(c[0])) {
- i_dokeys(stdkeys, LENGTH(stdkeys));
+ i_dokeys(stdkeys, LEN(stdkeys));
continue;
}
statusflags &= ~(S_InsEsc);
- /* TODO: format if else */
if(t_rw() && t_ins()) {
f_insert(&(const Arg) { .v = c });
}
#if VIM_BINDINGS
else if(!t_ins()) {
- /* TODO: use isdigit() */
if(ch >= '0' && ch <= '9' && !(statusflags & S_Parameter)) {
if(statusflags & S_Multiply) {
multiply *= 10;
@@ -1049,7 +1102,7 @@ i_edit(void) {
multiply = (int) ch - '0';
}
} else {
- i_dokeys(commkeys, LENGTH(commkeys));
+ i_dokeys(commkeys, LEN(commkeys));
}
}
#endif /* VIM_BINDINGS */
@@ -1063,7 +1116,7 @@ i_edit(void) {
void
i_find(bool fw) {
char *s, *subs;
- int wp, _so, _eo, status;
+ int wp, _so, _eo, status, flags;
Filepos start, end;
regmatch_t result[1];
@@ -1073,20 +1126,23 @@ i_find(bool fw) {
end.o = lstline->len;
i_sortpos(&fsel, &fcur);
- for(wp = 0; wp < 2; free(s), wp++) {
- if(wp)
+ for(wp = 0; wp < 2; wp++) {
+ if(wp > 0)
s = i_gettext(start, end);
else if(fw)
s = i_gettext(fcur, end);
else
s = i_gettext(start, fsel);
- if((status = regexec(find_res[sel_re], s, 1, result,
- (fw ? (fcur.o == 0 ? 0 : REG_NOTBOL) : fsel.o ==
- fsel.l->len ? 0 : REG_NOTEOL))) == 0) {
+ flags = 0;
+ if(fw && (fcur.o != 0))
+ flags = REG_NOTBOL;
+ else if(!fw && (fsel.o != fsel.l->len))
+ flags = REG_NOTEOL;
+ if((status = regexec(find_res[sel_re], s, 1, result, flags)) == 0) {
f_mark(NULL);
- if(wp || !fw)
+ if(wp > 0 || !fw)
fcur = start;
fsel = fcur;
_so = result[0].rm_so;
@@ -1096,8 +1152,9 @@ i_find(bool fw) {
while(!regexec(find_res[sel_re], subs, 1,
result, REG_NOTBOL)
&& result[0].rm_eo) {
- /* This is blatantly over-simplified: do not try to match an
- * empty string backwards as it will match the first hit on the file. */
+ /* This is blatantly over-simplified: do not try to match
+ * an empty string backwards as it will match the first hit
+ * on the file. */
_so = _eo + result[0].rm_so;
_eo += result[0].rm_eo;
subs = &s[_eo];
@@ -1107,6 +1164,7 @@ i_find(bool fw) {
i_advpos(&fcur, _eo);
wp++;
}
+ free(s);
}
}
@@ -1120,7 +1178,7 @@ i_gettext(Filepos pos0, Filepos pos1) {
for(l = pos0.l; l != pos1.l->next; l = l->next)
i += 1 + (l == pos1.l ? pos1.o : l->len) - (l == pos0.l ? pos0.o : 0);
- buf = calloc(1, i);
+ buf = ecalloc(1, i);
for(l = pos0.l, i = 0; l != pos1.l->next; l = l->next) {
memcpy(buf + i, l->c + (l == pos0.l ? pos0.o : 0),
(l == pos1.l ? pos1.o : l->len) - (l == pos0.l ? pos0.o : 0));
@@ -1149,6 +1207,7 @@ Line *
i_lineat(unsigned long il) {
unsigned long i;
Line *l;
+
for(i = 1, l = fstline; i != il && l && l->next; i++)
l = l->next;
return l;
@@ -1168,8 +1227,8 @@ i_lineno(Line * l0) {
/* Process mouse input */
void
i_mouse(void) {
- int i;
- static MEVENT ev;
+ unsigned int i;
+ MEVENT ev;
Filepos f;
if(getmouse(&ev) == ERR)
@@ -1177,8 +1236,9 @@ i_mouse(void) {
if(!wmouse_trafo(textwin, &ev.y, &ev.x, FALSE))
return;
- for(i = 0; i < LENGTH(clks); i++)
- /* Warning! cursor placement code takes place BEFORE tests are taken into account */
+ for(i = 0; i < LEN(clks); i++)
+ /* Warning! cursor placement code takes place BEFORE tests are taken
+ * into account */
if(ev.bstate & clks[i].mask) {
/* While this allows to extend the selection, it may cause some confusion */
f = i_scrtofpos(ev.x, ev.y);
@@ -1269,16 +1329,17 @@ i_pipetext(const char *cmd) {
close(pout[1]);
close(perr[1]);
if(t_rw()) {
- i_addundo(FALSE, fsel, fcur, strdup(s));
- undos->flags ^= RedoMore;
+ i_addundo(FALSE, fsel, fcur, s);
+ if(undos)
+ undos->flags ^= RedoMore;
i_deltext(fsel, fcur);
fcur = fsel;
}
fcntl(pin[1], F_SETFL, O_NONBLOCK);
fcntl(pout[0], F_SETFL, O_NONBLOCK);
fcntl(perr[0], F_SETFL, O_NONBLOCK);
- buf = calloc(1, BUFSIZ + 1);
- ebuf = calloc(1, BUFSIZ + 1);
+ buf = ecalloc(1, BUFSIZ + 1);
+ ebuf = ecalloc(1, BUFSIZ + 1);
FD_ZERO(&fdO);
FD_SET(pin[1], &fdO);
FD_ZERO(&fdI);
@@ -1287,8 +1348,8 @@ i_pipetext(const char *cmd) {
tv.tv_sec = 5;
tv.tv_usec = 0;
nw = s ? strlen(s) : 0;
- while(select(FD_SETSIZE, &fdI, &fdO, NULL, &tv) && (nw > 0
- || nr > 0)) {
+ while(select(FD_SETSIZE, &fdI, &fdO, NULL, &tv) > 0 &&
+ (nw > 0 || nr > 0)) {
fflush(NULL);
if(FD_ISSET(pout[0], &fdI) && nr > 0) {
nr = read(pout[0], buf, BUFSIZ);
@@ -1298,15 +1359,16 @@ i_pipetext(const char *cmd) {
break; /* ...not seen it yet */
if(nr && t_rw()) {
auxp = i_addtext(buf, fcur);
- i_addundo(TRUE, fcur, auxp,
- strdup(buf));
- undos->flags ^= RedoMore | UndoMore;
+ i_addundo(TRUE, fcur, auxp, buf);
+ if(undos)
+ undos->flags ^= RedoMore | UndoMore;
fcur = auxp;
}
- } else if(nr > 0)
+ } else if(nr > 0) {
FD_SET(pout[0], &fdI);
- else
+ } else {
FD_CLR(pout[0], &fdI);
+ }
if(FD_ISSET(perr[0], &fdI) && nerr > 0) {
/* Blatant TODO: take last line of stderr and copy as tmptitle */
nerr = read(perr[0], ebuf, BUFSIZ);
@@ -1314,10 +1376,11 @@ i_pipetext(const char *cmd) {
tmptitle = "WARNING! command reported an error!!!";
if(nerr < 0)
break;
- } else if(nerr > 0)
+ } else if(nerr > 0) {
FD_SET(perr[0], &fdI);
- else
+ } else {
FD_CLR(perr[0], &fdI);
+ }
if(FD_ISSET(pin[1], &fdO) && nw > 0) {
written = write(pin[1], &(s[iw]),
(nw < BUFSIZ ? nw : BUFSIZ));
@@ -1325,16 +1388,18 @@ i_pipetext(const char *cmd) {
break; /* broken pipe? */
iw += (nw < BUFSIZ ? nw : BUFSIZ);
nw -= written;
- } else if(nw > 0)
+ } else if(nw > 0) {
FD_SET(pin[1], &fdO);
- else {
+ } else {
if(!closed++)
close(pin[1]);
FD_ZERO(&fdO);
}
}
- if(t_rw())
- undos->flags ^= RedoMore;
+ if(t_rw()) {
+ if(undos)
+ undos->flags ^= RedoMore;
+ }
free(buf);
free(ebuf);
if(!closed)
@@ -1350,8 +1415,6 @@ i_pipetext(const char *cmd) {
close(perr[0]);
close(perr[1]);
}
-
- /* Things I want back to normal */
free(s);
}
@@ -1360,25 +1423,29 @@ void
i_readfifo(void) {
char *buf, *tofree;
regmatch_t result[2];
- int i;
-
- if((buf = tofree = calloc(1, BUFSIZ + 1)) == NULL)
- i_die("Can't malloc.\n");
- i = read(fifofd, buf, BUFSIZ);
- buf[i] = '\0';
- buf = strtok(buf, "\n");
- while(buf != NULL) {
- for(i = 0; i < LENGTH(cmds); i++)
- if(!regexec(cmd_res[i], buf, 2, result, 0)
- && i_dotests(cmds[i].test)) {
- *(buf + result[1].rm_eo) = '\0';
- if(cmds[i].arg.i > 0)
- cmds[i].func(&(cmds[i].arg));
- else
- cmds[i].func(&(const Arg) { .v = (buf + result[1].rm_so) });
- break;
+ unsigned int i;
+ int r;
+
+ tofree = ecalloc(1, BUFSIZ + 1);
+ buf = tofree;
+ r = read(fifofd, buf, BUFSIZ);
+ if(r != -1) {
+ buf[r] = '\0';
+ buf = strtok(buf, "\n");
+ while(buf != NULL) {
+ for(i = 0; i < LEN(cmds); i++) {
+ if(!regexec(cmd_res[i], buf, 2, result, 0) &&
+ i_dotests(cmds[i].test)) {
+ *(buf + result[1].rm_eo) = '\0';
+ if(cmds[i].arg.i > 0)
+ cmds[i].func(&(cmds[i].arg));
+ else
+ cmds[i].func(&(const Arg) { .v = (buf + result[1].rm_so) });
+ break;
+ }
}
- buf = strtok(NULL, "\n");
+ buf = strtok(NULL, "\n");
+ }
}
free(tofree);
@@ -1395,30 +1462,41 @@ void
i_readfile(char *fname) {
int fd;
ssize_t n;
- char *buf = NULL;
+ char *buf = NULL, *linestr = "1";
if(fname == NULL || !strcmp(fname, "-")) {
fd = 0;
reset_shell_mode();
} else {
- filename = strdup(fname);
+ free(filename);
+ filename = estrdup(fname);
setenv(envs[EnvFile], filename, 1);
- f_syntax(NULL); /* Try to guess a syntax */
if((fd = open(filename, O_RDONLY)) == -1) {
- tmptitle = "WARNING! Can't read file!!!";
- return;
+ /* start at line number if specified, NOTE that filenames
+ * containing ':' are possible. */
+ if((linestr = strrchr(filename, ':'))) {
+ *(linestr++) = '\0';
+ setenv(envs[EnvFile], filename, 1);
+ fd = open(filename, O_RDONLY);
+ } else {
+ linestr = "1";
+ }
+ if(fd == -1) {
+ tmptitle = "WARNING! Can't read file!!!";
+ return;
+ }
}
+ f_syntax(NULL); /* Try to guess a syntax */
}
- if((buf = calloc(1, BUFSIZ + 1)) == NULL)
- i_die("Can't malloc.\n");
+ buf = ecalloc(1, BUFSIZ + 1);
while((n = read(fd, buf, BUFSIZ)) > 0) {
buf[n] = '\0';
fcur = i_addtext(buf, fcur);
}
- if(fd > 0)
+ if(fd > 0) {
close(fd);
- else {
+ } else {
if((fd = open("/dev/tty", O_RDONLY)) == -1)
i_die("Can't reopen stdin.\n");
dup2(fd, 0);
@@ -1429,6 +1507,7 @@ i_readfile(char *fname) {
fcur.l = fstline;
fcur.o = 0;
fsel = fcur;
+ f_line(&(const Arg) { .v = linestr });
}
/* Handle term resize, ugly. TODO: clean and change */
@@ -1445,7 +1524,7 @@ i_resize(void) {
return;
result = ioctl(fd, TIOCGWINSZ, &ws);
close(fd);
- if(result < 0)
+ if(result == -1)
return;
cols = ws.ws_col;
lines = ws.ws_row;
@@ -1467,7 +1546,7 @@ i_scrtofpos(int x, int y) {
pos.o = pos.l->len;
for(l = scrline, irow = 0; l && irow < LINESABS; l = l->next, irow += vlines) {
vlines = VLINES(l);
- for(ixrow = ivchar = 0; ixrow < vlines && (irow + ixrow) < LINESABS; ixrow++)
+ for(ixrow = ivchar = 0; ixrow < vlines && (irow + ixrow) < LINESABS; ixrow++) {
if(irow + ixrow == y) {
pos.l = l;
pos.o = 0;
@@ -1480,6 +1559,7 @@ i_scrtofpos(int x, int y) {
pos.o = pos.l->len;
break;
}
+ }
}
return pos;
}
@@ -1488,26 +1568,28 @@ i_scrtofpos(int x, int y) {
/* Update find_res[sel_re] and sel_re. Return TRUE if find term is a valid
RE or NULL */
bool
-i_setfindterm(char *find_term) {
+i_setfindterm(const char *find_term) {
+ int flags;
+
/* Modify find term; use NULL to repeat search */
- if(find_term) {
- if(!regcomp(find_res[sel_re ^ 1], find_term,
- REG_EXTENDED | REG_NEWLINE | (statusflags & S_CaseIns
- ? REG_ICASE : 0))) {
- sel_re ^= 1;
- setenv(envs[EnvFind], find_term, 1);
- return TRUE;
- } else {
- return FALSE;
- }
+ if(!find_term)
+ return TRUE;
+
+ flags = REG_EXTENDED | REG_NEWLINE;
+ if(statusflags & S_CaseIns)
+ flags |= REG_ICASE;
+ if(!regcomp(find_res[sel_re ^ 1], find_term, flags)) {
+ sel_re ^= 1;
+ setenv(envs[EnvFind], find_term, 1);
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
/* Setup everything */
void
i_setup(void) {
- int i, j;
+ unsigned int i, j;
Line *l = NULL;
/* Signal handling, default */
@@ -1517,33 +1599,28 @@ i_setup(void) {
signal(SIGTERM, i_cleanup);
/* Some allocs */
- title = calloc(1, BUFSIZ);
- fifopath = calloc(1, PATH_MAX);
- if(((find_res[0] = (regex_t *) calloc(1, sizeof(regex_t))) == NULL)
- || (find_res[1] = (regex_t *) calloc(1, sizeof(regex_t))) == NULL)
- i_die("Can't malloc.\n");
-
- for(i = 0; i < LENGTH(cmds); i++) {
- if((cmd_res[i] = (regex_t *) calloc(1, sizeof(regex_t))) == NULL)
- i_die("Can't malloc.\n");
+ title[0] = '\0';
+ fifopath[0] = '\0';
+ find_res[0] = (regex_t *) ecalloc(1, sizeof(regex_t));
+ find_res[1] = (regex_t *) ecalloc(1, sizeof(regex_t));
+
+ for(i = 0; i < LEN(cmds); i++) {
+ cmd_res[i] = (regex_t *) ecalloc(1, sizeof(regex_t));
if(regcomp(cmd_res[i], cmds[i].re_text,
REG_EXTENDED | REG_ICASE | REG_NEWLINE))
i_die("Faulty regex.\n");
}
- for(i = 0; i < LENGTH(syntaxes); i++) {
- if((syntax_file_res[i] = (regex_t *) calloc(1, sizeof(regex_t))) == NULL)
- i_die("Can't malloc.\n");
+ for(i = 0; i < LEN(syntaxes); i++) {
+ syntax_file_res[i] = (regex_t *) ecalloc(1, sizeof(regex_t));
if(regcomp(syntax_file_res[i], syntaxes[i].file_re_text,
REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE))
i_die("Faulty regex.\n");
- for(j = 0; j < SYN_COLORS; j++) {
- if((syntax_res[i][j] = (regex_t *) calloc(1, sizeof(regex_t))) == NULL)
- i_die("Can't malloc.\n");
- }
+ for(j = 0; j < SYN_COLORS; j++)
+ syntax_res[i][j] = (regex_t *) ecalloc(1, sizeof(regex_t));
}
- snprintf(fifopath, PATH_MAX, "%s%d", fifobase, getpid());
+ snprintf(fifopath, sizeof(fifopath), "%s%d", fifobase, getpid());
if(mkfifo(fifopath, (S_IRUSR | S_IWUSR)) != 0)
i_die("FIFO already exists.\n");
if((fifofd = open(fifopath, O_RDONLY | O_NONBLOCK)) == -1)
@@ -1553,13 +1630,14 @@ i_setup(void) {
regcomp(find_res[1], "\0\0", 0);
if(!newterm(NULL, stderr, stdin)) {
- newterm("xterm", stderr, stdin);
- tmptitle = "WARNING! $TERM not recognized!!!";
+ if(!(newterm("xterm", stderr, stdin)))
+ i_die("Can't fallback $TERM to xterm, exiting...\n");
+ tmptitle = "WARNING! $TERM not recognized, using xterm as fallback!!!";
}
if(has_colors()) {
start_color();
use_default_colors();
- for(i = 0; i < LastFG; i++)
+ for(i = 0; i < LastFG; i++) {
for(j = 0; j < LastBG; j++) {
/* Handle more than 8 colors */
if(fgcolors[i] > 7)
@@ -1572,20 +1650,20 @@ i_setup(void) {
init_pair((i * LastBG) + j, fgcolors[i], bgcolors[j]);
textattrs[i][j] = COLOR_PAIR((i * LastBG) + j) | colorattrs[i];
}
+ }
} else {
- for(i = 0; i < LastFG; i++)
+ for(i = 0; i < LastFG; i++) {
for(j = 0; j < LastBG; j++)
textattrs[i][j] = bwattrs[i];
+ }
}
lines = LINES;
cols = COLS;
i_termwininit();
/* Init line structure */
- if(((l = (Line *) malloc(sizeof(Line))) == NULL) ||
- ((l->c = calloc(1, LINSIZ)) == NULL))
- i_die("Can't malloc.\n");
- l->c[0] = '\0';
+ l = (Line *) ecalloc(1, sizeof(Line));
+ l->c = ecalloc(1, LINSIZ);
l->dirty = FALSE;
l->len = l->vlen = 0;
l->mul = 1;
@@ -1599,12 +1677,16 @@ i_setup(void) {
/* Process SIGWINCH, the terminal has been resized */
void
i_sigwinch(int unused) {
+ (void) unused;
+
statusflags |= S_NeedResize;
}
/* Process SIGCONT to return after STOP */
void
i_sigcont(int unused) {
+ (void) unused;
+
i_resize();
}
@@ -1627,7 +1709,7 @@ i_sortpos(Filepos * pos0, Filepos * pos1) {
/* Initialize terminal */
void
i_termwininit(void) {
- int i;
+ unsigned int i;
raw();
noecho();
@@ -1653,7 +1735,7 @@ i_termwininit(void) {
curs_set(1);
scrollok(textwin, FALSE);
#if HANDLE_MOUSE
- for(i = 0; i < LENGTH(clks); i++)
+ for(i = 0; i < LEN(clks); i++)
defmmask |= clks[i].mask;
mousemask(defmmask, NULL);
#endif /* HANDLE_MOUSE */
@@ -1663,16 +1745,15 @@ i_termwininit(void) {
unnecessary complexity and length */
void
i_update(void) {
- /* TODO: make this non-static? */
- static int iline, irow, ixrow, ivchar, i, ifg, ibg, vlines;
- static size_t ichar;
- static int cursor_r, cursor_c;
- static int lines3; /* How many lines fit on screen */
- static long int nscr, ncur, nlst; /* Line number for scrline, fcur.l and lstline */
- static bool selection;
- static regmatch_t match[SYN_COLORS][1];
- static Line *l;
- static char c[7], buf[16];
+ int iline, irow, ixrow, ivchar, i, ifg, ibg, vlines;
+ size_t ichar;
+ int cursor_r, cursor_c;
+ int lines3; /* How many lines fit on screen */
+ long int nscr, ncur, nlst; /* Line number for scrline, fcur.l and lstline */
+ bool selection;
+ regmatch_t match[SYN_COLORS][1];
+ Line *l;
+ char c[7], buf[16];
/* Check if we need to resize */
if(statusflags & S_NeedResize)
@@ -1826,16 +1907,18 @@ i_update(void) {
}
}
}
- } else if(l == fsel.l || l == fcur.l)
+ } else if(l == fsel.l || l == fcur.l) {
selection = !selection;
+ }
if(l)
l = l->next;
}
/* Calculate nlst */
- for(iline = ncur, l = fcur.l; l; l = l->next, iline++)
+ for(iline = ncur, l = fcur.l; l; l = l->next, iline++) {
if(l == lstline)
nlst = iline;
+ }
/* Position cursor */
wmove(textwin, cursor_r, cursor_c);
@@ -1848,7 +1931,7 @@ i_update(void) {
/* Update title */
if(tmptitle)
- strncpy(title, tmptitle, BUFSIZ);
+ snprintf(title, sizeof(title), "%s", tmptitle);
else {
statusflags &= ~S_Warned; /* Reset warning */
snprintf(buf, 4, "%ld%%", (100 * ncur) / nlst);
@@ -1895,9 +1978,8 @@ i_update(void) {
/* Print help, die */
void
i_usage(void) {
- fputs("sandy - simple editor\n", stderr);
- i_die
- ("usage: sandy [-a] [-d] [-r] [-u] [-t TABSTOP] [-S] [-s SYNTAX] [file | -]\n");
+ i_die("sandy - simple editor\n"
+ "usage: sandy [-a] [-d] [-r] [-u] [-t TABSTOP] [-S] [-s SYNTAX] [file | -]\n");
}
/* Write buffer to disk */
@@ -2034,7 +2116,7 @@ m_prevword(Filepos pos) {
/* Advance one line, or to eol if at last line */
Filepos
m_nextline(Filepos pos) {
- int ivchar, ichar;
+ size_t ivchar, ichar;
for(ivchar = ichar = 0; ichar < pos.o; ichar++)
ivchar += VLEN(pos.l->c[ichar], ivchar);
@@ -2053,7 +2135,7 @@ m_nextline(Filepos pos) {
/* Backup one line, or to bol if at first line */
Filepos
m_prevline(Filepos pos) {
- int ivchar, ichar;
+ size_t ivchar, ichar;
for(ivchar = ichar = 0; ichar < pos.o; ichar++)
ivchar += VLEN(pos.l->c[ichar], (ivchar % (cols - 1)));
@@ -2137,13 +2219,15 @@ m_tomark(Filepos pos) {
/* Go to selection point */
Filepos
m_tosel(Filepos pos) {
+ (void) pos;
+
return fsel;
}
/* T_* FUNCTIONS
* Used to test for conditions, take no arguments and return bool. */
-/* TRUE is autoindent is on */
+/* TRUE if autoindent is on */
bool
t_ai(void) {
return (statusflags & S_AutoIndent);
@@ -2225,8 +2309,7 @@ t_warn(void) {
/* main() starts everything else */
int
-main(int argc, char **argv) {
- int i;
+main(int argc, char *argv[]) {
char *local_syn = NULL;
/* Use system locale, hopefully UTF-8 */
@@ -2234,36 +2317,36 @@ main(int argc, char **argv) {
/* FIXME: Change this to something else to support num keys? */
ESCDELAY = 0;
- for(i = 1; i < argc && argv[i][0] == '-' && argv[i][1] != '\0'; i++) {
- if(!strcmp(argv[i], "-r")) {
- statusflags |= S_Readonly;
- } else if(!strcmp(argv[i], "-a")) {
- statusflags |= S_AutoIndent;
- } else if(!strcmp(argv[i], "-d")) {
- statusflags |= S_DumpStdout;
- } else if(!strcmp(argv[i], "-t")) {
- if(++i < argc) {
- tabstop = atoi(argv[i]); /* TODO: strtol */
- } else
- i_usage();
- } else if(!strcmp(argv[i], "-S")) {
- local_syn = "";
- } else if(!strcmp(argv[i], "-s")) {
- if(++i < argc) {
- local_syn = argv[i];
- } else
- i_usage();
- } else if(!strcmp(argv[i], "--")) {
- i++;
- break;
- } else if(!strcmp(argv[i], "-v"))
- i_die("sandy-" VERSION ", © 2014 sandy engineers, see LICENSE for details\n");
- else
- i_usage();
- }
+ ARGBEGIN {
+ case 'r':
+ statusflags |= S_Readonly;
+ break;
+ case 'a':
+ statusflags |= S_AutoIndent;
+ break;
+ case 'd':
+ statusflags |= S_DumpStdout;
+ break;
+ case 't':
+ tabstop = atoi(EARGF(i_usage()));
+ break;
+ case 'S':
+ local_syn = "";
+ break;
+ case 's':
+ local_syn = EARGF(i_usage());
+ break;
+ case 'v':
+ i_die("sandy-" VERSION ", © 2014 sandy engineers, see LICENSE for details\n");
+ break;
+ default:
+ i_usage();
+ break;
+ } ARGEND;
+
i_setup();
- if(i < argc)
- i_readfile(argv[i]);
+ if(argc > 0)
+ i_readfile(argv[0]);
if(local_syn)
f_syntax(&(const Arg) { .v = local_syn });
i_edit();