mirror of git://git.suckless.org/sbase
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 sha512sum .
|
||||
=*|o sleep .
|
||||
# sort (-d, -f, -i)
|
||||
#*|o sort (-d, -f, -i)
|
||||
=*|o split .
|
||||
=*|x sponge .
|
||||
#*|o strings .
|
||||
|
|
64
sort.c
64
sort.c
|
@ -27,17 +27,9 @@ enum {
|
|||
|
||||
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 char *fieldsep = NULL;
|
||||
static size_t fieldseplen = 0;
|
||||
static char *col1, *col2;
|
||||
static size_t col1siz, col2siz;
|
||||
|
||||
|
@ -46,6 +38,7 @@ skipblank(char *s)
|
|||
{
|
||||
while (*s == ' ' || *s == '\t')
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -54,21 +47,25 @@ skipnonblank(char *s)
|
|||
{
|
||||
while (*s && *s != '\n' && *s != ' ' && *s != '\t')
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static char *
|
||||
skipcolumn(char *s, char *eol, int next_col)
|
||||
skipcolumn(char *s, char *eol, int skip_to_next_col)
|
||||
{
|
||||
if (fieldsep) {
|
||||
if ((s = strstr(s, fieldsep)))
|
||||
s += next_col ? strlen(fieldsep) : 0;
|
||||
else
|
||||
if ((s = strstr(s, fieldsep))) {
|
||||
if (skip_to_next_col)
|
||||
s += fieldseplen;
|
||||
} else {
|
||||
s = eol;
|
||||
}
|
||||
} else {
|
||||
s = skipblank(s);
|
||||
s = skipnonblank(s);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -107,13 +104,14 @@ columns(char *line, const struct keydef *kd, char **col, size_t *colsiz)
|
|||
} else {
|
||||
end = eol;
|
||||
}
|
||||
len = start > end ? 0 : end - start;
|
||||
len = (start > end) ? 0 : (end - start);
|
||||
if (!*col || *colsiz < len)
|
||||
*col = erealloc(*col, len + 1);
|
||||
memcpy(*col, start, len);
|
||||
(*col)[len] = '\0';
|
||||
if (*colsiz < len)
|
||||
*colsiz = len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -136,7 +134,7 @@ linecmp(const char **a, const char **b)
|
|||
} else if (kd->flags & MOD_N) {
|
||||
x = strtold(col1, NULL);
|
||||
y = strtold(col2, NULL);
|
||||
res = (x < y) ? (-1) : (x > y);
|
||||
res = (x < y) ? -1 : (x > y);
|
||||
} else {
|
||||
res = strcmp(col1, col2);
|
||||
}
|
||||
|
@ -150,23 +148,26 @@ linecmp(const char **a, const char **b)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
check(FILE *fp)
|
||||
static int
|
||||
check(FILE *fp, const char *fname)
|
||||
{
|
||||
static struct { char *buf; size_t size; } prev, cur, tmp;
|
||||
|
||||
if (!prev.buf && getline(&prev.buf, &prev.size, fp) < 0)
|
||||
eprintf("getline:");
|
||||
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)
|
||||
weprintf("disorder: %s", cur.buf);
|
||||
exit(1);
|
||||
weprintf("disorder %s: %s", fname, cur.buf);
|
||||
return 1;
|
||||
}
|
||||
tmp = cur;
|
||||
cur = prev;
|
||||
prev = tmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -212,7 +213,8 @@ addkeydef(char *kdstr, int flags)
|
|||
|
||||
if (*kdstr == '.') {
|
||||
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)
|
||||
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");
|
||||
if (*kdstr == '.') {
|
||||
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)
|
||||
enprintf(2, "invalid end flags in key definition\n");
|
||||
|
@ -281,6 +284,7 @@ main(int argc, char *argv[])
|
|||
break;
|
||||
case 't':
|
||||
fieldsep = EARGF(usage());
|
||||
fieldseplen = strlen(fieldsep);
|
||||
break;
|
||||
case 'u':
|
||||
uflag = 1;
|
||||
|
@ -296,7 +300,8 @@ main(int argc, char *argv[])
|
|||
|
||||
if (!argc) {
|
||||
if (Cflag || cflag) {
|
||||
check(stdin);
|
||||
if (check(stdin, "<stdin>") && !ret)
|
||||
ret = 1;
|
||||
} else {
|
||||
getlines(stdin, &linebuf);
|
||||
}
|
||||
|
@ -309,12 +314,13 @@ main(int argc, char *argv[])
|
|||
continue;
|
||||
}
|
||||
if (Cflag || cflag) {
|
||||
check(fp);
|
||||
if (check(fp, *argv) && !ret)
|
||||
ret = 1;
|
||||
} else {
|
||||
getlines(fp, &linebuf);
|
||||
}
|
||||
if (fp != stdin && fshut(fp, *argv))
|
||||
ret = 1;
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
if (!Cflag && !cflag) {
|
||||
|
@ -325,14 +331,16 @@ main(int argc, char *argv[])
|
|||
(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])) {
|
||||
if (!uflag || i == 0 ||
|
||||
linecmp((const char **)&linebuf.lines[i],
|
||||
(const char **)&linebuf.lines[i - 1])) {
|
||||
fputs(linebuf.lines[i], ofp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
|
||||
if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>") |
|
||||
fshut(stderr, "<stderr>"))
|
||||
ret = 2;
|
||||
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue