C-Routinen zum Lesen/Schreiben von EAS2/3-Dateien

Einleitung

Diese Bibliothek stellt C-Routinen zur Manipulation von EAS2/3 Dateien zur Verfügung. Zur Zeit funktioniert die Bibliothek auf SGI (auch 64bit), HP-VClass, Linux und NEC SX4, jedoch noch nicht auf der Cray. Dateien größer 2GB werden unterstützt, sofern das Betriebssystem dies erlaubt.

Das grundsätzliche Vorgehen entspricht dem im Fortran-Modul: Eine Datei wird durch ihren Namen und eine zugeordnete Dateinummer gekennzeichnet. Der Dateiname wird nur einmal beim ersten Schreiben/Lesen des Kennsatzes benötigt, danach wird die Datei über die Dateinummer angesprochen. Es werden maximal EAS3_MAXFILES+1 Dateien gleichzeitig unterstützt, sofern das Betriebssystem dies zuläßt.

Diese Dokumentation ist nicht so ausführlich wie die entsprechende Fortran Doku, deswegen ist ein Studium des entsprechenden Quelltextes unumgänglich (insbesondere die Headerdatei eas3llc.h sollte man sich anschauen). Es wird nur das User Interface dokumentiert, nicht jedoch interne Routinen oder das erweiterte User Interface.

Datenstrukturen

Die Bibliotheksroutinen arbeiten im wesentlichen mit zwei Datenstrukturen, dies sind "Kennsätze" (eas3Hdr) und "Parameter" (eas3Par).

Der Kennsatz entspricht weitgehend dem aus dem Fortran-Modul (eas3ks_t); geändert werden musste der Name für das benutzerdefinierte Integerfeld (Fortran90: ks%if), weil sich der Compiler nicht mit dem Namen if anfreunden wollte. Daher heißen die benutzerdefinierten Felder ucf, uif und urf. Zusätzlich zu den gleichen Daten wie eas3ks_t besitzt der C-Kennsatz eas3Hdr jedoch noch zwei Felder, die die Namen und Grössen der fünf Dateidimensionen (Zeitindex, Parameter, Dimensionen 1..3) enthalten. Dies ist sehr nützlich bei Schleifen über mehrere dieser Dimensionen.

Der eas3Par-Datentyp dient dazu, alle Operationen auf die Daten selbst von deren Typ (single/double/quadruple precision) unabhängig zu machen.

Die wichstigsten Datenstrukturen sind im Folgenden aus der Headerdatei eas3llc.h entnommen:

/*-------------------- eas3Hdr -----------------------------*/
typedef struct
{
  char eas3id[EAS3KENNLEN+1];

  eas3Dform dform;
  eas3Bform bform;

  Int64 nzs;
  Int64 npar;
  Int64 ndim1, ndim2, ndim3;

  Int64 *zsf;

  eas3AttrMode amode;

  char **zsattr;
  char **parattr;
  char dim1attr[ATTRLEN+1];
  char dim2attr[ATTRLEN+1];
  char dim3attr[ATTRLEN+1];

  eas3GeomMode gmode[5];
  Int64 ng[5];
  Float64 **gf;

  eas3UdefMode umode;
  Int64 nu[3];
 
  char **ucf;
  Int64 *uif;
  Float64 *urf;

  /* Zusaetzliche Informationen, werden nicht in der Datei gespeichert */
  char **dimname;
  Int64 dimsize[5];
  Int64 len;

} eas3Hdr;



/*-------------------- eas3Par -----------------------------*/
typedef struct
{
  /* Typ und Groesse */
  eas3Bform type;
  Int32 dim1, dim2, dim3;
  Int32 bytes, count, itemsize;

  /* Arrays */
  Float32 *f;
  Float64 *d;
  Float128 *q;
  
  /* void-pointer auf Datenblock fuer fread/fwrite */
  void *vp;
} eas3Par;


/* --------------- Konstanten fuer EAS3 --------------------*/

/* eas3Dform */
typedef enum {EAS2=1, EAS3} eas3Dform;

/* eas3Bform */
typedef enum {IEEES=1, IEEED, IEEEQ} eas3Bform;

/* eas3AttrMode */
typedef enum {EAS3_NO_ATTR=1, EAS3_ALL_ATTR} eas3AttrMode;

