Sort bug causes data loss
Andrew A. Chernov
ache at hq.demos.su
Sun Sep 23 06:17:19 AEST 1990
In article <2675 at crdos1.crd.ge.COM> davidsen at crdos1.crd.ge.com (bill davidsen) writes:
>
> I have discovered what appears to be a serious bug in the sort
>routine used in several SysV variants including Stellar. Since it
>causes silent loss of data I am cross posting a bit more than I usually
>do.
>
> The problem occurs when the options -n (numeric) and -u (discard
>duplicates) are used together sorting data which has a fixed width
>numeric as the first key field. The results is output of only one line,
>regardless of the input data. I found this by losing 15 months of data
>(yes it was backed up). Since sort is often in shell scripts run from
>cron to do system things, this problem might not be instantly noticed.
>
> I have generated the following shell script to test for the problem.
I have & send my version of sort under SCO XENIX: this test run correctly!
-----------------------------------------------------------------------
Start test of sort error
Starting check
Output appears okay unless diff reported below:
Test ends
=== CUT HERE =============================================================
/*
* It is version of SORT, maybe old, but BUG FREE!
*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define lcmp(a,b) ((a&0377)-(b&0377)) /* My RUSSIAN version of lcmp was here */
#define L 512
#define C 20
#define N 15 /* Max. files number for merge */
#define MEM (((unsigned)56)*1024) /* 56K max */
#define NF 10 /* Max. fields number */
FILE *is, *os;
char isbuf[BUFSIZ], osbuf[BUFSIZ];
char *dirtry[] = {
"/usr/tmp", "/tmp", NULL
};
char **dirs;
char file1[30];
char *file = file1;
char *filep;
int nfiles;
unsigned nlines;
unsigned ntext;
int *lspace;
char *tspace;
int cmp (), cmpa ();
int (*compare) () = cmpa;
char *eol ();
int term ();
int mflg;
int cflg;
int uflg;
char *outfil;
int unsafeout; /* kludge to assure -m -o works
*/
char tabchar;
int eargc;
char **eargv;
char *progname;
char zero[256]; /* All arrays extended to 256 for my RUSSIAN version */
/* You may reduce it to 128 */
char fold[256] = {
0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
0370, 0371, 0372, 0373, 0374, 0375, 0376, 0337,
0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
0370, 0371, 0372, 0373, 0374, 0375, 0376, 0337,
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177
};
char nofold[256] = {
0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177
};
char nonprint[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
};
char dict[256] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1
};
struct field {
char *code;
char *ignore;
char nflg;
char rflg;
char zflg;
char bflg[2];
int m[2];
int n[2];
} fields[NF];
struct field proto = {
nofold + 128,
zero + 128,
0,
1,
0,
{0, 0},
{0, -1},
{0, 0}
};
int nfields;
int error = 1;
char *setfil ();
main (argc, argv)
char **argv;
{
register a;
unsigned ep, curr, fp, maxmem;
char *arg;
register struct field *p,
*q;
int i;
for (arg = progname = argv[0]; *arg; arg++)
if (*arg == '/')
progname = arg + 1;
copyproto ();
eargv = argv;
while (--argc > 0) {
if (**++argv == '-')
for (arg = *argv;;) {
switch (*++arg) {
case '\0':
if (arg[-1] == '-')
eargv[eargc++] = "-";
break;
case 'o':
if (--argc > 0)
outfil = *++argv;
continue;
case 'T':
if (--argc > 0)
dirtry[0] = *++argv;
continue;
default:
field (++*argv, nfields > 0);
break;
}
break;
}
else
if (**argv == '+') {
if (++nfields >= NF) {
diag ("too many fields", "");
exit (1);
}
copyproto ();
field (++*argv, 0);
}
else
eargv[eargc++] = *argv;
}
q = &fields[0];
for (a = 1; a <= nfields; a++) {
p = &fields[a];
if (p -> code != proto.code)
continue;
if (p -> ignore != proto.ignore)
continue;
if (p -> nflg != proto.nflg)
continue;
if (p -> rflg != proto.rflg)
continue;
if (p -> zflg != proto.zflg)
continue;
if (p -> bflg[0] != proto.bflg[0])
continue;
if (p -> bflg[1] != proto.bflg[1])
continue;
p -> code = q -> code;
p -> ignore = q -> ignore;
p -> nflg = q -> nflg;
p -> rflg = q -> rflg;
p -> zflg = q -> zflg;
p -> bflg[0] = p -> bflg[1] = q -> bflg[0];
}
if (eargc == 0)
eargv[eargc++] = "-";
if (cflg && eargc > 1) {
diag ("can check only 1 file", "");
exit (1);
}
safeoutfil ();
fp = sbrk (0);
lspace = (int *) fp;
ep = min (MEM, ((unsigned) ~0) - 512 - fp) &~ 0777;
maxmem = fp + ep;
for (curr = fp; ep >= 512 && curr < maxmem; ep /= 2) {
while ((long) curr + ep < (unsigned) ~0 - 512 && sbrk (ep) != -1) {
if ((curr += ep) >= maxmem)
goto Out;
}
}
Out:
ep = ((unsigned) sbrk (0)) - fp;
nlines = ep - L;
nlines /= (5 * (sizeof (char *) / sizeof (char)));
ntext = nlines * 8;
tspace = (char *) (lspace + nlines);
a = -1;
for (dirs = dirtry; *dirs; dirs++) {
sprintf (filep = file1, "%s/stm%05uaa", *dirs, getpid ());
while (*filep)
filep++;
filep -= 2;
if ((a = creat (file, 0600)) >= 0)
break;
}
if (a < 0) {
diag ("can't locate temp: ", file);
exit (1);
}
close (a);
signal (SIGHUP, term);
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
signal (SIGINT, term);
if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
signal (SIGQUIT, term);
signal (SIGPIPE, term);
signal (SIGTERM, term);
nfiles = eargc;
if (!mflg && !cflg) {
sort ();
fclose (stdin);
}
for (a = mflg | cflg ? 0 : eargc;
a + N < nfiles
|| unsafeout
&& a < eargc;
a = i) {
i = a + N;
if (i >= nfiles)
i = nfiles;
newfile ();
merge (a, i);
}
if (a != nfiles) {
oldfile ();
merge (a, nfiles);
}
error = 0;
term ();
}
sort () {
register char *cp;
register char **lp;
register c;
int done;
int i;
char *f;
done = 0;
i = 0;
c = EOF;
do {
cp = tspace;
lp = (char **) lspace;
while (lp < (char **) lspace + nlines
&& cp < tspace + ntext) {
*lp++ = cp;
while (c != '\n') {
if (c != EOF) {
*cp++ = c;
c = getc (is);
continue;
}
else
if (is)
fclose (is);
if (i < eargc) {
if ((f = setfil (i++)) == 0)
is = stdin;
else {
if ((is = fopen (f, "r")) == NULL)
cant (f);
setbuf (is, isbuf);
}
c = getc (is);
}
else
break;
}
*cp++ = '\n';
if (c == EOF) {
done++;
lp--;
break;
}
c = getc (is);
}
qsort ((char **) lspace, lp);
if (done == 0 || nfiles != eargc)
newfile ();
else
oldfile ();
while (lp > (char **) lspace) {
cp = *--lp;
if (*cp)
do
putc (*cp, os);
while (*cp++ != '\n');
}
fclose (os);
} while (done == 0);
}
struct merg {
char l[L];
FILE * b;
} *ibuf[256];
merge (a, b) {
static char merbufs[N][BUFSIZ];
struct merg *p;
register char *cp,
*dp;
register i;
struct merg **ip,
*jp;
char *f;
int j;
int k,
l;
int muflg;
p = (struct merg *) lspace;
j = 0;
for (i = a; i < b; i++) {
f = setfil (i);
if (f == 0)
p -> b = stdin;
else {
if ((p -> b = fopen (f, "r")) == NULL)
cant (f);
setbuf (p -> b, merbufs[i - a]);
}
ibuf[j] = p;
if (!rline (p))
j++;
p++;
}
do {
i = j;
qsort ((char **) ibuf, (char **) (ibuf + i));
l = 0;
while (i--) {
cp = ibuf[i] -> l;
if (*cp == '\0') {
l = 1;
if (rline (ibuf[i])) {
k = i;
while (++k < j)
ibuf[k - 1] = ibuf[k];
j--;
}
}
}
} while (l);
muflg = mflg & uflg | cflg;
i = j;
while (i > 0) {
cp = ibuf[i - 1] -> l;
if (!cflg && (uflg == 0 || muflg ||
(*compare) (ibuf[i - 1] -> l, ibuf[i - 2] -> l)))
do
putc (*cp, os);
while (*cp++ != '\n');
if (muflg) {
cp = ibuf[i - 1] -> l;
dp = p -> l;
do {
} while ((*dp++ = *cp++) != '\n');
}
for (;;) {
if (rline (ibuf[i - 1])) {
i--;
if (i == 0)
break;
if (i == 1)
muflg = uflg;
}
ip = &ibuf[i];
while (--ip > ibuf
&& (*compare) (ip[0] -> l, ip[-1] -> l) < 0) {
jp = *ip;
*ip = *(ip - 1);
*(ip - 1) = jp;
}
if (!muflg)
break;
j = (*compare) (ibuf[i - 1] -> l, p -> l);
if (cflg) {
if (j > 0)
disorder ("disorder: ", ibuf[i - 1] -> l);
else
if (uflg && j == 0)
disorder ("nonunique: ", ibuf[i - 1] -> l);
}
else
if (j == 0)
continue;
break;
}
}
p = (struct merg *) lspace;
for (i = a; i < b; i++) {
fclose (p -> b);
p++;
if (i >= eargc)
unlink (setfil (i));
}
fclose (os);
}
rline (mp)
struct merg *mp;
{
register char *cp;
register char *ce;
FILE * bp;
register c;
bp = mp -> b;
cp = mp -> l;
ce = cp + L;
do {
c = getc (bp);
if (c == EOF)
return (1);
if (cp >= ce)
cp--;
*cp++ = c;
} while (c != '\n');
return (0);
}
disorder (s, t)
char *s,
*t;
{
register char *u;
for (u = t; *u != '\n'; u++);
*u = 0;
diag (s, t);
term ();
}
newfile () {
register char *f;
f = setfil (nfiles);
if ((os = fopen (f, "w")) == NULL) {
diag ("can't create ", f);
term ();
}
setbuf (os, osbuf);
nfiles++;
}
char *
setfil (i) {
if (i < eargc)
if (eargv[i][0] == '-' && eargv[i][1] == '\0')
return (0);
else
return (eargv[i]);
i -= eargc;
filep[0] = i / 26 + 'a';
filep[1] = i % 26 + 'a';
return (file);
}
oldfile () {
if (outfil) {
if ((os = fopen (outfil, "w")) == NULL) {
diag ("can't create ", outfil);
term ();
}
setbuf (os, osbuf);
}
else
os = stdout;
}
safeoutfil () {
register int i;
struct stat obuf,
ibuf;
if (!mflg || outfil == 0)
return;
if (stat (outfil, &obuf) == -1)
return;
for (i = eargc - N; i < eargc; i++) {
/*-N is suff., not nec.*/
if (stat (eargv[i], &ibuf) == -1)
continue;
if (obuf.st_dev == ibuf.st_dev &&
obuf.st_ino == ibuf.st_ino)
unsafeout++;
}
}
cant (f)
char *f;
{
diag ("can't open ", f);
term ();
}
diag (s, t)
char *s,
*t;
{
fputs (progname, stderr);
fputs (": ", stderr);
fputs (s, stderr);
fputs (t, stderr);
putc ('\n', stderr);
}
term () {
register i;
signal (SIGQUIT, SIG_IGN);
signal (SIGINT, SIG_IGN);
signal (SIGHUP, SIG_IGN);
signal (SIGTERM, SIG_IGN);
if (nfiles == eargc)
nfiles++;
for (i = eargc; i <= nfiles; i++) {
/* <= in case of interrupt */
unlink (setfil (i)); /* with nfiles not updated */
}
exit (error);
}
cmp (i, j)
char *i,
*j;
{
register char *pa,
*pb;
char *skip ();
char *code,
*ignore;
int a,
b;
int k;
char *la,
*lb;
register int sa;
int sb;
char *ipa,
*ipb,
*jpa,
*jpb;
struct field *fp;
for (k = nfields > 0; k <= nfields; k++) {
fp = &fields[k];
pa = i;
pb = j;
if (k) {
la = skip (pa, fp, 1);
pa = skip (pa, fp, 0);
lb = skip (pb, fp, 1);
pb = skip (pb, fp, 0);
}
else {
la = eol (pa);
lb = eol (pb);
}
if (fp -> nflg || k == 0 && fp -> bflg[0]) {
while (blank (*pa))
pa++;
while (blank (*pb))
pb++;
}
if (fp -> nflg) {
sa = sb = fp -> rflg;
if (*pa == '-') {
pa++;
sa = -sa;
}
if (*pb == '-') {
pb++;
sb = -sb;
}
for (ipa = pa; ipa < la && isdigit (*ipa); ipa++);
for (ipb = pb; ipb < lb && isdigit (*ipb); ipb++);
jpa = ipa;
jpb = ipb;
a = 0;
if (sa == sb)
while (ipa > pa && ipb > pb)
if (b = *--ipb - *--ipa)
a = b;
while (ipa > pa)
if (*--ipa != '0')
return (-sa);
while (ipb > pb)
if (*--ipb != '0')
return (sb);
if (a)
return (a * sa);
if (*(pa = jpa) == '.')
pa++;
if (*(pb = jpb) == '.')
pb++;
if (sa == sb)
while (pa < la && isdigit (*pa)
&& pb < lb && isdigit (*pb))
if (a = *pb++ - *pa++)
return (a * sa);
while (pa < la && isdigit (*pa))
if (*pa++ != '0')
return (-sa);
while (pb < lb && isdigit (*pb))
if (*pb++ != '0')
return (sb);
continue;
}
code = fp -> code;
ignore = fp -> ignore;
loop:
while (ignore[*pa])
pa++;
while (ignore[*pb])
pb++;
if (pa >= la || *pa == '\n')
if (pb < lb && *pb != '\n')
return (fp -> rflg);
else
continue;
if (pb >= lb || *pb == '\n')
return (-fp -> rflg);
/* STUPID Ritchie compiler can't swallow whole expression */
{ register c1 = code[*pb++], c2 = code[*pa++];
sa = fp -> zflg ? (c1&0377) - (c2&0377) : lcmp (c1, c2);
}
if (sa == 0)
goto loop;
return (sa * fp -> rflg);
}
if (uflg)
return (0);
return (cmpa (i, j));
}
cmpa (pa, pb)
register char *pa,
*pb;
{
while (*pa == *pb) {
if (*pa++ == '\n')
return (0);
pb++;
}
if (*pa == '\n' ) return fields[0].rflg;
else if (*pb == '\n') return -fields[0].rflg;
else if (fields[0].zflg && (*pb&0377) > (*pa&0377)) return fields[0].rflg;
else if (!fields[0].zflg && lcmp (*pb, *pa) > 0) return fields[0].rflg;
else return -fields[0].rflg;
}
char *
skip (pp, fp, j)
struct field *fp;
char *pp;
{
register i;
register char *p;
p = pp;
if ((i = fp -> m[j]) < 0)
return (eol (p));
while (i-- > 0) {
if (tabchar != 0) {
while (*p != tabchar)
if (*p != '\n')
p++;
else
goto ret;
p++;
}
else {
while (blank (*p))
p++;
while (!blank (*p))
if (*p != '\n')
p++;
else
goto ret;
}
}
if (fp -> bflg[j])
while (blank (*p))
p++;
i = fp -> n[j];
while (i-- > 0) {
if (*p != '\n')
p++;
else
goto ret;
}
ret:
return (p);
}
char *
eol (p)
register char *p;
{
while (*p != '\n')
p++;
return (p);
}
copyproto () {
register i;
register int *p,
*q;
p = (int *) & proto;
q = (int *) & fields[nfields];
for (i = 0; i < sizeof (proto) / sizeof (*p); i++)
*q++ = *p++;
}
field (s, k)
char *s;
{
register struct field *p;
register d;
p = &fields[nfields];
d = 0;
for (; *s != 0; s++) {
switch (*s) {
case '\0':
return;
case 'b':
p -> bflg[k]++;
break;
case 'd':
p -> ignore = dict + 128;
break;
case 'f':
p -> code = fold + 128;
break;
case 'i':
p -> ignore = nonprint + 128;
break;
case 'c':
cflg = 1;
continue;
case 'm':
mflg = 1;
continue;
case 'n':
p -> nflg++;
break;
case 't':
tabchar = *++s;
if (tabchar == 0)
s--;
continue;
case 'r':
p -> rflg = -1;
continue;
case 'u':
uflg = 1;
break;
case 'z':
p -> zflg++;
break;
case '.':
if (p -> m[k] == -1)/* -m.n with m missing */
p -> m[k] = 0;
d = &fields[0].n[0] - &fields[0].m[0];
s++;
default:
if (!isdigit (*s)) {
diag (
"usage: [-mucbdfinrz] [-tc] [+p1 [-p2]]... [-o file] [-T dir] [file]...",
"");
exit (1);
}
p -> m[k + d] = number (&s);
}
compare = cmp;
}
}
number (ppa)
char **ppa;
{
int n;
register char *pa;
pa = *ppa;
n = 0;
while (isdigit (*pa)) {
n = n * 10 + *pa - '0';
*ppa = pa++;
}
return (n);
}
blank (c) {
if (c == ' ' || c == '\t')
return (1);
return (0);
}
#define qsexc(p,q) t= *p;*p= *q;*q=t
#define qstexc(p,q,r) t= *p;*p= *r;*r= *q;*q=t
qsort (a, l)
char **a,
**l;
{
register char **i,
**j;
char **k;
char **lp,
**hp;
int c;
char *t;
unsigned n;
start:
if ((n = l - a) <= 1)
return;
n /= 2;
hp = lp = a + n;
i = a;
j = l - 1;
for (;;) {
if (i < lp) {
if ((c = (*compare) (*i, *lp)) == 0) {
--lp;
qsexc (i, lp);
continue;
}
if (c < 0) {
++i;
continue;
}
}
loop:
if (j > hp) {
if ((c = (*compare) (*hp, *j)) == 0) {
++hp;
qsexc (hp, j);
goto loop;
}
if (c > 0) {
if (i == lp) {
++hp;
qstexc (i, hp, j);
i = ++lp;
goto loop;
}
qsexc (i, j);
--j;
++i;
continue;
}
--j;
goto loop;
}
if (i == lp) {
if (uflg)
for (k = lp + 1; k <= hp;)
**k++ = '\0';
if (lp - a >= l - hp) {
qsort (hp + 1, l);
l = lp;
}
else {
qsort (a, lp);
a = hp + 1;
}
goto start;
}
--lp;
qstexc (j, lp, i);
j = --hp;
}
}
=== CUT HERE =============================================================
__________________________________________________________________________
In-Real-Life: Andrew A. Chernov | Domain: ache at hq.demos.su,
Zodiac-Sign: Virgo | ache%hq.demos.su at relay.eu.net
Organization: DEMOS Cooperative, | Phone: +7 095 2312129
Moscow, USSR | Fax: +7 095 2335016
--
__________________________________________________________________________
In-Real-Life: Andrew A. Chernov | Domain: ache at hq.demos.su,
Zodiac-Sign: Virgo | ache%hq.demos.su at relay.eu.net
Organization: DEMOS Cooperative, | Phone: +7 095 2312129
More information about the Comp.bugs.sys5
mailing list