mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-14 12:23:58 +00:00
uniq: Fix interactive use.
Output a line as soon as it is possible to determine that it will have to be output. For the basic case, this means output each line as it is read unless it is identical to the previous one. For the -d case, it means output the first instance as soon as the second is read, unless the -c option was also given. The -D and -u cases were already fine. Add test cases for interactive use with no options and with -d. Explicitly ignore -d when -D is also specified. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: rew, kevans Differential Revision: https://reviews.freebsd.org/D43382
This commit is contained in:
parent
e762fd81e2
commit
11715600e6
|
@ -133,6 +133,30 @@ count_unique_body() {
|
||||||
atf_check_uniq --count --unique
|
atf_check_uniq --count --unique
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atf_test_case interactive
|
||||||
|
interactive_head() {
|
||||||
|
atf_set descr "test interactive use"
|
||||||
|
}
|
||||||
|
interactive_body() {
|
||||||
|
sh -c 'yes | stdbuf -oL uniq >actual' &
|
||||||
|
pid=$!
|
||||||
|
sleep 1
|
||||||
|
kill $!
|
||||||
|
atf_check -o inline:"y\n" cat actual
|
||||||
|
}
|
||||||
|
|
||||||
|
atf_test_case interactive_repeated
|
||||||
|
interactive_repeated_head() {
|
||||||
|
atf_set descr "test interactive use with -d"
|
||||||
|
}
|
||||||
|
interactive_repeated_body() {
|
||||||
|
sh -c 'yes | stdbuf -oL uniq -d >actual' &
|
||||||
|
pid=$!
|
||||||
|
sleep 1
|
||||||
|
kill $!
|
||||||
|
atf_check -o inline:"y\n" cat actual
|
||||||
|
}
|
||||||
|
|
||||||
atf_init_test_cases()
|
atf_init_test_cases()
|
||||||
{
|
{
|
||||||
atf_add_test_case basic
|
atf_add_test_case basic
|
||||||
|
@ -146,4 +170,6 @@ atf_init_test_cases()
|
||||||
atf_add_test_case skip_chars
|
atf_add_test_case skip_chars
|
||||||
atf_add_test_case unique
|
atf_add_test_case unique
|
||||||
atf_add_test_case count_unique
|
atf_add_test_case count_unique
|
||||||
|
atf_add_test_case interactive
|
||||||
|
atf_add_test_case interactive_repeated
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd June 7, 2020
|
.Dd January 12, 2024
|
||||||
.Dt UNIQ 1
|
.Dt UNIQ 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -72,6 +72,9 @@ Precede each output line with the count of the number of times the line
|
||||||
occurred in the input, followed by a single space.
|
occurred in the input, followed by a single space.
|
||||||
.It Fl d , Fl -repeated
|
.It Fl d , Fl -repeated
|
||||||
Output a single copy of each line that is repeated in the input.
|
Output a single copy of each line that is repeated in the input.
|
||||||
|
Ignored if
|
||||||
|
.Fl D
|
||||||
|
is also specified.
|
||||||
.It Fl D , Fl -all-repeated Op Ar septype
|
.It Fl D , Fl -all-repeated Op Ar septype
|
||||||
Output all lines that are repeated (like
|
Output all lines that are repeated (like
|
||||||
.Fl d ,
|
.Fl d ,
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <nl_types.h>
|
#include <nl_types.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -51,14 +52,9 @@
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
|
||||||
static int Dflag, cflag, dflag, uflag, iflag;
|
static enum { DF_NONE, DF_NOSEP, DF_PRESEP, DF_POSTSEP } Dflag;
|
||||||
static int numchars, numfields, repeats;
|
static bool cflag, dflag, uflag, iflag;
|
||||||
|
static long long numchars, numfields, repeats;
|
||||||
/* Dflag values */
|
|
||||||
#define DF_NONE 0
|
|
||||||
#define DF_NOSEP 1
|
|
||||||
#define DF_PRESEP 2
|
|
||||||
#define DF_POSTSEP 3
|
|
||||||
|
|
||||||
static const struct option long_opts[] =
|
static const struct option long_opts[] =
|
||||||
{
|
{
|
||||||
|
@ -88,7 +84,7 @@ main (int argc, char *argv[])
|
||||||
int ch, comp;
|
int ch, comp;
|
||||||
size_t prevbuflen, thisbuflen, b1;
|
size_t prevbuflen, thisbuflen, b1;
|
||||||
char *prevline, *thisline, *p;
|
char *prevline, *thisline, *p;
|
||||||
const char *ifn, *errstr;;
|
const char *errstr, *ifn;
|
||||||
cap_rights_t rights;
|
cap_rights_t rights;
|
||||||
|
|
||||||
(void) setlocale(LC_ALL, "");
|
(void) setlocale(LC_ALL, "");
|
||||||
|
@ -108,13 +104,13 @@ main (int argc, char *argv[])
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
cflag = 1;
|
cflag = true;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
dflag = 1;
|
dflag = true;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
iflag = 1;
|
iflag = true;
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
numfields = strtonum(optarg, 0, INT_MAX, &errstr);
|
numfields = strtonum(optarg, 0, INT_MAX, &errstr);
|
||||||
|
@ -127,7 +123,7 @@ main (int argc, char *argv[])
|
||||||
errx(1, "character skip value is %s: %s", errstr, optarg);
|
errx(1, "character skip value is %s: %s", errstr, optarg);
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
uflag = 1;
|
uflag = true;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
default:
|
default:
|
||||||
|
@ -140,6 +136,9 @@ main (int argc, char *argv[])
|
||||||
if (argc > 2)
|
if (argc > 2)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
|
if (Dflag && dflag)
|
||||||
|
dflag = false;
|
||||||
|
|
||||||
ifp = stdin;
|
ifp = stdin;
|
||||||
ifn = "stdin";
|
ifn = "stdin";
|
||||||
ofp = stdout;
|
ofp = stdout;
|
||||||
|
@ -180,6 +179,8 @@ main (int argc, char *argv[])
|
||||||
err(1, "%s", ifn);
|
err(1, "%s", ifn);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
if (!cflag && !Dflag && !dflag && !uflag)
|
||||||
|
show(ofp, prevline);
|
||||||
tprev = convert(prevline);
|
tprev = convert(prevline);
|
||||||
|
|
||||||
tthis = NULL;
|
tthis = NULL;
|
||||||
|
@ -199,7 +200,11 @@ main (int argc, char *argv[])
|
||||||
/* If different, print; set previous to new value. */
|
/* If different, print; set previous to new value. */
|
||||||
if (Dflag == DF_POSTSEP && repeats > 0)
|
if (Dflag == DF_POSTSEP && repeats > 0)
|
||||||
fputc('\n', ofp);
|
fputc('\n', ofp);
|
||||||
if (!Dflag)
|
if (!cflag && !Dflag && !dflag && !uflag)
|
||||||
|
show(ofp, thisline);
|
||||||
|
else if (!Dflag &&
|
||||||
|
(!dflag || (cflag && repeats > 0)) &&
|
||||||
|
(!uflag || repeats == 0))
|
||||||
show(ofp, prevline);
|
show(ofp, prevline);
|
||||||
p = prevline;
|
p = prevline;
|
||||||
b1 = prevbuflen;
|
b1 = prevbuflen;
|
||||||
|
@ -220,13 +225,20 @@ main (int argc, char *argv[])
|
||||||
show(ofp, prevline);
|
show(ofp, prevline);
|
||||||
}
|
}
|
||||||
show(ofp, thisline);
|
show(ofp, thisline);
|
||||||
|
} else if (dflag && !cflag) {
|
||||||
|
if (repeats == 0)
|
||||||
|
show(ofp, prevline);
|
||||||
}
|
}
|
||||||
++repeats;
|
++repeats;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ferror(ifp))
|
if (ferror(ifp))
|
||||||
err(1, "%s", ifn);
|
err(1, "%s", ifn);
|
||||||
if (!Dflag)
|
if (!cflag && !Dflag && !dflag && !uflag)
|
||||||
|
/* already printed */ ;
|
||||||
|
else if (!Dflag &&
|
||||||
|
(!dflag || (cflag && repeats > 0)) &&
|
||||||
|
(!uflag || repeats == 0))
|
||||||
show(ofp, prevline);
|
show(ofp, prevline);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -291,11 +303,8 @@ inlcmp(const char *s1, const char *s2)
|
||||||
static void
|
static void
|
||||||
show(FILE *ofp, const char *str)
|
show(FILE *ofp, const char *str)
|
||||||
{
|
{
|
||||||
|
|
||||||
if ((!Dflag && dflag && repeats == 0) || (uflag && repeats > 0))
|
|
||||||
return;
|
|
||||||
if (cflag)
|
if (cflag)
|
||||||
(void)fprintf(ofp, "%4d %s", repeats + 1, str);
|
(void)fprintf(ofp, "%4lld %s", repeats + 1, str);
|
||||||
else
|
else
|
||||||
(void)fprintf(ofp, "%s", str);
|
(void)fprintf(ofp, "%s", str);
|
||||||
}
|
}
|
||||||
|
@ -303,7 +312,7 @@ show(FILE *ofp, const char *str)
|
||||||
static wchar_t *
|
static wchar_t *
|
||||||
skip(wchar_t *str)
|
skip(wchar_t *str)
|
||||||
{
|
{
|
||||||
int nchars, nfields;
|
long long nchars, nfields;
|
||||||
|
|
||||||
for (nfields = 0; *str != L'\0' && nfields++ != numfields; ) {
|
for (nfields = 0; *str != L'\0' && nfields++ != numfields; ) {
|
||||||
while (iswblank(*str))
|
while (iswblank(*str))
|
||||||
|
|
Loading…
Reference in a new issue