Home | History | Annotate | Line # | Download | only in sort
msort.c revision 1.28
      1  1.28       dsl /*	$NetBSD: msort.c,v 1.28 2009/10/09 20:29:43 dsl 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.1     bjh21 #ifndef lint
     68  1.28       dsl __RCSID("$NetBSD: msort.c,v 1.28 2009/10/09 20:29:43 dsl Exp $");
     69   1.2     bjh21 __SCCSID("@(#)msort.c	8.1 (Berkeley) 6/6/93");
     70   1.1     bjh21 #endif /* not lint */
     71   1.1     bjh21 
     72   1.1     bjh21 #include <stdlib.h>
     73   1.1     bjh21 #include <string.h>
     74   1.1     bjh21 #include <unistd.h>
     75  1.27       dsl #include <util.h>
     76   1.1     bjh21 
     77   1.1     bjh21 /* Subroutines using comparisons: merge sort and check order */
     78   1.1     bjh21 #define DELETE (1)
     79   1.8  jdolecek 
     80   1.1     bjh21 typedef struct mfile {
     81  1.27       dsl 	FILE         *fp;
     82  1.27       dsl 	get_func_t   get;
     83  1.27       dsl 	RECHEADER    *rec;
     84  1.27       dsl 	u_char       *end;
     85   1.1     bjh21 } MFILE;
     86   1.8  jdolecek 
     87  1.19       dsl static int cmp(RECHEADER *, RECHEADER *);
     88  1.27       dsl static int insert(struct mfile **, struct mfile *, int, int);
     89  1.28       dsl static void merge_sort_fstack(FILE *, put_func_t, struct field *);
     90  1.27       dsl 
     91  1.27       dsl /*
     92  1.27       dsl  * Number of files merge() can merge in one pass.
     93  1.27       dsl  */
     94  1.27       dsl #define MERGE_FNUM      16
     95  1.27       dsl 
     96  1.27       dsl static struct mfile fstack[MERGE_FNUM];
     97  1.28       dsl static struct mfile fstack_1[MERGE_FNUM];
     98  1.28       dsl static struct mfile fstack_2[MERGE_FNUM];
     99  1.28       dsl static int fstack_count, fstack_1_count, fstack_2_count;
    100   1.1     bjh21 
    101   1.1     bjh21 void
    102  1.27       dsl save_for_merge(FILE *fp, get_func_t get, struct field *ftbl)
    103   1.1     bjh21 {
    104  1.28       dsl 	FILE *mfp, *mfp1, *mfp2;
    105  1.27       dsl 
    106  1.27       dsl 	if (fstack_count == MERGE_FNUM) {
    107  1.27       dsl 		/* Must reduce the number of temporary files */
    108  1.27       dsl 		mfp = ftmp();
    109  1.28       dsl 		merge_sort_fstack(mfp, putrec, ftbl);
    110  1.28       dsl 		/* Save output in next layer */
    111  1.28       dsl 		if (fstack_1_count == MERGE_FNUM) {
    112  1.28       dsl 			mfp1 = ftmp();
    113  1.28       dsl 			memcpy(fstack, fstack_1, sizeof fstack);
    114  1.28       dsl 			merge_sort_fstack(mfp1, putrec, ftbl);
    115  1.28       dsl 			if (fstack_2_count == MERGE_FNUM) {
    116  1.28       dsl 				/* More than 4096 files! */
    117  1.28       dsl 				mfp2 = ftmp();
    118  1.28       dsl 				memcpy(fstack, fstack_2, sizeof fstack);
    119  1.28       dsl 				merge_sort_fstack(mfp2, putrec, ftbl);
    120  1.28       dsl 				fstack_2[0].fp = mfp2;
    121  1.28       dsl 				fstack_2_count = 1;
    122  1.28       dsl 			}
    123  1.28       dsl 			fstack_2[fstack_2_count].fp = mfp1;
    124  1.28       dsl 			fstack_2[fstack_2_count].get = geteasy;
    125  1.28       dsl 			fstack_2_count++;
    126  1.28       dsl 			fstack_1_count = 0;
    127  1.28       dsl 		}
    128  1.28       dsl 		fstack_1[fstack_1_count].fp = mfp;
    129  1.28       dsl 		fstack_1[fstack_1_count].get = geteasy;
    130  1.28       dsl 		fstack_1_count++;
    131  1.28       dsl 		fstack_count = 0;
    132   1.1     bjh21 	}
    133  1.27       dsl 
    134  1.27       dsl 	fstack[fstack_count].fp = fp;
    135  1.27       dsl 	fstack[fstack_count++].get = get;
    136   1.1     bjh21 }
    137   1.1     bjh21 
    138  1.27       dsl void
    139  1.27       dsl fmerge(struct filelist *filelist, int nfiles, FILE *outfp, struct field *ftbl)
    140   1.1     bjh21 {
    141  1.27       dsl 	get_func_t get = SINGL_FLD ? makeline : makekey;
    142  1.27       dsl 	FILE *fp;
    143  1.27       dsl 	int i;
    144  1.27       dsl 
    145  1.27       dsl 	for (i = 0; i < nfiles; i++) {
    146  1.27       dsl 		fp = fopen(filelist->names[i], "r");
    147  1.27       dsl 		if (fp == NULL)
    148  1.27       dsl 			err(2, "%s", filelist->names[i]);
    149  1.27       dsl 		save_for_merge(fp, get, ftbl);
    150  1.27       dsl 	}
    151   1.9  jdolecek 
    152  1.27       dsl 	merge_sort(outfp, putline, ftbl);
    153  1.27       dsl }
    154   1.9  jdolecek 
    155  1.27       dsl void
    156  1.27       dsl merge_sort(FILE *outfp, put_func_t put, struct field *ftbl)
    157  1.27       dsl {
    158  1.28       dsl 	int count = fstack_1_count + fstack_2_count;
    159  1.28       dsl 	FILE *mfp;
    160  1.28       dsl 	int i;
    161  1.28       dsl 
    162  1.28       dsl 	if (count == 0) {
    163  1.28       dsl 		/* All files in initial array */
    164  1.28       dsl 		merge_sort_fstack(outfp, put, ftbl);
    165  1.28       dsl 		return;
    166  1.28       dsl 	}
    167  1.28       dsl 
    168  1.28       dsl 	count += fstack_count;
    169  1.28       dsl 
    170  1.28       dsl 	/* Too many files for one merge sort */
    171  1.28       dsl 	for (;;) {
    172  1.28       dsl 		/* Sort latest 16 files */
    173  1.28       dsl 		i = count;
    174  1.28       dsl 		if (i > MERGE_FNUM)
    175  1.28       dsl 			i = MERGE_FNUM;
    176  1.28       dsl 		while (fstack_count > 0)
    177  1.28       dsl 			fstack[--i] = fstack[--fstack_count];
    178  1.28       dsl 		while (i > 0 && fstack_1_count > 0)
    179  1.28       dsl 			fstack[--i] = fstack_1[--fstack_1_count];
    180  1.28       dsl 		while (i > 0)
    181  1.28       dsl 			fstack[--i] = fstack_2[--fstack_2_count];
    182  1.28       dsl 		if (count <= MERGE_FNUM) {
    183  1.28       dsl 			/* Got all the data */
    184  1.28       dsl 			fstack_count = count;
    185  1.28       dsl 			merge_sort_fstack(outfp, put, ftbl);
    186  1.28       dsl 			return;
    187  1.28       dsl 		}
    188  1.28       dsl 		mfp = ftmp();
    189  1.28       dsl 		fstack_count = count > MERGE_FNUM ? MERGE_FNUM : count;
    190  1.28       dsl 		merge_sort_fstack(mfp, putrec, ftbl);
    191  1.28       dsl 		fstack[0].fp = mfp;
    192  1.28       dsl 		fstack[0].get = geteasy;
    193  1.28       dsl 		fstack_count = 1;
    194  1.28       dsl 		count -= MERGE_FNUM - 1;
    195  1.28       dsl 	}
    196  1.28       dsl }
    197  1.28       dsl 
    198  1.28       dsl static void
    199  1.28       dsl merge_sort_fstack(FILE *outfp, put_func_t put, struct field *ftbl)
    200  1.28       dsl {
    201  1.27       dsl 	struct mfile *flistb[MERGE_FNUM], **flist = flistb, *cfile;
    202  1.27       dsl 	RECHEADER *new_rec;
    203  1.27       dsl 	u_char *new_end;
    204  1.27       dsl 	void *tmp;
    205  1.27       dsl 	int c, i, nfiles;
    206  1.27       dsl 	size_t sz;
    207   1.8  jdolecek 
    208  1.23       dsl 	/* Read one record from each file (read again if a duplicate) */
    209  1.27       dsl 	for (nfiles = i = 0; i < fstack_count; i++) {
    210  1.27       dsl 		cfile = &fstack[i];
    211  1.27       dsl 		if (cfile->rec == NULL) {
    212  1.27       dsl 			cfile->rec = emalloc(DEFLLEN);
    213  1.27       dsl 			cfile->end = (u_char *)cfile->rec + DEFLLEN;
    214  1.27       dsl 		}
    215  1.27       dsl 		rewind(cfile->fp);
    216  1.27       dsl 
    217  1.27       dsl 		for (;;) {
    218  1.27       dsl 			c = cfile->get(cfile->fp, cfile->rec, cfile->end, ftbl);
    219  1.27       dsl 			if (c == EOF)
    220   1.1     bjh21 				break;
    221   1.9  jdolecek 
    222   1.9  jdolecek 			if (c == BUFFEND) {
    223  1.27       dsl 				/* Double buffer size */
    224  1.27       dsl 				sz = (cfile->end - (u_char *)cfile->rec) * 2;
    225  1.27       dsl 				cfile->rec = erealloc(cfile->rec, sz);
    226  1.27       dsl 				cfile->end = (u_char *)cfile->rec + sz;
    227   1.9  jdolecek 				continue;
    228   1.9  jdolecek 			}
    229   1.9  jdolecek 
    230  1.27       dsl 			if (nfiles != 0) {
    231  1.27       dsl 				if (insert(flist, cfile, nfiles, !DELETE))
    232  1.27       dsl 					/* Duplicate removed */
    233  1.27       dsl 					continue;
    234  1.27       dsl 			} else
    235   1.1     bjh21 				flist[0] = cfile;
    236  1.27       dsl 			nfiles++;
    237  1.27       dsl 			break;
    238   1.1     bjh21 		}
    239   1.1     bjh21 	}
    240   1.9  jdolecek 
    241  1.27       dsl 	if (nfiles == 0)
    242  1.27       dsl 		return;
    243  1.27       dsl 
    244  1.24       dsl 	/*
    245  1.24       dsl 	 * We now loop reading a new record from the file with the
    246  1.24       dsl 	 * 'sorted first' existing record.
    247  1.24       dsl 	 * As each record is added, the 'first' record is written to the
    248  1.24       dsl 	 * output file - maintaining one record from each file in the sorted
    249  1.24       dsl 	 * list.
    250  1.24       dsl 	 */
    251  1.27       dsl 	new_rec = emalloc(DEFLLEN);
    252  1.27       dsl 	new_end = (u_char *)new_rec + DEFLLEN;
    253  1.24       dsl 	for (;;) {
    254  1.27       dsl 		cfile = flist[0];
    255  1.27       dsl 		c = cfile->get(cfile->fp, new_rec, new_end, ftbl);
    256  1.24       dsl 		if (c == EOF) {
    257  1.24       dsl 			/* Write out last record from now-empty input */
    258  1.27       dsl 			put(cfile->rec, outfp);
    259  1.24       dsl 			if (--nfiles == 0)
    260   1.1     bjh21 				break;
    261  1.24       dsl 			/* Replace from file with now-first sorted record. */
    262  1.24       dsl 			/* (Moving base 'flist' saves copying everything!) */
    263  1.24       dsl 			flist++;
    264  1.24       dsl 			continue;
    265  1.24       dsl 		}
    266  1.24       dsl 		if (c == BUFFEND) {
    267  1.24       dsl 			/* Buffer not large enough - double in size */
    268  1.27       dsl 			sz = (new_end - (u_char *)new_rec) * 2;
    269  1.27       dsl 			new_rec = erealloc(new_rec, sz);
    270  1.27       dsl 			new_end = (u_char *)new_rec +sz;
    271  1.24       dsl 			continue;
    272   1.1     bjh21 		}
    273  1.27       dsl 
    274  1.27       dsl 		/* Swap in new buffer, saving old */
    275  1.27       dsl 		tmp = cfile->rec;
    276  1.27       dsl 		cfile->rec = new_rec;
    277  1.27       dsl 		new_rec = tmp;
    278  1.27       dsl 		tmp = cfile->end;
    279  1.27       dsl 		cfile->end = new_end;
    280  1.27       dsl 		new_end = tmp;
    281  1.27       dsl 
    282  1.24       dsl 		/* Add into sort, removing the original first entry */
    283  1.27       dsl 		c = insert(flist, cfile, nfiles, DELETE);
    284  1.27       dsl 		if (c != 0 || (UNIQUE && cfile == flist[0]
    285  1.27       dsl 			    && cmp(new_rec, cfile->rec) == 0)) {
    286  1.27       dsl 			/* Was an unwanted duplicate, restore buffer */
    287  1.27       dsl 			tmp = cfile->rec;
    288  1.27       dsl 			cfile->rec = new_rec;
    289  1.27       dsl 			new_rec = tmp;
    290  1.27       dsl 			tmp = cfile->end;
    291  1.27       dsl 			cfile->end = new_end;
    292  1.27       dsl 			new_end = tmp;
    293  1.27       dsl 			continue;
    294  1.27       dsl 		}
    295  1.24       dsl 
    296  1.27       dsl 		/* Write out 'old' record */
    297  1.27       dsl 		put(new_rec, outfp);
    298  1.24       dsl 	}
    299  1.27       dsl 
    300  1.27       dsl 	free(new_rec);
    301   1.1     bjh21 }
    302   1.1     bjh21 
    303   1.1     bjh21 /*
    304  1.27       dsl  * if delete: inserts rec in flist, deletes flist[0];
    305   1.1     bjh21  * otherwise just inserts *rec in flist.
    306  1.27       dsl  * Returns 1 if record is a duplicate to be ignored.
    307  1.10  jdolecek  */
    308   1.1     bjh21 static int
    309  1.27       dsl insert(struct mfile **flist, struct mfile *rec, int ttop, int delete)
    310   1.1     bjh21 {
    311   1.8  jdolecek 	int mid, top = ttop, bot = 0, cmpv = 1;
    312   1.8  jdolecek 
    313  1.16    itojun 	for (mid = top / 2; bot + 1 != top; mid = (bot + top) / 2) {
    314  1.27       dsl 		cmpv = cmp(rec->rec, flist[mid]->rec);
    315  1.24       dsl 		if (cmpv == 0 ) {
    316   1.8  jdolecek 			if (UNIQUE)
    317  1.24       dsl 				/* Duplicate key, read another record */
    318  1.27       dsl 				/* NB: This doesn't guarantee to keep any
    319  1.27       dsl 				 * particular record. */
    320  1.24       dsl 				return 1;
    321  1.23       dsl 			/*
    322  1.27       dsl 			 * Apply sort by input file order.
    323  1.24       dsl 			 * We could truncate the sort is the fileno are
    324  1.24       dsl 			 * adjacent - but that is all too hard!
    325  1.24       dsl 			 * The fileno cannot be equal, since we only have one
    326  1.24       dsl 			 * record from each file (+ flist[0] which never
    327  1.24       dsl 			 * comes here).
    328  1.23       dsl 			 */
    329  1.27       dsl 			cmpv = rec < flist[mid] ? -1 : 1;
    330  1.26       dsl 			if (REVERSE)
    331  1.26       dsl 				cmpv = -cmpv;
    332   1.1     bjh21 		}
    333  1.24       dsl 		if (cmpv < 0)
    334  1.24       dsl 			top = mid;
    335  1.24       dsl 		else
    336  1.24       dsl 			bot = mid;
    337   1.1     bjh21 	}
    338   1.8  jdolecek 
    339  1.24       dsl 	/* At this point we haven't yet compared against flist[0] */
    340  1.24       dsl 
    341   1.1     bjh21 	if (delete) {
    342  1.27       dsl 		/* flist[0] is ourselves, only the caller knows the old data */
    343  1.27       dsl 		if (bot != 0) {
    344  1.27       dsl 			memmove(flist, flist + 1, bot * sizeof(MFILE *));
    345  1.27       dsl 			flist[bot] = rec;
    346  1.27       dsl 		}
    347  1.24       dsl 		return 0;
    348  1.24       dsl 	}
    349  1.24       dsl 
    350  1.24       dsl 	/* Inserting original set of records */
    351  1.24       dsl 
    352  1.24       dsl 	if (bot == 0 && cmpv != 0) {
    353  1.24       dsl 		/* Doesn't match flist[1], must compare with flist[0] */
    354  1.27       dsl 		cmpv = cmp(rec->rec, flist[0]->rec);
    355  1.24       dsl 		if (cmpv == 0 && UNIQUE)
    356  1.24       dsl 			return 1;
    357  1.24       dsl 		/* Add matching keys in file order (ie new is later) */
    358  1.24       dsl 		if (cmpv < 0)
    359  1.24       dsl 			bot = -1;
    360   1.1     bjh21 	}
    361  1.24       dsl 	bot++;
    362  1.27       dsl 	memmove(flist + bot + 1, flist + bot, (ttop - bot) * sizeof(MFILE *));
    363  1.27       dsl 	flist[bot] = rec;
    364  1.24       dsl 	return 0;
    365   1.1     bjh21 }
    366   1.1     bjh21 
    367   1.1     bjh21 /*
    368   1.1     bjh21  * check order on one file
    369   1.1     bjh21  */
    370   1.1     bjh21 void
    371  1.27       dsl order(struct filelist *filelist, struct field *ftbl)
    372   1.1     bjh21 {
    373  1.27       dsl 	get_func_t get = SINGL_FLD ? makeline : makekey;
    374  1.25       dsl 	RECHEADER *crec, *prec, *trec;
    375   1.6  jdolecek 	u_char *crec_end, *prec_end, *trec_end;
    376  1.27       dsl 	FILE *fp;
    377   1.1     bjh21 	int c;
    378   1.1     bjh21 
    379  1.27       dsl 	fp = fopen(filelist->names[0], "r");
    380  1.27       dsl 	if (fp == NULL)
    381  1.27       dsl 		err(2, "%s", filelist->names[0]);
    382  1.27       dsl 
    383  1.25       dsl 	crec = malloc(offsetof(RECHEADER, data[DEFLLEN]));
    384  1.25       dsl 	crec_end = crec->data + DEFLLEN;
    385  1.25       dsl 	prec = malloc(offsetof(RECHEADER, data[DEFLLEN]));
    386  1.25       dsl 	prec_end = prec->data + DEFLLEN;
    387  1.23       dsl 
    388  1.23       dsl 	/* XXX this does exit(0) for overlong lines */
    389  1.27       dsl 	if (get(fp, prec, prec_end, ftbl) != 0)
    390  1.23       dsl 		exit(0);
    391  1.27       dsl 	while (get(fp, crec, crec_end, ftbl) == 0) {
    392   1.1     bjh21 		if (0 < (c = cmp(prec, crec))) {
    393   1.1     bjh21 			crec->data[crec->length-1] = 0;
    394   1.1     bjh21 			errx(1, "found disorder: %s", crec->data+crec->offset);
    395   1.1     bjh21 		}
    396   1.1     bjh21 		if (UNIQUE && !c) {
    397   1.1     bjh21 			crec->data[crec->length-1] = 0;
    398   1.1     bjh21 			errx(1, "found non-uniqueness: %s",
    399   1.1     bjh21 			    crec->data+crec->offset);
    400   1.1     bjh21 		}
    401   1.6  jdolecek 		/*
    402   1.6  jdolecek 		 * Swap pointers so that this record is on place pointed
    403   1.6  jdolecek 		 * to by prec and new record is read to place pointed to by
    404   1.6  jdolecek 		 * crec.
    405   1.6  jdolecek 		 */
    406   1.1     bjh21 		trec = prec;
    407   1.1     bjh21 		prec = crec;
    408   1.1     bjh21 		crec = trec;
    409   1.6  jdolecek 		trec_end = prec_end;
    410   1.6  jdolecek 		prec_end = crec_end;
    411   1.6  jdolecek 		crec_end = trec_end;
    412   1.1     bjh21 	}
    413   1.1     bjh21 	exit(0);
    414   1.1     bjh21 }
    415   1.1     bjh21 
    416   1.1     bjh21 static int
    417  1.19       dsl cmp(RECHEADER *rec1, RECHEADER *rec2)
    418   1.1     bjh21 {
    419  1.26       dsl 	int len;
    420   1.4  jdolecek 	int r;
    421  1.23       dsl 
    422  1.26       dsl 	/* key is weights */
    423  1.26       dsl 	len = min(rec1->keylen, rec2->keylen);
    424  1.26       dsl 	r = memcmp(rec1->data, rec2->data, len);
    425  1.26       dsl 	if (r == 0)
    426  1.26       dsl 		r = rec1->keylen - rec2->keylen;
    427  1.26       dsl 	if (REVERSE)
    428  1.26       dsl 		r = -r;
    429  1.26       dsl 	return r;
    430   1.1     bjh21 }
    431