sort: Implement -c and -C flags

This commit is contained in:
Michael Forney 2014-11-23 19:35:56 +00:00 committed by sin
parent e23d20e1d4
commit cb427d553a
2 changed files with 58 additions and 10 deletions

11
sort.1
View File

@ -15,9 +15,20 @@ writes the sorted concatenation of the given files to stdout. If no file is
given, sort reads from stdin.
.SH OPTIONS
.TP
.B \-C
check that the concatenation of the given files is sorted rather than sorting
them. In this mode, no output is printed to stdout, and the exit status
indicates the result of the check.
.TP
.B \-b
skip leading whitespace of columns when sorting.
.TP
.B \-c
the same as
.B \-C
except that when disorder is detected, a message is printed to stderr
indicating the location of the disorder.
.TP
.BI \-k \ key
specifies a key definition of the form
.BR S [. s ][ f ][, E [. e ][ f ]]

57
sort.c
View File

@ -32,6 +32,7 @@ static struct kdlist *head = NULL;
static struct kdlist *tail = NULL;
static void addkeydef(char *, int);
static void check(FILE *);
static void freelist(void);
static int linecmp(const char **, const char **);
static char *skipblank(char *);
@ -40,13 +41,13 @@ static int parse_keydef(struct keydef *, char *, int);
static char *nextcol(char *);
static char *columns(char *, const struct keydef *);
static int uflag = 0;
static int Cflag = 0, cflag = 0, uflag = 0;
static char *fieldsep = NULL;
static void
usage(void)
{
enprintf(2, "usage: %s [-bnru] [-t delim] [-k def]... [file...]\n", argv0);
enprintf(2, "usage: %s [-Cbcnru] [-t delim] [-k def]... [file...]\n", argv0);
}
int
@ -58,9 +59,15 @@ main(int argc, char *argv[])
int global_flags = 0;
ARGBEGIN {
case 'C':
Cflag = 1;
break;
case 'b':
global_flags |= MOD_STARTB | MOD_ENDB;
break;
case 'c':
cflag = 1;
break;
case 'k':
addkeydef(EARGF(usage()), global_flags);
break;
@ -87,22 +94,33 @@ main(int argc, char *argv[])
addkeydef("1", global_flags & MOD_R);
if (argc == 0) {
getlines(stdin, &linebuf);
if (Cflag || cflag) {
check(stdin);
} else {
getlines(stdin, &linebuf);
}
} else for (; argc > 0; argc--, argv++) {
if (!(fp = fopen(argv[0], "r"))) {
enprintf(2, "fopen %s:", argv[0]);
continue;
}
getlines(fp, &linebuf);
if (Cflag || cflag) {
check(fp);
} else {
getlines(fp, &linebuf);
}
fclose(fp);
}
qsort(linebuf.lines, linebuf.nlines, sizeof *linebuf.lines,
(int (*)(const void *, const void *))linecmp);
for (i = 0; i < linebuf.nlines; i++) {
if (!uflag || i == 0 || linecmp((const char **)&linebuf.lines[i],
(const char **)&linebuf.lines[i-1])) {
fputs(linebuf.lines[i], stdout);
if (!Cflag && !cflag) {
qsort(linebuf.lines, linebuf.nlines, sizeof *linebuf.lines,
(int (*)(const void *, const void *))linecmp);
for (i = 0; i < linebuf.nlines; i++) {
if (!uflag || i == 0 || linecmp((const char **)&linebuf.lines[i],
(const char **)&linebuf.lines[i-1])) {
fputs(linebuf.lines[i], stdout);
}
}
}
@ -128,6 +146,25 @@ addkeydef(char *def, int flags)
tail = node;
}
static void
check(FILE *fp)
{
static struct { char *buf; size_t size; } prev, cur, tmp;
if (!prev.buf)
getline(&prev.buf, &prev.size, fp);
while (getline(&cur.buf, &cur.size, fp) != -1) {
if (uflag > linecmp((const char **) &cur.buf, (const char **) &prev.buf)) {
if (!Cflag)
weprintf("disorder: %s", cur.buf);
exit(1);
}
tmp = cur;
cur = prev;
prev = tmp;
}
}
static void
freelist(void)
{