/* eas3GeomMode */
typedef enum {EAS3_NO_G=1, EAS3_X0DX_G, EAS3_UDEF_G, EAS3_ALL_G} eas3GeomMode;

/* eas3UdefMode */
typedef enum {EAS3_NO_UDEF=1, EAS3_ALL_UDEF, EAS3_INT_UDEF} eas3UdefMode;

/* eas3OpenMode */
typedef enum {EAS3_CLOSED=0, EAS3_RO, EAS3_WO, EAS3_RW, EAS3_WRA} eas3OpenMode;

/* eas3ReordMode */
typedef enum {EAS3_NOREORD=0, EAS3_CORD_XY, EAS3_CORD_YX} eas3ReordMode;

Zahlenformate

Weil die C-Zahlenformate je nach Rechner verschieden viel Platz belegen, werden in eas3llc.h neue Typen definiert, die unabhängig von der Rechnerarchitektur feste Längen haben. Soll die Bibliothek auf eine weitere Maschine portiert werden, müssen hier entsprechende zusätzliche Einträge vorgenommen werden. Der ganze restliche Code ist damit frei von Hardware-Abängigkeiten (hoffe ich).

Beispiel:

     #define Int32             int
     #define Int64             long long int
     #define Float32           float
     #define Float64           double
     #define Float128          long double
     #define QUAD_SUPPORT      1
    

Die Konstante QUAD_SUPPORT gibt an, ob der grösste Typ wirklich 128bit lang ist oder (wie z.B. auf Cray) nicht. Diese Konstante entscheided, ob 128bit Zahlen überhaupt gelesen werden können oder nicht. Betriebssystemabhängig sind leider auch die Aufrufe von ftell/fseek für große Dateien sowie der Typ für Dateioffsets. Bei Bedarf werden diese Namen also an gleicher Stelle umdefiniert.

Hinweise zur Verwendung

Fast alle Routinen manipulieren Pointer, damit nicht (potenziell große) Parameterfelder in den Stack und wieder heraus kopiert werden müssen. Bei Zuweisungen wie

eas3Par *prm1;
eas3Par *prm2;

....

prm1 = prm2; /* Pointerkopie */

ist daher Vorsicht geboten; es handelt sich um das Kopieren von Pointern, wobei vermutlich eher

eas3_copyPar(prm1, prm2); /* Inhalt kopieren */

erreicht werden sollte.

Da alle internen Strings dynamisch verwaltet werden, müssen sie mit den str...() Funktionen aus <string.h> bearbeitet werden (strcat, strcpy,...). Eine Zuweisung wie dfile->hdr.parattr[3] = "w_xx" ändert dummerweise nicht nur den Inhalt des allokierten Strings, sondern biegt auch dessen Pointer um, sodass der dann ziemlich sicher nicht mehr auf einen Speicherbereich der richtigen Länge (hier: ATTRLEN+1) zeigt. Empfehlenswerte Alternative für Zuweisungen wäre sprintf(dfile->hdr.parattr[3], "w_xx");

Make

Vor dem Build bitte die der Architektur entsprechende Zeile im Kopf des Makefile auskommentieren. Wenn als default-Fliesskommazahlformat nicht "double" verwendet werden soll, kann die entsprechende #define DefaultFloat double Direktive auch nocht geändert werden.

In eigenen Programmen muss dann mit #include <eas3llc.h> der Header eigebunden werden und beim Linken die Bibliothek mit angegeben werden: cc -O2 prog.c -o prog -leas3llc . Den eas3llc.h - Header bitte nach etwaigen Systemheadern (stdio.h & Co.) einbinden, da er bei manchen Systemen deren #defines überschreiben muss.


Bibliotheksroutinen

Kennsatz

Daten

Dateien


Kurzbeschreibung der Funktionen

Funktionen mit Rückgabetyp 'Int32' geben EAS3_SUCCESS bzw. EAS3_FAILURE zurück, sofern nicht anders angegeben.

Es werden maximal EAS3_MAXFILES+1 Dateien verwaltet. Die zulässigen Dateinummern liegen im Bereich 0..EAS3_MAXFILES.

