git: 06520254ed83 - stable/13 - ctags: Support writing to stdout instead of a file.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Wed, 14 Jun 2023 13:26:31 UTC
The branch stable/13 has been updated by des:

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

commit 06520254ed83c12fe176e719ef130be6c924bb6b
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2023-05-25 11:55:56 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2023-06-14 12:48:54 +0000

    ctags: Support writing to stdout instead of a file.
    
    * Understand "-" to mean stdout as per convention.
    * Check that the output is a regular file and ignore -u if not, otherwise we might try to rm /dev/stdout.
    * As a bonus, if -u was specified but the output file does not exist, proceed as if -u had not been specified instead of erroring out.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    cracauer, debdrup
    Differential Revision:  https://reviews.freebsd.org/D40237
    
    (cherry picked from commit 430d064ba5b0cb2e91a26af34c15df48d290e417)
    
    ctags: Recognize __attribute__ in function declarations.
    
    MFC after:      1 week
    Obtained from:  NetBSD
    Sponsored by:   Klara, Inc.
    Reviewed by:    kevans
    Differential Revision:  https://reviews.freebsd.org/D40264
    
    (cherry picked from commit 9f35eb8f96a55aac92fc0c7d08f4b6ab0ae9bc39)
    
    ctags: Don't undercount lines when handling // comments.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    kevans
    Differential Revision:  https://reviews.freebsd.org/D40374
    
    (cherry picked from commit 7ba6119e22b54c2104b1948f0e8a4157d4112958)
---
 usr.bin/ctags/C.c     | 35 +++++++++++++++++++++++++++++++++--
 usr.bin/ctags/ctags.1 | 16 +++++++++++++---
 usr.bin/ctags/ctags.c | 23 +++++++++++++++++++++--
 3 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/usr.bin/ctags/C.c b/usr.bin/ctags/C.c
index aca50c67226b..e36b60de4a55 100644
--- a/usr.bin/ctags/C.c
+++ b/usr.bin/ctags/C.c
@@ -39,6 +39,7 @@ static char sccsid[] = "@(#)C.c	8.4 (Berkeley) 4/2/94";
 __FBSDID("$FreeBSD$");
 
 #include <limits.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -261,6 +262,9 @@ func_entry(void)
 {
 	int	c;			/* current character */
 	int	level = 0;		/* for matching '()' */
+	static char attribute[] = "__attribute__";
+	char	maybe_attribute[sizeof attribute + 1],
+		*anext;
 
 	/*
 	 * Find the end of the assumed function declaration.
@@ -298,10 +302,37 @@ fnd:
 	 * is a token character if it's a function and a non-token
 	 * character if it's a declaration.  Comments don't count...
 	 */
-	for (;;) {
+	for (anext = maybe_attribute;;) {
 		while (GETC(!=, EOF) && iswhite(c))
 			if (c == '\n')
 				SETLINE;
+		if (c == EOF)
+			return NO;
+		/*
+		 * Recognize the gnu __attribute__ extension, which would
+		 * otherwise make the heuristic test DTWT
+		 */
+		if (anext == maybe_attribute) {
+			if (intoken(c)) {
+				*anext++ = c;
+				continue;
+			}
+		} else {
+			if (intoken(c)) {
+				if (anext - maybe_attribute 
+				 < (ptrdiff_t)(sizeof attribute - 1))
+					*anext++ = c;
+				else	break;
+				continue;
+			} else {
+				*anext++ = '\0';
+				if (strcmp(maybe_attribute, attribute) == 0) {
+					(void)ungetc(c, inf);
+					return NO;
+				}
+				break;
+			}
+		}
 		if (intoken(c) || c == '{')
 			break;
 		if (c == '/' && (GETC(==, '*') || c == '/'))
@@ -452,9 +483,9 @@ skip_comment(int t) /* t is comment character */
 				return;
 			break;
 		case '\n':
+			SETLINE;
 			if (t == '/')
 				return;
-			SETLINE;
 			/*FALLTHROUGH*/
 		default:
 			star = NO;
diff --git a/usr.bin/ctags/ctags.1 b/usr.bin/ctags/ctags.1
index 9b68f669202e..40c502b3ecdd 100644
--- a/usr.bin/ctags/ctags.1
+++ b/usr.bin/ctags/ctags.1
@@ -28,7 +28,7 @@
 .\"     @(#)ctags.1	8.1 (Berkeley) 6/6/93
 .\" $FreeBSD$
 .\"
-.Dd June 6, 1993
+.Dd May 23, 2023
 .Dt CTAGS 1
 .Os
 .Sh NAME
@@ -93,16 +93,26 @@ Place the tag descriptions in a file called
 .Ar tagsfile .
 The default behaviour is to place them in a file called
 .Pa tags .
+If
+.Ar tagsfile
+is
+.Dq - ,
+the tags will be written to standard output instead.
 .It Fl u
 Update the specified files in the
 .Pa tags
 file, that is, all
 references to them are deleted, and the new values are appended to the
 file.
-(Beware: this option is implemented in a way which is rather
+This is ignored if the tags file does not exist or is not a regular
+file (e.g.
+.Fl f Ns -
+was used to write to standard output).
+.Pp
+Beware: this option is implemented in a way which is rather
 slow; it is usually faster to simply rebuild the
 .Pa tags
-file.)
+file.
 .It Fl v
 An index of the form expected by
 .Xr vgrind 1
diff --git a/usr.bin/ctags/ctags.c b/usr.bin/ctags/ctags.c
index 3e933f033b3f..7bdf5922a634 100644
--- a/usr.bin/ctags/ctags.c
+++ b/usr.bin/ctags/ctags.c
@@ -42,11 +42,14 @@ static char sccsid[] = "@(#)ctags.c	8.4 (Berkeley) 2/7/95";
 #endif
 
 #include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
-__FBSDID("$FreeBSD$");
 
 #include <err.h>
+#include <errno.h>
 #include <limits.h>
 #include <locale.h>
 #include <regex.h>
@@ -143,6 +146,9 @@ main(int argc, char **argv)
 	if (!argc)
 		usage();
 
+	if (strcmp(outfile, "-") == 0)
+		outfile = "/dev/stdout";
+
 	if (!xflag)
 		setlocale(LC_COLLATE, "C");
 
@@ -164,11 +170,23 @@ main(int argc, char **argv)
 			put_entries(head);
 		else {
 			if (uflag) {
+				struct stat sb;
 				FILE *oldf;
 				regex_t *regx;
 
-				if ((oldf = fopen(outfile, "r")) == NULL)
+				if ((oldf = fopen(outfile, "r")) == NULL) {
+					if (errno == ENOENT) {
+						uflag = 0;
+						goto udone;
+					}
 					err(1, "opening %s", outfile);
+				}
+				if (fstat(fileno(oldf), &sb) != 0 ||
+				    !S_ISREG(sb.st_mode)) {
+					fclose(oldf);
+					uflag = 0;
+					goto udone;
+				}
 				if (unlink(outfile))
 					err(1, "unlinking %s", outfile);
 				if ((outf = fopen(outfile, "w")) == NULL)
@@ -198,6 +216,7 @@ nextline:
 				fclose(outf);
 				++aflag;
 			}
+udone:
 			if (!(outf = fopen(outfile, aflag ? "a" : "w")))
 				err(1, "%s", outfile);
 			put_entries(head);