git: e51aabf8cbb9 - main - diff: implement option -F (--show-function-line)

Piotr Pawel Stefaniak pstef at FreeBSD.org
Wed Sep 15 23:59:57 UTC 2021


The branch main has been updated by pstef:

URL: https://cgit.FreeBSD.org/src/commit/?id=e51aabf8cbb9b412c725c4c9c727ca6faa0630c6

commit e51aabf8cbb9b412c725c4c9c727ca6faa0630c6
Author:     Piotr Pawel Stefaniak <pstef at FreeBSD.org>
AuthorDate: 2021-09-05 14:54:07 +0000
Commit:     Piotr Pawel Stefaniak <pstef at FreeBSD.org>
CommitDate: 2021-09-15 23:46:44 +0000

    diff: implement option -F (--show-function-line)
    
    With unified and context diffs, show the last line that matches the
    provided pattern before the context.
    
    Reviewed by:    bapt
    Differential Revision:  https://reviews.freebsd.org/D31714
---
 usr.bin/diff/diff.1    |  8 +++++++
 usr.bin/diff/diff.c    | 59 +++++++++++++++++++++++++++++++++-----------------
 usr.bin/diff/diff.h    |  6 +++--
 usr.bin/diff/diffreg.c | 14 +++++++++---
 4 files changed, 62 insertions(+), 25 deletions(-)

diff --git a/usr.bin/diff/diff.1 b/usr.bin/diff/diff.1
index 6056ddd3ac76..dea01bf918f4 100644
--- a/usr.bin/diff/diff.1
+++ b/usr.bin/diff/diff.1
@@ -65,11 +65,13 @@
 .Op Fl -text
 .Op Fl -unified
 .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern
+.Op Fl F Ar pattern | Fl -show-function-line Ar pattern
 .Op Fl L Ar label | Fl -label Ar label
 .Ar file1 file2
 .Nm diff
 .Op Fl aBbdilpTtw
 .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern
+.Op Fl F Ar pattern | Fl -show-function-line Ar pattern
 .Op Fl L Ar label | Fl -label Ar label
 .Op Fl -brief
 .Op Fl -color Ns = Ns Ar when
@@ -123,6 +125,7 @@
 .Nm diff
 .Op Fl aBbdilpTtw
 .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern
+.Op Fl F Ar pattern | Fl -show-function-line Ar pattern
 .Op Fl L Ar label | Fl -label Ar label
 .Op Fl -brief
 .Op Fl -color Ns = Ns Ar when
@@ -180,6 +183,7 @@
 .Op Fl -unidirectional-new-file
 .Op Fl -unified
 .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern
+.Op Fl F Ar pattern | Fl -show-function-line Ar pattern
 .Bk -words
 .Op Fl L Ar label | Fl -label Ar label
 .Op Fl S Ar name | Fl -starting-file Ar name
@@ -357,6 +361,10 @@ environment variable is set to a non-empty string.
 Try very hard to produce a diff as small as possible.
 This may consume a lot of processing power and memory when processing
 large files with many changes.
+.It Fl F Ar pattern, Fl -show-function-line Ar pattern
+Like
+.Fl p,
+but display the last line that matches provided pattern.
 .It Fl I Ar pattern Fl -ignore-matching-lines Ar pattern
 Ignores changes, insertions, and deletions whose lines match the
 extended regular expression
diff --git a/usr.bin/diff/diff.c b/usr.bin/diff/diff.c
index 4fc3094035d9..8074261742ae 100644
--- a/usr.bin/diff/diff.c
+++ b/usr.bin/diff/diff.c
@@ -43,14 +43,15 @@ bool	 ignore_file_case, suppress_common, color;
 int	 diff_format, diff_context, status;
 int	 tabsize = 8, width = 130;
 static int	colorflag = COLORFLAG_NEVER;
-char	*start, *ifdefname, *diffargs, *label[2], *ignore_pats;
+char	*start, *ifdefname, *diffargs, *label[2];
+char	*ignore_pats, *most_recent_pat;
 char	*group_format = NULL;
 const char	*add_code, *del_code;
 struct stat stb1, stb2;
 struct excludes *excludes_list;
-regex_t	 ignore_re;
+regex_t	 ignore_re, most_recent_re;
 
