diff --git a/usr.bin/ctags/ctags.1 b/usr.bin/ctags/ctags.1 --- 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 @@ .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 --- a/usr.bin/ctags/ctags.c +++ b/usr.bin/ctags/ctags.c @@ -42,11 +42,14 @@ #endif #include +__FBSDID("$FreeBSD$"); + #include +#include #include -__FBSDID("$FreeBSD$"); #include +#include #include #include #include @@ -143,6 +146,9 @@ if (!argc) usage(); + if (strcmp(outfile, "-") == 0) + outfile = "/dev/stdout"; + if (!xflag) setlocale(LC_COLLATE, "C"); @@ -164,11 +170,23 @@ 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 @@ fclose(outf); ++aflag; } +udone: if (!(outf = fopen(outfile, aflag ? "a" : "w"))) err(1, "%s", outfile); put_entries(head);