guy d77c676749 Patch level : 10.0
Files correlati     : ve1 ba8
Ricompilazione Demo : [ ]
Commento            :
Corretto ordinamento date nelle espressioni BY delle query.
Portato limite di lunghezza dei nomi dei file temporanei da 42 a 260 caratteri.


git-svn-id: svn://10.65.10.50/trunk@19764 c028cbd2-c16b-5b4b-a496-9718f37d4682
2009-12-14 14:09:35 +00:00

670 lines
17 KiB
C
Executable File

#include "xvt.h"
#include <cfiles.h>
#include <csort.h>
#include <stdio.h>
#define MOSTMEM 51200
#define LEASTMEM 10240
/*----------------------- STATIC PER PRIMA PARTE ----------------------------*/
static struct s_prm datisort;
static int nsortfield;
/*----------------------- STATIC PER SECONDA PARTE --------------------------*/
static struct s_prm *sp;
/* @(!) 2.3.00.112 */
static unsigned long totrcd;
static unsigned no_seq;
static unsigned no_seq1;
/* @(:) 2.3.00.112 */
static unsigned bspace;
/* @(!) 2.3.00.112 */
static unsigned nrcds;
static unsigned nrcds1;
/* @(:) 2.3.00.112 */
static char *bf, *bf1;
/* @(!) 2.3.00.112 */
static unsigned inbf;
/* @(:) 2.3.00.112 */
static char **sptr;
static char *init_sptr;
/* @(!) 2.3.00.112 */
static unsigned rcds_seq;
/* @(:) 2.3.00.112 */
static FILE *fp1, *fp2;
static char fdname [_MAX_PATH];
static char f2name [_MAX_PATH];
//static int sortcomp(char **, char **);
static int sortcomp(const void*, const void*);
static char *appr_mem(unsigned *);
/* @(!) 2.3.00.112 */
static FILE *wopen(char *, int);
/* @(:) 2.3.00.112 */
static void dumpbuff(void);
static void merge(void);
static void prep_merge(void);
/* @(!) 2.3.01.245 */
void dummy(void);
/* @(:) 2.3.01.245 */
/*----------------------- PRIMA PARTE ---------------------------------------*/
/*
@(#) init_sort SORT
@(ID)
Inizializza le variabili globali per il sort.
@(FD)
*/
/* struttura di descrizione del sort */
int init_sort(struct s_prm *prms)
{
sp = prms;
if ((bf = appr_mem(&bspace)) != NULL) {
nrcds1 = nrcds = bspace / (sp->rc_len + sizeof(char *));
init_sptr = bf;
sptr = (char **) bf;
bf += nrcds * sizeof(char *);
fp1 = fp2 = NULL;
totrcd = no_seq = inbf = 0;
return 0;
}
else
return -1;
}
/*
@(#) sort SORT
@(ID)
Funzione per l'input dei record da ordinare.
@(FD)
@(IN)
La chiamata sort(char *) NULL) chiude la fase di input dei record.
@(FN)
*/
void sort(const char* s_rcd) /* buffer contenente il record da ordinare */
{
/* @(!) 2.3.00.112 */
if (inbf == nrcds) { /* if the sort buffer is full */
/* @(:) 2.3.00.112 */
qsort(init_sptr, inbf, sizeof (char *), sortcomp);
if (s_rcd) { /* if there are more records to sort */
dumpbuff(); /* dump the buffer to a sort work file*/
no_seq++; /* count the sorted sequences */
}
}
if (s_rcd !=NULL) {
/* --- this is a record to sort --- */
totrcd++;
/* --- put the rcd addr in the pointer array --- */
*sptr = bf + inbf * sp->rc_len;
inbf++;
/* --- move the rcd to the buffer --- */
memcpy(*sptr, s_rcd, sp->rc_len);
sptr++; /* point to next array entry*/
}
else { /* null pointer means no more rcds */
if (inbf) { /* any records in the buffer? */
qsort(init_sptr, inbf, sizeof (char *), sortcomp);
if (no_seq) /* if this isn't the only sequence*/
dumpbuff(); /* dump the buffer to a work file */
no_seq++; /* count the sequence */
}
no_seq1 = no_seq;
if (no_seq > 1) /* if there is more than 1 sequence */
prep_merge(); /* prepare for the merge */
}
}
/*
@($) prep_merge SORT
@(ID)
Funzione per la preparazione del Merge.
@(FD)
@(ISV)
i = contatore.
rr = puntatore ad una struttura di sequenza (di lavoro).
n_bfsz = ampiezza in byte del merge buffer.
@(FSV)
*/
static void prep_merge()
{
unsigned i;
struct bp *rr;
unsigned n_bfsz;
memset(init_sptr, '\0', bspace);
/* -------- merge buffer size ------ */
n_bfsz = bspace - no_seq * sizeof(struct bp);
/* ------ # rcds/seq in merge buffer ------- */
rcds_seq = n_bfsz / no_seq / sp->rc_len;
if (rcds_seq < 2) {
/* ---- more sequence blocks than will fit in buffer,
merge down ---- */
while (rcds_seq < 2) {
FILE *hd;
/* @(!) 2.3.00.112 */
char wname[_MAX_PATH]; /* sort work name */
fp2 = wopen(f2name, sizeof(wname)); /* open a sort work file */
/* @(:) 2.3.00.112 */
merge(); /* binary merge */
hd = fp1; /* swap fds */
fp1 = fp2;
fp2 = hd;
/* @(!) 2.3.00.112 */
strcpy(wname, fdname);
strcpy(fdname, f2name);
strcpy(f2name, wname);
fclose(fp2);
xvt_fsys_remove_file(f2name);
fp2 = NULL;
/* @(:) 2.3.00.112 */
nrcds *= 2;
/* ------ adjust number of sequence ------ */
no_seq = (no_seq + 1) / 2;
n_bfsz = bspace - no_seq * sizeof(struct bp);
rcds_seq = n_bfsz / no_seq / sp->rc_len;
}
}
bf1 = init_sptr;
rr = (struct bp *) init_sptr;
bf1 += no_seq * sizeof(struct bp);
bf = bf1;
/* fill the merge buffer with records from all sequences */
for (i = 0; i < no_seq; i++) {
fseek(fp1, (long) i * ((long) nrcds * sp->rc_len), 0);
/* ------ read them all at once ------ */
/* @(!) 2.3.00.112 modificata fread(bf1, rcds_seq * sp->rc_len, 1, fp1); */
fread(bf1, sp->rc_len, rcds_seq, fp1);
/* @(:) 2.3.00.112 */
rr->rc = bf1;
/* --- the last seq has fewer rcds than the rest --- */
if (i == no_seq-1) {
unsigned nrcd_last = (unsigned) totrcd % nrcds;
if (nrcd_last == 0)
nrcd_last = nrcds;
if (nrcd_last > rcds_seq) {
rr->rbuf = rcds_seq;
/* @(!) 2.3.00.112 */
rr->rdsk = nrcd_last - rcds_seq;
/* @(:) 2.3.00.112 */
}
else {
/* @(!) 2.3.00.112 */
rr->rbuf = nrcd_last;
/* @(:) 2.3.00.112 */
rr->rdsk = 0;
}
}
else {
rr->rbuf = rcds_seq;
rr->rdsk = nrcds - rcds_seq;
}
rr++;
bf1 += rcds_seq * sp->rc_len;
}
}
/* @(!) 2.3.01.245 */
/* Funzione che non fa assolutamente nulla, ma e' estremamente
utile all'interno di sort_op, quando si supera una certa mole di
dati immessi nel buffer di sort; e' necessaria solo per la
compilazione di eseguibili per 386. Questa funzione inserita tra
le righe rtn= k+..... e memcpy(..) evita il fastidioso memory
fault che si ottiene utilizzando strutture molto ampie o molto
numerose. Probabilmente evita, in fase di compilazione, che vengano
creati indirizzi strani, oppure in fase di esecuzione, che vengano
reperite zone di memoria che non c'entrano per nulla.
*/
void dummy()
{
}
/* @(:) 2.3.01.245 */
/*
@($) merge SORT
@(ID)
Effettua un merge.
E' un merge binario di records dalla sequenza fp1 in fp2.
@(FD
@(ISV)
i = contatore.
needy,needx = se true necessita un record da (x/y).
xcnt,ycnt = numero di records lasciati in ogni sequenza.
x,y = contatori per le sequenze.
adx,ady = indirizzi sul disco delle sequenze di record.
ysptr = stringa di lavoro.
@(FSV)
*/
static void merge()
{
unsigned i;
int needy, needx; /* true = need a rcd from (x/y) */
/* @(!) 2.3.00.112 */
unsigned xcnt, ycnt; /* # rcds left each sequence */
/* @(:) 2.3.00.112 */
unsigned x, y; /* sequence counters */
long adx, ady; /* sequence record disk addresses */
/* @(!) 2.3.00.112 */
char *ysptr = init_sptr + sp->rc_len;
/* Calcolo dei records residui nell'ultima sequenza */
/* nel caso in cui sia piena */
unsigned nrcd_last = (unsigned) totrcd % nrcds;
if (nrcd_last == 0)
nrcd_last = nrcds;
/* @(:) 2.3.00.112 */
/* --- the two sets of sequences are x and y ----- */
fseek (fp2, 0L, 0);
for (i = 0; i < no_seq; i += 2) {
x = y = i;
y++;
ycnt =
(y == no_seq) ? 0 : (y == no_seq - 1 ?
/* @(!) 2.3.00.112 */
nrcd_last : nrcds);
xcnt = y == no_seq ? nrcd_last : nrcds;
/* @(:) 2.3.00.112 */
adx = (long) x * (long) nrcds * sp->rc_len;
ady = adx + (long) nrcds * sp ->rc_len;
needy = needx = 1;
while (xcnt || ycnt) {
if (needx && xcnt) { /* need a rcd from x? */
fseek(fp1, adx, 0);
adx += (long) sp->rc_len;
fread(init_sptr, sp->rc_len, 1, fp1);
needx = 0;
}
if (needy && ycnt) { /* need a rcd from y? */
fseek(fp1, ady, 0);
ady += sp->rc_len;
/* @(!) 2.3.00.112 modificata fread(init_sptr+sp->rc_len, sp->rc_len, 1, fp1); */
fread(ysptr, sp->rc_len, 1, fp1);
/* @(:) 2.3.00.112 */
needy = 0;
}
if (xcnt || ycnt) { /* if anything is left */
/* ---- compare the two sequences --- */
/* @(!) 2.3.00.112 modificata if (!ycnt || (xcnt && (sortcomp(&init_sptr, &init_sptr + sp->rc_len)) < 0)) { */
if (!ycnt || (xcnt && (sortcomp(&init_sptr, &ysptr)) < 0)) {
/* @(:) 2.3.00.112 */
/* ----- record from x is lower ---- */
fwrite(init_sptr, sp->rc_len, 1, fp2);
--xcnt;
needx = 1;
}
else if (ycnt) { /* record from y is lower */
/* @(!) 2.3.00.112 */
fwrite(ysptr, sp->rc_len, 1, fp2);
/* @(:) 2.3.00.112 */
--ycnt;
needy = 1;
}
}
}
}
}
/*
@($) dumpbuff SORT
@(ID)
Copia il buffer di sort nel file di lavoro.
@(FD)
@(ISV)
i = contatore.
@(FSV)
*/
static void dumpbuff()
{
/* @(!) 2.3.00.112 */
unsigned i;
/* @(:) 2.3.00.112 */
if (fp1 == NULL)
/* @(!) 2.3.00.112 */
fp1 = wopen(fdname, sizeof(fdname));
/* @(:) 2.3.00.112 */
sptr = (char **) init_sptr;
for (i = 0; i < inbf; i++) {
fwrite(*(sptr + i), sp->rc_len, 1, fp1);
/* @(!) 2.3.00.112 */
*(sptr + i) = 0;
/* @(:) 2.3.00.112 */
}
inbf = 0;
}
/*
@($) wopen SORT
@(ID)
Apre un file di lavoro temporaneo (per il sort).
@(FD)
@(ISV)
fp = puntatore al file temporaneo.
s = stringa di formato.
n = numero del file.
@(FSV)
*/
static FILE *wopen(char* name, int size) /* nome del file temporaneo */
{
FILE* fp = NULL;
char* tmp = _tempnam(".", "srt");
if (tmp != NULL)
{
strncpy(name, tmp, size);
free(tmp);
}
else
tmpnam_s(name, size);
fp = fopen(name, "wb+");
if (fp == NULL)
xvt_dm_post_fatal_exit("Can't open SORT file");
return fp;
}
/*
@(#) sort_op SORT
@(ID)
Ritorna il puntatore al primo record non ancora elaborato nella sequenza ordinata.
@(FD)
@(ISV)
j = e' true se una qualche sequenza contiene ancora dei records.
i = contatore.
k,nrd,l = variabili di lavoro.
rr = variabile di lavoro.
r1 = variabile di lavoro.
rtn = indirizzo del buffer da ritornare.
ad,tr = variabili di lavoro.
@(FSV)
@(FN)
Se la funzione sort_op ritorna NULL non ci sono piu' records nella sequenza ordinata.
@(FN)
*/
char *sort_op()
{
int j = 0;
/* @(!) 2.3.00.112 */
unsigned i, k, nrd, l;
/* @(:) 2.3.00.112 */
struct bp *rr;
/* @(!) 2.3.00.112 */
static unsigned r1 = 0;
/* @(:) 2.3.00.112 */
char *rtn;
long ad, tr;
if (init_sptr == NULL) return NULL;
sptr = (char **) init_sptr;
if (no_seq < 2) {
/* -- with only 1 sequence, mo merge has been done -- */
/* @(!) 2.3.00.112 */
if (r1 == (unsigned) totrcd) {
/* @(:) 2.3.00.112 */
if (init_sptr != NULL) free(init_sptr);
/* @(!) 2.3.00.112 */
init_sptr = NULL;
/* @(:) 2.3.00.112 */
fp1 = fp2 = NULL;
r1 = 0;
return NULL;
}
return *(sptr + r1++);
}
rr = (struct bp *) init_sptr;
for (i = 0; i < no_seq; i++)
/* @(!) 2.3.00.112 */
j |= (int) (rr + i)->rbuf | (rr + i)->rdsk;
/* @(:) 2.3.00.112 */
/* -- j will be true if any sequence still has records - */
if (!j)
{
fclose(fp1); /* none left */
xvt_fsys_remove_file(fdname);
/* @(!) 2.3.00.112 eliminata if (fp2) */
/* @(!) 2.3.00.112 eliminata { */
/* @(!) 2.3.00.112 eliminata fclose(fp2); */
/* @(!) 2.3.00.112 eliminata unlink(f2name); */
/* @(!) 2.3.00.112 eliminata } */
/* @(:) 2.3.00.112 */
if (init_sptr != NULL) free(init_sptr);
/* @(!) 2.3.00.112 */
init_sptr = NULL;
/* @(:) 2.3.00.112 */
fp1 = fp2 = NULL;
r1 = 0;
return NULL;
}
k = 0;
/* --- find the sequence in the merge buffer
with the lowest record --- */
/* for (i = 0; i < no_seq; i++) */
for (i = 1; i < no_seq; i++)
k = ((sortcomp( &(rr + k)->rc, &(rr + i)->rc) < 0) ? k : i);
/* --- k is an integer sequence number that offsets to the
sequence with the lowest record ---- */
(rr + k)->rbuf--; /* decrement the rcd counter */
rtn = (rr + k)->rc; /* set the return pointer */
(rr + k)->rc += sp->rc_len;
if ((rr + k)->rbuf == 0) {
/* ---- the sequence got empty ---- */
/* --- so get some more if there are any --- */
rtn = bf + k * rcds_seq * sp->rc_len;
/* @(!) 2.3.01.245 */
dummy();
/* @(:) 2.3.01.245 */
memcpy(rtn, (rr + k)->rc - sp->rc_len, sp->rc_len);
(rr + k)->rc = rtn + sp->rc_len;
if ((rr + k)->rdsk != 0) {
l = ((rcds_seq-1) < (rr+k)->rdsk) ? rcds_seq-1 : (rr+k)->rdsk;
/* @(!) 2.3.00.112 */
nrd = k == no_seq - 1 ? (unsigned) (totrcd % nrcds) : nrcds;
if (nrd == 0)
nrd = nrcds;
/* @(:) 2.3.00.112 */
tr = (long) ((k * nrcds + (nrd - (rr + k)->rdsk)));
ad = tr * sp->rc_len;
fseek(fp1, ad, 0);
/* @(!) 2.3.00.112 modificata fread(rtn + sp->rc_len, l * sp->rc_len, 1, fp1); */
fread(rtn + sp->rc_len, sp->rc_len, l, fp1);
/* @(:) 2.3.00.112 */
(rr + k)->rbuf = l;
(rr + k)->rdsk -= l;
}
else
memset((rr + k)->rc, 127, sp->rc_len);
}
return rtn;
}
/*
@(#) sort_stats SORT
@(ID)
Visualizza la statistica sul sort.
@(FD)
*/
void sort_stats()
{
char msg[256];
sprintf(msg,
"Record length = %d\n"
"%lu records sorted\n"
"%u sequences\n"
"%u bytes of sort buffer\n"
"%u records per buffer",
sp->rc_len, totrcd, no_seq, bspace, nrcds
);
xvt_dm_post_note(msg);
}
/*
@($) appr_mem SORT
@(ID)
Alloca memoria per un buffer.
@(FD)
@(ISV)
buff = buffer di memoria allocato.
@(FSV)
@(IN)
Se puo' alloca MOSTMEM altrimenti ne alloca quanto puo',
non scendendo mai sotto il minimo LEASTMEM
@(FN)
*/
static char *appr_mem(unsigned* h)
{
char *buff = NULL;
*h = (unsigned) MOSTMEM + 1024;
while (buff == NULL && *h > LEASTMEM)
{
*h -= 1024;
buff = malloc(*h);
}
return buff;
}
/*
@($) sortcomp SORT
@(ID)
Esegue i confronti per il sort ed il merge.
@(FD)
@(ISV)
i = contatore.
k = risultato della comparazione.
@(FSV)
@(IN)
Ritorna un intero < 0 se a < b
0 se a = b
> 0 se a > b
@(FN)
*/
// static int sortcomp(a,b)
// char **a; char **b; /* puntatori ai puntatori ai record da confrontare */
static int sortcomp(const void* pa, const void* pb)
{
int i, k;
const char** a = (const char**)pa;
const char** b = (const char**)pb;
if (**a == 127 || **b == 127)
return (int) **a - (int) **b;
for (i = 0; i < NOFLDS; i++)
{
if (sp->s_fld[i].f_pos == 0) break;
if (sp->s_fld[i].f_len >= 0) /* string compare */
{
if ( ( k=strncmp ( (*a)+sp->s_fld[i].f_pos-1,
(*b)+sp->s_fld[i].f_pos-1,
sp->s_fld[i].f_len
) ) != 0)
return (sp->s_fld[i].ad == 'd')?-k:k;
}
if (sp->s_fld[i].f_len == -1) /* integer compare */
{
if ( (*( (int*) (*a)+sp->s_fld[i].f_pos-1 )) !=
(*( (int*) (*b)+sp->s_fld[i].f_pos-1 )) )
{
k=(*( (int*) (*a)+sp->s_fld[i].f_pos-1 )) - (*( (int*) (*b)+sp->s_fld[i].f_pos-1 ));
return (sp->s_fld[i].ad == 'd')?-k:k;
}
}
if (sp->s_fld[i].f_len == -2) /* BOOLEAN compare */
{
if ( (*( (BOOLEAN*) (*a)+sp->s_fld[i].f_pos-1 )) !=
(*( (BOOLEAN*) (*b)+sp->s_fld[i].f_pos-1 )) )
{
k=(int) ( (*( (BOOLEAN*) (*a)+sp->s_fld[i].f_pos-1 )) - (*( (BOOLEAN*) (*b)+sp->s_fld[i].f_pos-1 )) );
return (sp->s_fld[i].ad == 'd')?-k:k;
}
}
}
return 0;
}
/*---------------------------- SECONDA PARTE --------------------------------*/
/*
@(#) initsortfield SORT
@(ID)
Definizione di sort per un record ISAM.
@(FD)
*/
void initsortfield ()
{
nsortfield = datisort.s_fld[0].f_pos = 0; /* sort su nessun campo */
}
/*---------------------------------------------------------------------------*/