Beispiele zur Verwendung der Routinen sind in den Demoprogrammen create.c und avg.c zu finden, die mit der Bibliothek eas3llc zusammen compiliert werden.


Kennsatz


eas3_writeHdr

Int32 eas3_writeHdr(const Int32 filenr, const char *fn, eas3Hdr *hdr, eas3OpenMode mode)

Öffnet die Datei und schreibt den Kennsatz hdr auf die Datei mit dem Namen fn und der Nummer filenr. Die Datei wird im Modus mode geöffnet.

Verfügbare Modi sind:

EAS3_WO write-only
EAS3_RW read-write
EAS3_WRA read-write / random-access

Der letzte Modus beschreibt die Datei beim Öffnen vollständig mit Nullen, was bei sehr großen Dateien entsprechend lange dauert. Dadurch wird erreicht, dass jede Dateiposition direkt ansprechbar ist (random access). Wird eine neue Datei nicht mit EAS3_WRA geöffnet, ist nur sequentielles Schreiben möglich, da nicht ohne weiteres hinter das aktuelle EOF geschrieben werden kann.


eas3_readHdr

eas3Hdr *eas3_readHdr(const Int32 filenr, const char *fn, eas3OpenMode mode)

Öffnet die Datei und liest den Kennsatz hdr von der Datei mit dem Namen fn und der Nummer filenr. Die Datei wird im Modus mode geöffnet.

Verfügbare Modi sind:

EAS3_RO write-only
EAS3_RW read-write

eas3_newHdr

void eas3_newHdr(eas3Hdr *hdr)

Diese Routine allokiert den Speicher für die Felder innerhalb des Kennsatzes. Die Elemente, welche die Felddimensionen beschreiben, müssen bereits mit sinnvollen Werten belegt sein. Alle Feldeinträge werden mit den entsprechenden Defaultwerten (wie im Fortran-Modul beim Aufruf von eas3getks) belegt.

Beispiel:

  eas3Hdr *ks;

  /* Dimensionierung festlegen */

  ks->dform = EAS3;
  ks->bform = IEEED;
  ks->nzs = 12;
  ks->npar = 60;
  ks->ndim1 = 100;
  ks->ndim2 = 10;
  ks->ndim3 = 10;

  ks->amode = EAS3_ALL_ATTR;

  ks->umode = EAS3_ALL_UDEF;
  ks->nu[0] = 3;
  ks->nu[1] = 5;
  ks->nu[2] = 9;

  for (i=0; i<5; i++)
    {
      ks->gmode[i] = EAS3_UDEF_G;
      ks->ng[i] = 4;
    }

  /* Speicher fuer Feldeintraege allokieren und Defaultwerte setzen */

  eas3_newHdr(ks);

  /* Ab hier koennen die dynamischen Felder belegt werden, z.B.: */

  for (i=0; i<fs->hdr.npar; i++)
    sprintf(fs->hdr.parattr[i], "par %d", i+1);

eas3_freeHdr

void eas3_freeHdr(eas3Hdr **hdr)

Gibt den mit eas3_newHdr reservierten Speicher für die Feldelemente des Kennsatzes wieder frei und setzt anschließend den Pointer auf NULL.


eas3_getHdr

eas3Hdr *eas3_getHdr(const Int32 filenr)

Liefert den Header zur Datei mit der Nummer filenr. Die Datei muß vorher durch eas3_readHdr oder eas3_writeHdr geöffnet worden sein.


eas3_copyHdr

eas3Hdr *eas3_copyHdr(eas3Hdr *src)

Liefert eine Kopie des Kennsatzes src auf den neuen Kennsatz zurück. Der neue Kennsatz wird vollständig allokiert und der Inhalt des Quellkennsatzes kopiert.


eas3_printHdr

void eas3_printHdr(eas3Hdr *hdr, FILE* fp)

Druckt den übergebenen Kennsatz hdr auf die Datei fp (auch stdout möglich).


Daten


eas3_writePar

void eas3_writePar(const Int32 filenr, eas3Par *prm, Int32 zs, Int32 par)

Schreibt den Parameter prm auf die Datei mit der Nummer filenr, an die Position Zeitindex zs, Parameter par. Sollte der Parameter ein anderes Binärformat aufweisen als die Datei, wird automatisch konvertiert.


