NetBSD/usr.bin/sort/files.c

362 lines
8.7 KiB
C
Raw Normal View History

/* $NetBSD: files.c,v 1.5 2000/10/16 21:53:19 jdolecek Exp $ */
2000-10-07 20:39:34 +04:00
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Peter McIlroy.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "sort.h"
#include "fsort.h"
#ifndef lint
__RCSID("$NetBSD: files.c,v 1.5 2000/10/16 21:53:19 jdolecek Exp $");
__SCCSID("@(#)files.c 8.1 (Berkeley) 6/6/93");
#endif /* not lint */
2000-10-07 20:39:34 +04:00
#include <string.h>
static int seq __P((FILE *, DBT *, DBT *));
2000-10-07 20:39:34 +04:00
/*
* this is the subroutine for file management for fsort().
* It keeps the buffers for all temporary files.
*/
int
getnext(binno, infl0, nfiles, pos, end, dummy)
int binno, nfiles;
union f_handle infl0;
2000-10-16 00:46:33 +04:00
struct recheader *pos;
u_char *end;
2000-10-07 20:39:34 +04:00
struct field *dummy;
{
2000-10-16 00:46:33 +04:00
int i;
u_char *hp;
2000-10-07 20:39:34 +04:00
static long nleft = 0;
static int cnt = 0, flag = -1;
static u_char maxb = 0;
static FILE *fp;
2000-10-07 20:39:34 +04:00
if (nleft == 0) {
if (binno < 0) /* reset files. */ {
for (i = 0; i < nfiles; i++) {
rewind(fstack[infl0.top + i].fp);
2000-10-07 20:39:34 +04:00
fstack[infl0.top + i].max_o = 0;
}
flag = -1;
nleft = cnt = 0;
return(-1);
}
maxb = fstack[infl0.top].maxb;
for (; nleft == 0; cnt++) {
if (cnt >= nfiles) {
cnt = 0;
return (EOF);
}
fp = fstack[infl0.top + cnt].fp;
2000-10-07 20:39:34 +04:00
hp = (u_char *) &nleft;
for (i = sizeof(TRECHEADER); i; --i)
*hp++ = getc(fp);
2000-10-07 20:39:34 +04:00
if (binno < maxb)
fstack[infl0.top+cnt].max_o
+= sizeof(nleft) + nleft;
else if (binno == maxb) {
if (binno != fstack[infl0.top].lastb) {
fseek(fp, fstack[infl0.top+
2000-10-07 20:39:34 +04:00
cnt].max_o, SEEK_SET);
fread(&nleft, sizeof(nleft), 1, fp);
2000-10-07 20:39:34 +04:00
}
if (nleft == 0)
fclose(fp);
2000-10-07 20:39:34 +04:00
} else if (binno == maxb + 1) { /* skip a bin */
fseek(fp, nleft, SEEK_CUR);
fread(&nleft, sizeof(nleft), 1, fp);
2000-10-07 20:39:34 +04:00
flag = cnt;
}
}
}
if ((u_char *) pos > end - sizeof(TRECHEADER))
return (BUFFEND);
hp = (u_char *) pos;
for (i = sizeof(TRECHEADER); i ; --i)
*hp++ = (u_char) getc(fp);
2000-10-07 20:39:34 +04:00
if (end - pos->data < pos->length) {
for (i = sizeof(TRECHEADER); i ; i--)
ungetc(*--hp, fp);
2000-10-07 20:39:34 +04:00
return (BUFFEND);
}
fread(pos->data, pos->length, 1, fp);
2000-10-07 20:39:34 +04:00
nleft -= pos->length + sizeof(TRECHEADER);
if (nleft == 0 && binno == fstack[infl0.top].maxb)
fclose(fp);
2000-10-07 20:39:34 +04:00
return (0);
}
/*
* this is called when there is no special key. It's only called
* in the first fsort pass.
*/
int
makeline(flno, filelist, nfiles, buffer, bufend, dummy2)
int flno, nfiles;
union f_handle filelist;
struct recheader *buffer;
u_char *bufend;
struct field *dummy2;
{
static size_t olen;
char *pos;
2000-10-07 20:39:34 +04:00
static int fileno = 0, overflow = 0;
static FILE *fp = 0;
2000-10-16 00:46:33 +04:00
int c;
2000-10-07 20:39:34 +04:00
pos = (char *) buffer->data;
if (overflow) {
pos += olen;
2000-10-07 20:39:34 +04:00
overflow = 0;
}
for (;;) {
if (flno >= 0) {
if (!(fp = fstack[flno].fp))
2000-10-07 20:39:34 +04:00
return (EOF);
} else if (!fp) {
2000-10-07 20:39:34 +04:00
if (fileno >= nfiles) return(EOF);
if (!(fp = fopen(filelist.names[fileno], "r")))
2000-10-07 20:39:34 +04:00
err(2, "%s", filelist.names[fileno]);
++fileno;
}
while ((pos < (char *)bufend) && ((c = getc(fp)) != EOF)) {
2000-10-07 20:39:34 +04:00
if ((*pos++ = c) == REC_D) {
buffer->offset = 0;
buffer->length = pos - (char *) buffer->data;
return (0);
}
}
if (pos >= (char *)bufend) {
if (buffer->data < bufend) {
2000-10-07 20:39:34 +04:00
overflow = 1;
olen = (size_t) (((char *) bufend) -
((char *) buffer->data));
2000-10-07 20:39:34 +04:00
}
return (BUFFEND);
} else if (c == EOF) {
if (buffer->data != (u_char *) pos) {
warnx("last character not record delimiter");
*pos++ = REC_D;
buffer->offset = 0;
buffer->length = pos - (char *) buffer->data;
return(0);
}
FCLOSE(fp);
fp = 0;
if(flno >= 0) fstack[flno].fp = 0;
2000-10-07 20:39:34 +04:00
} else {
warnx("makeline: line too long: ignoring '%.100s...'", buffer->data);
/* consume rest of line from input */
while((c = getc(fp)) != REC_D && c != EOF);
buffer->offset = 0;
buffer->length = 0;
return BUFFEND;
2000-10-07 20:39:34 +04:00
}
}
}
/*
* This generates keys. It's only called in the first fsort pass
*/
int
makekey(flno, filelist, nfiles, buffer, bufend, ftbl)
int flno, nfiles;
union f_handle filelist;
struct recheader *buffer;
u_char *bufend;
struct field *ftbl;
{
static int fileno = 0;
static FILE *dbdesc = 0;
static DBT dbkey[1], line[1];
static int overflow = 0;
int c;
if (overflow) {
overflow =
enterkey(buffer, line, bufend - (u_char *) buffer, ftbl);
if (overflow)
return (BUFFEND);
else
return (0);
2000-10-07 20:39:34 +04:00
}
for (;;) {
if (flno >= 0) {
if (!(dbdesc = fstack[flno].fp))
2000-10-07 20:39:34 +04:00
return(EOF);
} else if (!dbdesc) {
if (fileno >= nfiles)
return (EOF);
dbdesc = fopen(filelist.names[fileno], "r");
if (!dbdesc)
err(2, "%s", filelist.names[fileno]);
++fileno;
}
if (!(c = seq(dbdesc, line, dbkey))) {
if ((signed)line->size > bufend - buffer->data) {
2000-10-07 20:39:34 +04:00
overflow = 1;
} else {
2000-10-07 20:39:34 +04:00
overflow = enterkey(buffer, line,
bufend - (u_char *) buffer, ftbl);
}
2000-10-07 20:39:34 +04:00
if (overflow)
return (BUFFEND);
else
return (0);
}
if (c == EOF) {
FCLOSE(dbdesc);
dbdesc = 0;
if (flno >= 0) fstack[flno].fp = 0;
2000-10-07 20:39:34 +04:00
} else {
((char *) line->data)[60] = '\000';
warnx("makekey: line too long: ignoring %.100s...",
2000-10-07 20:39:34 +04:00
(char *)line->data);
}
}
}
/*
* get a key/line pair from fp
2000-10-07 20:39:34 +04:00
*/
static int
seq(fp, line, key)
FILE *fp;
2000-10-07 20:39:34 +04:00
DBT *key, *line;
{
static char *buf, flag = 1;
2000-10-16 00:46:33 +04:00
char *end, *pos;
int c;
2000-10-07 20:39:34 +04:00
if (flag) {
flag = 0;
buf = (char *) linebuf;
end = buf + linebuf_size;
2000-10-07 20:39:34 +04:00
line->data = buf;
}
pos = buf;
while ((c = getc(fp)) != EOF) {
2000-10-07 20:39:34 +04:00
if ((*pos++ = c) == REC_D) {
line->size = pos - buf;
return (0);
}
if (pos == end) {
linebuf_size *= 2;
linebuf = realloc(linebuf, linebuf_size);
if (!linebuf)
err(2, "realloc for linebuf to %lu bytes failed", (unsigned long) linebuf_size);
end = linebuf + linebuf_size;
pos = linebuf + (pos - buf);
line->data = buf = (char *)linebuf;
continue;
#if 0
line->size = DEFLLEN;
2000-10-07 20:39:34 +04:00
*--pos = REC_D;
while ((c = getc(fp)) != EOF) {
2000-10-07 20:39:34 +04:00
if (c == REC_D)
return (BUFFEND);
}
break;
#endif
2000-10-07 20:39:34 +04:00
}
}
if (pos != buf) {
warnx("last character not record delimiter");
*pos++ = REC_D;
line->size = pos - buf;
return (0);
} else
return (EOF);
}
/*
* write a key/line pair to a temporary file
*/
void
putrec(rec, fp)
const struct recheader *rec;
2000-10-16 00:46:33 +04:00
FILE *fp;
2000-10-07 20:39:34 +04:00
{
EWRITE(rec, 1, rec->length + sizeof(TRECHEADER), fp);
2000-10-07 20:39:34 +04:00
}
/*
* write a line to output
*/
void
putline(rec, fp)
const struct recheader *rec;
2000-10-16 00:46:33 +04:00
FILE *fp;
2000-10-07 20:39:34 +04:00
{
EWRITE(rec->data+rec->offset, 1, rec->length - rec->offset, fp);
2000-10-07 20:39:34 +04:00
}
/*
* get a record from a temporary file. (Used by merge sort.)
*/
int
geteasy(flno, filelist, nfiles, rec, end, dummy2)
int flno, nfiles;
union f_handle filelist;
2000-10-16 00:46:33 +04:00
struct recheader *rec;
u_char *end;
2000-10-07 20:39:34 +04:00
struct field *dummy2;
{
int i;
FILE *fp;
fp = fstack[flno].fp;
2000-10-07 20:39:34 +04:00
if ((u_char *) rec > end - sizeof(TRECHEADER))
return (BUFFEND);
if (!fread(rec, 1, sizeof(TRECHEADER), fp)) {
fclose(fp);
fstack[flno].fp = 0;
2000-10-07 20:39:34 +04:00
return (EOF);
}
if (end - rec->data < rec->length) {
for (i = sizeof(TRECHEADER) - 1; i >= 0; i--)
ungetc(*((char *) rec + i), fp);
2000-10-07 20:39:34 +04:00
return (BUFFEND);
}
fread(rec->data, rec->length, 1, fp);
2000-10-07 20:39:34 +04:00
return (0);
}