1
/*===========================================================================
2
Copyright (C) 1995-2010 European Southern Observatory (ESO)
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; either version 2 of
7
the License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public
15
License along with this program; if not, write to the Free
16
Software Foundation, Inc., 675 Massachusetts Ave, Cambridge,
19
Correspondence concerning ESO-MIDAS should be addressed as follows:
20
Internet e-mail: midas@eso.org
21
Postal address: European Southern Observatory
22
Data Management Division
23
Karl-Schwarzschild-Strasse 2
24
D 85748 Garching bei Muenchen
26
===========================================================================*/
28
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
32
.AUTHOR J.D.Ponz IPG-ESO - Garching
33
.CATEGORY table interface (Design 2.0)
34
.VERSION 1.0 25-Mar-1987 Implementation JDP
35
.VERSION 1.1 20-Oct-1987 Modify calling sequence
36
.VERSION 1.2 23-Nov-1987 New SC calling sequence
37
.VERSION 1.3 11-Apr-1988 Include new routines without type conversion.
38
Character string always ending with a '\0'.
39
New SC calling sequence.
40
.VERSION 1.4 26-Sep-1988 Modify calling sequence in TCCINI to
41
include data types and array length.
42
.VERSION 3.0 01-Jul-1990 New Version with Arrays / Elementary IO
43
Added TCCSEL routine (selection of Columns)
44
.VERSION 3.1 26-Sep-1990 Removed bug in TCCSRT
45
.VERSION 3.2 06-Dec-1990 Force New Version as soon as something modified.
46
.VERSION 3.3 18-Dec-1990 FO: Take into account the number of selected rows.
47
.VERSION 3.4 23-Feb-1991 Sort always writes NULL values at the end.
48
.VERSION 3.5 29-Apr-1991: TCCINI must work whatever the table size is ...
49
.VERSION 3.6 10-Jun-1991: Added TCCPAM (Partial Column Mapping)
50
.VERSION 3.7 22-Sep-1992: treats in a proper way NULL values (i.e convex)
57
This module contains the routines to handle columns in a table.
58
Access to the table is done through the table identifier,
59
returned by the routines TCTOPN and TCTINI.
60
Access to a column is done through the column number, given
61
by the routines TCCINI, TCCSER and TCLSER.
63
The following main functions are defined in this module:
64
create a column in the table (TCCINI),
65
delete a column from the table (TCCDEL),
66
map a column (TCCMAP),
67
unmap a column (TCCUNM),
68
table sorting according to column values (TCCSRT),
69
search the column number (TCCSER).
71
Main arguments used by the routines are:
73
Integer number to define the number of items in a multiple
75
In the case of character strings 'alen' defines the maximum
77
[colref] reference to the column by label or by number.
78
It is a character string containing the ':label'
79
if the column is referenced by label, or '\#n' if the
80
column is referenced by its sequential number.
81
[column] sequential column number. It is an integer number
82
provided by the system when a new column is created or
84
[dtype] column data type.
85
The system file 'midas\_def.h' in 'MID\_INCLUDE:' provides the
86
symbols D\_xx\_FORMAT where 'xx' is 'I4' for integer data,
87
'R4' for float, 'R8' for double precision and
90
Display format associated to the column.
91
The format is defined like in standard FORTRAN.
92
[label] column label. Character string (up to 16 characters)
93
provided by the use when the column is created.
94
Valid characters are letters, digits and the underscore
96
In the current version labels are NOT case independent.
97
[tid] table identifier. It is an integer number provided
98
by the system when the table is created or opened.
99
[unit] column unit. Character string (up to 16 characters)
100
to define the units of the column.
102
------------------------------------------------------------*/
104
#include <midas_def.h> /* ANSI-C Prototyping */
105
#include <computer.h>
106
#include <tblsys.h> /* Table System parameters */
107
#include <tbldef.h> /* Symbols used for Tables */
108
#include <tblerr.h> /* List of Table Errors */
110
#include <atype.h> /* Character classification */
111
#include <macrogen.h> /* Classical macros */
113
#include <stdlib.h> /* Classical macros */
117
static int dunit; /* Not yet used */
120
#define SELW sizeof(int) /* Length of Selection Column */
122
char *osmmget(), *osmmexp();
128
/*===================================================================
130
*===================================================================*/
132
static int strloc(char *str, char c)
134
static int strloc(str, c)
136
.PURPOSE Locate the first occurence of character `c'
137
.RETURNS Index of `c' in str; length of str if `c' not found.
139
char *str; /* IN: string to scan */
140
char c; /* IN: char to locate */
155
static int find_space (TABLE *tp, int align, int bytes)
157
static int find_space (tp, align, bytes)
160
.PURPOSE Find an offset where a new column can be added
161
.RETURNS Where it can be added.
162
.METHOD A template record is filled with x for used parts, zeroes
163
for empty parts. It is then scanned for a suitable position.
166
TABLE *tp; /* IN: Table Concerned */
167
int align; /* IN: Alignment requirement */
168
int bytes; /* IN: Bytes required */
177
static int alloc_size=0;
181
totbytes = tp->reclen;
182
if (alloc_size < totbytes)
184
if (alloc_size > 0) free(record);
185
alloc_size = totbytes;
186
ptr = record = (char *) malloc((size_t) alloc_size);
187
for (ir=0; ir<4; ir++) *ptr++ = 'x'; /* The Selection Column */
190
memset ((void *) (record+4),0,(size_t) (totbytes-4));
192
for (ir=0; ir<tp->cols; ir++)
193
memset((void *)(record + tp->offset[ir]),'x',(size_t)tp->bytes[ir]);
197
for (ir=4; ir<totbytes; ir++) /* 1st 4 bytes always set... */
199
if (record[ir]) continue;
202
if (lim > totbytes) lim = totbytes;
204
for (jr=ir; (jr<lim) && (record[jr]==0); jr++) ;
205
if (jr == lim) break;
212
for (ir=4; ir<totbytes; ir++)
214
if (record[ir]) continue;
215
if (ir%align) continue;
218
if (lim > totbytes) lim = totbytes;
220
for (jr=ir; (jr<lim) && (record[jr]==0); jr++) ;
221
if (jr == lim) break;
233
/*===================================================================
235
*===================================================================*/
237
int TCCDEL(tid, column, ncol)
238
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
239
.PURPOSE Delete column in a table
241
.REMARKS This implementation FORCES the table version to TBL_VERSION.
242
.METHOD Just modify Descriptors.
243
-------------------------------------------------------------*/
244
int tid; /* IN: table id number */
245
int column; /* IN: column number */
246
int *ncol; /* OUT:actual number of columns */
251
int status, i, i1, lenl, lenf, got;
253
char buf[TBL_DESLAB+1];
256
/* checks arguments */
260
if ((status = CheckTable(tp)))
261
return(TBL_errs(tid, status,0));
263
if ((status = CheckTrueColumn(tp, column)))
264
return(TBL_errs(tid, status, column));
267
/* Force New Version */
269
if (tp->version == 0) tp->version = TBL_VERSION;
272
/* Modifs in Memory */
278
for (i=column; i<tp->cols; i++)
280
tp->dtypes[i1] = tp->dtypes[i];
281
tp->bytes[i1] = tp->bytes[i];
282
tp->offset[i1] = tp->offset[i];
283
tp->abytes[i1] = tp->abytes[i];
284
oscopy (tp->label+(i1*lenl),tp->label+(i*lenl),lenl);
285
oscopy (tp->format+(i1*lenf),tp->format+(i*lenf),lenf);
289
/* Modify sorting & ref column */
291
if (tp->scol == column)
293
else if (tp->scol > column)
296
if (tp->kcol == column)
298
else if (tp->kcol > column)
301
*ncol = tp->cols - 1;
303
if (tp->tflags & TBL__READONLY)
309
/* Update Descriptors */
312
for (i=column; i<tp->cols; i++)
314
if ((status = SCDGETC(tp->imno,TBL_Dlab(i+1),1,TBL_DESLAB,&got,buf)))
316
if ((status = SCDWRC(tp->imno,TBL_Dlab(i),1,buf,1,got,&dunit)))
320
/* finally delete last descriptor, and update table information */
322
if ((status = SCDDEL(tp->imno,TBL_Dlab(tp->cols)))) goto error;
324
tp->dtypes[--tp->cols] = 0;
325
tp->offset[tp->cols] = 0;
327
if ((status = SCDWRI(tp->imno,TBL_Ddtypes,tp->dtypes,1,tp->colitems,&dunit)))
329
if ((status = SCDWRI(tp->imno,TBL_Doffset,tp->offset,1,tp->colitems,&dunit)))
331
if ((status = SCDWRI(tp->imno,TBL_Dmain, &tp->acols,1,TBL_Dmain_SIZE,&dunit)))
337
error: /* error in SC routines */
338
TBL_errs(tid, status, 0);
345
int TCCINI(tid, dtype, alen, form, unit, label, column)
346
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
347
.PURPOSE Initializes table column. Elements in the column are
348
initialized as undefined (null values).
349
.METHOD Check if column has been already defined,
350
otherwise add the new column descriptors.
352
The routine provides an overflow mechanism when the
353
new column exceeds the allocated space.
355
------------------------------------------------------------------*/
356
int tid; /* IN: table id number */
357
int dtype; /* IN: column data type (Midas) */
358
int alen; /* IN: no. of array items */
359
char *form; /* IN: column form */
360
char *unit; /* IN: column unit */
361
char *label; /* IN: column label */
362
int *column; /* OUT:column number */
367
int status, align, where;
368
int ttype, nbytes, new_cols, i, j ,maxrows, mapped_rows, incr;
370
char buf[TBL_DESLAB+1];
373
char check[TBL_LABLEN+4]; /* LABLEN .ge. UNILEN, FORLEN */
378
if ((status = CheckTable(tp)) )
379
return(TBL_errs(tid, status, 0));
381
if (tp->version == 0)
382
tp->version = TBL_VERSION; /* Force New Version */
385
/* check if column overflow */
387
if (tp->cols >= tp->colitems)
390
tp->colitems = tp->cols + 4;
392
tp->dtypes = (int *)osmmexp((char *)tp->dtypes,2*sizeof(int)*tp->colitems);
393
tp->offset = tp->dtypes + tp->colitems;
394
oscopy ((char *)tp->offset, (char *)(tp->dtypes + i), i*sizeof(int));
396
tp->bytes = (int *)osmmexp((char *)tp->bytes,2*sizeof(int)*tp->colitems);
397
tp->abytes = tp->bytes + tp->colitems;
398
oscopy ((char *)tp->abytes,(char *)(tp->bytes + i),i*sizeof(int));
399
for (j=i; j<tp->colitems; j++)
401
tp->dtypes[j] = tp->offset[j] = tp->bytes[j] = tp->abytes[j] = 0;
403
tp->label = osmmexp(tp->label,(2+TBL_LABLEN+TBL_FORLEN)*tp->colitems);
404
tp->format = tp->label + tp->colitems*(1+TBL_LABLEN);
405
oscopy (tp->format, tp->label + i*(1+TBL_LABLEN), i*(1+TBL_FORLEN));
408
/* check type of column */
409
if ((status = TBL_TYPCHK(dtype,alen,&ttype)))
411
/* check column label */
412
j = (int) strlen(label);
414
if (*label != ':') i --; /* without ':' => 1 char. less */
417
{ /* truncate if necessary */
418
(void) strncpy(check,label,i);
421
(void) SCTPUT("(I/W) - column label truncated..");
427
if ((status = TBL_LABCHK(chptr,p)))
431
j = (int) strlen(unit);
433
{ /* truncate if necessary */
434
(void) strncpy(check,unit,TBL_UNILEN);
435
check[TBL_UNILEN] = '\0';
437
(void) SCTPUT("(I/W) - column unit truncated..");
443
if ((status = TBL_UNICHK(unit,p)))
448
if ((status = TBL_FMTCHK(form, ttype, p)))
452
/* Adjust parameters */
454
nbytes = TBL_ElementSize(ttype);
455
/**** NEW: Align Offset */
456
align = (tp->swise == F_RECORD ? nbytes : 1);
457
nbytes *= TBL_Items(ttype);
458
where = find_space(tp,align,nbytes);
460
*column = tp->cols + 1;
461
/* allocate column(s) if overflow */
462
new_cols = (where + nbytes + 3)/4 - 1;
463
if (new_cols > tp->acols)
465
if ((status = TBL_ALLOCOL(tid, new_cols))) return(status);
469
/* force NULL terminated string, write descriptor */
471
buf[TBL_DESLAB] = '\0';
472
if ((status = SCDWRC(tp->imno,TBL_Dlab(*column),1,buf,1,TBL_DESLAB,&dunit)))
473
return (TBL_errf(status, "table %s", tp->phname));
475
/* Update Header Info */
478
tp->dtypes[i] = ttype;
479
tp->bytes[i] = nbytes;
480
tp->offset[i] = where;
481
tp->abytes[i] = -1; /* uninitialized...*/
482
tp->label [i*(1+TBL_LABLEN)] = '\0';
483
tp->format[i*(1+TBL_FORLEN)] = '\0';
488
/* Initialize to NULL values */
490
incr = TBL_offset (tp, 2, *column) - TBL_offset (tp, 1, *column);
491
maxrows = TBL_EIO_LIMIT / incr;
492
maxrows = MAX (maxrows, 1);
494
for (i=0; i<tp->arows; i+=maxrows)
496
mapped_rows = MIN ((tp->arows - i), maxrows);
497
if_not (x = TBL_RDF (tp, TBL_offset(tp, i+1, *column),incr*mapped_rows, 1))
499
TBL_toNULL (ttype, x); /* NULL first element */
500
for (p = x + incr; --mapped_rows > 0; p += incr)
501
oscopy(p ,x, nbytes);
510
int TCCMAP(tid, col, address)
511
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
513
Return the address of the column in the table.
515
Finds the position of the physical column and get address
516
via the virtual memory mechanism.
518
Note: This routine only works on tables stored by columns
519
(transposed format, parameter F_TRANS in TCTINI).
522
------------------------------------------------------------------*/
523
int tid; /* IN: table id number */
524
int col; /* IN: column number */
525
char **address; /* OUT:column address */
532
if ((status = CheckTable(tp))) return(TBL_errs(tid, status, 0));
533
if ((status = CheckColumn(tp, col))) return(TBL_errs(tid, status, col));
535
if (tp->swise != F_TRANS)
536
return (TBL_errf(ERR_TBLMAP, "Can't MAP column on RECORD table: %s",
539
ic = TBL_offset(tp, 1, col);
540
len = TBL_offset(tp, tp->arows, col) -ic + ColumnWidth(tp, col);
541
if_not(*address = TBL_RDF (tp, ic, len, TBL__MAPPED))
543
if (col == 0) tp->selected = -1; /* Unknown */
549
int TCCPAM(tid, col, starting_row, asked_rows, mapped_rows, address)
550
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
551
.PURPOSE Map a part of a table, namely up to asked_row from row # starting_row
552
.REMARKS A value of zero for asked_rows provide some default.
554
------------------------------------------------------------------*/
555
int tid; /* IN: table id number */
556
int col; /* IN: column number */
557
int starting_row; /* IN: First row to map (from 1)*/
558
int asked_rows; /* IN: Number of rows to map,
559
0 to map as many rows as possible */
560
int *mapped_rows; /* OUT: Number of rows mapped */
561
char **address; /* OUT: address of mapped first row */
566
static unsigned char bit_mask[8] = { 0x80, 0x40, 0x20, 0x10,
567
0x08, 0x04, 0x02, 0x01};
571
*mapped_rows = 0; /* Default return */
572
if ((status = CheckTable(tp))) return(TBL_errs(tid, status, 0));
574
if (tp->swise != F_TRANS)
575
return (TBL_errf(ERR_TBLMAP, "Can't MAP column on RECORD table: %s",
578
if ((status = CheckColumn(tp, col))) return(TBL_errs(tid, status, col));
579
if ((status = CheckRow(tp, starting_row)))
580
return(TBL_errs(tid, status, starting_row));
582
if (asked_rows <= 0) { /* Compute Default number of Rows */
583
len = ColumnWidth(tp, col);
584
asked_rows = TBL_EIO_LIMIT/len/2;
585
if (asked_rows < 1) asked_rows = 1;
588
/* Check the number of rows */
589
if ((starting_row + asked_rows) > tp->arows)
590
asked_rows = 1 + tp->arows - starting_row;
592
if (col == 0 && tp->usname != '\0') {
593
*address = osmmget(asked_rows * sizeof(int));
594
for (i=starting_row; i < starting_row+asked_rows; i++) {
595
ic = (tp->vsel[i>>3] & bit_mask[i&7]);
596
*(int *) (*address + (i-starting_row) *sizeof(int)) = (ic != 0);
599
else { /* Do now the mapping */
600
len = ColumnWidth(tp, col) * asked_rows;
601
ic = TBL_offset(tp, starting_row, col);
602
if_not(*address = TBL_RDF (tp, ic, len, TBL__MAPPED))
606
/* Write output parameters */
607
*mapped_rows = asked_rows;
608
if (col == 0) tp->selected = -1; /* Unknown */
613
int TCCSEL(tid, text, max_cols, cols, flags, found_cols)
614
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
615
.PURPOSE Searchs a set of columns column by references (their name).
616
.METHOD A set of columns has the general syntax
619
where "col" may be #number or :label.
620
The Sequence column may be designated by # or :
622
-------------------------------------------------------------*/
623
int tid; /* IN : table id */
624
char *text; /* IN : textual designation */
625
int max_cols; /* IN: Size of cols & flags arrays */
626
int *cols; /* OUT: column numbers */
627
int *flags; /* OUT: column flags (in brackets) */
628
int *found_cols; /* OUT: How many columns were found */
632
int k, j, ic, ib, id;
643
status = TCIGET(tid,found_cols,&dummy,&dummy,&dummy,&dummy);
644
for (j=1; j <= *found_cols; j++) cols[j-1] = j;
648
/* Tokenize from commas, then from brackets */
649
for (j=0, p=text; (*p) && (j < max_cols) && (status == ERR_NORMAL); j++)
651
ic = strloc (p, ','); c = p[ic]; p[ic] = '\0';
653
if ( p[id] && p[id+1] == '.')
660
ib = strloc (p, '('); b = p[ib]; p[ib] = '\0';
661
flags[j] = 1; /* Default Flag */
662
if ((status = TCCSER (tid, p, &cols[j]))) continue; /* Get Label*/
667
TBL_errf(status, "unknown column %s", p);
675
if (flags[j] == 0) flags[j] = (*p == '-' ? -1 : 1);
679
{ /* column interval: #m..n */
683
if ((status = TCCSER (tid, p, &temp))) continue;
687
TBL_errf(status,"unknown column %s",p);
690
temp = temp-cols[j]; /* no. of cols in interval */
691
mm = max_cols - j - 1; /* no. of cols still available */
693
printf("temp = %d, cols[%d] = %d, mm = %d\n",temp,j,cols[j],mm);
695
if (temp > mm) temp = mm;
696
for (k=1; k<= temp; k++) *(cols+j+k) = *(cols+j)+k;
698
j = j + temp; /* last filled column */
706
/* Check if not too many cols */
707
if ( (j >= max_cols) && (isgraph(*p)) && (status == ERR_NORMAL) )
708
TBL_errf (-1, "list truncated to %d items: %s", max_cols, text);
717
int TCCSER(tid, colref, column)
718
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
719
.PURPOSE Searchs column by reference (its name).
720
The column may be designated as #number or :name or name
721
The Sequence column may be designated by # or :
722
.METHOD Sequential search for the column label.
723
The routine returns the column number as the last
724
argument or -1 if the column is not found.
726
-------------------------------------------------------------*/
727
int tid; /* IN : table id */
728
char *colref; /* IN : column reference */
729
int *column; /* OUT: column number */
736
char *chptr, check[TBL_LABLEN+4];
742
if ((status = CheckTable(tp)))
743
return(TBL_errs(tid, status, 0));
751
case '#' : /* column by number */
753
for (i = 0; isdigit(p[i]); i++) ;
758
TBL_errf(status, "invalid number #'%s', table: %s", p,
764
if ((i > tp->cols) || (i < 0))
767
TBL_errs(tid, status, i);
774
case 's' : case 'S' : /* column sequence */
775
q = p + 1; /* check at least for SEQ */
776
if ((*q != 'e') && (*q != 'E')) break;
778
if ((*q == 'q') || (*q == 'Q')) *column = 0;
781
case ':' : /* column by label */
784
default : /* assume it's name */
785
if (isspace(*p) || (*p == '\0'))
786
*column = 0; /* use sequence no. */
789
i = TBL_LABLEN - 1; /* :name is checked... */
790
if ((int) strlen(p) > i)
791
{ /* truncate if necessary */
792
(void) strncpy(check,p,i);
801
status = TCLSER (tid, chptr, column); /* without : */
815
/*====================================================================
816
* Internal Routines for Sort
817
*====================================================================*/
819
/* When several sort parameters are given, the address of the other
820
parameters to test are computed from the address of the first parameter
821
Let @ be the address of line i of the first parameter,
822
@0 the address of line 1 of the first parameter
823
the address @n of the 2nd parameter of line i can be computed via
824
@n = (@-@0)*a/l0 + Cte where a = difference of widths
825
l0= width of first parameter column
827
The parameters are stored as Cte: in sort_offset
833
typedef int (*FUNCTION)(); /* Just to simplify the declarations....*/
835
static char *sort_astart; /* Origin of 1st sort parameter */
836
static int sort_width; /* Width of first column to be sorted */
837
static int sort_order; /* 1 for ascending, -1 for descending */
838
static int sort_len; /* Number of items in Table */
839
static FUNCTION diff;
840
/* Several parameters used for sorting */
841
static FUNCTION sort_list[SORT_MAX];
842
static int sort_array[SORT_MAX], sort_items[SORT_MAX];
843
static int sort_offset[SORT_MAX], sort_factor[SORT_MAX];
844
static int sort_keys = 0;
849
static int diff_m(s1, s2)
851
.PURPOSE Compute differences when several keys are used.
852
.RETURNS Negative value if s1<s2, positive value if s1>s2, null if s1=s2)
859
sort_order = sort_array[0];
860
sort_len = sort_items[0];
861
what_to_do = sort_list[0];
863
result = (*what_to_do)(s1, s2);
865
for (i = 1; (i < sort_keys) && (result == 0); i++) {
866
sort_order = sort_array[i];
867
sort_len = sort_items[i];
868
what_to_do = sort_list[i];
869
result = (*what_to_do)(
870
s1+sort_offset[i] + sort_factor[i]*(s1-sort_astart)/sort_width,
871
s2+sort_offset[i] + sort_factor[i]*(s2-sort_astart)/sort_width);
876
static int diffi1 (s1, s2)
878
.PURPOSE Compute difference between two char strings
879
.RETURNS s1-s2 (negative value if s1<s2, positive if s1>s2, null if s1=s2)
880
.REMARKS NULL values always at end
886
for (i = sort_len; --i >= 0; s1++, s2++){
887
if (*s1 == *s2) continue;
888
if (*s1 == NULL1) return(1); /* NULL value at end */
889
if (*s2 == NULL1) return(-1); /* NULL value at end */
890
if (*s1 > *s2) return (sort_order);
891
if (*s1 < *s2) return (-sort_order);
895
static int diffi2 (s1, s2)
897
.PURPOSE Compute difference between two short arrays
898
.RETURNS s1-s2 (negative value if s1<s2, positive if s1>s2, null if s1=s2)
899
.REMARKS NULL values always at end
905
for (i = sort_len; --i >= 0; s1++, s2++){
906
if (*s1 == *s2) continue;
907
if (*s1 == NULL2) return(1); /* NULL value at end */
908
if (*s2 == NULL2) return(-1); /* NULL value at end */
909
if (*s1 > *s2) return (sort_order);
910
if (*s1 < *s2) return (-sort_order);
914
static int diffi4 (s1, s2)
916
.PURPOSE Compute difference between two int arrays
917
.RETURNS s1-s2 (negative value if s1<s2, positive if s1>s2, null if s1=s2)
918
.REMARKS NULL values always at end
924
for (i = sort_len; --i >= 0; s1++, s2++){
925
if (*s1 == *s2) continue;
926
if (*s1 == NULL4) return(1); /* NULL value at end */
927
if (*s2 == NULL4) return(-1); /* NULL value at end */
928
if (*s1 > *s2) return (sort_order);
929
if (*s1 < *s2) return (-sort_order);
934
static int diffa1 (s1, s2)
936
.PURPOSE Compute difference between two unsigned chars
937
.RETURNS s1-s2 (negative value if s1<s2, positive if s1>s2, null if s1=s2)
938
.REMARKS No NULL values...
940
unsigned char *s1, *s2;
944
for (i = sort_len; --i >= 0; s1++, s2++){
945
if (*s1 > *s2) return (sort_order);
946
if (*s1 < *s2) return (-sort_order);
950
static int diffa2 (s1, s2)
952
.PURPOSE Compute difference between two unsigned shorts
953
.RETURNS s1-s2 (negative value if s1<s2, positive if s1>s2, null if s1=s2)
955
unsigned short *s1, *s2;
959
for (i = sort_len; --i >= 0; s1++, s2++){
960
if (*s1 > *s2) return (sort_order);
961
if (*s1 < *s2) return (-sort_order);
965
static int diffa4 (s1, s2)
967
.PURPOSE Compute difference between two unsigned ints
968
.RETURNS s1-s2 (negative value if s1<s2, positive if s1>s2, null if s1=s2)
970
unsigned int *s1, *s2;
974
for (i = sort_len; --i >= 0; s1++, s2++){
975
if (*s1 > *s2) return (sort_order);
976
if (*s1 < *s2) return (-sort_order);
981
static int diffr4 (s1, s2)
983
.PURPOSE Compute difference between two floats
984
.RETURNS s1-s2 (negative value if s1<s2, positive if s1>s2, null if s1=s2)
985
.REMARKS NULL values always at end
991
for (i = sort_len; --i >= 0; s1++, s2++){
992
if (*s1 == *s2) continue;
993
if (isNULLF(s1)) return(1); /* NULL value at end */
994
if (isNULLF(s2)) return(-1); /* NULL value at end */
995
if (*s1 > *s2) return (sort_order);
996
if (*s1 < *s2) return (-sort_order);
1001
static int diffr8 (s1, s2)
1003
.PURPOSE Compute difference between two doubles
1004
.RETURNS s1-s2 (negative value if s1<s2, positive if s1>s2, null if s1=s2)
1005
.REMARKS NULL values always at end
1011
for (i = sort_len; --i >= 0; s1++, s2++){
1012
if (*s1 == *s2) continue;
1013
if (isNULLD(s1)) return(1); /* NULL value at end */
1014
if (isNULLD(s2)) return(-1); /* NULL value at end */
1015
if (*s1 > *s2) return (sort_order);
1016
if (*s1 < *s2) return (-sort_order);
1021
/*===================================================================*/
1023
static void Qsort(data, first, last)
1027
Quick sort modified with insert sort for small partitions.
1028
The routine sorts the array of pointers to actual data.
1030
The comparison routine is external.
1033
char **data; /* MOD: The arrays of pointers to sort */
1034
int first, last; /* IN: Indexes of first / last pointer */
1039
i = first; j = last;
1040
px = data[(first+last)/2];
1043
while ( (i < last ) && ((*diff)(data[i], px) < 0)) i++;
1044
while ( (j > first) && ((*diff)(data[j], px) > 0)) j--;
1047
t = data[i], data[i] = data[j], data[j] = t;
1052
if (first < j) Qsort (data, first, j);
1053
if (i < last) Qsort (data, i, last );
1056
int TCCSRT(tid, nc, column, sortfl)
1057
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1058
.PURPOSE Sort table.
1059
.METHOD Use Quick sort algorithm to sort the table data
1060
in ascending (sort flag > 0) or descending
1061
(sort flag < 0) sequence.
1063
-------------------------------------------------------------*/
1064
int tid; /* IN : table id */
1065
int nc; /* IN : number of columns*/
1066
int column[]; /* IN : column numbers */
1067
int sortfl[]; /* IN : sort flags */
1072
int i, j, len, icol, ic, dtype, incr, mapped_bytes;
1076
char *x, *copy, *root[SORT_MAX];
1081
if ((status = CheckTable(tp))) return(TBL_errs(tid, status,0));
1083
if (tp->rows <= 1) return (status);
1087
/* Check the list of sort keys */
1092
TBL_errf(-1, "value %d of SORT parameters assumed to be 1, table: %s",
1093
sort_keys, tp->phname);
1097
if (sort_keys > SORT_MAX)
1099
TBL_errf(-1, "Number %d of SORT parameters truncated to %d, table: %s",
1100
sort_keys, SORT_MAX, tp->phname);
1101
sort_keys = SORT_MAX;
1105
/* check column numbers */
1107
for (i=0; i<sort_keys; i++)
1110
if (icol > tp->cols || icol <= 0)
1111
return (TBL_errs (ERR_TBLCOL, tid, icol));
1115
sort_width = ColumnWidth(tp, icol);
1118
/* All existing data will be modified */
1120
for (i=0,ic=0; i<tp->cols; i++)
1122
if (tp->offset[i] > tp->offset[ic]) ic = i;
1126
if (tp->swise == F_TRANS)
1136
for (i=0; i<sort_keys;i++)
1139
sort_offset[i] = offset;
1140
mapped_bytes = ColumnWidth(tp,icol)*tp->rows;
1141
offset = offset + mapped_bytes;
1142
if_not (root[i] = TBL_RDF (tp, TBL_offset(tp,1,icol), mapped_bytes, 2))
1146
lolo = (long int) offset;
1147
copy = osmmget(lolo);
1148
ic = TBL_offset (tp, 1, column[0]);
1149
for (i=0; i<sort_keys; i++)
1152
dtype = ColumnType (tp, icol);
1153
oscopy(copy+sort_offset[i],root[i],ColumnWidth(tp,icol)*tp->rows);
1154
sort_array[i] = sortfl[i];
1155
sort_items[i] = TBL_Items(dtype);
1156
sort_factor[i]= ColumnWidth(tp, icol) - sort_width;
1158
/* Choose the comparison function */
1159
switch (TBL_ElementType(dtype))
1161
case TBL_D_I1: diff = diffi1; break;
1162
case TBL_D_I2: diff = diffi2; break;
1163
case TBL_D_I4: diff = diffi4; break;
1164
case TBL_D_A1: diff = diffa1; break;
1165
case TBL_D_A2: diff = diffa2; break;
1166
case TBL_D_A4: diff = diffa4; break;
1167
case TBL_D_R4: diff = diffr4; break;
1168
case TBL_D_R8: diff = diffr8; break;
1169
default: diff = diffr4;
1171
sort_list[i] = diff;
1174
/* Take Values if sort_keys == 1*/
1177
sort_order = sort_array[0];
1178
sort_len = sort_items[0];
1179
if (sort_keys > 1) diff = diff_m;
1181
/* Create the array of pointers to data */
1183
lolo = (long int)(sizeof(char *) * tp->rows);
1184
data = (char **)osmmget(lolo);
1185
incr = TBL_offset (tp, 2, icol) - ic;
1186
for (i=0, x = copy ; i < tp->rows; i++, x += incr) data[i] = x;
1187
sort_astart = data[0];
1189
/* Sort the data array */
1190
Qsort (data,0,tp->rows-1);
1193
/* Follow the permutation */
1194
for (i = 0, perm = (int *)data; i < tp->rows; i++, perm++)
1195
*perm = (data[i]-sort_astart)/sort_width;
1199
len = SELW; incr = 0;
1200
for (j = 0; j < tp->cols; j++)
1203
incr= tp->offset[j]*tp->arows;
1205
mapped_bytes = ColumnWidth(tp,j+1)*tp->rows;
1206
root[0] = TBL_RDF (tp, TBL_offset(tp,1,j+1), mapped_bytes, 1);
1207
lolo = (long int) mapped_bytes;
1208
copy = osmmget(lolo);
1209
oscopy (copy, root[0], mapped_bytes);
1212
asShort = (short *)from; asInt = (int *)from;
1213
for (i=0; i < tp->rows; i++, x += len) switch (len)
1215
case sizeof(char): *x = from[perm[i]]; continue;
1216
case sizeof(short): *(short *)x = asShort[perm[i]]; continue;
1217
case sizeof(int): *(int *)x = asInt[perm[i]]; continue;
1218
default: oscopy (x, from + len*perm[i], len); continue;
1225
mapped_bytes = tp->reclen * tp->rows;
1226
if_not(root[0] = TBL_RDF (tp, 0, mapped_bytes, 1)) return (TBL_RDst());
1228
/* Copy a table to a new piece */
1229
lolo = (long int) mapped_bytes;
1230
copy = osmmget (lolo);
1231
oscopy (copy, root[0], mapped_bytes);
1232
ic = TBL_offset (tp, 1, icol);
1234
for (i=0; i<sort_keys; i++)
1237
dtype = ColumnType (tp, icol);
1238
sort_offset[i] = TBL_offset (tp, 1, icol) - ic;
1239
sort_array[i] = sortfl[i];
1240
sort_items[i] = TBL_Items(dtype);
1241
sort_factor[i] = ColumnWidth(tp, icol) - sort_width;
1243
/* Choose the comparison function */
1244
switch (TBL_ElementType(dtype))
1246
case TBL_D_I1: diff = diffi1; break;
1247
case TBL_D_I2: diff = diffi2; break;
1248
case TBL_D_I4: diff = diffi4; break;
1249
case TBL_D_A1: diff = diffa1; break;
1250
case TBL_D_A2: diff = diffa2; break;
1251
case TBL_D_A4: diff = diffa4; break;
1252
case TBL_D_R4: diff = diffr4; break;
1253
case TBL_D_R8: diff = diffr8; break;
1254
default: diff = diffr4;
1256
sort_list[i] = diff;
1259
sort_order = sort_array[0];
1260
sort_len = sort_items[0];
1261
if (sort_keys > 1) diff = diff_m;
1263
/* Create the array of pointers to data */
1264
lolo = (long int) (sizeof(char *) * tp->rows);
1265
data = (char **)osmmget(lolo);
1266
incr = TBL_offset (tp, 2, icol) - ic;
1267
for (i=0, x=copy + ic; i<tp->rows; i++, x += incr) data[i] = x;
1269
sort_astart = data[0];
1270
Qsort (data,0,tp->rows-1);
1272
for (i=0, x=root[0]; i<tp->rows; i++, x += len)
1273
oscopy (x, data[i] - ic, len);
1277
/* update table descriptors */
1281
osmmfree ((char *)data);
1285
int TCCUNM(tid, address)
1286
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1287
.PURPOSE Unmap the part of a file that was mapped before.
1288
.METHOD Identical to TCEUNM
1289
.RETURNS status (-1 if address not found)
1290
------------------------------------------------------------------*/
1291
int tid; /* IN: table id number */
1292
char *address; /* IN: column address */
1294
return (TCEUNM(tid, address));