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