DEFINITION MODULE DataTables;
(*******************************************************************
Module DataTables (Version 1.0)
Copyright (c) 1997-2006 by Dimitrios Gyalistras, Andreas Fischlin
and ETH Zurich.
Purpose Handles data tables.
Remarks A data table consists of a header and a rectangular data field.
The header is used to identify the individual columns of the data
field. All data within one column must contain data of one
and the same type. Any combinations of different types of
columns are possible.
Programming
o Design
Dimitrios Gyalistras 16/01/1997
Andreas Fischlin 16/01/1997
o Implementation
Dimitrios Gyalistras 16/01/1997
Andreas Fischlin 16/01/1997
ETH Zurich
Systems Ecology
CHN E 35.1
Universitaetstrasse 16
8092 Zurich
SWITZERLAND
URLs:
<mailto:RAMSES@env.ethz.ch>
<http://www.sysecol.ethz.ch>
<http://www.sysecol.ethz.ch/SimSoftware/RAMSES>
Last revision of definition: 09/08/1997 AF
*******************************************************************)
FROM SYSTEM IMPORT ADDRESS;
FROM DMStrings IMPORT String;
FROM DMFiles IMPORT TextFile;
FROM DMLanguage IMPORT onlyAnInsert;
CONST
notDone = onlyAnInsert;
(*
All procedures exported below return resCode = DMLanguage.allOk
if the call to the procedure was succesfull, else resCode = notDone.
*)
TYPE
DataTable;
(*
Data tables are matrix like objects consisting of rows and
colums. In contrast to the well known matrices consisting
of numbers, data tables may consist of elements of different
types (see DTElementType), however, within a single column
types should be the same. Missing values are tolerated
(symbol NA - not available). Implementation restriction:
Memory for data tables will be allocated efficiently, i.e.
only to the size actually required. Columns are numbered
from 1 to 256 and rows from 1 to 3072.
*)
CONST
unknownRowNr = 0; (* rows start at 1 *)
unknownColNr = 0; (* columns start at 1 *)
VAR
notExistingDataTable: DataTable; (* read only *)
(*****************************************************************************)
TYPE
String63 = ARRAY [0..63] OF CHAR;
DTElementType = ( unknownDTEle,
integer, longint, real, longreal,
boolean, ident, string );
DTColDescr = RECORD
type : DTElementType;
id : String63;
END;
DTElementPtr = POINTER TO DTElement;
SHORTENUM = CHAR; (* will hold [CHAR(MIN(DTElementType))..CHAR(MAX(DTElementType))] *)
DTElement = RECORD
def: BOOLEAN; (* def holds whether DTElement is defined *)
type: SHORTENUM; (* type holds the type *)
CASE : DTElementType OF
| unknownDTEle : undefval : ARRAY [0..(SIZE(LONGREAL) DIV SIZE(CHAR))-1] OF CHAR;
| real : real : REAL;
| longreal : lreal : LONGREAL;
| integer : int : INTEGER;
| longint : lint : LONGINT;
| boolean : boo : BOOLEAN;
| ident : id : String;
| string : str : String;
END;(*CASE*)
END;
(* assumptions made:
(i) SIZE(CHAR) = 1
(ii) SIZE(BOOLEAN) <= SIZE(INTEGER)
(iii) SIZE(INTEGER) <= SIZE(LONGINT)
(iv) SIZE(REAL) <= SIZE(LONGREAL)
(v) SIZE(ORD(MAX(DTElementType))) <= SIZE(CHAR)
(vi) SIZE(LONGREAL) = SIZE(undefval) (* implies assumption (i) *)
(vii) SIZE(undefval) >= SIZE(of all types)
Assumptions (v) to (vii) are tested during
module initialization. The latter are
assumed to be satisfied by all compilers.
*)
PROCEDURE ShortDTEType(t: DTElementType): SHORTENUM;
PROCEDURE DTEType(t: SHORTENUM): DTElementType;
(*****************************************************************************)
(* Object management *)
(*****************************************************************************)
PROCEDURE GetDTElementTypeDescr( dt: DTElementType; VAR descr: ARRAY OF CHAR );
(*--------------------------------------------------------------------------*)
PROCEDURE DeclDataTable( tableName : ARRAY OF CHAR;
nRows : INTEGER;
nCols : INTEGER;
VAR colDescr : ARRAY OF DTColDescr; (* VAR for speed-up only *)
VAR dt : DataTable;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
PROCEDURE RemoveDataTable( VAR dt : DataTable );
PROCEDURE DataTableExists( dt : DataTable ): BOOLEAN;
(*--------------------------------------------------------------------------*)
PROCEDURE FirstDataTable():DataTable;
PROCEDURE NextDataTable( dt: DataTable ):DataTable;
(*--------------------------------------------------------------------------*)
PROCEDURE GetDataTableAttr( dt : DataTable;
VAR attr : ADDRESS;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
PROCEDURE SetDataTableAttr( dt : DataTable;
attr : ADDRESS;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
(*--------------------------------------------------------------------------*)
PROCEDURE LockDataTable( dt : DataTable;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
(*
content of data table dt can no longer be modified. Data table dt can
only be discarded as a whole.
*)
PROCEDURE UnlockDataTable( dt : DataTable;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
PROCEDURE IsDataTableLocked( dt : DataTable ): BOOLEAN;
(*--------------------------------------------------------------------------*)
PROCEDURE GetDataTableName( dt : DataTable;
VAR tableName : ARRAY OF CHAR;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
PROCEDURE GetDataTableDescr( dt : DataTable;
VAR tableName : ARRAY OF CHAR;
VAR nRows : INTEGER;
VAR nCols : INTEGER;
VAR colDescr : ARRAY OF DTColDescr;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
PROCEDURE GetDataTableColDescr( dt : DataTable;
colNo : INTEGER;
VAR colDescr : DTColDescr;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
PROCEDURE SetDataTableDescr( dt : DataTable;
tableName : ARRAY OF CHAR;
VAR colDescr : ARRAY OF DTColDescr; (* VAR for speed-up only *)
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
PROCEDURE GetDataTableDim( dt : DataTable;
VAR nRows : INTEGER;
VAR nCols : INTEGER;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
(*--------------------------------------------------------------------------*)
VAR
emptyDataEle: DTElement; (* read only *)
(*
Inite your variables of type DTElement with emptyDataEle.
Strongly recommended prior to any further use!
*)
PROCEDURE ClearDTEle( eleType: DTElementType; VAR ele: DTElement );
(*
Sets ele to emptyDataEle; NOTE: It deallocates also strings, if
eleType requires this. Thus, precondition for ele is either
ele = emptyDataEle or a valid value of type eleType from previous
use.
*)
PROCEDURE CopyDTEle( eleType: DTElementType;
VAR from : DTElement; (* VAR for speed-up only *)
VAR to : DTElement );
(*
to has to satisfy the same preconditions as required by ClearDTEle
*)
(*
NOTE: for efficiency the following procedures do not
check the validity of the input parameters!!
*)
PROCEDURE GetDTEle( dt : DataTable;
row, col : INTEGER;
VAR ele : DTElement );
(*
ele has to satisfy the same preconditions as required by ClearDTEle
*)
PROCEDURE SetDTEle( VAR ele : DTElement; (* VAR for speed-up only *)
dt : DataTable;
row, col : INTEGER );
(*
ele has to satisfy the same preconditions as required by ClearDTEle
plus that dt contains already well defined types for all colums.
*)
PROCEDURE DTEleADR( dt : DataTable;
row, col : INTEGER): DTElementPtr;
(*
NOTE: This routine is a loophole circumventing the locking mechanism
entirely, so use it with caution and for reading ONLY, unless the dt is
not locked!!!
*)
(*****************************************************************************)
(* Reading of DataTables from file *)
(*****************************************************************************)
PROCEDURE SetMisValParams( misValStr,
misQuotStr : ARRAY OF CHAR;
misReal : REAL;
misInt : INTEGER;
misLReal : LONGREAL;
misLInt : LONGINT;
misBool : BOOLEAN;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
PROCEDURE GetMisValParams( VAR misValStr,
misQuotStr: ARRAY OF CHAR;
VAR misReal : REAL;
VAR misInt : INTEGER;
VAR misLReal : LONGREAL;
VAR misLInt : LONGINT;
VAR misBool : BOOLEAN);
(*
The values misReal and misInt are returned if the string "misValStr"
is encountered at the place of a real (or longreal), or an integer
(or longint), respectively.
The default settings are:
misValStr = 'NA'
misQuotStr = '???'
misReal = DMConversions.UndefREAL();
misInt = MIN(INTEGER)+1;
misLReal = DMConversions.UndefLONGREAL();
misLInt = MIN(LONGINT)+1;
misBool = BOOLEAN(ORD(MAX(BOOLEAN))+1);
*)
PROCEDURE ReadDataTable( inFName : ARRAY OF CHAR;
tryOpenFile : BOOLEAN;
keepFileOpen : BOOLEAN;
eolSeparated : BOOLEAN;
tableName : ARRAY OF CHAR;
VAR dt : DataTable;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
(*
Reads DataTable dt from file inFName. If tryOpenFile=FALSE the
file must have already been opened for scanning by means of
procedure Scanner.InitFileScan.
If the file is kept open, the Scanner procedures can be used to
continue reading, e.g. to read a further table.
The expected syntax is:
DataTable = TableHeader TableLine {TableLine} "END".
TableHeader = IDENTIFIER {IDENTIFIER} lineSeparator.
TableLine = TableEle {TableEle} lineSeparator.
TableEle = (INTEGER | LONGINT | REAL | LONGREAL |
IDENTIFIER | STRING | BOOLEAN ).
If eolSeparated=TRUE then
lineSeparator = "EOL".
and all elements of TableHeader or a TableLine are expected on one line.
Otherwise
lineSeparator = ";".
In this case the elements of TableHeader or a TableLine can be distributed
over any number of lines.
The elementary data types are (given in regular expression notation):
INTEGER = [+-]?[0-9]+
LONGINT = [+-]?[0-9]+ "D"
REAL = [+-]?[0-9]+ "." [0-9]+ (("E"|"e")[+-]?[0-9]+)?
LONGREAL = [+-]?[0-9]+ "." [0-9]+ (("D"|"d")[+-]?[0-9]+)?
IDENTIFIER = [a-zA-Z]+ [_a-zA-Z0-9]*
STRING = ('.*')|(".*")
BOOLEAN = "TRUE" | "FALSE"
Comments start with "(*" and close with "*)". Recursive comments
are possible.
*)
PROCEDURE GetColDescriptors( VAR fName : ARRAY OF CHAR; (* VAR for speed-up only *)
eolSeparated : BOOLEAN;
VAR nCols : INTEGER;
VAR colDescr : ARRAY OF DTColDescr;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
(*
Retrieves header line (column descriptors) by reading from current position
in a file previously opened by means of procedure Scanner.InitFileScan.
*)
PROCEDURE GetNextDataRow( VAR fName : ARRAY OF CHAR; (* VAR for speed-up only *)
eolSeparated : BOOLEAN;
nCols : INTEGER;
VAR colDescr : ARRAY OF DTColDescr; (* is also set! *)
VAR rowData : ARRAY OF DTElement;
VAR endOfData : BOOLEAN;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
(*
Retrieves a table row by reading from current position in a file
previously opened by means of procedure Scanner.InitFileScan.
If for the column descriptor of the i-th column holds colDescr[i].type=
unknownDTEle then the type will be set according to the type of
data found for column i (unless a missing value occurs).
endOfData returns TRUE if the end of the data table has been
reached (keyword "END"). rowData must be properly initialized
all with emptyDataEle, when calling GetNextDataRow the first time.
*)
(*****************************************************************************)
(* Writing of DataTables to file *)
(*****************************************************************************)
PROCEDURE SetNumOutputParams( nIntChars : INTEGER;
nLIntChars : INTEGER;
nRealChars : INTEGER;
nDecDigits : INTEGER;
nLRealChars : INTEGER;
nLRDecDigits : INTEGER);
PROCEDURE GetNumOutputParams( VAR nIntChars : INTEGER;
VAR nLIntChars : INTEGER;
VAR nRealChars : INTEGER;
VAR nDecDigits : INTEGER;
VAR nLRealChars : INTEGER;
VAR nLRDecDigits : INTEGER );
PROCEDURE WriteDataTable( outF : TextFile;
eolSeparated : BOOLEAN;
indentStr : ARRAY OF CHAR;
lastIndentStr : ARRAY OF CHAR;
VAR dt : DataTable;
VAR resCode : INTEGER;
VAR insert : ARRAY OF CHAR );
(*
Dumps DataTable dt to file outF. The file must have already been
opened for writing by means of a DMFiles procedure.
If eolSeparated=FALSE data lines will be separated by ";".
Each new line written starts with indentStr, the last line containing
the keyword "END" with lastIndentStr.
*)
END DataTables.