-#define	OPTIONS	"0123456789aBbC:cdD:efHhI:iL:lnNPpqrS:sTtU:uwW:X:x:y"
+#define	OPTIONS	"0123456789aBbC:cdD:efF:HhI:iL:lnNPpqrS:sTtU:uwW:X:x:y"
 enum {
 	OPT_TSIZE = CHAR_MAX + 1,
 	OPT_STRIPCR,
@@ -71,6 +72,7 @@ static struct option longopts[] = {
 	{ "minimal",			no_argument,		0,	'd' },
 	{ "ed",				no_argument,		0,	'e' },
 	{ "forward-ed",			no_argument,		0,	'f' },
+	{ "show-function-line",		required_argument,	0,	'F' },
 	{ "speed-large-files",		no_argument,		NULL,	'H' },
 	{ "ignore-blank-lines",		no_argument,		0,	'B' },
 	{ "ignore-matching-lines",	required_argument,	0,	'I' },
@@ -105,6 +107,7 @@ static struct option longopts[] = {
 	{ NULL,				0,			0,	'\0'}
 };
 
+static void checked_regcomp(char const *, regex_t *);
 static void usage(void) __dead2;
 static void conflicting_format(void) __dead2;
 static void push_excludes(char *);
@@ -190,6 +193,12 @@ main(int argc, char **argv)
 		case 'B':
 			dflags |= D_SKIPBLANKLINES;
 			break;
+		case 'F':
+			if (dflags & D_PROTOTYPE)
+				conflicting_format();
+			dflags |= D_MATCHLAST;
+			most_recent_pat = xstrdup(optarg);
+			break;
 		case 'I':
 			push_ignore_pats(optarg);
 			break;
@@ -216,6 +225,8 @@ main(int argc, char **argv)
 			diff_format = D_NREVERSE;
 			break;
 		case 'p':
+			if (dflags & D_MATCHLAST)
+				conflicting_format();
 			dflags |= D_PROTOTYPE;
 			break;
 		case 'P':
@@ -359,19 +370,8 @@ main(int argc, char **argv)
 	 */
 	if (argc != 2)
 		usage();
-	if (ignore_pats != NULL) {
-		char buf[BUFSIZ];
-		int error;
-
-		if ((error = regcomp(&ignore_re, ignore_pats,
-				     REG_NEWLINE | REG_EXTENDED)) != 0) {
-			regerror(error, &ignore_re, buf, sizeof(buf));
-			if (*ignore_pats != '\0')
-				errx(2, "%s: %s", ignore_pats, buf);
-			else
-				errx(2, "%s", buf);
-		}
-	}
+	checked_regcomp(ignore_pats, &ignore_re);
+	checked_regcomp(most_recent_pat, &most_recent_re);
 	if (strcmp(argv[0], "-") == 0) {
 		fstat(STDIN_FILENO, &stb1);
 		gotstdin = 1;
@@ -426,6 +426,25 @@ main(int argc, char **argv)
 	exit(status);
 }
 
+static void
+checked_regcomp(char const *pattern, regex_t *comp)
+{
+	char buf[BUFSIZ];
+	int error;
+
+	if (pattern == NULL)
+		return;
+
+	error = regcomp(comp, pattern, REG_NEWLINE | REG_EXTENDED);
+	if (error != 0) {
+		regerror(error, comp, buf, sizeof(buf));
+		if (*pattern != '\0')
+			errx(2, "%s: %s", pattern, buf);
+		else
+			errx(2, "%s", buf);
+	}
+}
+
 static void
 set_argstr(char **av, char **ave)
 {
@@ -548,18 +567,18 @@ usage(void)
 	(void)fprintf(stderr,
 	    "usage: diff [-aBbdilpTtw] [-c | -e | -f | -n | -q | -u] [--ignore-case]\n"
 	    "            [--no-ignore-case] [--normal] [--strip-trailing-cr] [--tabsize]\n"
-	    "            [-I pattern] [-L label] file1 file2\n"
+	    "            [-I pattern] [-F pattern] [-L label] file1 file2\n"
 	    "       diff [-aBbdilpTtw] [-I pattern] [-L label] [--ignore-case]\n"
 	    "            [--no-ignore-case] [--normal] [--strip-trailing-cr] [--tabsize]\n"
-	    "            -C number file1 file2\n"
+	    "            [-F pattern] -C number file1 file2\n"
 	    "       diff [-aBbdiltw] [-I pattern] [--ignore-case] [--no-ignore-case]\n"
 	    "            [--normal] [--strip-trailing-cr] [--tabsize] -D string file1 file2\n"
 	    "       diff [-aBbdilpTtw] [-I pattern] [-L label] [--ignore-case]\n"
 	    "            [--no-ignore-case] [--normal] [--tabsize] [--strip-trailing-cr]\n"
-	    "            -U number file1 file2\n"
+	    "            [-F pattern] -U number file1 file2\n"
 	    "       diff [-aBbdilNPprsTtw] [-c | -e | -f | -n | -q | -u] [--ignore-case]\n"
 	    "            [--no-ignore-case] [--normal] [--tabsize] [-I pattern] [-L label]\n"
-	    "            [-S name] [-X file] [-x pattern] dir1 dir2\n"
+	    "            [-F pattern] [-S name] [-X file] [-x pattern] dir1 dir2\n"
 	    "       diff [-aBbditwW] [--expand-tabs] [--ignore-all-blanks]\n"
 	    "            [--ignore-blank-lines] [--ignore-case] [--minimal]\n"
 	    "            [--no-ignore-file-name-case] [--strip-trailing-cr]\n"
diff --git a/usr.bin/diff/diff.h b/usr.bin/diff/diff.h
index 5164fe22ace4..4a7d19ee8982 100644
--- a/usr.bin/diff/diff.h
+++ b/usr.bin/diff/diff.h
@@ -74,6 +74,7 @@
 #define D_IGNOREBLANKS		0x200	/* Ignore white space changes */
 #define D_STRIPCR		0x400	/* Strip trailing cr */
 #define D_SKIPBLANKLINES	0x800	/* Skip blank lines */
+#define D_MATCHLAST		0x1000	/* Display last line matching provided regex */
 
 /*
  * Status values for print_status() and diffreg() return values
@@ -103,12 +104,13 @@ extern bool	lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag;
 extern bool	ignore_file_case, suppress_common, color;
 extern int	diff_format, diff_context, status;
 extern int	tabsize, width;
-extern char	*start, *ifdefname, *diffargs, *label[2], *ignore_pats;
+extern char	*start, *ifdefname, *diffargs, *label[2];
+extern char	*ignore_pats, *most_recent_pat;
 extern char	*group_format;
 extern const char	*add_code, *del_code;
 extern struct	stat stb1, stb2;
 extern struct	excludes *excludes_list;
-extern regex_t	ignore_re;
+extern regex_t	ignore_re, most_recent_re;
 
 int	diffreg(char *, char *, int, int);
 void	diffdir(char *, char *, int);
diff --git a/usr.bin/diff/diffreg.c b/usr.bin/diff/diffreg.c
index 47c1934a6a65..fc3c3406a073 100644
--- a/usr.bin/diff/diffreg.c
+++ b/usr.bin/diff/diffreg.c
@@ -1407,7 +1407,15 @@ match_function(const long *f, int pos, FILE *fp)
 			continue;
 		buf[nc] = '\0';
 		buf[strcspn(buf, "\n")] = '\0';
-		if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') {
+		if (most_recent_pat != NULL) {
+			int ret = regexec(&most_recent_re, buf, 0, NULL, 0);
+
+			if (ret != 0)
+				continue;
+			strlcpy(lastbuf, buf, sizeof(lastbuf));
+			lastmatchline = pos;
+			return (lastbuf);
+		} else if (isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$') {
 			if (begins_with(buf, "private:")) {
 				if (!state)
 					state = " (private)";
@@ -1448,7 +1456,7 @@ dump_context_vec(FILE *f1, FILE *f2, int flags)
 	upd = MIN(len[1], context_vec_ptr->d + diff_context);
 
 	printf("***************");
-	if ((flags & D_PROTOTYPE)) {
+	if (flags & (D_PROTOTYPE | D_MATCHLAST)) {
 		f = match_function(ixold, lowa - 1, f1);
 		if (f != NULL)
 			printf(" %s", f);
@@ -1555,7 +1563,7 @@ dump_unified_vec(FILE *f1, FILE *f2, int flags)
 	printf(" +");
 	uni_range(lowc, upd);
 	printf(" @@");
-	if ((flags & D_PROTOTYPE)) {
+	if (flags & (D_PROTOTYPE | D_MATCHLAST)) {
 		f = match_function(ixold, lowa - 1, f1);
 		if (f != NULL)
 			printf(" %s", f);


More information about the dev-commits-src-all mailing list