Audit sort(1) and mark it as finished
1) Remove the function prototypes. No need for them, as the functions are ordered. 2) Add fieldseplen, so the length of the field-separator is not calculated nearly each time skipcolumn() is called. 3) rename next_col to skip_to_next_col so the purpose is clear, also reorder the conditional accordingly. 4) Put parentheses around certain ternary expressions. 5) BUGFIX: Don't just exit() in check(), but make it return something, so we can cleanly fshut() everything. 6) OFF-POSIX: Posix for no apparent reason does not allow more than one file when the -c or -C flags are given. This can be problematic when you want to check multiple files. With the change 5), rewriting check() to return a value, I went off-posix after discussing this with Dimitris to just allow arbitrary numbers of files. Obviously, this does not break scripts and is convenient for everybody who wants to quickly check a big amount of files. As soon as 1 file is "unsorted", the return value is 1, as expected. For convenience reasons, check()'s warning now includes the filename. 7) BUGFIX: Set ret to 2 instead of 1 when the fshut(fp, *argv) fails. 8) BUGFIX: Don't forget to fshut stderr at the end. This would improperly return 1 in the following case: $ sort -c unsorted_file 2> /dev/full 9) Other style changes, line length, empty line before return.
This commit is contained in:
parent
0a2562e994
commit
51390a3c51
2
README
2
README
|
@ -69,7 +69,7 @@ The following tools are implemented:
|
||||||
=*|x sha256sum .
|
=*|x sha256sum .
|
||||||
=*|x sha512sum .
|
=*|x sha512sum .
|
||||||
=*|o sleep .
|
=*|o sleep .
|
||||||
# sort (-d, -f, -i)
|
#*|o sort (-d, -f, -i)
|
||||||
=*|o split .
|
=*|o split .
|
||||||
=*|x sponge .
|
=*|x sponge .
|
||||||
#*|o strings .
|
#*|o strings .
|
||||||
|
|
64
sort.c
64
sort.c
|
@ -27,17 +27,9 @@ enum {
|
||||||
|
|
||||||
static TAILQ_HEAD(kdhead, keydef) kdhead = TAILQ_HEAD_INITIALIZER(kdhead);
|
static TAILQ_HEAD(kdhead, keydef) kdhead = TAILQ_HEAD_INITIALIZER(kdhead);
|
||||||
|
|
||||||
static char *skipblank(char *);
|
|
||||||
static char *skipnonblank(char *);
|
|
||||||
static char *skipcolumn(char *, char *, int);
|
|
||||||
static size_t columns(char *, const struct keydef *, char **, size_t *);
|
|
||||||
static int linecmp(const char **, const char **);
|
|
||||||
static void check(FILE *);
|
|
||||||
static int parse_flags(char **, int *, int);
|
|
||||||
static void addkeydef(char *, int);
|
|
||||||
|
|
||||||
static int Cflag = 0, cflag = 0, uflag = 0;
|
static int Cflag = 0, cflag = 0, uflag = 0;
|
||||||
static char *fieldsep = NULL;
|
static char *fieldsep = NULL;
|
||||||
|
static size_t fieldseplen = 0;
|
||||||
static char *col1, *col2;
|
static char *col1, *col2;
|
||||||
static size_t col1siz, col2siz;
|
static size_t col1siz, col2siz;
|
||||||
|
|
||||||
|
@ -46,6 +38,7 @@ skipblank(char *s)
|
||||||
{
|
{
|
||||||
while (*s == ' ' || *s == '\t')
|
while (*s == ' ' || *s == '\t')
|
||||||
s++;
|
s++;
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,21 +47,25 @@ skipnonblank(char *s)
|
||||||
{
|
{
|
||||||
while (*s && *s != '\n' && *s != ' ' && *s != '\t')
|
while (*s && *s != '\n' && *s != ' ' && *s != '\t')
|
||||||
s++;
|
s++;
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
skipcolumn(char *s, char *eol, int next_col)
|
skipcolumn(char *s, char *eol, int skip_to_next_col)
|
||||||
{
|
{
|
||||||
if (fieldsep) {
|
if (fieldsep) {
|
||||||
if ((s = strstr(s, fieldsep)))
|
if ((s = strstr(s, fieldsep))) {
|
||||||
s += next_col ? strlen(fieldsep) : 0;
|
if (skip_to_next_col)
|
||||||
else
|
s += fieldseplen;
|
||||||
|
} else {
|
||||||
s = eol;
|
s = eol;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
s = skipblank(s);
|
s = skipblank(s);
|
||||||
s = skipnonblank(s);
|
s = skipnonblank(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,13 +104,14 @@ columns(char *line, const struct keydef *kd, char **col, size_t *colsiz)
|
||||||
} else {
|
} else {
|
||||||
end = eol;
|
end = eol;
|
||||||
}
|
}
|
||||||
len = start > end ? 0 : end - start;
|
len = (start > end) ? 0 : (end - start);
|
||||||
if (!*col || *colsiz < len)
|
if (!*col || *colsiz < len)
|
||||||
*col = erealloc(*col, len + 1);
|
*col = erealloc(*col, len + 1);
|
||||||
memcpy(*col, start, len);
|
memcpy(*col, start, len);
|
||||||
(*col)[len] = '\0';
|
(*col)[len] = '\0';
|
||||||
if (*colsiz < len)
|
if (*colsiz < len)
|
||||||
*colsiz = len;
|
*colsiz = len;
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +134,7 @@ linecmp(const char **a, const char **b)
|
||||||
} else if (kd->flags & MOD_N) {
|
} else if (kd->flags & MOD_N) {
|
||||||
x = strtold(col1, NULL);
|
x = strtold(col1, NULL);
|
||||||
y = strtold(col2, NULL);
|
y = strtold(col2, NULL);
|
||||||
res = (x < y) ? (-1) : (x > y);
|
res = (x < y) ? -1 : (x > y);
|
||||||
} else {
|
} else {
|
||||||
res = strcmp(col1, col2);
|
res = strcmp(col1, col2);
|
||||||
}
|
}
|
||||||
|
@ -150,23 +148,26 @@ linecmp(const char **a, const char **b)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
check(FILE *fp)
|
check(FILE *fp, const char *fname)
|
||||||
{
|
{
|
||||||
static struct { char *buf; size_t size; } prev, cur, tmp;
|
static struct { char *buf; size_t size; } prev, cur, tmp;
|
||||||
|
|
||||||
if (!prev.buf && getline(&prev.buf, &prev.size, fp) < 0)
|
if (!prev.buf && getline(&prev.buf, &prev.size, fp) < 0)
|
||||||
eprintf("getline:");
|
eprintf("getline:");
|
||||||
while (getline(&cur.buf, &cur.size, fp) > 0) {
|
while (getline(&cur.buf, &cur.size, fp) > 0) {
|
||||||
if (uflag > linecmp((const char **) &cur.buf, (const char **) &prev.buf)) {
|
if (uflag > linecmp((const char **)&cur.buf,
|
||||||
|
(const char **)&prev.buf)) {
|
||||||
if (!Cflag)
|
if (!Cflag)
|
||||||
weprintf("disorder: %s", cur.buf);
|
weprintf("disorder %s: %s", fname, cur.buf);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
tmp = cur;
|
tmp = cur;
|
||||||
cur = prev;
|
cur = prev;
|
||||||
prev = tmp;
|
prev = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -212,7 +213,8 @@ addkeydef(char *kdstr, int flags)
|
||||||
|
|
||||||
if (*kdstr == '.') {
|
if (*kdstr == '.') {
|
||||||
if ((kd->start_char = strtol(kdstr + 1, &kdstr, 10)) < 1)
|
if ((kd->start_char = strtol(kdstr + 1, &kdstr, 10)) < 1)
|
||||||
enprintf(2, "invalid start character in key definition\n");
|
enprintf(2, "invalid start character in key "
|
||||||
|
"definition\n");
|
||||||
}
|
}
|
||||||
if (parse_flags(&kdstr, &kd->flags, MOD_STARTB) < 0)
|
if (parse_flags(&kdstr, &kd->flags, MOD_STARTB) < 0)
|
||||||
enprintf(2, "invalid start flags in key definition\n");
|
enprintf(2, "invalid start flags in key definition\n");
|
||||||
|
@ -222,7 +224,8 @@ addkeydef(char *kdstr, int flags)
|
||||||
enprintf(2, "invalid end column in key definition\n");
|
enprintf(2, "invalid end column in key definition\n");
|
||||||
if (*kdstr == '.') {
|
if (*kdstr == '.') {
|
||||||
if ((kd->end_char = strtol(kdstr + 1, &kdstr, 10)) < 0)
|
if ((kd->end_char = strtol(kdstr + 1, &kdstr, 10)) < 0)
|
||||||
enprintf(2, "invalid end character in key definition\n");
|
enprintf(2, "invalid end character in key "
|
||||||
|
"definition\n");
|
||||||
}
|
}
|
||||||
if (parse_flags(&kdstr, &kd->flags, MOD_ENDB) < 0)
|
if (parse_flags(&kdstr, &kd->flags, MOD_ENDB) < 0)
|
||||||
enprintf(2, "invalid end flags in key definition\n");
|
enprintf(2, "invalid end flags in key definition\n");
|
||||||
|
@ -281,6 +284,7 @@ main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
fieldsep = EARGF(usage());
|
fieldsep = EARGF(usage());
|
||||||
|
fieldseplen = strlen(fieldsep);
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
uflag = 1;
|
uflag = 1;
|
||||||
|
@ -296,7 +300,8 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if (!argc) {
|
if (!argc) {
|
||||||
if (Cflag || cflag) {
|
if (Cflag || cflag) {
|
||||||
check(stdin);
|
if (check(stdin, "<stdin>") && !ret)
|
||||||
|
ret = 1;
|
||||||
} else {
|
} else {
|
||||||
getlines(stdin, &linebuf);
|
getlines(stdin, &linebuf);
|
||||||
}
|
}
|
||||||
|
@ -309,12 +314,13 @@ main(int argc, char *argv[])
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Cflag || cflag) {
|
if (Cflag || cflag) {
|
||||||
check(fp);
|
if (check(fp, *argv) && !ret)
|
||||||
|
ret = 1;
|
||||||
} else {
|
} else {
|
||||||
getlines(fp, &linebuf);
|
getlines(fp, &linebuf);
|
||||||
}
|
}
|
||||||
if (fp != stdin && fshut(fp, *argv))
|
if (fp != stdin && fshut(fp, *argv))
|
||||||
ret = 1;
|
ret = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Cflag && !cflag) {
|
if (!Cflag && !cflag) {
|
||||||
|
@ -325,14 +331,16 @@ main(int argc, char *argv[])
|
||||||
(int (*)(const void *, const void *))linecmp);
|
(int (*)(const void *, const void *))linecmp);
|
||||||
|
|
||||||
for (i = 0; i < linebuf.nlines; i++) {
|
for (i = 0; i < linebuf.nlines; i++) {
|
||||||
if (!uflag || i == 0 || linecmp((const char **)&linebuf.lines[i],
|
if (!uflag || i == 0 ||
|
||||||
(const char **)&linebuf.lines[i-1])) {
|
linecmp((const char **)&linebuf.lines[i],
|
||||||
|
(const char **)&linebuf.lines[i - 1])) {
|
||||||
fputs(linebuf.lines[i], ofp);
|
fputs(linebuf.lines[i], ofp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
|
if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>") |
|
||||||
|
fshut(stderr, "<stderr>"))
|
||||||
ret = 2;
|
ret = 2;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user