eas3_writeParSeq

void eas3_writeParSeq(const Int32 filenr, eas3Par *prm)

Schreibt den Parameter prm auf die Datei mit der Nummer filenr. Der Parameter wird entsprechend sequentieller Reihenfolge geschrieben. Sollte der Parameter ein anderes Binärformat aufweisen als die Datei, wird automatisch konvertiert.


eas3_readPar

eas3Par *eas3_readPar(const Int32 filenr, const Int32 zs, const Int32 par)

Liest einen Parameter von der angegebenen Position (zs, par) der Datei mit der Dateinummer filenr. Der gelesene Parameter wird als interner Parameter in die interne Dateiliste geschrieben. Zur Bequemlichkeit wird auch der Pointer auf den Parameter mit zurückgegeben.


eas3_readParSeq

eas3Par *eas3_readParSeq(const Int32 filenr)

Liest den nächsten Parameter von der Datei mit der Nummer filenr. Der gelesene Parameter wird als interner Parameter in die interne Dateiliste geschrieben. Zur Bequemlichkeit wird auch der Pointer auf den Parameter mit zurückgegeben.


eas3_newPar

eas3Par *eas3_newPar(const eas3Bform type, Int32 i, Int32 j, Int32 k)

Allokiert einen neuen Parameter im Binärformat type mit den Dimensionen i, j, k (dim1, dim2, dim3).


eas3_freePar

void eas3_freePar(eas3Par **p)

Deallokiert den Speicher des Parameters und setzt den Zeiger auf NULL.


eas3_getPar

eas3Par *eas3_getPar(const Int32 filenr)

Liefert den aktuellen internen Parameter zur Datei mit der Nummer filenr zurück.


eas3_copyPar

void eas3_copyPar(eas3Par *src, eas3Par *dst, const eas3reordMode reord)

Kopiert den Inhalt von src nach dst. Beide Parameter müssen dazu allokiert sein. Es können auch (evtl. Verlust an Genauigkeit und Wertebereich) Parameter verschiedenen Binärformats aufeinander kopiert werden. Mit dem Modusschalter reord kann die Anordnung der Daten auf dem Ausgabeparameter geändert werden.

Verwendbare Anordnungsmodi:

Modus Bedeutung
EAS3_NOREORD Daten in Fortran-Anordung auf dem Feld (erster Index ändert sich am schnellsten)
EAS3_CORD_XY Daten in C-Anordnung auf dem Feld (letzter Index ändert sich am schnellsten)
EAS3_CORD_YX Spezialmodus für Benutzung in x3dp (bzgl. der Fortran-Anordnung 1. und 2. Dimension vertauscht; 3. Dimension nach vorne geholt)

eas3_printPar

void eas3_printPar(eas3Par *prm, const char *fn)

Druckt den übergebenen Parameter prm auf die Datei fp (auch stdout möglich).


Dateien


eas3_closeFile

void eas3_closeFile(const Int32 filenr)

Schließt die Datei mit der Nummer filenr.


eas3_removeFile

void eas3_removeFile(const Int32 filenr)

Schließt gegebenenfalls die Datei mit der Nummer filenr und entfernt die Datei vom Dateissytem.


eas3_getFileName

char *eas3_getFileName(const Int32 filenr)

Liefert den Dateinamen zur Datei mit der Nummer filenr.


eas3_getFileLen

Int64 eas3_getFileLen(const Int32 filenr)

Liefert die Dateilänge in Byte zur Datei mit der Nummer filenr.


aktuelle Version

Hier steht eine aktuelle Version zum Download bereit.

Version Datum Kommentar
1.0.0 17.01.2000 erste freigegebene Version
1.1.0 29.02.2000 Userinterfaces des Moduls komplett überarbeitet und auf Form analog zum Fortran-Interface mit Dateinummern umgestellt.
1.2.0 15.05.2000 Möglichkeit zum Umsortieren der Daten auf den Parametern in C-Anordnung implementiert.
1.3.0 07.06.2000 Umstellung auf EAS3_I8R8-Kennsatz (8-Byte-Typen im Kennsatz).
1.3.1 02.07.2000 Fehler bei Speicherallokierung für Geometriefelder behoben.