diff --git a/pkgs/applications/editors/mg/darwin_no_libbsd.patch b/pkgs/applications/editors/mg/darwin_no_libbsd.patch index 9b6df6223244..2484c03255b1 100644 --- a/pkgs/applications/editors/mg/darwin_no_libbsd.patch +++ b/pkgs/applications/editors/mg/darwin_no_libbsd.patch @@ -1,6 +1,6 @@ diff -Naur a/GNUmakefile b/GNUmakefile ---- a/GNUmakefile 2020-02-01 21:23:32.000000000 +0000 -+++ b/GNUmakefile 2020-02-01 21:56:01.000000000 +0000 +--- a/GNUmakefile 2020-04-20 21:09:41.000000000 +0100 ++++ b/GNUmakefile 2020-04-20 21:31:19.000000000 +0100 @@ -18,7 +18,7 @@ STRIP= /usr/bin/strip @@ -10,20 +10,16 @@ diff -Naur a/GNUmakefile b/GNUmakefile BSD_CPPFLAGS:= BSD_LIBS:= -lutil else -@@ -35,11 +35,7 @@ - - CURSES_LIBS:= $(shell $(PKG_CONFIG) --libs ncurses) - ifeq ($(CURSES_LIBS),) -- $(error You probably need to install "libncurses5-dev" or "libncurses6-devel" or something like that.) --endif -- --ifdef STATIC -- LDFLAGS=-static -static-libgcc -+ $(error You probably need to install "libncurses5-dev" or "libnnurses6-devel" or something like that.) +@@ -38,24 +38,21 @@ + $(error You probably need to install "libncurses5-dev" or "libncurses6-devel" or something like that.) endif +-ifdef STATIC +- LDFLAGS=-static -static-libgcc +-endif +- CC?= gcc -@@ -47,14 +43,14 @@ + CFLAGS?= -O2 -pipe CFLAGS+= -g -Wall CPPFLAGS= -DREGEX CPPFLAGS+= -D_GNU_SOURCE @@ -33,25 +29,121 @@ diff -Naur a/GNUmakefile b/GNUmakefile OBJS= autoexec.o basic.o bell.o buffer.o cinfo.o dir.o display.o \ -- echo.o extend.o file.o fileio.o funmap.o help.o kbd.o keymap.o \ -+ echo.o extend.o file.o fileio.o funmap.o futimens.o help.o kbd.o keymap.o \ - line.o macro.o main.o match.o modes.o paragraph.o \ +- echo.o extend.o file.o fileio.o funmap.o interpreter.o help.o \ +- kbd.o keymap.o line.o macro.o main.o match.o modes.o paragraph.o \ - re_search.o region.o search.o spawn.o tty.o ttyio.o ttykbd.o \ -+ re_search.o reallocarray.o region.o search.o spawn.o strtonum.o tty.o ttyio.o ttykbd.o \ - undo.o util.o version.o window.o word.o yank.o +- undo.o util.o version.o window.o word.o yank.o ++ echo.o extend.o file.o fileio.o funmap.o futimens.o interpreter.o \ ++ help.o kbd.o keymap.o line.o macro.o main.o match.o modes.o \ ++ paragraph.o re_search.o reallocarray.o region.o search.o spawn.o \ ++ strtonum.o tty.o ttyio.o ttykbd.o undo.o util.o version.o window.o \ ++ word.o yank.o OBJS+= cmode.o cscope.o dired.o grep.o tags.o -@@ -68,6 +64,7 @@ - - all: $(name) +diff -Naur a/GNUmakefile~ b/GNUmakefile~ +--- a/GNUmakefile~ 1970-01-01 01:00:00.000000000 +0100 ++++ b/GNUmakefile~ 2020-04-20 21:27:39.000000000 +0100 +@@ -0,0 +1,96 @@ ++# Makefile for mg + - $(name): $(OBJS) - $(CC) $(LDFLAGS) $(OBJS) -o $(name) $(LIBS) - ++# This Makefile has been written by Han Boetes ++# and is released in Public Domain. ++ ++# *sigh* Those debian folks are really tidy on their licenses. ++ ++name= mg ++ ++prefix= /usr/local ++bindir= $(prefix)/bin ++libdir= $(prefix)/lib ++includedir= $(prefix)/include ++mandir= $(prefix)/man ++ ++PKG_CONFIG= /usr/bin/pkg-config --silence-errors ++INSTALL= /usr/bin/install ++STRIP= /usr/bin/strip ++ ++UNAME:= $(shell uname) ++ifeq ($(UNAME),FreeBSD) ++ BSD_CPPFLAGS:= ++ BSD_LIBS:= -lutil ++else ++ BSD_CPPFLAGS:= $(shell $(PKG_CONFIG) --cflags libbsd-overlay) ++ BSD_LIBS:= $(shell $(PKG_CONFIG) --libs libbsd-overlay) ++endif ++ ++# Test is some required libraries are installed. Rather bummer that ++# they are also required to run make clean or uninstall. Oh well... Who ++# does that? ++ifeq ($(BSD_LIBS),) ++ $(error You probably need to install "libbsd-dev" or "libbsd-devel" or something like that.) ++endif ++ ++CURSES_LIBS:= $(shell $(PKG_CONFIG) --libs ncurses) ++ifeq ($(CURSES_LIBS),) ++ $(error You probably need to install "libncurses5-dev" or "libncurses6-devel" or something like that.) ++endif ++ ++ifdef STATIC ++ LDFLAGS=-static -static-libgcc ++endif ++ ++CC?= gcc ++CFLAGS?= -O2 -pipe ++CFLAGS+= -g -Wall ++CPPFLAGS= -DREGEX ++CPPFLAGS+= -D_GNU_SOURCE ++CPPFLAGS+= $(BSD_CPPFLAGS) ++LIBS= $(CURSES_LIBS) $(BSD_LIBS) ++ ++ ++OBJS= autoexec.o basic.o bell.o buffer.o cinfo.o dir.o display.o \ ++ echo.o extend.o file.o fileio.o funmap.o interpreter.o help.o \ ++ kbd.o keymap.o line.o macro.o main.o match.o modes.o paragraph.o \ ++ re_search.o region.o search.o spawn.o tty.o ttyio.o ttykbd.o \ ++ undo.o util.o version.o window.o word.o yank.o ++OBJS+= cmode.o cscope.o dired.o grep.o tags.o ++ ++ ++# Portability stuff. ++CFLAGS+= -Wno-strict-aliasing -Wno-deprecated-declarations ++EXE_EXT= ++ ++.c.o: ++ $(CC) $(CFLAGS) $(CPPFLAGS) -c $< ++ ++all: $(name) ++ ++$(name): $(OBJS) ++ $(CC) $(LDFLAGS) $(OBJS) -o $(name) $(LIBS) ++ ++distclean: clean ++ -rm -f *.core core.* ++ ++clean: ++ -rm -f *.o $(name)$(EXE_EXT) ++ ++ ++install: $(name) $(name).1 ++ $(INSTALL) -d $(DESTDIR)$(bindir) ++ $(INSTALL) -d $(DESTDIR)$(mandir)/man1 ++ $(INSTALL) -m 755 $(name) $(DESTDIR)$(bindir)/$(name) ++ $(INSTALL) -m 444 $(name).1 $(DESTDIR)$(mandir)/man1/$(name).1 ++ ++install-strip: install ++ $(STRIP) $(DESTDIR)$(bindir)/$(name) ++ ++uninstall: ++ rm -f \ ++ $(DESTDIR)$(bindir)/$(name)$(EXE_EXT) \ ++ $(DESTDIR)$(mandir)/man1/$(name).1 ++ ++rebuild: ++ make clean all diff -Naur a/_null.h b/_null.h --- a/_null.h 1970-01-01 01:00:00.000000000 +0100 -+++ b/_null.h 2020-02-01 21:24:22.000000000 +0000 ++++ b/_null.h 2020-04-20 21:26:10.000000000 +0100 @@ -0,0 +1,18 @@ +/* $OpenBSD: _null.h,v 1.2 2016/09/09 22:07:58 millert Exp $ */ + @@ -73,7 +165,7 @@ diff -Naur a/_null.h b/_null.h +#endif diff -Naur a/apple.h b/apple.h --- a/apple.h 1970-01-01 01:00:00.000000000 +0100 -+++ b/apple.h 2020-02-01 21:41:50.000000000 +0000 ++++ b/apple.h 2020-04-20 21:26:10.000000000 +0100 @@ -0,0 +1,27 @@ +/* + * Mac OS X-specific support. @@ -103,8 +195,8 @@ diff -Naur a/apple.h b/apple.h +extern void *reallocarray(void *, size_t, size_t); +extern int futimens(int, const struct timespec[2]); diff -Naur a/autoexec.c b/autoexec.c ---- a/autoexec.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/autoexec.c 2020-02-01 21:34:02.000000000 +0000 +--- a/autoexec.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/autoexec.c 2020-04-20 21:26:10.000000000 +0100 @@ -9,6 +9,9 @@ #include #include @@ -116,8 +208,8 @@ diff -Naur a/autoexec.c b/autoexec.c #include "funmap.h" diff -Naur a/basic.c b/basic.c ---- a/basic.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/basic.c 2020-02-01 21:34:26.000000000 +0000 +--- a/basic.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/basic.c 2020-04-20 21:26:10.000000000 +0100 @@ -19,6 +19,9 @@ #include #include @@ -127,10 +219,615 @@ diff -Naur a/basic.c b/basic.c +#endif #include "def.h" - /* + #define percint(n1, n2) ((n1 * (int) n2) * 0.1) +diff -Naur a/basic.c.orig b/basic.c.orig +--- a/basic.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ b/basic.c.orig 2020-04-20 21:26:06.000000000 +0100 +@@ -0,0 +1,601 @@ ++/* $OpenBSD: basic.c,v 1.49 2019/06/17 11:39:26 lum Exp $ */ ++ ++/* This file is in the public domain */ ++ ++/* ++ * Basic cursor motion commands. ++ * ++ * The routines in this file are the basic ++ * command functions for moving the cursor around on ++ * the screen, setting mark, and swapping dot with ++ * mark. Only moves between lines, which might make the ++ * current buffer framing bad, are hard. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "def.h" ++ ++#define percint(n1, n2) ((n1 * (int) n2) * 0.1) ++ ++/* ++ * Go to beginning of line. ++ */ ++/* ARGSUSED */ ++int ++gotobol(int f, int n) ++{ ++ if (n == 0) ++ return (TRUE); ++ ++ curwp->w_doto = 0; ++ return (TRUE); ++} ++ ++/* ++ * Move cursor backwards. Do the ++ * right thing if the count is less than ++ * 0. Error if you try to move back from ++ * the beginning of the buffer. ++ */ ++/* ARGSUSED */ ++int ++backchar(int f, int n) ++{ ++ struct line *lp; ++ ++ if (n < 0) ++ return (forwchar(f, -n)); ++ while (n--) { ++ if (curwp->w_doto == 0) { ++ if ((lp = lback(curwp->w_dotp)) == curbp->b_headp) { ++ if (!(f & FFRAND)) { ++ dobeep(); ++ ewprintf("Beginning of buffer"); ++ } ++ return (FALSE); ++ } ++ curwp->w_dotp = lp; ++ curwp->w_doto = llength(lp); ++ curwp->w_rflag |= WFMOVE; ++ curwp->w_dotline--; ++ } else ++ curwp->w_doto--; ++ } ++ return (TRUE); ++} ++ ++/* ++ * Go to end of line. ++ */ ++/* ARGSUSED */ ++int ++gotoeol(int f, int n) ++{ ++ if (n == 0) ++ return (TRUE); ++ ++ curwp->w_doto = llength(curwp->w_dotp); ++ return (TRUE); ++} ++ ++/* ++ * Move cursor forwards. Do the ++ * right thing if the count is less than ++ * 0. Error if you try to move forward ++ * from the end of the buffer. ++ */ ++/* ARGSUSED */ ++int ++forwchar(int f, int n) ++{ ++ if (n < 0) ++ return (backchar(f, -n)); ++ while (n--) { ++ if (curwp->w_doto == llength(curwp->w_dotp)) { ++ curwp->w_dotp = lforw(curwp->w_dotp); ++ if (curwp->w_dotp == curbp->b_headp) { ++ curwp->w_dotp = lback(curwp->w_dotp); ++ if (!(f & FFRAND)) { ++ dobeep(); ++ ewprintf("End of buffer"); ++ } ++ return (FALSE); ++ } ++ curwp->w_doto = 0; ++ curwp->w_dotline++; ++ curwp->w_rflag |= WFMOVE; ++ } else ++ curwp->w_doto++; ++ } ++ return (TRUE); ++} ++ ++/* ++ * Go to the beginning of the buffer. Setting WFFULL is conservative, ++ * but almost always the case. A universal argument of higher than 9 ++ * puts the cursor back to the end of buffer. ++ */ ++int ++gotobob(int f, int n) ++{ ++ if (!curwp->w_markp) ++ (void) setmark(f, n); ++ curwp->w_dotp = bfirstlp(curbp); ++ curwp->w_doto = 0; ++ curwp->w_rflag |= WFFULL; ++ curwp->w_dotline = 1; ++ if (f & FFOTHARG && n > 0) { ++ if (n > 9) ++ gotoeob(0, 0); ++ else ++ forwline(f, percint(curwp->w_bufp->b_lines, n) - 1); ++ } ++ return (TRUE); ++} ++ ++/* ++ * Go to the end of the buffer. Leave dot 3 lines from the bottom of the ++ * window if buffer length is longer than window length; same as emacs. ++ * Setting WFFULL is conservative, but almost always the case. A universal ++ * argument of higher than 9 puts the cursor back to the start of buffer. ++ */ ++int ++gotoeob(int f, int n) ++{ ++ int ln; ++ struct line *lp; ++ ++ if (!curwp->w_markp) ++ (void) setmark(f, n); ++ curwp->w_dotp = blastlp(curbp); ++ curwp->w_doto = llength(curwp->w_dotp); ++ curwp->w_dotline = curwp->w_bufp->b_lines; ++ ++ lp = curwp->w_dotp; ++ ln = curwp->w_ntrows - 3; ++ ++ if (ln < curwp->w_bufp->b_lines && ln >= 3) { ++ while (ln--) ++ curwp->w_dotp = lback(curwp->w_dotp); ++ ++ curwp->w_linep = curwp->w_dotp; ++ curwp->w_dotp = lp; ++ } ++ if (f & FFOTHARG && n > 0) { ++ if (n > 9) ++ gotobob(0, 0); ++ else ++ backline(f, percint(curwp->w_bufp->b_lines, n)); ++ } ++ ++ curwp->w_rflag |= WFFULL; ++ return (TRUE); ++} ++ ++/* ++ * Move forward by full lines. ++ * If the number of lines to move is less ++ * than zero, call the backward line function to ++ * actually do it. The last command controls how ++ * the goal column is set. ++ */ ++/* ARGSUSED */ ++int ++forwline(int f, int n) ++{ ++ struct line *dlp; ++ ++ if (n < 0) ++ return (backline(f | FFRAND, -n)); ++ if ((dlp = curwp->w_dotp) == curbp->b_headp) { ++ if (!(f & FFRAND)) { ++ dobeep(); ++ ewprintf("End of buffer"); ++ } ++ return(TRUE); ++ } ++ if ((lastflag & CFCPCN) == 0) /* Fix goal. */ ++ setgoal(); ++ thisflag |= CFCPCN; ++ if (n == 0) ++ return (TRUE); ++ while (n--) { ++ dlp = lforw(dlp); ++ if (dlp == curbp->b_headp) { ++ curwp->w_dotp = lback(dlp); ++ curwp->w_doto = llength(curwp->w_dotp); ++ curwp->w_rflag |= WFMOVE; ++ if (!(f & FFRAND)) { ++ dobeep(); ++ ewprintf("End of buffer"); ++ } ++ return (TRUE); ++ } ++ curwp->w_dotline++; ++ } ++ curwp->w_rflag |= WFMOVE; ++ curwp->w_dotp = dlp; ++ curwp->w_doto = getgoal(dlp); ++ ++ return (TRUE); ++} ++ ++/* ++ * This function is like "forwline", but ++ * goes backwards. The scheme is exactly the same. ++ * Check for arguments that are less than zero and ++ * call your alternate. Figure out the new line and ++ * call "movedot" to perform the motion. ++ */ ++/* ARGSUSED */ ++int ++backline(int f, int n) ++{ ++ struct line *dlp; ++ ++ if (n < 0) ++ return (forwline(f | FFRAND, -n)); ++ if ((lastflag & CFCPCN) == 0) /* Fix goal. */ ++ setgoal(); ++ thisflag |= CFCPCN; ++ dlp = curwp->w_dotp; ++ if (lback(dlp) == curbp->b_headp) { ++ if (!(f & FFRAND)) { ++ dobeep(); ++ ewprintf("Beginning of buffer"); ++ } ++ return(TRUE); ++ } ++ while (n-- && lback(dlp) != curbp->b_headp) { ++ dlp = lback(dlp); ++ curwp->w_dotline--; ++ } ++ if (n > 0 && !(f & FFRAND)) { ++ dobeep(); ++ ewprintf("Beginning of buffer"); ++ } ++ curwp->w_dotp = dlp; ++ curwp->w_doto = getgoal(dlp); ++ curwp->w_rflag |= WFMOVE; ++ return (TRUE); ++} ++ ++/* ++ * Set the current goal column, which is saved in the external variable ++ * "curgoal", to the current cursor column. The column is never off ++ * the edge of the screen; it's more like display then show position. ++ */ ++void ++setgoal(void) ++{ ++ curgoal = getcolpos(curwp); /* Get the position. */ ++ /* we can now display past end of display, don't chop! */ ++} ++ ++/* ++ * This routine looks at a line (pointed ++ * to by the LINE pointer "dlp") and the current ++ * vertical motion goal column (set by the "setgoal" ++ * routine above) and returns the best offset to use ++ * when a vertical motion is made into the line. ++ */ ++int ++getgoal(struct line *dlp) ++{ ++ int c, i, col = 0; ++ char tmp[5]; ++ ++ ++ for (i = 0; i < llength(dlp); i++) { ++ c = lgetc(dlp, i); ++ if (c == '\t' ++#ifdef NOTAB ++ && !(curbp->b_flag & BFNOTAB) ++#endif ++ ) { ++ col |= 0x07; ++ col++; ++ } else if (ISCTRL(c) != FALSE) { ++ col += 2; ++ } else if (isprint(c)) ++ col++; ++ else { ++ col += snprintf(tmp, sizeof(tmp), "\\%o", c); ++ } ++ if (col > curgoal) ++ break; ++ } ++ return (i); ++} ++ ++/* ++ * Scroll forward by a specified number ++ * of lines, or by a full page if no argument. ++ * The "2" is the window overlap (this is the default ++ * value from ITS EMACS). Because the top line in ++ * the window is zapped, we have to do a hard ++ * update and get it back. ++ */ ++/* ARGSUSED */ ++int ++forwpage(int f, int n) ++{ ++ struct line *lp; ++ ++ if (!(f & FFARG)) { ++ n = curwp->w_ntrows - 2; /* Default scroll. */ ++ if (n <= 0) /* Forget the overlap */ ++ n = 1; /* if tiny window. */ ++ } else if (n < 0) ++ return (backpage(f | FFRAND, -n)); ++ ++ lp = curwp->w_linep; ++ while (n--) ++ if ((lp = lforw(lp)) == curbp->b_headp) { ++ dobeep(); ++ ewprintf("End of buffer"); ++ return(TRUE); ++ } ++ ++ curwp->w_linep = lp; ++ curwp->w_rflag |= WFFULL; ++ ++ /* if in current window, don't move dot */ ++ for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp)) ++ if (lp == curwp->w_dotp) ++ return (TRUE); ++ ++ /* Advance the dot the slow way, for line nos */ ++ while (curwp->w_dotp != curwp->w_linep) { ++ curwp->w_dotp = lforw(curwp->w_dotp); ++ curwp->w_dotline++; ++ } ++ curwp->w_doto = 0; ++ return (TRUE); ++} ++ ++/* ++ * This command is like "forwpage", ++ * but it goes backwards. The "2", like above, ++ * is the overlap between the two windows. The ++ * value is from the ITS EMACS manual. The ++ * hard update is done because the top line in ++ * the window is zapped. ++ */ ++/* ARGSUSED */ ++int ++backpage(int f, int n) ++{ ++ struct line *lp, *lp2; ++ ++ if (!(f & FFARG)) { ++ n = curwp->w_ntrows - 2; /* Default scroll. */ ++ if (n <= 0) /* Don't blow up if the */ ++ return (backline(f, 1));/* window is tiny. */ ++ } else if (n < 0) ++ return (forwpage(f | FFRAND, -n)); ++ ++ lp = lp2 = curwp->w_linep; ++ ++ while (n-- && lback(lp) != curbp->b_headp) { ++ lp = lback(lp); ++ } ++ if (lp == curwp->w_linep) { ++ dobeep(); ++ ewprintf("Beginning of buffer"); ++ } ++ curwp->w_linep = lp; ++ curwp->w_rflag |= WFFULL; ++ ++ /* if in current window, don't move dot */ ++ for (n = curwp->w_ntrows; n-- && lp != curbp->b_headp; lp = lforw(lp)) ++ if (lp == curwp->w_dotp) ++ return (TRUE); ++ ++ lp2 = lforw(lp2); ++ ++ /* Move the dot the slow way, for line nos */ ++ while (curwp->w_dotp != lp2) { ++ if (curwp->w_dotline <= curwp->w_ntrows) ++ goto out; ++ curwp->w_dotp = lback(curwp->w_dotp); ++ curwp->w_dotline--; ++ } ++out: ++ curwp->w_doto = 0; ++ return (TRUE); ++} ++ ++/* ++ * These functions are provided for compatibility with Gosling's Emacs. They ++ * are used to scroll the display up (or down) one line at a time. ++ */ ++int ++forw1page(int f, int n) ++{ ++ if (!(f & FFARG)) { ++ n = 1; ++ f = FFUNIV; ++ } ++ forwpage(f | FFRAND, n); ++ return (TRUE); ++} ++ ++int ++back1page(int f, int n) ++{ ++ if (!(f & FFARG)) { ++ n = 1; ++ f = FFUNIV; ++ } ++ backpage(f | FFRAND, n); ++ return (TRUE); ++} ++ ++/* ++ * Page the other window. Check to make sure it exists, then ++ * nextwind, forwpage and restore window pointers. ++ */ ++int ++pagenext(int f, int n) ++{ ++ struct mgwin *wp; ++ ++ if (wheadp->w_wndp == NULL) { ++ dobeep(); ++ ewprintf("No other window"); ++ return (FALSE); ++ } ++ wp = curwp; ++ (void) nextwind(f, n); ++ (void) forwpage(f, n); ++ curwp = wp; ++ curbp = wp->w_bufp; ++ return (TRUE); ++} ++ ++/* ++ * Internal set mark routine, used by other functions (daveb). ++ */ ++void ++isetmark(void) ++{ ++ curwp->w_markp = curwp->w_dotp; ++ curwp->w_marko = curwp->w_doto; ++ curwp->w_markline = curwp->w_dotline; ++} ++ ++/* ++ * Set the mark in the current window ++ * to the value of dot. A message is written to ++ * the echo line. (ewprintf knows about macros) ++ */ ++/* ARGSUSED */ ++int ++setmark(int f, int n) ++{ ++ isetmark(); ++ ewprintf("Mark set"); ++ return (TRUE); ++} ++ ++/* Clear the mark, if set. */ ++/* ARGSUSED */ ++int ++clearmark(int f, int n) ++{ ++ if (!curwp->w_markp) ++ return (FALSE); ++ ++ curwp->w_markp = NULL; ++ curwp->w_marko = 0; ++ curwp->w_markline = 0; ++ ++ return (TRUE); ++} ++ ++/* ++ * Swap the values of "dot" and "mark" in ++ * the current window. This is pretty easy, because ++ * all of the hard work gets done by the standard routine ++ * that moves the mark about. The only possible ++ * error is "no mark". ++ */ ++/* ARGSUSED */ ++int ++swapmark(int f, int n) ++{ ++ struct line *odotp; ++ int odoto, odotline; ++ ++ if (curwp->w_markp == NULL) { ++ dobeep(); ++ ewprintf("No mark in this window"); ++ return (FALSE); ++ } ++ odotp = curwp->w_dotp; ++ odoto = curwp->w_doto; ++ odotline = curwp->w_dotline; ++ curwp->w_dotp = curwp->w_markp; ++ curwp->w_doto = curwp->w_marko; ++ curwp->w_dotline = curwp->w_markline; ++ curwp->w_markp = odotp; ++ curwp->w_marko = odoto; ++ curwp->w_markline = odotline; ++ curwp->w_rflag |= WFMOVE; ++ return (TRUE); ++} ++ ++/* ++ * Go to a specific line, mostly for ++ * looking up errors in C programs, which give the ++ * error a line number. If an argument is present, then ++ * it is the line number, else prompt for a line number ++ * to use. ++ */ ++/* ARGSUSED */ ++int ++gotoline(int f, int n) ++{ ++ char buf[32], *bufp; ++ const char *err; ++ ++ if (!(f & FFARG)) { ++ if ((bufp = eread("Goto line: ", buf, sizeof(buf), ++ EFNUL | EFNEW | EFCR)) == NULL) ++ return (ABORT); ++ if (bufp[0] == '\0') ++ return (ABORT); ++ n = (int)strtonum(buf, INT_MIN, INT_MAX, &err); ++ if (err) { ++ dobeep(); ++ ewprintf("Line number %s", err); ++ return (FALSE); ++ } ++ } ++ return(setlineno(n)); ++} ++ ++/* ++ * Set the line number and switch to it. ++ */ ++int ++setlineno(int n) ++{ ++ struct line *clp; ++ ++ if (n >= 0) { ++ if (n == 0) ++ n++; ++ curwp->w_dotline = n; ++ clp = lforw(curbp->b_headp); /* "clp" is first line */ ++ while (--n > 0) { ++ if (lforw(clp) == curbp->b_headp) { ++ curwp->w_dotline = curwp->w_bufp->b_lines; ++ break; ++ } ++ clp = lforw(clp); ++ } ++ } else { ++ curwp->w_dotline = curwp->w_bufp->b_lines + n; ++ clp = lback(curbp->b_headp); /* "clp" is last line */ ++ while (n < 0) { ++ if (lback(clp) == curbp->b_headp) { ++ curwp->w_dotline = 1; ++ break; ++ } ++ clp = lback(clp); ++ n++; ++ } ++ } ++ curwp->w_dotp = clp; ++ curwp->w_doto = 0; ++ curwp->w_rflag |= WFMOVE; ++ return (TRUE); ++} diff -Naur a/cscope.c b/cscope.c ---- a/cscope.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/cscope.c 2020-02-01 21:34:59.000000000 +0000 +--- a/cscope.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/cscope.c 2020-04-20 21:26:10.000000000 +0100 @@ -20,6 +20,9 @@ #include #include @@ -142,8 +839,8 @@ diff -Naur a/cscope.c b/cscope.c #define CSSYMBOL 0 diff -Naur a/display.c b/display.c ---- a/display.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/display.c 2020-02-01 21:34:16.000000000 +0000 +--- a/display.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/display.c 2020-04-20 21:26:10.000000000 +0100 @@ -19,6 +19,9 @@ #include #include @@ -155,14 +852,8 @@ diff -Naur a/display.c b/display.c #include "kbd.h" diff -Naur a/fileio.c b/fileio.c ---- a/fileio.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/fileio.c 2020-02-01 21:42:18.000000000 +0000 -@@ -1,4 +1,4 @@ --/* $OpenBSD: fileio.c,v 1.105 2018/04/13 14:11:37 florian Exp $ */ -+/* $OpenBSD: fileio.c,v 1.104 2017/05/30 07:05:22 florian Exp $ */ - - /* This file is in the public domain. */ - +--- a/fileio.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/fileio.c 2020-04-20 21:26:10.000000000 +0100 @@ -22,19 +22,13 @@ #include #include @@ -186,7 +877,7 @@ diff -Naur a/fileio.c b/fileio.c static char *bkuplocation(const char *); static int bkupleavetmp(const char *); -@@ -714,7 +708,7 @@ +@@ -710,7 +704,7 @@ struct stat statbuf; const char *cp; char user[LOGIN_NAME_MAX], path[NFILEN]; @@ -195,7 +886,7 @@ diff -Naur a/fileio.c b/fileio.c size_t ulen, plen; path[0] = '\0'; -@@ -733,18 +727,21 @@ +@@ -729,18 +723,21 @@ return (NULL); return(ret); } @@ -222,9 +913,774 @@ diff -Naur a/fileio.c b/fileio.c ewprintf("Path too long"); return (NULL); } +diff -Naur a/fileio.c.orig b/fileio.c.orig +--- a/fileio.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ b/fileio.c.orig 2020-04-20 21:26:06.000000000 +0100 +@@ -0,0 +1,761 @@ ++/* $OpenBSD: fileio.c,v 1.106 2019/06/22 10:21:57 lum Exp $ */ ++ ++/* This file is in the public domain. */ ++ ++/* ++ * POSIX fileio.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "def.h" ++#include "kbd.h" ++#include "pathnames.h" ++ ++#ifndef MAXNAMLEN ++#define MAXNAMLEN 255 ++#endif ++ ++#ifndef DEFFILEMODE ++#define DEFFILEMODE 0666 ++#endif ++ ++static char *bkuplocation(const char *); ++static int bkupleavetmp(const char *); ++ ++static char *bkupdir; ++static int leavetmp = 0; /* 1 = leave any '~' files in tmp dir */ ++ ++/* ++ * Open a file for reading. ++ */ ++int ++ffropen(FILE ** ffp, const char *fn, struct buffer *bp) ++{ ++ if ((*ffp = fopen(fn, "r")) == NULL) { ++ if (errno == ENOENT) ++ return (FIOFNF); ++ return (FIOERR); ++ } ++ ++ /* If 'fn' is a directory open it with dired. */ ++ if (fisdir(fn) == TRUE) ++ return (FIODIR); ++ ++ ffstat(*ffp, bp); ++ ++ return (FIOSUC); ++} ++ ++/* ++ * Update stat/dirty info ++ */ ++void ++ffstat(FILE *ffp, struct buffer *bp) ++{ ++ struct stat sb; ++ ++ if (bp && fstat(fileno(ffp), &sb) == 0) { ++ /* set highorder bit to make sure this isn't all zero */ ++ bp->b_fi.fi_mode = sb.st_mode | 0x8000; ++ bp->b_fi.fi_uid = sb.st_uid; ++ bp->b_fi.fi_gid = sb.st_gid; ++ /* bp->b_fi.fi_mtime = sb.st_mtimespec; */ ++ bp->b_fi.fi_mtime.tv_sec = sb.st_mtime; ++ bp->b_fi.fi_mtime.tv_nsec = 0; ++ /* Clear the ignore flag */ ++ bp->b_flag &= ~(BFIGNDIRTY | BFDIRTY); ++ } ++} ++ ++/* ++ * Update the status/dirty info. If there is an error, ++ * there's not a lot we can do. ++ */ ++int ++fupdstat(struct buffer *bp) ++{ ++ FILE *ffp; ++ ++ if ((ffp = fopen(bp->b_fname, "r")) == NULL) { ++ if (errno == ENOENT) ++ return (FIOFNF); ++ return (FIOERR); ++ } ++ ffstat(ffp, bp); ++ (void)ffclose(ffp, bp); ++ return (FIOSUC); ++} ++ ++/* ++ * Open a file for writing. ++ */ ++int ++ffwopen(FILE ** ffp, const char *fn, struct buffer *bp) ++{ ++ int fd; ++ mode_t fmode = DEFFILEMODE; ++ ++ if (bp && bp->b_fi.fi_mode) ++ fmode = bp->b_fi.fi_mode & 07777; ++ ++ fd = open(fn, O_RDWR | O_CREAT | O_TRUNC, fmode); ++ if (fd == -1) { ++ ffp = NULL; ++ dobeep(); ++ ewprintf("Cannot open file for writing : %s", strerror(errno)); ++ return (FIOERR); ++ } ++ ++ if ((*ffp = fdopen(fd, "w")) == NULL) { ++ dobeep(); ++ ewprintf("Cannot open file for writing : %s", strerror(errno)); ++ close(fd); ++ return (FIOERR); ++ } ++ ++ /* ++ * If we have file information, use it. We don't bother to check for ++ * errors, because there's no a lot we can do about it. Certainly ++ * trying to change ownership will fail if we aren't root. That's ++ * probably OK. If we don't have info, no need to get it, since any ++ * future writes will do the same thing. ++ */ ++ if (bp && bp->b_fi.fi_mode) { ++ fchmod(fd, bp->b_fi.fi_mode & 07777); ++ fchown(fd, bp->b_fi.fi_uid, bp->b_fi.fi_gid); ++ } ++ return (FIOSUC); ++} ++ ++/* ++ * Close a file. ++ */ ++/* ARGSUSED */ ++int ++ffclose(FILE *ffp, struct buffer *bp) ++{ ++ if (fclose(ffp) == 0) ++ return (FIOSUC); ++ return (FIOERR); ++} ++ ++/* ++ * Write a buffer to the already opened file. bp points to the ++ * buffer. Return the status. ++ */ ++int ++ffputbuf(FILE *ffp, struct buffer *bp, int eobnl) ++{ ++ struct line *lp, *lpend; ++ ++ lpend = bp->b_headp; ++ ++ for (lp = lforw(lpend); lp != lpend; lp = lforw(lp)) { ++ if (fwrite(ltext(lp), 1, llength(lp), ffp) != llength(lp)) { ++ dobeep(); ++ ewprintf("Write I/O error"); ++ return (FIOERR); ++ } ++ if (lforw(lp) != lpend) /* no implied \n on last line */ ++ putc('\n', ffp); ++ } ++ if (eobnl) { ++ lnewline_at(lback(lpend), llength(lback(lpend))); ++ putc('\n', ffp); ++ } ++ return (FIOSUC); ++} ++ ++/* ++ * Read a line from a file, and store the bytes ++ * in the supplied buffer. Stop on end of file or end of ++ * line. When FIOEOF is returned, there is a valid line ++ * of data without the normally implied \n. ++ * If the line length exceeds nbuf, FIOLONG is returned. ++ */ ++int ++ffgetline(FILE *ffp, char *buf, int nbuf, int *nbytes) ++{ ++ int c, i; ++ ++ i = 0; ++ while ((c = getc(ffp)) != EOF && c != '\n') { ++ buf[i++] = c; ++ if (i >= nbuf) ++ return (FIOLONG); ++ } ++ if (c == EOF && ferror(ffp) != FALSE) { ++ dobeep(); ++ ewprintf("File read error"); ++ return (FIOERR); ++ } ++ *nbytes = i; ++ return (c == EOF ? FIOEOF : FIOSUC); ++} ++ ++/* ++ * Make a backup copy of "fname". On Unix the backup has the same ++ * name as the original file, with a "~" on the end; this seems to ++ * be newest of the new-speak. The error handling is all in "file.c". ++ * We do a copy instead of a rename since otherwise another process ++ * with an open fd will get the backup, not the new file. This is ++ * a problem when using mg with things like crontab and vipw. ++ */ ++int ++fbackupfile(const char *fn) ++{ ++ struct stat sb; ++ struct timespec new_times[2]; ++ int from, to, serrno; ++ ssize_t nread; ++ char buf[BUFSIZ]; ++ char *nname, *tname, *bkpth; ++ ++ if (stat(fn, &sb) == -1) { ++ dobeep(); ++ ewprintf("Can't stat %s : %s", fn, strerror(errno)); ++ return (FALSE); ++ } ++ ++ if ((bkpth = bkuplocation(fn)) == NULL) ++ return (FALSE); ++ ++ if (asprintf(&nname, "%s~", bkpth) == -1) { ++ dobeep(); ++ ewprintf("Can't allocate backup file name : %s", strerror(errno)); ++ free(bkpth); ++ return (ABORT); ++ } ++ if (asprintf(&tname, "%s.XXXXXXXXXX", bkpth) == -1) { ++ dobeep(); ++ ewprintf("Can't allocate temp file name : %s", strerror(errno)); ++ free(bkpth); ++ free(nname); ++ return (ABORT); ++ } ++ free(bkpth); ++ ++ if ((from = open(fn, O_RDONLY)) == -1) { ++ free(nname); ++ free(tname); ++ return (FALSE); ++ } ++ to = mkstemp(tname); ++ if (to == -1) { ++ serrno = errno; ++ close(from); ++ free(nname); ++ free(tname); ++ errno = serrno; ++ return (FALSE); ++ } ++ while ((nread = read(from, buf, sizeof(buf))) > 0) { ++ if (write(to, buf, (size_t)nread) != nread) { ++ nread = -1; ++ break; ++ } ++ } ++ serrno = errno; ++ (void) fchmod(to, (sb.st_mode & 0777)); ++ ++ /* copy the mtime to the backupfile */ ++ new_times[0] = sb.st_atim; ++ new_times[1] = sb.st_mtim; ++ futimens(to, new_times); ++ ++ close(from); ++ close(to); ++ if (nread == -1) { ++ if (unlink(tname) == -1) ++ ewprintf("Can't unlink temp : %s", strerror(errno)); ++ } else { ++ if (rename(tname, nname) == -1) { ++ ewprintf("Can't rename temp : %s", strerror(errno)); ++ (void) unlink(tname); ++ nread = -1; ++ } ++ } ++ free(nname); ++ free(tname); ++ errno = serrno; ++ ++ return (nread == -1 ? FALSE : TRUE); ++} ++ ++/* ++ * Convert "fn" to a canonicalized absolute filename, replacing ++ * a leading ~/ with the user's home dir, following symlinks, and ++ * remove all occurrences of /./ and /../ ++ */ ++char * ++adjustname(const char *fn, int slashslash) ++{ ++ static char fnb[PATH_MAX]; ++ const char *cp, *ep = NULL; ++ char *path; ++ ++ if (slashslash == TRUE) { ++ cp = fn + strlen(fn) - 1; ++ for (; cp >= fn; cp--) { ++ if (ep && (*cp == '/')) { ++ fn = ep; ++ break; ++ } ++ if (*cp == '/' || *cp == '~') ++ ep = cp; ++ else ++ ep = NULL; ++ } ++ } ++ if ((path = expandtilde(fn)) == NULL) ++ return (NULL); ++ ++ if (realpath(path, fnb) == NULL) ++ (void)strlcpy(fnb, path, sizeof(fnb)); ++ ++ free(path); ++ return (fnb); ++} ++ ++/* ++ * Find a startup file for the user and return its name. As a service ++ * to other pieces of code that may want to find a startup file (like ++ * the terminal driver in particular), accepts a suffix to be appended ++ * to the startup file name. ++ */ ++char * ++startupfile(char *suffix) ++{ ++ static char file[NFILEN]; ++ char *home; ++ int ret; ++ ++ if ((home = getenv("HOME")) == NULL || *home == '\0') ++ goto nohome; ++ ++ if (suffix == NULL) { ++ ret = snprintf(file, sizeof(file), _PATH_MG_STARTUP, home); ++ if (ret < 0 || ret >= sizeof(file)) ++ return (NULL); ++ } else { ++ ret = snprintf(file, sizeof(file), _PATH_MG_TERM, home, suffix); ++ if (ret < 0 || ret >= sizeof(file)) ++ return (NULL); ++ } ++ ++ if (access(file, R_OK) == 0) ++ return (file); ++nohome: ++#ifdef STARTUPFILE ++ if (suffix == NULL) { ++ ret = snprintf(file, sizeof(file), "%s", STARTUPFILE); ++ if (ret < 0 || ret >= sizeof(file)) ++ return (NULL); ++ } else { ++ ret = snprintf(file, sizeof(file), "%s%s", STARTUPFILE, ++ suffix); ++ if (ret < 0 || ret >= sizeof(file)) ++ return (NULL); ++ } ++ ++ if (access(file, R_OK) == 0) ++ return (file); ++#endif /* STARTUPFILE */ ++ return (NULL); ++} ++ ++int ++copy(char *frname, char *toname) ++{ ++ int ifd, ofd; ++ char buf[BUFSIZ]; ++ mode_t fmode = DEFFILEMODE; /* XXX?? */ ++ struct stat orig; ++ ssize_t sr; ++ ++ if ((ifd = open(frname, O_RDONLY)) == -1) ++ return (FALSE); ++ if (fstat(ifd, &orig) == -1) { ++ dobeep(); ++ ewprintf("fstat: %s", strerror(errno)); ++ close(ifd); ++ return (FALSE); ++ } ++ ++ if ((ofd = open(toname, O_WRONLY|O_CREAT|O_TRUNC, fmode)) == -1) { ++ close(ifd); ++ return (FALSE); ++ } ++ while ((sr = read(ifd, buf, sizeof(buf))) > 0) { ++ if (write(ofd, buf, (size_t)sr) != sr) { ++ ewprintf("write error : %s", strerror(errno)); ++ break; ++ } ++ } ++ if (fchmod(ofd, orig.st_mode) == -1) ++ ewprintf("Cannot set original mode : %s", strerror(errno)); ++ ++ if (sr == -1) { ++ ewprintf("Read error : %s", strerror(errno)); ++ close(ifd); ++ close(ofd); ++ return (FALSE); ++ } ++ /* ++ * It is "normal" for this to fail since we can't guarantee that ++ * we will be running as root. ++ */ ++ if (fchown(ofd, orig.st_uid, orig.st_gid) && errno != EPERM) ++ ewprintf("Cannot set owner : %s", strerror(errno)); ++ ++ (void) close(ifd); ++ (void) close(ofd); ++ ++ return (TRUE); ++} ++ ++/* ++ * return list of file names that match the name in buf. ++ */ ++struct list * ++make_file_list(char *buf) ++{ ++ char *dir, *file, *cp; ++ size_t len, preflen; ++ int ret; ++ DIR *dirp; ++ struct dirent *dent; ++ struct list *last, *current; ++ char fl_name[NFILEN + 2]; ++ char prefixx[NFILEN + 1]; ++ ++ /* ++ * We need three different strings: ++ ++ * dir - the name of the directory containing what the user typed. ++ * Must be a real unix file name, e.g. no ~user, etc.. ++ * Must not end in /. ++ * prefix - the portion of what the user typed that is before the ++ * names we are going to find in the directory. Must have a ++ * trailing / if the user typed it. ++ * names from the directory - We open dir, and return prefix ++ * concatenated with names. ++ */ ++ ++ /* first we get a directory name we can look up */ ++ /* ++ * Names ending in . are potentially odd, because adjustname will ++ * treat foo/bar/.. as a foo/, whereas we are ++ * interested in names starting with .. ++ */ ++ len = strlen(buf); ++ if (len && buf[len - 1] == '.') { ++ buf[len - 1] = 'x'; ++ dir = adjustname(buf, TRUE); ++ buf[len - 1] = '.'; ++ } else ++ dir = adjustname(buf, TRUE); ++ if (dir == NULL) ++ return (NULL); ++ /* ++ * If the user typed a trailing / or the empty string ++ * he wants us to use his file spec as a directory name. ++ */ ++ if (len && buf[len - 1] != '/') { ++ file = strrchr(dir, '/'); ++ if (file) { ++ *file = '\0'; ++ if (*dir == '\0') ++ dir = "/"; ++ } else ++ return (NULL); ++ } ++ /* Now we get the prefix of the name the user typed. */ ++ if (strlcpy(prefixx, buf, sizeof(prefixx)) >= sizeof(prefixx)) ++ return (NULL); ++ cp = strrchr(prefixx, '/'); ++ if (cp == NULL) ++ prefixx[0] = '\0'; ++ else ++ cp[1] = '\0'; ++ ++ preflen = strlen(prefixx); ++ /* cp is the tail of buf that really needs to be compared. */ ++ cp = buf + preflen; ++ len = strlen(cp); ++ ++ /* ++ * Now make sure that file names will fit in the buffers allocated. ++ * SV files are fairly short. For BSD, something more general would ++ * be required. ++ */ ++ if (preflen > NFILEN - MAXNAMLEN) ++ return (NULL); ++ ++ /* loop over the specified directory, making up the list of files */ ++ ++ /* ++ * Note that it is worth our time to filter out names that don't ++ * match, even though our caller is going to do so again, and to ++ * avoid doing the stat if completion is being done, because stat'ing ++ * every file in the directory is relatively expensive. ++ */ ++ ++ dirp = opendir(dir); ++ if (dirp == NULL) ++ return (NULL); ++ last = NULL; ++ ++ while ((dent = readdir(dirp)) != NULL) { ++ int isdir; ++ if (strncmp(cp, dent->d_name, len) != 0) ++ continue; ++ isdir = 0; ++ if (dent->d_type == DT_DIR) { ++ isdir = 1; ++ } else if (dent->d_type == DT_LNK || ++ dent->d_type == DT_UNKNOWN) { ++ struct stat statbuf; ++ ++ if (fstatat(dirfd(dirp), dent->d_name, &statbuf, 0) < 0) ++ continue; ++ if (S_ISDIR(statbuf.st_mode)) ++ isdir = 1; ++ } ++ ++ if ((current = malloc(sizeof(struct list))) == NULL) { ++ free_file_list(last); ++ closedir(dirp); ++ return (NULL); ++ } ++ ret = snprintf(fl_name, sizeof(fl_name), ++ "%s%s%s", prefixx, dent->d_name, isdir ? "/" : ""); ++ if (ret < 0 || ret >= sizeof(fl_name)) { ++ free(current); ++ continue; ++ } ++ current->l_next = last; ++ current->l_name = strdup(fl_name); ++ last = current; ++ } ++ closedir(dirp); ++ ++ return (last); ++} ++ ++/* ++ * Test if a supplied filename refers to a directory ++ * Returns ABORT on error, TRUE if directory. FALSE otherwise ++ */ ++int ++fisdir(const char *fname) ++{ ++ struct stat statbuf; ++ ++ if (stat(fname, &statbuf) != 0) ++ return (ABORT); ++ ++ if (S_ISDIR(statbuf.st_mode)) ++ return (TRUE); ++ ++ return (FALSE); ++} ++ ++/* ++ * Check the mtime of the supplied filename. ++ * Return TRUE if last mtime matches, FALSE if not, ++ * If the stat fails, return TRUE and try the save anyway ++ */ ++int ++fchecktime(struct buffer *bp) ++{ ++ struct stat sb; ++ ++ if (stat(bp->b_fname, &sb) == -1) ++ return (TRUE); ++ ++ /* if (bp->b_fi.fi_mtime.tv_sec != sb.st_mtimespec.tv_sec || ++ bp->b_fi.fi_mtime.tv_nsec != sb.st_mtimespec.tv_nsec) */ ++ if (bp->b_fi.fi_mtime.tv_sec != sb.st_mtime) ++ return (FALSE); ++ ++ return (TRUE); ++ ++} ++ ++/* ++ * Location of backup file. This function creates the correct path. ++ */ ++static char * ++bkuplocation(const char *fn) ++{ ++ struct stat sb; ++ char *ret; ++ ++ if (bkupdir != NULL && (stat(bkupdir, &sb) == 0) && ++ S_ISDIR(sb.st_mode) && !bkupleavetmp(fn)) { ++ char fname[NFILEN]; ++ const char *c; ++ int i = 0, len; ++ ++ c = fn; ++ len = strlen(bkupdir); ++ ++ while (*c != '\0') { ++ /* Make sure we don't go over combined: ++ * strlen(bkupdir + '/' + fname + '\0') ++ */ ++ if (i >= NFILEN - len - 1) ++ return (NULL); ++ if (*c == '/') { ++ fname[i] = '!'; ++ } else if (*c == '!') { ++ if (i >= NFILEN - len - 2) ++ return (NULL); ++ fname[i++] = '!'; ++ fname[i] = '!'; ++ } else ++ fname[i] = *c; ++ i++; ++ c++; ++ } ++ fname[i] = '\0'; ++ if (asprintf(&ret, "%s/%s", bkupdir, fname) == -1) ++ return (NULL); ++ ++ } else if ((ret = strndup(fn, NFILEN)) == NULL) ++ return (NULL); ++ ++ return (ret); ++} ++ ++int ++backuptohomedir(int f, int n) ++{ ++ const char *c = _PATH_MG_DIR; ++ char *p; ++ ++ if (bkupdir == NULL) { ++ p = adjustname(c, TRUE); ++ bkupdir = strndup(p, NFILEN); ++ if (bkupdir == NULL) ++ return(FALSE); ++ ++ if (mkdir(bkupdir, 0700) == -1 && errno != EEXIST) { ++ free(bkupdir); ++ bkupdir = NULL; ++ } ++ } else { ++ free(bkupdir); ++ bkupdir = NULL; ++ } ++ ++ return (TRUE); ++} ++ ++/* ++ * For applications that use mg as the editor and have a desire to keep ++ * '~' files in /tmp, toggle the location: /tmp | ~/.mg.d ++ */ ++int ++toggleleavetmp(int f, int n) ++{ ++ leavetmp = !leavetmp; ++ ++ return (TRUE); ++} ++ ++/* ++ * Returns TRUE if fn is located in the temp directory and we want to save ++ * those backups there. ++ */ ++int ++bkupleavetmp(const char *fn) ++{ ++ if (!leavetmp) ++ return(FALSE); ++ ++ if (strncmp(fn, "/tmp", 4) == 0) ++ return (TRUE); ++ ++ return (FALSE); ++} ++ ++/* ++ * Expand file names beginning with '~' if appropriate: ++ * 1, if ./~fn exists, continue without expanding tilde. ++ * 2, else, if username 'fn' exists, expand tilde with home directory path. ++ * 3, otherwise, continue and create new buffer called ~fn. ++ */ ++char * ++expandtilde(const char *fn) ++{ ++ struct passwd *pw; ++ struct stat statbuf; ++ const char *cp; ++ char user[LOGIN_NAME_MAX], path[NFILEN]; ++ char *ret; ++ size_t ulen, plen; ++ ++ path[0] = '\0'; ++ ++ if (fn[0] != '~' || stat(fn, &statbuf) == 0) { ++ if ((ret = strndup(fn, NFILEN)) == NULL) ++ return (NULL); ++ return(ret); ++ } ++ cp = strchr(fn, '/'); ++ if (cp == NULL) ++ cp = fn + strlen(fn); /* point to the NUL byte */ ++ ulen = cp - &fn[1]; ++ if (ulen >= sizeof(user)) { ++ if ((ret = strndup(fn, NFILEN)) == NULL) ++ return (NULL); ++ return(ret); ++ } ++ if (ulen == 0) /* ~/ or ~ */ ++ pw = getpwuid(geteuid()); ++ else { /* ~user/ or ~user */ ++ memcpy(user, &fn[1], ulen); ++ user[ulen] = '\0'; ++ pw = getpwnam(user); ++ } ++ if (pw != NULL) { ++ plen = strlcpy(path, pw->pw_dir, sizeof(path)); ++ if (plen == 0 || path[plen - 1] != '/') { ++ if (strlcat(path, "/", sizeof(path)) >= sizeof(path)) { ++ dobeep(); ++ ewprintf("Path too long"); ++ return (NULL); ++ } ++ } ++ fn = cp; ++ if (*fn == '/') ++ fn++; ++ } ++ if (strlcat(path, fn, sizeof(path)) >= sizeof(path)) { ++ dobeep(); ++ ewprintf("Path too long"); ++ return (NULL); ++ } ++ if ((ret = strndup(path, NFILEN)) == NULL) ++ return (NULL); ++ ++ return (ret); ++} diff -Naur a/futimens.c b/futimens.c --- a/futimens.c 1970-01-01 01:00:00.000000000 +0100 -+++ b/futimens.c 2020-02-01 21:55:02.000000000 +0000 ++++ b/futimens.c 2020-04-20 21:26:10.000000000 +0100 @@ -0,0 +1,14 @@ +/* This file is in the public domain. */ + @@ -241,9 +1697,9 @@ diff -Naur a/futimens.c b/futimens.c + return futimes(fildes, timevals); +} diff -Naur a/grep.c b/grep.c ---- a/grep.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/grep.c 2020-02-01 21:35:07.000000000 +0000 -@@ -16,6 +16,9 @@ +--- a/grep.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/grep.c 2020-04-20 21:26:10.000000000 +0100 +@@ -15,6 +15,9 @@ #include #include @@ -253,9 +1709,375 @@ diff -Naur a/grep.c b/grep.c #include "def.h" #include "kbd.h" #include "funmap.h" +diff -Naur a/grep.c.orig b/grep.c.orig +--- a/grep.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ b/grep.c.orig 2020-04-20 21:26:06.000000000 +0100 +@@ -0,0 +1,362 @@ ++/* $OpenBSD: grep.c,v 1.48 2019/07/11 18:20:18 lum Exp $ */ ++ ++/* This file is in the public domain */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "def.h" ++#include "kbd.h" ++#include "funmap.h" ++ ++int globalwd = FALSE; ++static int compile_goto_error(int, int); ++int next_error(int, int); ++static int grep(int, int); ++static int gid(int, int); ++static struct buffer *compile_mode(const char *, const char *); ++void grep_init(void); ++ ++static char compile_last_command[NFILEN] = "make "; ++ ++/* ++ * Hints for next-error ++ * ++ * XXX - need some kind of callback to find out when those get killed. ++ */ ++struct mgwin *compile_win; ++struct buffer *compile_buffer; ++ ++static PF compile_pf[] = { ++ compile_goto_error ++}; ++ ++static struct KEYMAPE (1) compilemap = { ++ 1, ++ 1, ++ rescan, ++ { ++ { CCHR('M'), CCHR('M'), compile_pf, NULL } ++ } ++}; ++ ++void ++grep_init(void) ++{ ++ funmap_add(compile_goto_error, "compile-goto-error", 0); ++ funmap_add(next_error, "next-error", 0); ++ funmap_add(grep, "grep", 1); ++ funmap_add(compile, "compile", 0); ++ funmap_add(gid, "gid", 1); ++ maps_add((KEYMAP *)&compilemap, "compile"); ++} ++ ++/* ARGSUSED */ ++static int ++grep(int f, int n) ++{ ++ char cprompt[NFILEN], *bufp; ++ struct buffer *bp; ++ struct mgwin *wp; ++ ++ (void)strlcpy(cprompt, "grep -n ", sizeof(cprompt)); ++ if ((bufp = eread("Run grep: ", cprompt, NFILEN, ++ EFDEF | EFNEW | EFCR)) == NULL) ++ return (ABORT); ++ else if (bufp[0] == '\0') ++ return (FALSE); ++ if (strlcat(cprompt, " /dev/null", sizeof(cprompt)) >= sizeof(cprompt)) ++ return (FALSE); ++ ++ if ((bp = compile_mode("*grep*", cprompt)) == NULL) ++ return (FALSE); ++ if ((wp = popbuf(bp, WNONE)) == NULL) ++ return (FALSE); ++ curbp = bp; ++ compile_win = curwp = wp; ++ return (TRUE); ++} ++ ++/* ARGSUSED */ ++int ++compile(int f, int n) ++{ ++ char cprompt[NFILEN], *bufp; ++ struct buffer *bp; ++ struct mgwin *wp; ++ ++ (void)strlcpy(cprompt, compile_last_command, sizeof(cprompt)); ++ if ((bufp = eread("Compile command: ", cprompt, NFILEN, ++ EFDEF | EFNEW | EFCR)) == NULL) ++ return (ABORT); ++ else if (bufp[0] == '\0') ++ return (FALSE); ++ if (savebuffers(f, n) == ABORT) ++ return (ABORT); ++ (void)strlcpy(compile_last_command, bufp, sizeof(compile_last_command)); ++ ++ if ((bp = compile_mode("*compile*", cprompt)) == NULL) ++ return (FALSE); ++ if ((wp = popbuf(bp, WNONE)) == NULL) ++ return (FALSE); ++ curbp = bp; ++ compile_win = curwp = wp; ++ gotoline(FFARG, 0); ++ return (TRUE); ++} ++ ++/* id-utils foo. */ ++/* ARGSUSED */ ++static int ++gid(int f, int n) ++{ ++ char command[NFILEN]; ++ char cprompt[NFILEN], *bufp; ++ int c; ++ struct buffer *bp; ++ struct mgwin *wp; ++ int i, j, len; ++ ++ /* catch ([^\s(){}]+)[\s(){}]* */ ++ ++ i = curwp->w_doto; ++ /* Skip backwards over delimiters we are currently on */ ++ while (i > 0) { ++ c = lgetc(curwp->w_dotp, i); ++ if (isalnum(c) || c == '_') ++ break; ++ ++ i--; ++ } ++ ++ /* Skip the symbol itself */ ++ for (; i > 0; i--) { ++ c = lgetc(curwp->w_dotp, i - 1); ++ if (!isalnum(c) && c != '_') ++ break; ++ } ++ /* Fill the symbol in cprompt[] */ ++ for (j = 0; j < sizeof(cprompt) - 1 && i < llength(curwp->w_dotp); ++ j++, i++) { ++ c = lgetc(curwp->w_dotp, i); ++ if (!isalnum(c) && c != '_') ++ break; ++ cprompt[j] = c; ++ } ++ cprompt[j] = '\0'; ++ ++ if ((bufp = eread("Run gid (with args): ", cprompt, NFILEN, ++ (j ? EFDEF : 0) | EFNEW | EFCR)) == NULL) ++ return (ABORT); ++ else if (bufp[0] == '\0') ++ return (FALSE); ++ len = snprintf(command, sizeof(command), "gid %s", cprompt); ++ if (len < 0 || len >= sizeof(command)) ++ return (FALSE); ++ ++ if ((bp = compile_mode("*gid*", command)) == NULL) ++ return (FALSE); ++ if ((wp = popbuf(bp, WNONE)) == NULL) ++ return (FALSE); ++ curbp = bp; ++ compile_win = curwp = wp; ++ return (TRUE); ++} ++ ++struct buffer * ++compile_mode(const char *name, const char *command) ++{ ++ struct buffer *bp; ++ FILE *fpipe; ++ char *buf; ++ size_t sz; ++ ssize_t len; ++ int ret, n, status; ++ char cwd[NFILEN], qcmd[NFILEN]; ++ char timestr[NTIME]; ++ time_t t; ++ ++ buf = NULL; ++ sz = 0; ++ ++ n = snprintf(qcmd, sizeof(qcmd), "%s 2>&1", command); ++ if (n < 0 || n >= sizeof(qcmd)) ++ return (NULL); ++ ++ bp = bfind(name, TRUE); ++ if (bclear(bp) != TRUE) ++ return (NULL); ++ ++ if (getbufcwd(bp->b_cwd, sizeof(bp->b_cwd)) != TRUE) ++ return (NULL); ++ addlinef(bp, "cd %s", bp->b_cwd); ++ addline(bp, qcmd); ++ addline(bp, ""); ++ ++ if (getcwd(cwd, sizeof(cwd)) == NULL) ++ panic("Can't get current directory!"); ++ if (chdir(bp->b_cwd) == -1) { ++ dobeep(); ++ ewprintf("Can't change dir to %s", bp->b_cwd); ++ return (NULL); ++ } ++ if ((fpipe = popen(qcmd, "r")) == NULL) { ++ dobeep(); ++ ewprintf("Problem opening pipe"); ++ return (NULL); ++ } ++ while ((len = getline(&buf, &sz, fpipe)) != -1) { ++ if (buf[len - 1] == '\n') ++ buf[len - 1] = '\0'; ++ addline(bp, buf); ++ } ++ free(buf); ++ if (ferror(fpipe)) ++ ewprintf("Problem reading pipe"); ++ ret = pclose(fpipe); ++ t = time(NULL); ++ strftime(timestr, sizeof(timestr), "%a %b %e %T %Y", localtime(&t)); ++ addline(bp, ""); ++ if (WIFEXITED(ret)) { ++ status = WEXITSTATUS(ret); ++ if (status == 0) ++ addlinef(bp, "Command finished at %s", timestr); ++ else ++ addlinef(bp, "Command exited abnormally with code %d " ++ "at %s", status, timestr); ++ } else ++ addlinef(bp, "Subshell killed by signal %d at %s", ++ WTERMSIG(ret), timestr); ++ ++ bp->b_dotp = bfirstlp(bp); ++ bp->b_modes[0] = name_mode("fundamental"); ++ bp->b_modes[1] = name_mode("compile"); ++ bp->b_nmodes = 1; ++ ++ compile_buffer = bp; ++ ++ if (chdir(cwd) == -1) { ++ dobeep(); ++ ewprintf("Can't change dir back to %s", cwd); ++ return (NULL); ++ } ++ return (bp); ++} ++ ++/* ARGSUSED */ ++static int ++compile_goto_error(int f, int n) ++{ ++ struct buffer *bp; ++ struct mgwin *wp; ++ char *fname, *line, *lp, *ln; ++ int lineno; ++ char *adjf, path[NFILEN]; ++ const char *errstr; ++ struct line *last; ++ ++ compile_win = curwp; ++ compile_buffer = curbp; ++ last = blastlp(compile_buffer); ++ ++ retry: ++ /* last line is compilation result */ ++ if (curwp->w_dotp == last) ++ return (FALSE); ++ ++ if ((line = linetostr(curwp->w_dotp)) == NULL) ++ return (FALSE); ++ lp = line; ++ if ((fname = strsep(&lp, ":")) == NULL || *fname == '\0') ++ goto fail; ++ if ((ln = strsep(&lp, ":")) == NULL || *ln == '\0') ++ goto fail; ++ lineno = (int)strtonum(ln, INT_MIN, INT_MAX, &errstr); ++ if (errstr) ++ goto fail; ++ ++ if (fname && fname[0] != '/') { ++ if (getbufcwd(path, sizeof(path)) == FALSE) ++ goto fail; ++ if (strlcat(path, fname, sizeof(path)) >= sizeof(path)) ++ goto fail; ++ adjf = path; ++ } else { ++ adjf = adjustname(fname, TRUE); ++ } ++ free(line); ++ ++ if (adjf == NULL) ++ return (FALSE); ++ ++ if ((bp = findbuffer(adjf)) == NULL) ++ return (FALSE); ++ if ((wp = popbuf(bp, WNONE)) == NULL) ++ return (FALSE); ++ curbp = bp; ++ curwp = wp; ++ if (bp->b_fname[0] == '\0') ++ readin(adjf); ++ gotoline(FFARG, lineno); ++ return (TRUE); ++fail: ++ free(line); ++ if (curwp->w_dotp != blastlp(curbp)) { ++ curwp->w_dotp = lforw(curwp->w_dotp); ++ curwp->w_rflag |= WFMOVE; ++ goto retry; ++ } ++ dobeep(); ++ ewprintf("No more hits"); ++ return (FALSE); ++} ++ ++/* ARGSUSED */ ++int ++next_error(int f, int n) ++{ ++ if (compile_win == NULL || compile_buffer == NULL) { ++ dobeep(); ++ ewprintf("No compilation active"); ++ return (FALSE); ++ } ++ curwp = compile_win; ++ curbp = compile_buffer; ++ if (curwp->w_dotp == blastlp(curbp)) { ++ dobeep(); ++ ewprintf("No more hits"); ++ return (FALSE); ++ } ++ curwp->w_dotp = lforw(curwp->w_dotp); ++ curwp->w_rflag |= WFMOVE; ++ ++ return (compile_goto_error(f, n)); ++} ++ ++/* ++ * Since we don't have variables (we probably should) these are command ++ * processors for changing the values of mode flags. ++ */ ++/* ARGSUSED */ ++int ++globalwdtoggle(int f, int n) ++{ ++ if (f & FFARG) ++ globalwd = n > 0; ++ else ++ globalwd = !globalwd; ++ ++ sgarbf = TRUE; ++ ++ return (TRUE); ++} diff -Naur a/main.c b/main.c ---- a/main.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/main.c 2020-02-01 21:34:42.000000000 +0000 +--- a/main.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/main.c 2020-04-20 21:26:10.000000000 +0100 @@ -16,6 +16,9 @@ #include #include @@ -267,8 +2089,8 @@ diff -Naur a/main.c b/main.c #include "kbd.h" #include "funmap.h" diff -Naur a/paragraph.c b/paragraph.c ---- a/paragraph.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/paragraph.c 2020-02-01 21:34:49.000000000 +0000 +--- a/paragraph.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/paragraph.c 2020-04-20 21:26:10.000000000 +0100 @@ -14,6 +14,9 @@ #include #include @@ -279,9 +2101,554 @@ diff -Naur a/paragraph.c b/paragraph.c #include "def.h" static int fillcol = 70; +diff -Naur a/paragraph.c.orig b/paragraph.c.orig +--- a/paragraph.c.orig 1970-01-01 01:00:00.000000000 +0100 ++++ b/paragraph.c.orig 2020-04-20 21:26:06.000000000 +0100 +@@ -0,0 +1,499 @@ ++/* $OpenBSD: paragraph.c,v 1.46 2018/11/17 09:52:34 lum Exp $ */ ++ ++/* This file is in the public domain. */ ++ ++/* ++ * Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6 ++ * and GNU-ified by mwm@ucbvax. Several bug fixes by blarson@usc-oberon. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "def.h" ++ ++static int fillcol = 70; ++ ++#define MAXWORD 256 ++ ++static int findpara(void); ++static int do_gotoeop(int, int, int *); ++ ++/* ++ * Move to start of paragraph. ++ * Move backwards by line, checking from the 1st character forwards for the ++ * existence a non-space. If a non-space character is found, move to the ++ * preceding line. Keep doing this until a line with only spaces is found or ++ * the start of buffer. ++ */ ++/* ARGSUSED */ ++int ++gotobop(int f, int n) ++{ ++ int col, nospace; ++ ++ /* the other way... */ ++ if (n < 0) ++ return (gotoeop(f, -n)); ++ ++ while (n-- > 0) { ++ nospace = 0; ++ while (lback(curwp->w_dotp) != curbp->b_headp) { ++ curwp->w_doto = 0; ++ col = 0; ++ ++ while (col < llength(curwp->w_dotp) && ++ (isspace(lgetc(curwp->w_dotp, col)))) ++ col++; ++ ++ if (col >= llength(curwp->w_dotp)) { ++ if (nospace) ++ break; ++ } else ++ nospace = 1; ++ ++ curwp->w_dotline--; ++ curwp->w_dotp = lback(curwp->w_dotp); ++ } ++ } ++ /* force screen update */ ++ curwp->w_rflag |= WFMOVE; ++ return (TRUE); ++} ++ ++/* ++ * Move to end of paragraph. ++ * See comments for gotobop(). Same, but moving forwards. ++ */ ++/* ARGSUSED */ ++int ++gotoeop(int f, int n) ++{ ++ int i; ++ ++ return(do_gotoeop(f, n, &i)); ++} ++ ++int ++do_gotoeop(int f, int n, int *i) ++{ ++ int col, nospace, j = 0; ++ ++ /* the other way... */ ++ if (n < 0) ++ return (gotobop(f, -n)); ++ ++ /* for each one asked for */ ++ while (n-- > 0) { ++ *i = ++j; ++ nospace = 0; ++ while (lforw(curwp->w_dotp) != curbp->b_headp) { ++ col = 0; ++ curwp->w_doto = 0; ++ ++ while (col < llength(curwp->w_dotp) && ++ (isspace(lgetc(curwp->w_dotp, col)))) ++ col++; ++ ++ if (col >= llength(curwp->w_dotp)) { ++ if (nospace) ++ break; ++ } else ++ nospace = 1; ++ ++ curwp->w_dotp = lforw(curwp->w_dotp); ++ curwp->w_dotline++; ++ ++ } ++ } ++ /* do not continue after end of buffer */ ++ if (lforw(curwp->w_dotp) == curbp->b_headp) { ++ gotoeol(FFRAND, 1); ++ curwp->w_rflag |= WFMOVE; ++ return (FALSE); ++ } ++ ++ /* force screen update */ ++ curwp->w_rflag |= WFMOVE; ++ return (TRUE); ++} ++ ++/* ++ * Justify a paragraph. Fill the current paragraph according to the current ++ * fill column. ++ */ ++/* ARGSUSED */ ++int ++fillpara(int f, int n) ++{ ++ int c; /* current char during scan */ ++ int wordlen; /* length of current word */ ++ int clength; /* position on line during fill */ ++ int i; /* index during word copy */ ++ int eopflag; /* Are we at the End-Of-Paragraph? */ ++ int firstflag; /* first word? (needs no space) */ ++ int newlength; /* tentative new line length */ ++ int eolflag; /* was at end of line */ ++ int retval; /* return value */ ++ struct line *eopline; /* pointer to line just past EOP */ ++ char wbuf[MAXWORD]; /* buffer for current word */ ++ ++ if (n == 0) ++ return (TRUE); ++ ++ undo_boundary_enable(FFRAND, 0); ++ ++ /* record the pointer to the line just past the EOP */ ++ (void)gotoeop(FFRAND, 1); ++ if (curwp->w_doto != 0) { ++ /* paragraph ends at end of buffer */ ++ (void)lnewline(); ++ eopline = lforw(curwp->w_dotp); ++ } else ++ eopline = curwp->w_dotp; ++ ++ /* and back top the beginning of the paragraph */ ++ (void)gotobop(FFRAND, 1); ++ ++ /* initialize various info */ ++ while (inword() == 0 && forwchar(FFRAND, 1)); ++ ++ clength = curwp->w_doto; ++ wordlen = 0; ++ ++ /* scan through lines, filling words */ ++ firstflag = TRUE; ++ eopflag = FALSE; ++ while (!eopflag) { ++ ++ /* get the next character in the paragraph */ ++ if ((eolflag = (curwp->w_doto == llength(curwp->w_dotp)))) { ++ c = ' '; ++ if (lforw(curwp->w_dotp) == eopline) ++ eopflag = TRUE; ++ } else ++ c = lgetc(curwp->w_dotp, curwp->w_doto); ++ ++ /* and then delete it */ ++ if (ldelete((RSIZE) 1, KNONE) == FALSE && !eopflag) { ++ retval = FALSE; ++ goto cleanup; ++ } ++ ++ /* if not a separator, just add it in */ ++ if (c != ' ' && c != '\t') { ++ if (wordlen < MAXWORD - 1) ++ wbuf[wordlen++] = c; ++ else { ++ /* ++ * You lose chars beyond MAXWORD if the word ++ * is too long. I'm too lazy to fix it now; it ++ * just silently truncated the word before, ++ * so I get to feel smug. ++ */ ++ ewprintf("Word too long!"); ++ } ++ } else if (wordlen) { ++ ++ /* calculate tentative new length with word added */ ++ newlength = clength + 1 + wordlen; ++ ++ /* ++ * if at end of line or at doublespace and previous ++ * character was one of '.','?','!' doublespace here. ++ * behave the same way if a ')' is preceded by a ++ * [.?!] and followed by a doublespace. ++ */ ++ if (dblspace && (!eopflag && ((eolflag || ++ curwp->w_doto == llength(curwp->w_dotp) || ++ (c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' ++ || c == '\t') && (ISEOSP(wbuf[wordlen - 1]) || ++ (wbuf[wordlen - 1] == ')' && wordlen >= 2 && ++ ISEOSP(wbuf[wordlen - 2])))) && ++ wordlen < MAXWORD - 1)) ++ wbuf[wordlen++] = ' '; ++ ++ /* at a word break with a word waiting */ ++ if (newlength <= fillcol) { ++ /* add word to current line */ ++ if (!firstflag) { ++ (void)linsert(1, ' '); ++ ++clength; ++ } ++ firstflag = FALSE; ++ } else { ++ if (curwp->w_doto > 0 && ++ lgetc(curwp->w_dotp, curwp->w_doto - 1) == ' ') { ++ curwp->w_doto -= 1; ++ (void)ldelete((RSIZE) 1, KNONE); ++ } ++ /* start a new line */ ++ (void)lnewline(); ++ clength = 0; ++ } ++ ++ /* and add the word in in either case */ ++ for (i = 0; i < wordlen; i++) { ++ (void)linsert(1, wbuf[i]); ++ ++clength; ++ } ++ wordlen = 0; ++ } ++ } ++ /* and add a last newline for the end of our new paragraph */ ++ (void)lnewline(); ++ ++ /* ++ * We really should wind up where we started, (which is hard to keep ++ * track of) but I think the end of the last line is better than the ++ * beginning of the blank line. ++ */ ++ (void)backchar(FFRAND, 1); ++ retval = TRUE; ++cleanup: ++ undo_boundary_enable(FFRAND, 1); ++ return (retval); ++} ++ ++/* ++ * Delete n paragraphs. Move to the beginning of the current paragraph, or if ++ * the cursor is on an empty line, move down the buffer to the first line with ++ * non-space characters. Then mark n paragraphs and delete. ++ */ ++/* ARGSUSED */ ++int ++killpara(int f, int n) ++{ ++ int lineno, status; ++ ++ if (n == 0) ++ return (TRUE); ++ ++ if (findpara() == FALSE) ++ return (TRUE); ++ ++ /* go to the beginning of the paragraph */ ++ (void)gotobop(FFRAND, 1); ++ ++ /* take a note of the line number for after deletions and set mark */ ++ lineno = curwp->w_dotline; ++ curwp->w_markp = curwp->w_dotp; ++ curwp->w_marko = curwp->w_doto; ++ ++ (void)gotoeop(FFRAND, n); ++ ++ if ((status = killregion(FFRAND, 1)) != TRUE) ++ return (status); ++ ++ curwp->w_dotline = lineno; ++ return (TRUE); ++} ++ ++/* ++ * Mark n paragraphs starting with the n'th and working our way backwards. ++ * This leaves the cursor at the beginning of the paragraph where markpara() ++ * was invoked. ++ */ ++/* ARGSUSED */ ++int ++markpara(int f, int n) ++{ ++ int i = 0; ++ ++ if (n == 0) ++ return (TRUE); ++ ++ clearmark(FFARG, 0); ++ ++ if (findpara() == FALSE) ++ return (TRUE); ++ ++ (void)do_gotoeop(FFRAND, n, &i); ++ ++ /* set the mark here */ ++ curwp->w_markp = curwp->w_dotp; ++ curwp->w_marko = curwp->w_doto; ++ ++ (void)gotobop(FFRAND, i); ++ ++ return (TRUE); ++} ++ ++/* ++ * Transpose the current paragraph with the following paragraph. If invoked ++ * multiple times, transpose to the n'th paragraph. If invoked between ++ * paragraphs, move to the previous paragraph, then continue. ++ */ ++/* ARGSUSED */ ++int ++transposepara(int f, int n) ++{ ++ int i = 0, status; ++ char flg; ++ ++ if (n == 0) ++ return (TRUE); ++ ++ undo_boundary_enable(FFRAND, 0); ++ ++ /* find a paragraph, set mark, then goto the end */ ++ gotobop(FFRAND, 1); ++ curwp->w_markp = curwp->w_dotp; ++ curwp->w_marko = curwp->w_doto; ++ (void)gotoeop(FFRAND, 1); ++ ++ /* take a note of buffer flags - we may need them */ ++ flg = curbp->b_flag; ++ ++ /* clean out kill buffer then kill region */ ++ kdelete(); ++ if ((status = killregion(FFRAND, 1)) != TRUE) ++ return (status); ++ ++ /* ++ * Now step through n paragraphs. If we reach the end of buffer, ++ * stop and paste the killed region back, then display a message. ++ */ ++ if (do_gotoeop(FFRAND, n, &i) == FALSE) { ++ ewprintf("Cannot transpose paragraph, end of buffer reached."); ++ (void)gotobop(FFRAND, i); ++ (void)yank(FFRAND, 1); ++ curbp->b_flag = flg; ++ return (FALSE); ++ } ++ (void)yank(FFRAND, 1); ++ ++ undo_boundary_enable(FFRAND, 1); ++ ++ return (TRUE); ++} ++ ++/* ++ * Go down the buffer until we find a line with non-space characters. ++ */ ++int ++findpara(void) ++{ ++ int col, nospace = 0; ++ ++ /* we move forward to find a para to mark */ ++ do { ++ curwp->w_doto = 0; ++ col = 0; ++ ++ /* check if we are on a blank line */ ++ while (col < llength(curwp->w_dotp)) { ++ if (!isspace(lgetc(curwp->w_dotp, col))) ++ nospace = 1; ++ col++; ++ } ++ if (nospace) ++ break; ++ ++ if (lforw(curwp->w_dotp) == curbp->b_headp) ++ return (FALSE); ++ ++ curwp->w_dotp = lforw(curwp->w_dotp); ++ curwp->w_dotline++; ++ } while (1); ++ ++ return (TRUE); ++} ++ ++/* ++ * Insert char with work wrap. Check to see if we're past fillcol, and if so, ++ * justify this line. As a last step, justify the line. ++ */ ++/* ARGSUSED */ ++int ++fillword(int f, int n) ++{ ++ char c; ++ int col, i, nce; ++ ++ for (i = col = 0; col <= fillcol; ++i, ++col) { ++ if (i == curwp->w_doto) ++ return selfinsert(f, n); ++ c = lgetc(curwp->w_dotp, i); ++ if (c == '\t' ++#ifdef NOTAB ++ && !(curbp->b_flag & BFNOTAB) ++#endif ++ ) ++ col |= 0x07; ++ else if (ISCTRL(c) != FALSE) ++ ++col; ++ } ++ if (curwp->w_doto != llength(curwp->w_dotp)) { ++ (void)selfinsert(f, n); ++ nce = llength(curwp->w_dotp) - curwp->w_doto; ++ } else ++ nce = 0; ++ curwp->w_doto = i; ++ ++ if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t') ++ do { ++ (void)backchar(FFRAND, 1); ++ } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && ++ c != '\t' && curwp->w_doto > 0); ++ ++ if (curwp->w_doto == 0) ++ do { ++ (void)forwchar(FFRAND, 1); ++ } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && ++ c != '\t' && curwp->w_doto < llength(curwp->w_dotp)); ++ ++ (void)delwhite(FFRAND, 1); ++ (void)lnewline(); ++ i = llength(curwp->w_dotp) - nce; ++ curwp->w_doto = i > 0 ? i : 0; ++ curwp->w_rflag |= WFMOVE; ++ if (nce == 0 && curwp->w_doto != 0) ++ return (fillword(f, n)); ++ return (TRUE); ++} ++ ++/* ++ * Set fill column to n for justify. ++ */ ++int ++setfillcol(int f, int n) ++{ ++ char buf[32], *rep; ++ const char *es; ++ int nfill; ++ ++ if ((f & FFARG) != 0) { ++ fillcol = n; ++ } else { ++ if ((rep = eread("Set fill-column: ", buf, sizeof(buf), ++ EFNEW | EFCR)) == NULL) ++ return (ABORT); ++ else if (rep[0] == '\0') ++ return (FALSE); ++ nfill = strtonum(rep, 0, INT_MAX, &es); ++ if (es != NULL) { ++ dobeep(); ++ ewprintf("Invalid fill column: %s", rep); ++ return (FALSE); ++ } ++ fillcol = nfill; ++ ewprintf("Fill column set to %d", fillcol); ++ } ++ return (TRUE); ++} ++ ++int ++sentencespace(int f, int n) ++{ ++ if (f & FFARG) ++ dblspace = n > 1; ++ else ++ dblspace = !dblspace; ++ ++ return (TRUE); ++} +diff -Naur a/reallocarray.c b/reallocarray.c +--- a/reallocarray.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/reallocarray.c 2020-04-20 21:26:10.000000000 +0100 +@@ -0,0 +1,38 @@ ++/* $OpenBSD: reallocarray.c,v 1.3 2015/09/13 08:31:47 guenther Exp $ */ ++/* ++ * Copyright (c) 2008 Otto Moerbeek ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* ++ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX ++ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW ++ */ ++#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) ++ ++void * ++reallocarray(void *optr, size_t nmemb, size_t size) ++{ ++ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && ++ nmemb > 0 && SIZE_MAX / nmemb < size) { ++ errno = ENOMEM; ++ return NULL; ++ } ++ return realloc(optr, size * nmemb); ++} diff -Naur a/strtonum.c b/strtonum.c --- a/strtonum.c 1970-01-01 01:00:00.000000000 +0100 -+++ b/strtonum.c 2020-02-01 21:55:24.000000000 +0000 ++++ b/strtonum.c 2020-04-20 21:26:10.000000000 +0100 @@ -0,0 +1,65 @@ +/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */ + @@ -349,8 +2716,8 @@ diff -Naur a/strtonum.c b/strtonum.c + return (ll); +} diff -Naur a/tags.c b/tags.c ---- a/tags.c 2020-02-01 21:23:32.000000000 +0000 -+++ b/tags.c 2020-02-01 21:27:56.000000000 +0000 +--- a/tags.c 2020-04-20 21:09:41.000000000 +0100 ++++ b/tags.c 2020-04-20 21:26:10.000000000 +0100 @@ -8,7 +8,11 @@ #include @@ -392,7 +2759,7 @@ diff -Naur a/tags.c b/tags.c struct tagpos { diff -Naur a/tree.h b/tree.h --- a/tree.h 1970-01-01 01:00:00.000000000 +0100 -+++ b/tree.h 2020-02-01 21:25:11.000000000 +0000 ++++ b/tree.h 2020-04-20 21:26:10.000000000 +0100 @@ -0,0 +1,1006 @@ +/* $OpenBSD: tree.h,v 1.29 2017/07/30 19:27:20 deraadt Exp $ */ +/* diff --git a/pkgs/applications/editors/mg/default.nix b/pkgs/applications/editors/mg/default.nix index f97e34aff8dd..e019baaf727b 100644 --- a/pkgs/applications/editors/mg/default.nix +++ b/pkgs/applications/editors/mg/default.nix @@ -1,12 +1,14 @@ -{ stdenv, fetchurl, pkgconfig, ncurses, buildPackages, libbsd }: +{ stdenv, fetchFromGitHub, pkgconfig, ncurses, buildPackages, libbsd }: stdenv.mkDerivation rec { pname = "mg"; - version = "20180927"; + version = "20200215"; - src = fetchurl { - url = "https://github.com/hboetes/mg/archive/${version}.tar.gz"; - sha256 = "fbb09729ea00fe42dcdbc96ac7fc1d2b89eac651dec49e4e7af52fad4f5788f6"; + src = fetchFromGitHub { + owner = "hboetes"; + repo = "mg"; + rev = "20200215"; + sha256 = "1rss7d43hbq43n63gxfvx4b2vh2km58cchwzdf2ssqhaz3qj40m6"; }; enableParallelBuilding = true;