Home | History | Annotate | Line # | Download | only in sort
msort.c revision 1.30
      1  1.30     enami /*	$NetBSD: msort.c,v 1.30 2010/02/05 21:58:42 enami Exp $	*/
      2  1.14  jdolecek 
      3  1.14  jdolecek /*-
      4  1.14  jdolecek  * Copyright (c) 2000-2003 The NetBSD Foundation, Inc.
      5  1.14  jdolecek  * All rights reserved.
      6  1.14  jdolecek  *
      7  1.14  jdolecek  * This code is derived from software contributed to The NetBSD Foundation
      8  1.14  jdolecek  * by Ben Harris and Jaromir Dolecek.
      9  1.14  jdolecek  *
     10  1.14  jdolecek  * Redistribution and use in source and binary forms, with or without
     11  1.14  jdolecek  * modification, are permitted provided that the following conditions
     12  1.14  jdolecek  * are met:
     13  1.14  jdolecek  * 1. Redistributions of source code must retain the above copyright
     14  1.14  jdolecek  *    notice, this list of conditions and the following disclaimer.
     15  1.14  jdolecek  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.14  jdolecek  *    notice, this list of conditions and the following disclaimer in the
     17  1.14  jdolecek  *    documentation and/or other materials provided with the distribution.
     18  1.14  jdolecek  *
     19  1.14  jdolecek  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.14  jdolecek  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.14  jdolecek  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.14  jdolecek  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.14  jdolecek  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.14  jdolecek  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.14  jdolecek  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.14  jdolecek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.14  jdolecek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.14  jdolecek  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.14  jdolecek  * POSSIBILITY OF SUCH DAMAGE.
     30  1.14  jdolecek  */
     31   1.2     bjh21 
     32   1.1     bjh21 /*-
     33   1.1     bjh21  * Copyright (c) 1993
     34   1.1     bjh21  *	The Regents of the University of California.  All rights reserved.
     35   1.1     bjh21  *
     36   1.1     bjh21  * This code is derived from software contributed to Berkeley by
     37   1.1     bjh21  * Peter McIlroy.
     38   1.1     bjh21  *
     39   1.1     bjh21  * Redistribution and use in source and binary forms, with or without
     40   1.1     bjh21  * modification, are permitted provided that the following conditions
     41   1.1     bjh21  * are met:
     42   1.1     bjh21  * 1. Redistributions of source code must retain the above copyright
     43   1.1     bjh21  *    notice, this list of conditions and the following disclaimer.
     44   1.1     bjh21  * 2. Redistributions in binary form must reproduce the above copyright
     45   1.1     bjh21  *    notice, this list of conditions and the following disclaimer in the
     46   1.1     bjh21  *    documentation and/or other materials provided with the distribution.
     47  1.13       agc  * 3. Neither the name of the University nor the names of its contributors
     48   1.1     bjh21  *    may be used to endorse or promote products derived from this software
     49   1.1     bjh21  *    without specific prior written permission.
     50   1.1     bjh21  *
     51   1.1     bjh21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     52   1.1     bjh21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     53   1.1     bjh21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     54   1.1     bjh21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     55   1.1     bjh21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     56   1.1     bjh21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     57   1.1     bjh21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58   1.1     bjh21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     59   1.1     bjh21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     60   1.1     bjh21  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     61   1.1     bjh21  * SUCH DAMAGE.
     62   1.1     bjh21  */
     63   1.1     bjh21 
     64   1.2     bjh21 #include "sort.h"
     65   1.2     bjh21 #include "fsort.h"
     66   1.2     bjh21 
     67  1.30     enami __RCSID("$NetBSD: msort.c,v 1.30 2010/02/05 21:58:42 enami Exp $");
     68   1.1     bjh21 
     69   1.1     bjh21 #include <stdlib.h>
     70   1.1     bjh21 #include <string.h>
     71   1.1     bjh21 #include <unistd.h>
     72  1.27       dsl #include <util.h>
     73   1.1     bjh21 
     74   1.1     bjh21 /* Subroutines using comparisons: merge sort and check order */
     75   1.1     bjh21 #define DELETE (1)
     76   1.8  jdolecek 
     77   1.1     bjh21 typedef struct mfile {
     78  1.27       dsl 	FILE         *fp;
     79  1.27       dsl 	get_func_t   get;
     80  1.27       dsl 	RECHEADER    *rec;
     81  1.27       dsl 	u_char       *end;
     82   1.1     bjh21 } MFILE;
     83   1.8  jdolecek 
     84  1.19       dsl static int cmp(RECHEADER *, RECHEADER *);
     85  1.27       dsl static int insert(struct mfile **, struct mfile *, int, int);
     86  1.28       dsl static void merge_sort_fstack(FILE *, put_func_t, struct field *);
     87  1.27       dsl 
     88  1.27       dsl /*
     89  1.27       dsl  * Number of files merge() can merge in one pass.
     90  1.27       dsl  */
     91  1.27       dsl #define MERGE_FNUM      16
     92  1.27       dsl 
     93  1.27       dsl static struct mfile fstack[MERGE_FNUM];
     94  1.28       dsl static struct mfile fstack_1[MERGE_FNUM];
     95  1.28       dsl static struct mfile fstack_2[MERGE_FNUM];
     96  1.28       dsl static int fstack_count, fstack_1_count, fstack_2_count;
     97   1.1     bjh21 
     98   1.1     bjh21 void
     99  1.27       dsl save_for_merge(FILE *fp, get_func_t get, struct field *ftbl)
    100   1.1     bjh21 {
    101  1.28       dsl 	FILE *mfp, *mfp1, *mfp2;
    102  1.27       dsl 
    103  1.27       dsl 	if (fstack_count == MERGE_FNUM) {
    104  1.27       dsl 		/* Must reduce the number of temporary files */
    105  1.27       dsl 		mfp = ftmp();
    106  1.28       dsl 		merge_sort_fstack(mfp, putrec, ftbl);
    107  1.28       dsl 		/* Save output in next layer */
    108  1.28       dsl 		if (fstack_1_count == MERGE_FNUM) {
    109  1.28       dsl 			mfp1 = ftmp();
    110  1.28       dsl 			memcpy(fstack, fstack_1, sizeof fstack);
    111  1.28       dsl 			merge_sort_fstack(mfp1, putrec, ftbl);
    112  1.28       dsl 			if (fstack_2_count == MERGE_FNUM) {
    113  1.28       dsl 				/* More than 4096 files! */
    114  1.28       dsl 				mfp2 = ftmp();
    115  1.28       dsl 				memcpy(fstack, fstack_2, sizeof fstack);
    116  1.28       dsl 				merge_sort_fstack(mfp2, putrec, ftbl);
    117  1.28       dsl 				fstack_2[0].fp = mfp2;
    118  1.28       dsl 				fstack_2_count = 1;
    119  1.28       dsl 			}
    120  1.28       dsl 			fstack_2[fstack_2_count].fp = mfp1;
    121  1.28       dsl 			fstack_2[fstack_2_count].get = geteasy;
    122  1.28       dsl 			fstack_2_count++;
    123  1.28       dsl 			fstack_1_count = 0;
    124  1.28       dsl 		}
    125  1.28       dsl 		fstack_1[fstack_1_count].fp = mfp;
    126  1.28       dsl 		fstack_1[fstack_1_count].get = geteasy;
    127  1.28       dsl 		fstack_1_count++;
    128  1.28       dsl 		fstack_count = 0;
    129   1.1     bjh21 	}
    130  1.27       dsl 
    131  1.27       dsl 	fstack[fstack_count].fp = fp;
    132  1.27       dsl 	fstack[fstack_count++].get = get;
    133   1.1     bjh21 }
    134   1.1     bjh21 
    135  1.27       dsl void
    136  1.27       dsl fmerge(struct filelist *filelist, int nfiles, FILE *outfp, struct field *ftbl)
    137   1.1     bjh21 {
    138  1.27       dsl 	get_func_t get = SINGL_FLD ? makeline : makekey;
    139  1.27       dsl 	FILE *fp;
    140  1.27       dsl 	int i;
    141  1.27       dsl 
    142  1.27       dsl 	for (i = 0; i < nfiles; i++) {
    143  1.27       dsl 		fp = fopen(filelist->names[i], "r");
    144  1.27       dsl 		if (fp == NULL)
    145  1.27       dsl 			err(2, "%s", filelist->names[i]);
    146  1.27       dsl 		save_for_merge(fp, get, ftbl);
    147  1.27       dsl 	}
    148   1.9  jdolecek 
    149  1.27       dsl 	merge_sort(outfp, putline, ftbl);
    150  1.27       dsl }
    151   1.9  jdolecek 
    152  1.27       dsl void
    153  1.27       dsl merge_sort(FILE *outfp, put_func_t put, struct field *ftbl)
    154  1.27       dsl {
    155  1.28       dsl 	int count = fstack_1_count + fstack_2_count;
    156  1.28       dsl 	FILE *mfp;
    157  1.28       dsl 	int i;
    158  1.28       dsl 
    159  1.28       dsl 	if (count == 0) {
    160  1.28       dsl 		/* All files in initial array */
    161  1.28       dsl 		merge_sort_fstack(outfp, put, ftbl);
    162  1.28       dsl 		return;
    163  1.28       dsl 	}
    164  1.28       dsl 
    165  1.28       dsl 	count += fstack_count;
    166  1.28       dsl 
    167  1.28       dsl 	/* Too many files for one merge sort */
    168  1.28       dsl 	for (;;) {
    169  1.28       dsl 		/* Sort latest 16 files */
    170  1.28       dsl 		i = count;
    171  1.28       dsl 		if (i > MERGE_FNUM)
    172  1.28       dsl 			i = MERGE_FNUM;
    173  1.28       dsl 		while (fstack_count > 0)
    174  1.28       dsl 			fstack[--i] = fstack[--fstack_count];
    175  1.28       dsl 		while (i > 0 && fstack_1_count > 0)
    176  1.28       dsl 			fstack[--i] = fstack_1[--fstack_1_count];
    177  1.28       dsl 		while (i > 0)
    178  1.28       dsl 			fstack[--i] = fstack_2[--fstack_2_count];
    179  1.28       dsl 		if (count <= MERGE_FNUM) {
    180  1.28       dsl 			/* Got all the data */
    181  1.28       dsl 			fstack_count = count;
    182  1.28       dsl 			merge_sort_fstack(outfp, put, ftbl);
    183  1.28       dsl 			return;
    184  1.28       dsl 		}
    185  1.28       dsl 		mfp = ftmp();
    186  1.28       dsl 		fstack_count = count > MERGE_FNUM ? MERGE_FNUM : count;
    187  1.28       dsl 		merge_sort_fstack(mfp, putrec, ftbl);
    188  1.28       dsl 		fstack[0].fp = mfp;
    189  1.28       dsl 		fstack[0].get = geteasy;
    190  1.28       dsl 		fstack_count = 1;
    191  1.28       dsl 		count -= MERGE_FNUM - 1;
    192  1.28       dsl 	}
    193  1.28       dsl }
    194  1.28       dsl 
    195  1.28       dsl static void
    196  1.28       dsl merge_sort_fstack(FILE *outfp, put_func_t put, struct field *ftbl)
    197  1.28       dsl {
    198  1.27       dsl 	struct mfile *flistb[MERGE_FNUM], **flist = flistb, *cfile;
    199  1.27       dsl 	RECHEADER *new_rec;
    200  1.27       dsl 	u_char *new_end;
    201  1.27       dsl 	void *tmp;
    202  1.27       dsl 	int c, i, nfiles;
    203  1.27       dsl 	size_t sz;
    204   1.8  jdolecek 
    205  1.23       dsl 	/* Read one record from each file (read again if a duplicate) */
    206  1.27       dsl 	for (nfiles = i = 0; i < fstack_count; i++) {
    207  1.27       dsl 		cfile = &fstack[i];
    208  1.27       dsl 		if (cfile->rec == NULL) {
    209  1.30     enami 			cfile->rec = allocrec(NULL, DEFLLEN);
    210  1.27       dsl 			cfile->end = (u_char *)cfile->rec + DEFLLEN;
    211  1.27       dsl 		}
    212  1.27       dsl 		rewind(cfile->fp);
    213  1.27       dsl 
    214  1.27       dsl 		for (;;) {
    215  1.27       dsl 			c = cfile->get(cfile->fp, cfile->rec, cfile->end, ftbl);
    216  1.27       dsl 			if (c == EOF)
    217   1.1     bjh21 				break;
    218   1.9  jdolecek 
    219   1.9  jdolecek 			if (c == BUFFEND) {
    220  1.27       dsl 				/* Double buffer size */
    221  1.27       dsl 				sz = (cfile->end - (u_char *)cfile->rec) * 2;
    222  1.30     enami 				cfile->rec = allocrec(cfile->rec, sz);
    223  1.27       dsl 				cfile->end = (u_char *)cfile->rec + sz;
    224   1.9  jdolecek 				continue;
    225   1.9  jdolecek 			}
    226   1.9  jdolecek 
    227  1.27       dsl 			if (nfiles != 0) {
    228  1.27       dsl 				if (insert(flist, cfile, nfiles, !DELETE))
    229  1.27       dsl 					/* Duplicate removed */
    230  1.27       dsl 					continue;
    231  1.27       dsl 			} else
    232   1.1     bjh21 				flist[0] = cfile;
    233  1.27       dsl 			nfiles++;
    234  1.27       dsl 			break;
    235   1.1     bjh21 		}
    236   1.1     bjh21 	}
    237   1.9  jdolecek 
    238  1.27       dsl 	if (nfiles == 0)
    239  1.27       dsl 		return;
    240  1.27       dsl 
    241  1.24       dsl 	/*
    242  1.24       dsl 	 * We now loop reading a new record from the file with the
    243  1.24       dsl 	 * 'sorted first' existing record.
    244  1.24       dsl 	 * As each record is added, the 'first' record is written to the
    245  1.24       dsl 	 * output file - maintaining one record from each file in the sorted
    246  1.24       dsl 	 * list.
    247  1.24       dsl 	 */
    248  1.30     enami 	new_rec = allocrec(NULL, DEFLLEN);
    249  1.27       dsl 	new_end = (u_char *)new_rec + DEFLLEN;
    250  1.24       dsl 	for (;;) {
    251  1.27       dsl 		cfile = flist[0];
    252  1.27       dsl 		c = cfile->get(cfile->fp, new_rec, new_end, ftbl);
    253  1.24       dsl 		if (c == EOF) {
    254  1.24       dsl 			/* Write out last record from now-empty input */
    255  1.27       dsl 			put(cfile->rec, outfp);
    256  1.24       dsl 			if (--nfiles == 0)
    257   1.1     bjh21 				break;
    258  1.24       dsl 			/* Replace from file with now-first sorted record. */
    259  1.24       dsl 			/* (Moving base 'flist' saves copying everything!) */
    260  1.24       dsl 			flist++;
    261  1.24       dsl 			continue;
    262  1.24       dsl 		}
    263  1.24       dsl 		if (c == BUFFEND) {
    264  1.24       dsl 			/* Buffer not large enough - double in size */
    265  1.27       dsl 			sz = (new_end - (u_char *)new_rec) * 2;
    266  1.30     enami 			new_rec = allocrec(new_rec, sz);
    267  1.27       dsl 			new_end = (u_char *)new_rec +sz;
    268  1.24       dsl 			continue;
    269   1.1     bjh21 		}
    270  1.27       dsl 
    271  1.27       dsl 		/* Swap in new buffer, saving old */
    272  1.27       dsl 		tmp = cfile->rec;
    273  1.27       dsl 		cfile->rec = new_rec;
    274  1.27       dsl 		new_rec = tmp;
    275  1.27       dsl 		tmp = cfile->end;
    276  1.27       dsl 		cfile->end = new_end;
    277  1.27       dsl 		new_end = tmp;
    278  1.27       dsl 
    279  1.24       dsl 		/* Add into sort, removing the original first entry */
    280  1.27       dsl 		c = insert(flist, cfile, nfiles, DELETE);
    281  1.27       dsl 		if (c != 0 || (UNIQUE && cfile == flist[0]
    282  1.27       dsl 			    && cmp(new_rec, cfile->rec) == 0)) {
    283  1.27       dsl 			/* Was an unwanted duplicate, restore buffer */
    284  1.27       dsl 			tmp = cfile->rec;
    285  1.27       dsl 			cfile->rec = new_rec;
    286  1.27       dsl 			new_rec = tmp;
    287  1.27       dsl 			tmp = cfile->end;
    288  1.27       dsl 			cfile->end = new_end;
    289  1.27       dsl 			new_end = tmp;
    290  1.27       dsl 			continue;
    291  1.27       dsl 		}
    292  1.24       dsl 
    293  1.27       dsl 		/* Write out 'old' record */
    294  1.27       dsl 		put(new_rec, outfp);
    295  1.24       dsl 	}
    296  1.27       dsl 
    297  1.27       dsl 	free(new_rec);
    298   1.1     bjh21 }
    299   1.1     bjh21 
    300   1.1     bjh21 /*
    301  1.27       dsl  * if delete: inserts rec in flist, deletes flist[0];
    302   1.1     bjh21  * otherwise just inserts *rec in flist.
    303  1.27       dsl  * Returns 1 if record is a duplicate to be ignored.
    304  1.10  jdolecek  */
    305   1.1     bjh21 static int
    306  1.27       dsl insert(struct mfile **flist, struct mfile *rec, int ttop, int delete)
    307   1.1     bjh21 {
    308   1.8  jdolecek 	int mid, top = ttop, bot = 0, cmpv = 1;
    309   1.8  jdolecek 
    310  1.16    itojun 	for (mid = top / 2; bot + 1 != top; mid = (bot + top) / 2) {
    311  1.27       dsl 		cmpv = cmp(rec->rec, flist[mid]->rec);
    312  1.24       dsl 		if (cmpv == 0 ) {
    313   1.8  jdolecek 			if (UNIQUE)
    314  1.24       dsl 				/* Duplicate key, read another record */
    315  1.27       dsl 				/* NB: This doesn't guarantee to keep any
    316  1.27       dsl 				 * particular record. */
    317  1.24       dsl 				return 1;
    318  1.23       dsl 			/*
    319  1.27       dsl 			 * Apply sort by input file order.
    320  1.24       dsl 			 * We could truncate the sort is the fileno are
    321  1.24       dsl 			 * adjacent - but that is all too hard!
    322  1.24       dsl 			 * The fileno cannot be equal, since we only have one
    323  1.24       dsl 			 * record from each file (+ flist[0] which never
    324  1.24       dsl 			 * comes here).
    325  1.23       dsl 			 */
    326  1.27       dsl 			cmpv = rec < flist[mid] ? -1 : 1;
    327  1.26       dsl 			if (REVERSE)
    328  1.26       dsl 				cmpv = -cmpv;
    329   1.1     bjh21 		}
    330  1.24       dsl 		if (cmpv < 0)
    331  1.24       dsl 			top = mid;
    332  1.24       dsl 		else
    333  1.24       dsl 			bot = mid;
    334   1.1     bjh21 	}
    335   1.8  jdolecek 
    336  1.24       dsl 	/* At this point we haven't yet compared against flist[0] */
    337  1.24       dsl 
    338   1.1     bjh21 	if (delete) {
    339  1.27       dsl 		/* flist[0] is ourselves, only the caller knows the old data */
    340  1.27       dsl 		if (bot != 0) {
    341  1.27       dsl 			memmove(flist, flist + 1, bot * sizeof(MFILE *));
    342  1.27       dsl 			flist[bot] = rec;
    343  1.27       dsl 		}
    344  1.24       dsl 		return 0;
    345  1.24       dsl 	}
    346  1.24       dsl 
    347  1.24       dsl 	/* Inserting original set of records */
    348  1.24       dsl 
    349  1.24       dsl 	if (bot == 0 && cmpv != 0) {
    350  1.24       dsl 		/* Doesn't match flist[1], must compare with flist[0] */
    351  1.27       dsl 		cmpv = cmp(rec->rec, flist[0]->rec);
    352  1.24       dsl 		if (cmpv == 0 && UNIQUE)
    353  1.24       dsl 			return 1;
    354  1.24       dsl 		/* Add matching keys in file order (ie new is later) */
    355  1.24       dsl 		if (cmpv < 0)
    356  1.24       dsl 			bot = -1;
    357   1.1     bjh21 	}
    358  1.24       dsl 	bot++;
    359  1.27       dsl 	memmove(flist + bot + 1, flist + bot, (ttop - bot) * sizeof(MFILE *));
    360  1.27       dsl 	flist[bot] = rec;
    361  1.24       dsl 	return 0;
    362   1.1     bjh21 }
    363   1.1     bjh21 
    364   1.1     bjh21 /*
    365   1.1     bjh21  * check order on one file
    366   1.1     bjh21  */
    367   1.1     bjh21 void
    368  1.27       dsl order(struct filelist *filelist, struct field *ftbl)
    369   1.1     bjh21 {
    370  1.27       dsl 	get_func_t get = SINGL_FLD ? makeline : makekey;
    371  1.25       dsl 	RECHEADER *crec, *prec, *trec;
    372   1.6  jdolecek 	u_char *crec_end, *prec_end, *trec_end;
    373  1.27       dsl 	FILE *fp;
    374   1.1     bjh21 	int c;
    375   1.1     bjh21 
    376  1.27       dsl 	fp = fopen(filelist->names[0], "r");
    377  1.27       dsl 	if (fp == NULL)
    378  1.27       dsl 		err(2, "%s", filelist->names[0]);
    379  1.27       dsl 
    380  1.25       dsl 	crec = malloc(offsetof(RECHEADER, data[DEFLLEN]));
    381  1.25       dsl 	crec_end = crec->data + DEFLLEN;
    382  1.25       dsl 	prec = malloc(offsetof(RECHEADER, data[DEFLLEN]));
    383  1.25       dsl 	prec_end = prec->data + DEFLLEN;
    384  1.23       dsl 
    385  1.23       dsl 	/* XXX this does exit(0) for overlong lines */
    386  1.27       dsl 	if (get(fp, prec, prec_end, ftbl) != 0)
    387  1.23       dsl 		exit(0);
    388  1.27       dsl 	while (get(fp, crec, crec_end, ftbl) == 0) {
    389   1.1     bjh21 		if (0 < (c = cmp(prec, crec))) {
    390   1.1     bjh21 			crec->data[crec->length-1] = 0;
    391   1.1     bjh21 			errx(1, "found disorder: %s", crec->data+crec->offset);
    392   1.1     bjh21 		}
    393   1.1     bjh21 		if (UNIQUE && !c) {
    394   1.1     bjh21 			crec->data[crec->length-1] = 0;
    395   1.1     bjh21 			errx(1, "found non-uniqueness: %s",
    396   1.1     bjh21 			    crec->data+crec->offset);
    397   1.1     bjh21 		}
    398   1.6  jdolecek 		/*
    399   1.6  jdolecek 		 * Swap pointers so that this record is on place pointed
    400   1.6  jdolecek 		 * to by prec and new record is read to place pointed to by
    401   1.6  jdolecek 		 * crec.
    402   1.6  jdolecek 		 */
    403   1.1     bjh21 		trec = prec;
    404   1.1     bjh21 		prec = crec;
    405   1.1     bjh21 		crec = trec;
    406   1.6  jdolecek 		trec_end = prec_end;
    407   1.6  jdolecek 		prec_end = crec_end;
    408   1.6  jdolecek 		crec_end = trec_end;
    409   1.1     bjh21 	}
    410   1.1     bjh21 	exit(0);
    411   1.1     bjh21 }
    412   1.1     bjh21 
    413   1.1     bjh21 static int
    414  1.19       dsl cmp(RECHEADER *rec1, RECHEADER *rec2)
    415   1.1     bjh21 {
    416  1.26       dsl 	int len;
    417   1.4  jdolecek 	int r;
    418  1.23       dsl 
    419  1.26       dsl 	/* key is weights */
    420  1.26       dsl 	len = min(rec1->keylen, rec2->keylen);
    421  1.26       dsl 	r = memcmp(rec1->data, rec2->data, len);
    422  1.26       dsl 	if (r == 0)
    423  1.26       dsl 		r = rec1->keylen - rec2->keylen;
    424  1.26       dsl 	if (REVERSE)
    425  1.26       dsl 		r = -r;
    426  1.26       dsl 	return r;
    427   1.1     bjh21 }
    428