/* @(#)tcc.c 17.1.1.1 (ESO-DMD) 01/25/02 17:36:44 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. Correspondence concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .NAME tcc.c .LANGUAGE C .AUTHOR J.D.Ponz IPG-ESO - Garching .CATEGORY table interface (Design 2.0) .VERSION 1.0 25-Mar-1987 Implementation JDP .VERSION 1.1 20-Oct-1987 Modify calling sequence .VERSION 1.2 23-Nov-1987 New SC calling sequence .VERSION 1.3 11-Apr-1988 Include new routines without type conversion. Character string always ending with a '\0'. New SC calling sequence. .VERSION 1.4 26-Sep-1988 Modify calling sequence in TCCINI to include data types and array length. .VERSION 3.0 01-Jul-1990 New Version with Arrays / Elementary IO Added TCCSEL routine (selection of Columns) .VERSION 3.1 26-Sep-1990 Removed bug in TCCSRT .VERSION 3.2 06-Dec-1990 Force New Version as soon as something modified. .VERSION 3.3 18-Dec-1990 FO: Take into account the number of selected rows. .VERSION 3.4 23-Feb-1991 Sort always writes NULL values at the end. .VERSION 3.5 29-Apr-1991: TCCINI must work whatever the table size is ... .VERSION 3.6 10-Jun-1991: Added TCCPAM (Partial Column Mapping) .VERSION 3.7 22-Sep-1992: treats in a proper way NULL values (i.e convex) .COMMENTS \begin{TeX} This module contains the routines to handle columns in a table. Access to the table is done through the table identifier, returned by the routines TCTOPN and TCTINI. Access to a column is done through the column number, given by the routines TCCINI, TCCSER and TCLSER. The following main functions are defined in this module: \begin{itemize} \item create a column in the table (TCCINI), \item delete a column from the table (TCCDEL), \item map a column (TCCMAP), \item unmap a column (TCCUNM), \item table sorting according to column values (TCCSRT), \item search the column number (TCCSER). \end{itemize} Main arguments used by the routines are: \begin{description} \item[alen] array length. Integer number to define the number of items in a multiple column. In the case of character strings 'alen' defines the maximum length of the string. \item[colref] reference to the column by label or by number. It is a character string containing the ':label' if the column is referenced by label, or '\#n' if the column is referenced by its sequential number. \item[column] sequential column number. It is an integer number provided by the system when a new column is created or defined by the user. \item[dtype] column data type. The system file 'midas\_def.h' in 'MID\_INCLUDE:' provides the symbols D\_xx\_FORMAT where 'xx' is 'I4' for integer data, 'R4' for float, 'R8' for double precision and 'C' for character. \item[form] column format. Display format associated to the column. The format is defined like in standard FORTRAN. \item[label] column label. Character string (up to 16 characters) provided by the use when the column is created. Valid characters are letters, digits and the underscore symbol '\_'. In the current version labels are NOT case independent. \item[tid] table identifier. It is an integer number provided by the system when the table is created or opened. \item[unit] column unit. Character string (up to 16 characters) to define the units of the column. \end{description} \end{TeX} ------------------------------------------------------------*/ #include /* ANSI-C Prototyping */ #include #include /* Table System parameters */ #include /* Symbols used for Tables */ #include /* List of Table Errors */ #include /* Character classification */ #include /* Classical macros */ static int dunit; /* Not yet used */ static int dnull = 0; #define SELW sizeof(int) /* Length of Selection Column */ char *osmmget(), *osmmexp(); /*=================================================================== * Private Routines *===================================================================*/ #ifdef __STDC__ static int strloc(char *str, char c) #else static int strloc(str, c) /*+++++++ .PURPOSE Locate the first occurence of character `c' .RETURNS Index of `c' in str; length of str if `c' not found. ---------*/ char *str; /* IN: string to scan */ char c; /* IN: char to locate */ #endif { register char *p; for (p=str; *p; p++) if (*p == c) break; return(p-str); } #ifdef __STDC__ static int find_space (TABLE *tp, int align, int bytes) #else static int find_space (tp, align, bytes) /*+++++++ .PURPOSE Find an offset where a new column can be added .RETURNS Where it can be added. .METHOD A template record is filled with x for used parts, zeroes for empty parts. It is then scanned for a suitable position. ---------*/ TABLE *tp; /* IN: Table Concerned */ int align; /* IN: Alignment requirement */ int bytes; /* IN: Bytes required */ #endif { char *record; int i,j,lim; record = osmmget (tp->reclen); oscfill (record, tp->reclen, '\0'); oscfill (record, 4, 'x'); /* The Selection Column */ for (i=0; i < tp->cols; i++) oscfill (record + tp->offset[i], tp->bytes[i], 'x'); for (i=0; i < tp->reclen; i++) { if (record[i]) continue; if (i%align) continue; lim = i + bytes; if (lim > tp->reclen) lim = tp->reclen; for (j = i; (j < lim) && (record[j] == 0); j++) ; if (j == lim) break; i = j; } osmmfree (record); return(i); } /*=================================================================== * Public Routines *===================================================================*/ int TCCDEL(tid, column, ncol) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Delete column in a table .RETURNS status .REMARKS This implementation FORCES the table version to TBL_VERSION. .METHOD Just modify Descriptors. -------------------------------------------------------------*/ int tid; /* IN: table id number */ int column; /* IN: column number */ int *ncol; /* OUT:actual number of columns */ { TABLE *tp; int status, i, ii ,i1, len; int got; char buf[TBL_DESLAB+1]; /* checks arguments */ tp = TBL_ptr(tid); if (status = CheckTable(tp)) return(TBL_errs(tid, status,0)); if (status = CheckTrueColumn(tp, column)) return(TBL_errs(tid, status, column)); /* Force New Version */ if (tp->version == 0) tp->version = TBL_VERSION; /* Modifs in Memory */ for (i = column; i < tp->cols; i++) { i1 = i - 1; tp->dtypes[i1] = tp->dtypes[i]; tp->bytes[i1] = tp->bytes[i]; tp->offset[i1] = tp->offset[i]; tp->abytes[i1] = tp->abytes[i]; len = 1+TBL_LABLEN; oscopy (tp->label+i1*len, tp->label+i*len, len); len = 1+TBL_FORLEN; oscopy (tp->format+i1*len, tp->format+i*len, len); } /* Modify sorting & ref column */ if (tp->scol == column) tp->scol = 0; else if (tp->scol > column) tp->scol -= 1; if (tp->kcol == column) tp->kcol = 0; else if (tp->kcol > column) tp->kcol -= 1; tp->cols -= 1; *ncol = tp->cols; if (tp->tflags & TBL__READONLY) return(status); /* Update Descriptors */ tp->cols += 1; for (i = column; i < tp->cols; i++) { for (ii=0; iiimno, TBL_Dlab(i+1),1L, 1L,TBL_DESLAB, &got, buf, &dunit, &dnull)) goto error; if (status = SCDWRC(tp->imno, TBL_Dlab(i),1L, buf,1L,got,&dunit)) goto error; } /* finally delete last descriptor, * and update table information */ if (status = SCDDEL(tp->imno, TBL_Dlab(tp->cols))) goto error; tp->cols -= 1; tp->dtypes[tp->cols] = 0; tp->offset[tp->cols] = 0; if (status = SCDWRI(tp->imno, TBL_Ddtypes, tp->dtypes, 1,tp->colitems, &dunit)) goto error; if (status = SCDWRI(tp->imno, TBL_Doffset, tp->offset, 1,tp->colitems, &dunit)) goto error; if (status = SCDWRI(tp->imno, TBL_Dmain, &tp->acols, 1,TBL_Dmain_SIZE,&dunit)) goto error; error: /* error in SC routines */ if (status) TBL_errs(tid, status, 0); return (status); } int TCCINI(tid, dtype, alen, form, unit, label, column) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Initializes table column. Elements in the column are initialized as undefined (null values). .METHOD Check if column has been already defined, otherwise add the new column descriptors. The routine provides an overflow mechanism when the new column exceeds the allocated space. .RETURNS Status ------------------------------------------------------------------*/ int tid; /* IN: table id number */ int dtype; /* IN: column data type (Midas) */ int alen; /* IN: no. of array items */ char *form; /* IN: column form */ char *unit; /* IN: column unit */ char *label; /* IN: column label */ int *column; /* OUT:column number */ { TABLE *tp; int status, align, where; int ttype, nbytes, new_cols, i, j ,maxrows, mapped_rows, incr; char buf[TBL_DESLAB+1]; char *x, *p; tp = TBL_ptr(tid); if (status = CheckTable(tp)) return(TBL_errs(tid, status, 0)); if (tp->version == 0) tp->version = TBL_VERSION; /* Force New Version */ /* check if column overflow */ if (tp->cols >= tp->colitems) { i = tp->colitems; tp->colitems = tp->cols + 4; tp->dtypes = (int *)osmmexp((char *)tp->dtypes, 2*sizeof(int)*tp->colitems); tp->offset = tp->dtypes + tp->colitems; oscopy ((char *)tp->offset, (char *)(tp->dtypes + i), i*sizeof(int)); tp->bytes = (int *)osmmexp((char *)tp->bytes, 2*sizeof(int)*tp->colitems); tp->abytes = tp->bytes + tp->colitems; oscopy ((char *)tp->abytes, (char *)(tp->bytes + i), i*sizeof(int)); for (j=i; jcolitems; j++) tp->dtypes[j] = tp->offset[j] = tp->bytes[j] = tp->abytes[j] = 0; tp->label = osmmexp(tp->label, (2+TBL_LABLEN+TBL_FORLEN)*tp->colitems); tp->format = tp->label + tp->colitems*(1+TBL_LABLEN); oscopy (tp->format, tp->label + i*(1+TBL_LABLEN), i*(1+TBL_FORLEN)); /* MP 180291 */ } /* check type of column */ if (status = TBL_TYPCHK(dtype, alen, &ttype)) return(status); p = buf; /* check column label */ if (status = TBL_LABCHK(label,p)) return(status); p += TBL_LABLEN; /* Check Unit */ if (status = TBL_UNICHK(unit,p)) return(status); p += TBL_UNILEN; /* check format */ if (status = TBL_FMTCHK(form, ttype, p)) return(status); /* Adjust parameters */ nbytes = TBL_ElementSize(ttype); /**** NEW: Align Offset */ align = (tp->swise == F_RECORD ? nbytes : 1); nbytes *= TBL_Items(ttype); where = find_space (tp, align, nbytes); *column = tp->cols + 1; /* allocate column(s) if overflow */ new_cols = (where + nbytes + 3)/4 - 1; if (new_cols > tp->acols) { if (status = TBL_ALLOCOL(tid, new_cols)) return(status); tp = TBL_ptr(tid); } buf[TBL_DESLAB] = '\0'; /* force NULL terminated string */ /* write descriptor */ if (status = SCDWRC(tp->imno, TBL_Dlab(*column),1, buf, 1,TBL_DESLAB,&dunit)) return (TBL_errf(status, "table %s", tp->phname)); /* Update Header Info */ i = tp->cols; tp->dtypes[i] = ttype; tp->bytes[i] = nbytes; tp->offset[i] = where; tp->abytes[i] = -1; /* uninitialized...*/ tp->label [i*(1+TBL_LABLEN)] = '\0'; tp->format[i*(1+TBL_FORLEN)] = '\0'; tp->cols = *column; /* Initialize to NULL values */ incr = TBL_offset (tp, 2, *column) - TBL_offset (tp, 1, *column); maxrows = TBL_EIO_LIMIT / incr; maxrows = MAX (maxrows, 1); for (i=0; i < tp->arows; i += maxrows) { mapped_rows = tp->arows - i; mapped_rows = MIN (mapped_rows, maxrows); if_not (x = TBL_RDF (tp, TBL_offset(tp, i+1, *column), incr*mapped_rows, 1)) return(TBL_RDst()); TBL_toNULL (ttype, x); /* NULL first element */ for (p = x + incr; --mapped_rows > 0; p += incr) oscopy(p ,x, nbytes); } return (status); } int TCCMAP(tid, col, address) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Return the address of the column in the table. .METHOD Finds the position of the physical column and get address via the virtual memory mechanism. Note: This routine only works on tables stored by columns (transposed format, parameter F_TRANS in TCTINI). .RETURNS status ------------------------------------------------------------------*/ int tid; /* IN: table id number */ int col; /* IN: column number */ char **address; /* OUT:column address */ { TABLE *tp; int status; int ic, len; tp = TBL_ptr(tid); if (status = CheckTable(tp)) return(TBL_errs(tid, status, 0)); if (status = CheckColumn(tp, col)) return(TBL_errs(tid, status, col)); if (tp->swise != F_TRANS) return (TBL_errf(ERR_TBLMAP, "Can't MAP column on RECORD table: %s", tp->phname)); else { ic = TBL_offset(tp, 1, col); len = TBL_offset(tp, tp->arows, col) -ic + ColumnWidth(tp, col); if_not(*address = TBL_RDF (tp, ic, len, TBL__MAPPED)) return (TBL_RDst()); if (col == 0) tp->selected = -1; /* Unknown */ } return (status); } int TCCPAM(tid, col, starting_row, asked_rows, mapped_rows, address) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Map a part of a table, namely up to asked_row from row # starting_row .REMARKS A value of zero for asked_rows provide some default. .RETURNS status ------------------------------------------------------------------*/ int tid; /* IN: table id number */ int col; /* IN: column number */ int starting_row; /* IN: First row to map (from 1)*/ int asked_rows; /* IN: Number of rows to map, 0 to map as many rows as possible */ int *mapped_rows; /* OUT: Number of rows mapped */ char **address; /* OUT: address of mapped first row */ { TABLE *tp; int status; int i,ic, len; static unsigned char bit_mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; tp = TBL_ptr(tid); *mapped_rows = 0; /* Default return */ if (status = CheckTable(tp)) return(TBL_errs(tid, status, 0)); if (tp->swise != F_TRANS) return (TBL_errf(ERR_TBLMAP, "Can't MAP column on RECORD table: %s", tp->phname)); if (status = CheckColumn(tp, col)) return(TBL_errs(tid, status, col)); if (status = CheckRow(tp, starting_row)) return(TBL_errs(tid, status, starting_row)); if (asked_rows <= 0) { /* Compute Default number of Rows */ len = ColumnWidth(tp, col); asked_rows = TBL_EIO_LIMIT/len/2; if (asked_rows < 1) asked_rows = 1; } /* Check the number of rows */ if ((starting_row + asked_rows) > tp->arows) asked_rows = 1 + tp->arows - starting_row; if (col == 0 && tp->usname != '\0') { *address = osmmget(asked_rows * sizeof(int)); for (i=starting_row; i < starting_row+asked_rows; i++) { ic = (tp->vsel[i>>3] & bit_mask[i&7]); *(int *) (*address + (i-starting_row) *sizeof(int)) = (ic != 0); } } else { /* Do now the mapping */ len = ColumnWidth(tp, col) * asked_rows; ic = TBL_offset(tp, starting_row, col); if_not(*address = TBL_RDF (tp, ic, len, TBL__MAPPED)) return (TBL_RDst()); } /* Write output parameters */ *mapped_rows = asked_rows; if (col == 0) tp->selected = -1; /* Unknown */ return (status); } int TCCSEL(tid, text, max_cols, cols, flags, found_cols) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Searchs a set of columns column by references (their name). .METHOD A set of columns has the general syntax col[(flag)][,col]... where "col" may be #number or :label. The Sequence column may be designated by # or : .RETURNS Status -------------------------------------------------------------*/ int tid; /* IN : table id */ char *text; /* IN : textual designation */ int max_cols; /* IN: Size of cols & flags arrays */ int *cols; /* OUT: column numbers */ int *flags; /* OUT: column flags (in brackets) */ int *found_cols; /* OUT: How many columns were found */ { int status; int temp,dummy; char *p, b, c, d; int k, j, ic, ib, id; status = ERR_NORMAL; if (*text == '\0') { status = TCIGET(tid,found_cols,&dummy,&dummy,&dummy,&dummy); for (j=1; j <= *found_cols; j++) cols[j-1] = j; return(status); } /* Tokenize from commas, then from brackets */ for (j=0, p=text; (*p) && (j < max_cols) && (status == ERR_NORMAL); j++) { ic = strloc (p, ','); c = p[ic]; p[ic] = '\0'; id = strloc(p,'.'); if ( p[id] && p[id+1] == '.') { d = p[id]; p[id] = '\0'; } else d = '\0'; ib = strloc (p, '('); b = p[ib]; p[ib] = '\0'; flags[j] = 1; /* Default Flag */ if (status = TCCSER (tid, p, &cols[j])) continue; /* Get Label*/ if (cols[j] < 0) { status = ERR_TBLCOL; TBL_errf(status, "unknown column %s", p); } if (b) { p += ib; ic -= ib; *p = b; p++; ic--; flags[j] = atoi(p); if (flags[j] == 0) flags[j] = (*p == '-' ? -1 : 1); } if (d) { p += id+1; *p = '#'; ic -= ib+1; if (status = TCCSER (tid, p, &temp)) continue; if (temp < 0) { status = ERR_TBLCOL; TBL_errf(status,"unknown column %s",p); } temp = temp-cols[j]+1; for (k=1; k<= temp; k++) *(cols+j+k) = *(cols+j)+k; j = j+temp-1; *p =d; } p += ic; *p = c; if (c) p++; } /* Check if not too many cols */ if ( (status == ERR_NORMAL) && (j == max_cols) && (isgraph(*p))) TBL_errf (-1, "list truncated to %d items: %s", max_cols, text); *found_cols = j; return (status); } int TCCSER(tid, colref, column) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Searchs column by reference (its name). The column may be designated as #number or :name or name The Sequence column may be designated by # or : .METHOD Sequential search for the column label. The routine returns the column number as the last argument or -1 if the column is not found. .RETURNS Status -------------------------------------------------------------*/ int tid; /* IN : table id */ char *colref; /* IN : column reference */ int *column; /* OUT: column number */ { TABLE *tp; int status, i; char *p; tp = TBL_ptr(tid); if (status = CheckTable(tp)) return(TBL_errs(tid, status, 0)); /* init variables */ p = colref; *column = -1; switch (*p) { case '#' : /* column by number */ p++; for (i = 0; isdigit(p[i]); i++) ; if (isalpha(p[i])) { i = -1; status = ERR_TBLCOL; TBL_errf(status, "invalid number #'%s', table: %s", p, tp->phname); } else { i = atoi(p); if ((i > tp->cols) || (i < 0)) status = ERR_TBLCOL, TBL_errs(tid, status, i); else *column = i; } break; case ':' : /* column by label */ p++; default : /* assume its name */ if (isspace(*p) || (*p == '\0')) *column = 0; /* use sequence no. */ else status = TCLSER (tid, p, column); break; case 's' : case 'S' : /* column sequence*/ *column = 0; break; } return (status); } /*==================================================================== * Internal Routines for Sort *====================================================================*/ /* When several sort parameters are given, the address of the other parameters to test are computed from the address of the first parameter Let @ be the address of line i of the first parameter, @0 the address of line 1 of the first parameter the address @n of the 2nd parameter of line i can be computed via @n = (@-@0)*a/l0 + Cte where a = difference of widths l0= width of first parameter column The parameters are stored as Cte: in sort_offset a : in sort_factor l0 : in sort_width */ typedef int (*FUNCTION)(); /* Just to simplify the declarations....*/ static char *sort_astart; /* Origin of 1st sort parameter */ static int sort_width; /* Width of first column to be sorted */ static int sort_order; /* 1 for ascending, -1 for descending */ static int sort_len; /* Number of items in Table */ static FUNCTION diff; /* Several parameters used for sorting */ static FUNCTION sort_list[SORT_MAX]; static int sort_array[SORT_MAX], sort_items[SORT_MAX]; static int sort_offset[SORT_MAX], sort_factor[SORT_MAX]; static int sort_keys = 0; static int diff_m(s1, s2) /*++++++++++++++++ .PURPOSE Compute differences when several keys are used. .RETURNS Negative value if s1s2, null if s1=s2) -----------------*/ char *s1, *s2; { int result, i; FUNCTION what_to_do; sort_order = sort_array[0]; sort_len = sort_items[0]; what_to_do = sort_list[0]; result = (*what_to_do)(s1, s2); for (i = 1; (i < sort_keys) && (result == 0); i++) { sort_order = sort_array[i]; sort_len = sort_items[i]; what_to_do = sort_list[i]; result = (*what_to_do)( s1+sort_offset[i] + sort_factor[i]*(s1-sort_astart)/sort_width, s2+sort_offset[i] + sort_factor[i]*(s2-sort_astart)/sort_width); } return(result); } static int diffi1 (s1, s2) /*++++++++++++++++ .PURPOSE Compute difference between two char strings .RETURNS s1-s2 (negative value if s1s2, null if s1=s2) .REMARKS NULL values always at end -----------------*/ char *s1, *s2; { int i; for (i = sort_len; --i >= 0; s1++, s2++){ if (*s1 == *s2) continue; if (*s1 == NULL1) return(1); /* NULL value at end */ if (*s2 == NULL1) return(-1); /* NULL value at end */ if (*s1 > *s2) return (sort_order); if (*s1 < *s2) return (-sort_order); } return(0); } static int diffi2 (s1, s2) /*++++++++++++++++ .PURPOSE Compute difference between two short arrays .RETURNS s1-s2 (negative value if s1s2, null if s1=s2) .REMARKS NULL values always at end -----------------*/ short *s1, *s2; { int i; for (i = sort_len; --i >= 0; s1++, s2++){ if (*s1 == *s2) continue; if (*s1 == NULL2) return(1); /* NULL value at end */ if (*s2 == NULL2) return(-1); /* NULL value at end */ if (*s1 > *s2) return (sort_order); if (*s1 < *s2) return (-sort_order); } return(0); } static int diffi4 (s1, s2) /*++++++++++++++++ .PURPOSE Compute difference between two int arrays .RETURNS s1-s2 (negative value if s1s2, null if s1=s2) .REMARKS NULL values always at end -----------------*/ int *s1, *s2; { int i; for (i = sort_len; --i >= 0; s1++, s2++){ if (*s1 == *s2) continue; if (*s1 == NULL4) return(1); /* NULL value at end */ if (*s2 == NULL4) return(-1); /* NULL value at end */ if (*s1 > *s2) return (sort_order); if (*s1 < *s2) return (-sort_order); } return(0); } static int diffa1 (s1, s2) /*++++++++++++++++ .PURPOSE Compute difference between two unsigned chars .RETURNS s1-s2 (negative value if s1s2, null if s1=s2) .REMARKS No NULL values... -----------------*/ unsigned char *s1, *s2; { int i; for (i = sort_len; --i >= 0; s1++, s2++){ if (*s1 > *s2) return (sort_order); if (*s1 < *s2) return (-sort_order); } return(0); } static int diffa2 (s1, s2) /*++++++++++++++++ .PURPOSE Compute difference between two unsigned shorts .RETURNS s1-s2 (negative value if s1s2, null if s1=s2) -----------------*/ unsigned short *s1, *s2; { int i; for (i = sort_len; --i >= 0; s1++, s2++){ if (*s1 > *s2) return (sort_order); if (*s1 < *s2) return (-sort_order); } return(0); } static int diffa4 (s1, s2) /*++++++++++++++++ .PURPOSE Compute difference between two unsigned ints .RETURNS s1-s2 (negative value if s1s2, null if s1=s2) -----------------*/ unsigned int *s1, *s2; { int i; for (i = sort_len; --i >= 0; s1++, s2++){ if (*s1 > *s2) return (sort_order); if (*s1 < *s2) return (-sort_order); } return(0); } static int diffr4 (s1, s2) /*++++++++++++++++ .PURPOSE Compute difference between two floats .RETURNS s1-s2 (negative value if s1s2, null if s1=s2) .REMARKS NULL values always at end -----------------*/ float *s1, *s2; { int i; for (i = sort_len; --i >= 0; s1++, s2++){ if (*s1 == *s2) continue; if (isNULLF(s1)) return(1); /* NULL value at end */ if (isNULLF(s2)) return(-1); /* NULL value at end */ if (*s1 > *s2) return (sort_order); if (*s1 < *s2) return (-sort_order); } return(0); } static int diffr8 (s1, s2) /*++++++++++++++++ .PURPOSE Compute difference between two doubles .RETURNS s1-s2 (negative value if s1s2, null if s1=s2) .REMARKS NULL values always at end -----------------*/ double *s1, *s2; { int i; for (i = sort_len; --i >= 0; s1++, s2++){ if (*s1 == *s2) continue; if (isNULLD(s1)) return(1); /* NULL value at end */ if (isNULLD(s2)) return(-1); /* NULL value at end */ if (*s1 > *s2) return (sort_order); if (*s1 < *s2) return (-sort_order); } return(0); } /*===================================================================*/ static Qsort(data, first, last) /*++++++++++++++++ .PURPOSE Quick Sort .METHOD Quick sort modified with insert sort for small partitions. The routine sorts the array of pointers to actual data. The comparison routine is external. .RETURNS --- -----------------*/ char **data; /* MOD: The arrays of pointers to sort */ int first, last; /* IN: Indexes of first / last pointer */ { char *px, *t; int i,j; i = first; j = last; px = data[(first+last)/2]; do { while ( (i < last ) && ((*diff)(data[i], px) < 0)) i++; while ( (j > first) && ((*diff)(data[j], px) > 0)) j--; if (i <= j) { if (i < j) t = data[i], data[i] = data[j], data[j] = t; i++; j--; } } while (i <= j); if (first < j) Qsort (data, first, j); if (i < last) Qsort (data, i, last ); } int TCCSRT(tid, nc, column, sortfl) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Sort table. .METHOD Use Quick sort algorithm to sort the table data in ascending (sort flag > 0) or descending (sort flag < 0) sequence. .RETURNS Status -------------------------------------------------------------*/ int tid; /* IN : table id */ int nc; /* IN : number of columns*/ int column[]; /* IN : column numbers */ int sortfl[]; /* IN : sort flag */ { TABLE *tp; int status; int i, j, len, icol, ic, dtype, incr, mapped_bytes, offset; char **data; char *x, *copy, *root[SORT_MAX]; tp = TBL_ptr(tid); if (status = CheckTable(tp)) return(TBL_errs(tid, status,0)); /* Is there something to sort ?? */ if (tp->rows <= 1) return (status); data = (char **)0; /* Check the list of sort keys */ sort_keys = nc; if (sort_keys < 1) { TBL_errf(-1, "value %d of SORT parameters assumed to be 1, table: %s", sort_keys, tp->phname); sort_keys = 1; } if (sort_keys > SORT_MAX) { TBL_errf(-1, "Number %d of SORT parameters truncated to %d, table: %s", sort_keys, SORT_MAX, tp->phname); sort_keys = SORT_MAX; } /* check column numbers */ for (i=0; i tp->cols || icol <= 0) return (TBL_errs (ERR_TBLCOL, tid, icol)); } icol = column[0]; sort_width = ColumnWidth(tp, icol); /* All existing data will be modified */ for (i=0, ic=0; i < tp->cols; i++) { if (tp->offset[i] > tp->offset[ic]) ic = i; } ic += 1; if (tp->swise == F_TRANS) { int offset; int *perm; char *from; int *asLong; short *asShort; offset = 0; for (i=0; irows; offset = offset + mapped_bytes; if_not (root[i] = TBL_RDF (tp, TBL_offset(tp,1,icol), mapped_bytes, 2)) return(TBL_RDst()); } copy = osmmget(offset); ic = TBL_offset (tp, 1L, column[0]); for (i=0; irows); sort_array[i] = sortfl[i]; sort_items[i] = TBL_Items(dtype); sort_factor[i] = ColumnWidth(tp, icol) - sort_width; /* Choose the comparison function */ switch (TBL_ElementType(dtype)) { case TBL_D_I1: diff = diffi1; break; case TBL_D_I2: diff = diffi2; break; case TBL_D_I4: diff = diffi4; break; case TBL_D_A1: diff = diffa1; break; case TBL_D_A2: diff = diffa2; break; case TBL_D_A4: diff = diffa4; break; case TBL_D_R4: diff = diffr4; break; case TBL_D_R8: diff = diffr8; break; } sort_list[i] = diff; } /* Take Values if sort_keys == 1*/ icol = column[0]; sort_order = sort_array[0]; sort_len = sort_items[0]; if (sort_keys > 1) diff = diff_m; /* Create the array of pointers to data */ data = (char **)osmmget(sizeof(char *)*tp->rows); incr = TBL_offset (tp, 2L, icol) - ic; for (i=0, x = copy ; i < tp->rows; i++, x += incr) data[i] = x; sort_astart = data[0]; /* Sort the data array */ Qsort (data, 0L, tp->rows-1); /* Follow the permutation */ for (i = 0, perm = (int *)data; i < tp->rows; i++, perm++) *perm = (data[i]-sort_astart)/sort_width; perm = (int *)data; len = SELW; incr = 0; for (j = 0; j < tp->cols; j++) { if (j >= 0) len = tp->bytes[j], incr= tp->offset[j]*tp->arows; mapped_bytes = ColumnWidth(tp,j+1)*tp->rows; root[0] = TBL_RDF (tp, TBL_offset(tp,1,j+1), mapped_bytes, 1); copy = osmmget(mapped_bytes); oscopy (copy, root[0], mapped_bytes); from= copy ; x = root[0] ; asShort = (short *)from; asLong = (int *)from; for (i=0; i < tp->rows; i++, x += len) switch (len) { case sizeof(char): *x = from[perm[i]]; continue; case sizeof(short): *(short *)x = asShort[perm[i]]; continue; case sizeof(int): *(int *)x = asLong[perm[i]]; continue; default: oscopy (x, from + len*perm[i], len); continue; } osmmfree(copy); } } else { mapped_bytes = tp->reclen * tp->rows; if_not(root[0] = TBL_RDF (tp, 0L, mapped_bytes, 1)) return (TBL_RDst()); /* Copy a table to a new piece */ copy = osmmget (mapped_bytes); oscopy (copy, root[0], mapped_bytes); ic = TBL_offset (tp, 1L, icol); for (i=0; i 1) diff = diff_m; /* Create the array of pointers to data */ data = (char **)osmmget(sizeof(char *)*tp->rows); incr = TBL_offset (tp, 2L, icol) - ic; for (i=0, x = copy + ic; i < tp->rows; i++, x += incr) data[i] = x; sort_astart = data[0]; Qsort (data, 0L, tp->rows-1); len = tp->reclen; for (i=0, x = root[0]; i < tp->rows; i++, x += len) oscopy (x, data[i] - ic, len); osmmfree (copy); } /* update table descriptors */ tp->scol = icol; osmmfree ((char *)data); return (status); } int TCCUNM(tid, address) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Unmap the part of a file that was mapped before. .METHOD Identical to TCEUNM .RETURNS status (-1 if address not found) ------------------------------------------------------------------*/ int tid; /* IN: table id number */ char *address; /* IN: column address */ { return (TCEUNM(tid, address)); }