diff options
Diffstat (limited to 'app/eudas/4.4/src/eudas.dateistruktur')
-rw-r--r-- | app/eudas/4.4/src/eudas.dateistruktur | 1690 |
1 files changed, 1690 insertions, 0 deletions
diff --git a/app/eudas/4.4/src/eudas.dateistruktur b/app/eudas/4.4/src/eudas.dateistruktur new file mode 100644 index 0000000..b4a57e5 --- /dev/null +++ b/app/eudas/4.4/src/eudas.dateistruktur @@ -0,0 +1,1690 @@ +PACKET eudas dateien + +(*************************************************************************) +(* *) +(* EUDAS-Dateien als indexsequentielle Dateien *) +(* *) +(* Version 05 *) +(* *) +(* Autor: Thomas Berlage *) +(* Stand: 25.04.87 *) +(* *) +(*************************************************************************) + + DEFINES + + EUDAT, +(*dump, Test *) + oeffne, + satznr, + dateiende, + saetze, + auf satz, + weiter, + zurueck, + satz lesen, + satz aendern, + satz loeschen, + satz einfuegen, + feld lesen, + feld aendern, + feld bearbeiten, + felderzahl, + feldnamen lesen, + feldnamen aendern, + notizen lesen, + notizen aendern, + feldinfo, + automatischer schluessel, + dezimalkomma, + wert berechnen, + reorganisiere, + sortiere, + sortierreihenfolge, + unsortierte saetze : + + +LET + maxhash = 531, + maxindex = 121, + maxsatz = 5000, + eudat typ = 3243, + maxeintrag = 64, + dreiviertel maxeintrag = 48; + +LET + INTVEC = TEXT, + + INDEX = STRUCT + (INT vorgaenger, nachfolger, + INT eintraege, stelle, + INTVEC satzindex), + + EINTRAG = STRUCT + (INT vorgaenger, nachfolger, indexblock, attribut, + SATZ satz), + + DATEI = STRUCT + (INT felderzahl, + SATZ feldnamen, + INTVEC feldinfo, + TEXT sortierfelder, + INT letzter index, indexblocks, erster leerindex, + INT erster leersatz, anz satzeintraege, + INT anz saetze, satznr, + INT indexzeiger, indexstelle, satzzeiger, + INT anz unsortierte, schluesselzaehler, + ROW 3 TEXT notizen, + ROW maxhash INT hashliste, + ROW maxindex INDEX index, + ROW maxsatz EINTRAG ablage); + +TYPE EUDAT = BOUND DATEI; + +LET + niltext = ""; + +LET + datei ist keine eudas datei = #201# + "Datei ist keine EUDAS-Datei", + inkonsistente datei = #202# + "inkonsistente EUDAS-Datei", + eudas datei voll = #203# + "EUDAS-Datei voll", + nicht erlaubtes dezimalkomma = #204# + "Nicht erlaubtes Dezimalkomma"; + +TEXT VAR + feldpuffer; + +TEXT VAR + inttext := " "; + +INTVEC CONST + blockreservierung := intvec (maxeintrag, 1); + + +(*************************** Test-Dump ***********************************) +(* +PROC dump (EUDAT CONST datei, TEXT CONST file) : + + FILE VAR f := sequential file (output, file); + idump (CONCR (datei), f) + +END PROC dump; + +PROC idump (DATEI CONST datei, FILE VAR f) : + + put (f, "Felderzahl:"); put (f, datei. felderzahl); line (f); + INT VAR i; putline (f, "feldnamen:"); + FOR i FROM 1 UPTO felderzahl (datei. feldnamen) REP + TEXT VAR feld; feld lesen (datei. feldnamen, i, feld); + write (f, feld); write (f, ",") + END REP; line (f); putline (f, "feldinfo:"); + FOR i FROM 1 UPTO length (datei. feldinfo) DIV 2 REP + put (f, datei. feldinfo ISUB i) + END REP; line (f); + put (f, "letzter index:"); put (f, datei. letzter index); + put (f, "indexblocks:"); put (f, datei. indexblocks); + put (f, "erster leerindex:"); put (f, datei. erster leerindex); line (f); + put (f, "erster leersatz:"); put (f, datei. erster leersatz); + put (f, "anz satzeintraege:"); put (f, datei. anz satzeintraege); line (f); + put (f, "anz saetze:"); put (f, datei. anz saetze); + put (f, "satznr:"); put (f, datei.satznr); line (f); + put (f, "indexzeiger:"); put (f, datei. indexzeiger); + put (f, "indexstelle:"); put (f, datei. indexstelle); + put (f, "satzzeiger:"); put (f, datei. satzzeiger); line (f); + put (f, "anz unsortierte:"); put (f, datei. anz unsortierte); line (f); + ROW 10 INT VAR anzahl ketten; + FOR i FROM 1 UPTO 10 REP anzahl ketten (i) := 0 END REP; + FOR i FROM 1 UPTO maxhash REP + INT VAR laenge := 0; + laenge der hashkette bestimmen; + IF laenge > 10 THEN laenge := 10 END IF; + IF laenge > 0 THEN anzahl ketten (laenge) INCR 1 END IF + END REP; + put (f, "Hash:"); + FOR i FROM 1 UPTO 10 REP put (f, anzahl ketten (i)) END REP; line (f); + FOR i FROM 1 UPTO datei. indexblocks REP + put (f, "INDEX"); put (f, i); put (f, "vor:"); put (f, + datei. index (i). vorgaenger); put (f, "nach:"); put (f, + datei. index (i). nachfolger); put (f, "eintraege:"); put (f, + datei. index (i). eintraege); line (f); INT VAR j; + FOR j FROM 1 UPTO length (datei. index (i). satzindex) DIV 2 REP + put (f, datei. index (i). satzindex ISUB j) + END REP; + line (f) + END REP; + FOR i FROM 1 UPTO datei. anz satzeintraege REP + put (f, "SATZ"); put (f,i); put (f, "vor:"); put (f, + datei. ablage (i). vorgaenger); put (f, "nach:"); put (f, + datei. ablage (i). nachfolger); put (f, "index:"); put (f, + datei. ablage (i). indexblock); put (f, "attr:"); put (f, + datei. ablage (i). attribut); line (f); + FOR j FROM 1 UPTO felderzahl (datei. ablage (i). satz) REP + feld lesen (datei. ablage (i). satz, j, feld); + write (f, feld); write (f, ",") + END REP; cout (i); + line (f) + END REP . + +laenge der hashkette bestimmen : + INT VAR index := datei. hashliste (i); + WHILE index <> 0 REP + index := datei. ablage (index). vorgaenger; + laenge INCR 1 + END REP . + +END PROC i dump; +*) + +(**************************** INTVEC *************************************) + +(* An Stelle von maximal dimensionierten ROW max INT werden an ver- *) +(* schiedenen Stellen TEXTe mit eingeschriebenen Integern verwendet. *) +(* Auf diese Art und Weise werden auch das Einfuegen und Loeschen, sowie *) +(* das Aufsplitten und Zusammenfuegen effizienter realisiert. *) + +LET + empty intvec = ""; + +TEXT VAR + buffer; + +INTVEC PROC intvec (INT CONST length, value) : + + replace (inttext, 1, value); + length * inttext + +END PROC intvec; + +PROC insert (INTVEC VAR vector, INT CONST pos, value) : + + INT CONST begin := pos + pos - 1; + IF begin < 1 THEN + subscript underflow + ELIF begin > length (vector) + 1 THEN + subscript overflow + ELSE + replace (inttext, 1, value); + buffer := subtext (vector, begin); + vector := subtext (vector, 1, begin - 1); + vector CAT inttext; + vector CAT buffer + END IF + +END PROC insert; + +PROC delete (INTVEC VAR vector, INT CONST pos) : + + INT CONST begin := pos + pos - 1; + IF begin < 1 THEN + subscript underflow + ELIF begin >= length (vector) THEN + subscript overflow + ELSE + buffer := subtext (vector, begin + 2); + vector := subtext (vector, 1, begin - 1); + vector CAT buffer + END IF + +END PROC delete; + +INT PROC pos (INTVEC CONST vector, INT CONST value) : + + replace (inttext, 1, value); + INT VAR begin := 1; + REP + begin := pos (vector, inttext, begin) + 1 + UNTIL (begin AND 1) = 0 OR begin = 1 END REP; + begin DIV 2 + +END PROC pos; + +PROC split up (INTVEC VAR source, dest, INT CONST pos) : + + INT CONST begin := pos + pos - 1; + IF begin < 1 THEN + subscript underflow + ELIF begin > length (source) + 1 THEN + subscript overflow + ELSE + dest := subtext (source, begin); + source := subtext (source, 1, begin - 1) + END IF + +END PROC split up; + +PROC split down (INTVEC VAR source, dest, INT CONST pos) : + + INT CONST begin := pos + pos - 1; + IF begin < 1 THEN + subscript underflow + ELIF begin > length (source) + 1 THEN + subscript overflow + ELSE + dest := subtext (source, 1, begin - 1); + source := subtext (source, begin) + END IF + +END PROC split down; + +. +subscript overflow : + errorstop (9, niltext) . + +subscript underflow : + errorstop (10, niltext) . + + +(************************** Datei oeffnen ********************************) + +PROC initialisiere eudat (DATEI VAR datei) : + + datei. felderzahl := 0; + datei. feldinfo := empty intvec; + satz initialisieren (datei. feldnamen); + datei. sortierfelder := niltext; + datei. letzter index := 1; + datei. indexblocks := 1; + datei. erster leersatz := 0; + datei. erster leerindex := 0; + datei. anz saetze := 0; + datei. anz satzeintraege := 1; + datei. anz unsortierte := 0; + datei. notizen (1) := niltext; + datei. notizen (2) := niltext; + datei. notizen (3) := niltext; + datei. satznr := 1; + datei. indexzeiger := 1; + datei. indexstelle := 1; + datei. satzzeiger := 1; + datei. index (1). satzindex := blockreservierung; + datei. index (1) := INDEX : (0, 0, 1, 1, intvec(1, 1)); + INT VAR i; + FOR i FROM 1 UPTO maxhash REP + datei. hashliste (i) := 0 + END REP; + datei. ablage (1) := EINTRAG : (0, 0, 1, 0, leersatz) . + +leersatz : + datei. feldnamen . + +END PROC initialisiere eudat; + +PROC oeffne (EUDAT VAR datei, TEXT CONST dateiname) : + + enable stop; + IF NOT exists (dateiname) THEN + CONCR (datei) := new (dateiname); + initialisiere eudat (CONCR (datei)); + type (old (dateiname), eudat typ) + ELIF type (old (dateiname)) = eudat typ THEN + CONCR (datei) := old (dateiname) + ELSE + errorstop (datei ist keine eudas datei) + ENDIF + +END PROC oeffne; + +PROC oeffne (EUDAT VAR datei, DATASPACE CONST ds) : + + IF type (ds) < 0 THEN + CONCR (datei) := ds; + initialisiere eudat (CONCR (datei)); + type (ds, eudat typ) + ELIF type (ds) = eudat typ THEN + CONCR (datei) := ds + ELSE + errorstop (datei ist keine eudas datei) + END IF + +END PROC oeffne; + + +(************************* Feldzugriffe **********************************) + +PROC feld lesen (EUDAT CONST datei, INT CONST feldnr, TEXT VAR inhalt) : + + feld lesen (aktueller satz, feldnr, inhalt) . + +aktueller satz : + datei. ablage (datei. satzzeiger). satz . + +END PROC feld lesen; + +PROC feld aendern (EUDAT VAR datei, INT CONST feldnr, + TEXT CONST neuer inhalt) : + + IF nicht hinter letztem satz THEN + aktueller satz unsortiert (CONCR (datei)); + moeglicherweise schluessel aendern; + feld aendern (aktueller satz, feldnr, neuer inhalt) + END IF . + +nicht hinter letztem satz : + datei. satzzeiger <> 1 . + +moeglicherweise schluessel aendern : + IF feldnr = 1 THEN + disable stop; + schluessel aendern (CONCR (datei), hashindex (neuer inhalt)) + END IF . + +aktueller satz : + datei. ablage (datei. satzzeiger). satz . + +END PROC feld aendern; + +INT PROC felderzahl (EUDAT CONST datei) : + + datei. felderzahl + +END PROC felderzahl; + +PROC feld bearbeiten (EUDAT CONST datei, INT CONST feldnr, + PROC (TEXT CONST, INT CONST, INT CONST) bearbeite) : + + feld bearbeiten (aktueller satz, feldnr, + PROC (TEXT CONST, INT CONST, INT CONST) bearbeite) . + +aktueller satz : + datei. ablage (datei. satzzeiger). satz . + +END PROC feld bearbeiten; + + +(************************* Feldinformationen *****************************) + +(* Jedes Feld der Datei hat einen Namen und eine Typinformation. Die *) +(* Anzahl der vorhandenen Felder richtet sich nach dem hoechsten ver- *) +(* gebenen Feldnamen. 'feldinfo' kann folgende Werte annehmen : *) +(* -1 : normales Textfeld *) +(* 0 : Textfeld, das nach DIN-Norm verglichen wird *) +(* 1 : Zahlfeld (alle irrelevanten Zeichen werden ignoriert) *) +(* 2 : Datum mit einer Laenge von 8 Zeichen *) +(* Das Feldinfo eines noch nicht eingerichteten Feldes fuehrt zu *) +(* einer Fehlermeldung. *) + +PROC feldnamen lesen (EUDAT CONST datei, SATZ VAR namen) : + + namen := datei. feldnamen + +END PROC feldnamen lesen; + +PROC feldnamen aendern (EUDAT VAR datei, SATZ CONST neue namen) : + + datei. feldnamen := neue namen; + INT CONST neue felder := felderzahl (neue namen); + IF neue felder > datei. felderzahl THEN + feldinfo erweitern; + datei. felderzahl := neue felder + END IF . + +feldinfo erweitern : + datei. feldinfo CAT intvec (fehlende zeilen, - 1) . + +fehlende zeilen : + neue felder - length (datei. feldinfo) DIV 2. + +END PROC feldnamen aendern; + +INT PROC feldinfo (EUDAT CONST datei, INT CONST feldnr) : + + datei. feldinfo ISUB feldnr + +END PROC feldinfo; + +PROC feldinfo (EUDAT VAR datei, INT CONST feldnr, zeilen) : + + replace (datei. feldinfo, feldnr, zeilen); + IF pos (datei. sortierfelder, code (feldnr)) > 0 THEN + datei. anz unsortierte := datei. anz saetze + END IF + +END PROC feldinfo; + + +(*************************** Positionsabfragen ***************************) + +INT PROC satznr (EUDAT CONST datei) : + + datei. satznr + +END PROC satznr; + +BOOL PROC dateiende (EUDAT CONST datei) : + + datei. satznr > datei. anz saetze + +END PROC dateiende; + +INT PROC saetze (EUDAT CONST datei) : + + datei. anz saetze + +END PROC saetze; + + +(***************************** Positionieren *****************************) + +(* Positioniert werden kann nach der Satznummer oder nach dem ersten *) +(* Feld. Das erste Feld kann durch eine Hashtabelle schnell gefunden *) +(* werden. In der Hashtabelle sind die Saetze nach absoluten Positionen *) +(* eingetragen und nicht nach Satznummern. Ueber den Rueckverweis auf *) +(* den Indexblock kann die Satznummer zu einem gegebenen Satz gefunden *) +(* werden. *) + +PROC neue satzposition (DATEI VAR datei, INT CONST indexzeiger, stelle, + satznr) : + + IF indexzeiger < 1 OR indexzeiger > datei. indexblocks COR + stelle < 1 OR stelle > datei. index (indexzeiger). eintraege THEN + errorstop (inkonsistente datei) + END IF; + disable stop; + datei. indexzeiger := indexzeiger; + datei. indexstelle := stelle; + datei. satznr := satznr; + datei. satzzeiger := datei. index (indexzeiger). satzindex ISUB stelle + +END PROC neue satzposition; + +PROC auf satz (EUDAT VAR datei, INT CONST nr) : + + INT VAR satznr; + IF nr < 1 THEN + satznr := 1 + ELIF nr > datei. anz saetze THEN + satznr := datei. anz saetze + 1 + ELSE + satznr := nr + END IF; + auf satz intern (CONCR (datei), satznr) + +END PROC auf satz; + +PROC auf satz (EUDAT VAR datei, TEXT CONST muster) : + + auf satz (datei, 1); + IF nicht auf erstem satz THEN + weiter (datei, muster) + END IF . + +nicht auf erstem satz : + feld lesen (datei, 1, feldpuffer); + feldpuffer <> muster . + +END PROC auf satz; + +PROC auf satz intern (DATEI VAR datei, INT CONST satznr) : + + IF von anfang naeher THEN + neue satzposition (datei, 1, 1, 1) + END IF; + INT VAR + indexzeiger := datei. indexzeiger, + erreichter satz := datei. satznr - datei. indexstelle; + IF satznr > datei. satznr THEN + vorwaerts gehen + ELSE + rueckwaerts gehen + END IF; + neue satzposition (datei, indexzeiger, stelle, satznr) . + +von anfang naeher : + satznr + satznr < datei. satznr . + +vorwaerts gehen : + WHILE noch vor satz REP + erreichter satz INCR eintraege; + indexzeiger := datei. index (indexzeiger). nachfolger + END REP . + +noch vor satz : + INT CONST eintraege := datei. index (indexzeiger). eintraege; + erreichter satz + eintraege < satznr . + +rueckwaerts gehen : + WHILE noch hinter satz REP + indexzeiger := datei. index (indexzeiger). vorgaenger; + erreichter satz DECR datei. index (indexzeiger). eintraege + END REP . + +noch hinter satz : + erreichter satz >= satznr . + +stelle : + satznr - erreichter satz . + +END PROC auf satz intern; + +PROC weiter (EUDAT VAR datei) : + + weiter intern (CONCR (datei)) + +END PROC weiter; + +PROC weiter intern (DATEI VAR datei) : + + IF nicht dateiende THEN + naechster satz + END IF . + +nicht dateiende : + datei. satzzeiger <> 1 . + +naechster satz : + INT VAR + indexzeiger := datei. indexzeiger, + stelle := datei. indexstelle; + + IF stelle = index. eintraege THEN + indexzeiger := index. nachfolger; + stelle := 1 + ELSE + stelle INCR 1 + END IF; + neue satzposition (datei, indexzeiger, stelle, datei. satznr + 1) . + +index : + datei. index (indexzeiger) . + +END PROC weiter intern; + +PROC zurueck (EUDAT VAR datei) : + + zurueck intern (CONCR (datei)) + +END PROC zurueck; + +PROC zurueck intern (DATEI VAR datei) : + + IF nicht am anfang THEN + voriger satz + END IF . + +nicht am anfang : + datei. satznr <> 1 . + +voriger satz : + INT VAR + indexzeiger := datei. indexzeiger, + stelle := datei. indexstelle; + + IF stelle = 1 THEN + indexzeiger := indexblock. vorgaenger; + stelle := indexblock. eintraege + ELSE + stelle DECR 1 + END IF; + neue satzposition (datei, indexzeiger, stelle, datei. satznr - 1) . + +indexblock : + datei. index (indexzeiger) . + +END PROC zurueck intern; + +PROC weiter (EUDAT VAR datei, TEXT CONST muster) : + + weiter intern (CONCR (datei), muster) + +END PROC weiter; + +PROC weiter intern (DATEI VAR datei, TEXT CONST muster) : + + stelle in hashkette bestimmen; + WHILE noch weitere saetze CAND muster nicht gefunden REP + eine stelle weiter + END REP; + IF noch weitere saetze THEN + positioniere intern (datei, stelle) + ELSE + auf satz intern (datei, datei. anz saetze + 1) + END IF . + +stelle in hashkette bestimmen : + INT VAR dummy, stelle := datei. satzzeiger; + IF muster nicht gefunden THEN + stelle in hashkette (datei, hashindex (muster), stelle, dummy) + ELSE + eine stelle weiter + END IF . + +noch weitere saetze : + stelle <> 0 . + +muster nicht gefunden : + feld lesen (aktueller satz, 1, feldpuffer); + feldpuffer <> muster . + +aktueller satz : + datei. ablage (stelle). satz . + +eine stelle weiter : + stelle := datei. ablage (stelle). nachfolger . + +END PROC weiter intern; + +PROC zurueck (EUDAT VAR datei, TEXT CONST muster) : + + zurueck intern (CONCR (datei), muster) + +END PROC zurueck; + +PROC zurueck intern (DATEI VAR datei, TEXT CONST muster) : + + stelle in hashkette bestimmen; + WHILE noch weitere saetze CAND muster nicht gefunden REP + eine stelle zurueck + END REP; + IF noch weitere saetze THEN + positioniere intern (datei, stelle) + ELSE + auf satz intern (datei, 1) + END IF . + +stelle in hashkette bestimmen : + INT VAR stelle := datei. satzzeiger, dummy; + IF stelle = 1 OR schluessel stimmt nicht ueberein THEN + stelle in hashkette (datei, hashindex (muster), dummy, stelle) + END IF . + +noch weitere saetze : + stelle <> 0 . + +muster nicht gefunden : + stelle = datei. satzzeiger OR schluessel stimmt nicht ueberein . + +schluessel stimmt nicht ueberein : + feld lesen (aktueller satz, 1, feldpuffer); + feldpuffer <> muster . + +aktueller satz : + datei. ablage (stelle). satz . + +eine stelle zurueck : + stelle := datei. ablage (stelle). vorgaenger . + +END PROC zurueck intern; + +PROC positioniere intern (DATEI VAR datei, INT CONST stelle) : + + INT CONST zielblock := datei. ablage (stelle). indexblock; + INT VAR + indexstelle := 1, + satznr := 0; + WHILE indexstelle <> zielblock REP + satznr INCR datei. index (indexstelle). eintraege; + indexstelle := datei. index (indexstelle). nachfolger + END REP; + indexstelle := pos (datei. index (zielblock). satzindex, stelle); + satznr INCR indexstelle; + neue satzposition (datei, zielblock, indexstelle, satznr) . + +END PROC positioniere intern; + + +(************************* Hashverwaltung ********************************) + +INT VAR index; + +PROC hashindex berechnen (TEXT CONST feld, INT CONST von, bis) : + + INT VAR + zeiger := von; + index := 0; + IF bis - von < 4 THEN + mit faktor 4 streuen + ELSE + mit faktor 2 streuen + END IF; + index := index MOD maxhash + 1 . + +mit faktor 4 streuen : + WHILE zeiger <= bis REP + index := index * 4; + index INCR code (feld SUB zeiger); + zeiger INCR 1 + END REP . + +mit faktor 2 streuen : + WHILE zeiger <= bis REP + index INCR index; + index INCR code (feld SUB zeiger); + IF index > 16000 THEN index := index MOD maxhash END IF; + zeiger INCR 1 + END REP . + +END PROC hashindex berechnen; + +INT PROC hashindex (TEXT CONST feld) : + + hashindex berechnen (feld, 1, length (feld)); + index + +END PROC hashindex; + +INT PROC hashindex (SATZ CONST satz) : + + feld bearbeiten (satz, 1, + PROC (TEXT CONST, INT CONST, INT CONST) hashindex berechnen); + index + +END PROC hashindex; + +PROC stelle in hashkette (DATEI CONST datei, INT CONST hashindex, + INT VAR stelle, vorher) : + + INT VAR indexzeiger := datei. letzter index; + vorher := datei. hashliste (hashindex); + stelle := 0; + BOOL VAR hinter aktuellem satz := TRUE; + WHILE hinter aktuellem satz AND vorher <> 0 REP + stelle untersuchen; + eine stelle weiter + END REP . + +stelle untersuchen : + IF verweis auf aktuellen block THEN + ueberpruefe innerhalb block + ELSE + teste ob aktueller block in indexkette + END IF . + +verweis auf aktuellen block : + datei. ablage (vorher). indexblock = datei. indexzeiger . + +ueberpruefe innerhalb block : + indexzeiger := datei. indexzeiger; + INT CONST stelle in block := pos (satzindex, vorher); + IF stelle in block = 0 THEN + errorstop (inkonsistente datei) + ELIF stelle in block <= aktuelle stelle THEN + hinter aktuellem satz := FALSE + END IF . + +satzindex : + datei. index (indexzeiger). satzindex . + +aktuelle stelle : + datei. indexstelle . + +teste ob aktueller block in indexkette : + WHILE indexzeiger <> datei. ablage (vorher). indexblock REP + IF indexzeiger = datei. indexzeiger THEN + hinter aktuellem satz := FALSE; + LEAVE stelle untersuchen + ELSE + indexzeiger := datei. index (indexzeiger). vorgaenger + END IF + END REP . + +eine stelle weiter : + IF hinter aktuellem satz THEN + stelle := vorher; + vorher := datei. ablage (stelle). vorgaenger + END IF . + +END PROC stelle in hashkette; + +PROC hash ausketten (DATEI VAR datei, INT CONST hashindex) : + + disable stop; + INT CONST + stelle := datei. satzzeiger, + vorgaenger := datei. ablage (stelle). vorgaenger, + nachfolger := datei. ablage (stelle). nachfolger; + + IF nachfolger <> 0 THEN + datei. ablage (nachfolger). vorgaenger := vorgaenger + ELSE + datei. hashliste (hashindex) := vorgaenger + END IF; + IF vorgaenger <> 0 THEN + datei. ablage (vorgaenger). nachfolger := nachfolger + END IF . + +END PROC hash ausketten; + +PROC hash einketten (DATEI VAR datei, INT CONST hashindex, + nachfolger, vorgaenger) : + + disable stop; + INT CONST stelle := datei. satzzeiger; + datei. ablage (stelle). vorgaenger := vorgaenger; + datei. ablage (stelle). nachfolger := nachfolger; + IF vorgaenger <> 0 THEN + datei. ablage (vorgaenger). nachfolger := stelle + END IF; + IF nachfolger <> 0 THEN + datei. ablage (nachfolger). vorgaenger := stelle + ELSE + datei. hashliste (hashindex) := stelle + END IF + +END PROC hash einketten; + + +(************************** Satzzugriffe *********************************) + +PROC satz lesen (EUDAT CONST datei, SATZ VAR satz) : + + satz := datei. ablage (datei. satzzeiger). satz + +END PROC satz lesen; + +PROC satz aendern (EUDAT VAR datei, SATZ CONST neuer satz) : + + IF NOT dateiende (datei) THEN + satz wirklich aendern + END IF . + +satz wirklich aendern : + aktueller satz unsortiert (CONCR (datei)); + disable stop; + schluessel aendern (CONCR (datei), hashindex (neuer satz)); + aktueller satz := neuer satz . + +aktueller satz : + datei. ablage (datei. satzzeiger). satz . + +END PROC satz aendern; + +PROC schluessel aendern (DATEI VAR datei, INT CONST neuer hashindex) : + + IF anderer hashindex THEN + in neue hashkette + END IF . + +anderer hashindex : + INT CONST alter hashindex := hashindex (aktueller satz); + alter hashindex <> neuer hashindex . + +in neue hashkette : + in alter kette ausketten; + in neuer kette einketten . + +in alter kette ausketten : + hash ausketten (datei, alter hashindex) . + +in neuer kette einketten : + INT VAR vorgaenger, nachfolger; + stelle in hashkette (datei, neuer hashindex, vorgaenger, nachfolger); + hash einketten (datei, neuer hashindex, vorgaenger, nachfolger) . + +aktueller satz : + datei. ablage (datei. satzzeiger). satz . + +END PROC schluessel aendern; + +PROC satz loeschen (EUDAT VAR datei) : + + IF NOT dateiende (datei) THEN + satz wirklich loeschen + END IF . + +satz wirklich loeschen : + disable stop; + satzeintrag loeschen (CONCR (datei)); + indexeintrag loeschen (CONCR (datei)); + datei. anz saetze DECR 1 . + +END PROC satz loeschen; + +PROC satzeintrag loeschen (DATEI VAR datei) : + + aktueller satz sortiert (datei); + INT CONST stelle := datei. satzzeiger; + hash ausketten (datei, hashindex (aktueller satz)); + datei. ablage (stelle). nachfolger := datei. erster leersatz; + datei. erster leersatz := stelle . + +aktueller satz : + datei. ablage (stelle). satz . + +END PROC satzeintrag loeschen; + +PROC satz einfuegen (EUDAT VAR datei, SATZ CONST neuer satz) : + + satz einfuegen intern (CONCR (datei), neuer satz) + +END PROC satz einfuegen; + +PROC satz einfuegen intern (DATEI VAR datei, SATZ CONST neuer satz) : + + INT VAR + stelle, + vorgaenger, + nachfolger; + + enable stop; + satzeintrag belegen; + ggf schluessel einfuegen; + disable stop; + datei. anz saetze INCR 1; + indexeintrag einfuegen (datei, stelle); + INT CONST neuer index := hashindex (feldpuffer); + stelle in hashkette (datei, neuer index, nachfolger, vorgaenger); + hash einketten (datei, neuer index, nachfolger, vorgaenger); + aktueller satz unsortiert (datei) . + +satzeintrag belegen : + IF datei. erster leersatz <> 0 THEN + stelle := datei. erster leersatz; + datei. erster leersatz := datei. ablage (stelle). nachfolger + ELIF datei. anz satzeintraege = maxsatz THEN + errorstop (eudas datei voll) + ELSE + datei. anz satzeintraege INCR 1; + stelle := datei. anz satzeintraege + END IF; + datei. ablage (stelle). attribut := 0; + datei. ablage (stelle). satz := neuer satz . + +ggf schluessel einfuegen : + feld lesen (neuer satz, 1, feldpuffer); + IF datei. schluesselzaehler > 0 THEN + IF feldpuffer = "" THEN + neuen schluessel erzeugen; + feld aendern (datei. ablage (stelle). satz, 1, feldpuffer) + END IF + END IF . + +neuen schluessel erzeugen : + feldpuffer := text (datei. schluesselzaehler); + feldpuffer := fuehrende nullen + feldpuffer; + IF datei. schluesselzaehler > 32000 THEN + datei. schluesselzaehler := 1 + ELSE + datei. schluesselzaehler INCR 1 + END IF . + +fuehrende nullen : + (4 - length (feldpuffer)) * "0" . + +END PROC satz einfuegen intern; + +PROC automatischer schluessel (EUDAT VAR eudat, BOOL CONST automatisch) : + + IF automatisch AND eudat. schluesselzaehler < 0 OR + NOT automatisch AND eudat. schluesselzaehler > 0 THEN + eudat. schluesselzaehler := - eudat. schluesselzaehler + END IF + +END PROC automatischer schluessel; + +BOOL PROC automatischer schluessel (EUDAT CONST eudat) : + + eudat. schluesselzaehler > 0 + +END PROC automatischer schluessel; + + +(************************* Indexverwaltung *******************************) + +(* Die logische Reihenfolge der Saetze wird durch einen Index herge- *) +(* stellt. Dieser besteht aus einer Liste von INTVECs. Ein Listenelement *) +(* nimmt Satzeintraege auf, bis die Maximalgroesse erreicht ist. In *) +(* diesem Fall wird ein neues Listenelement eingefuegt. Beim Loeschen *) +(* von Eintraegen wird ueberprueft, ob zwei benachbarte Eintraege kom- *) +(* biniert werden koennen. Steht fuer eine Anforderung kein Eintrag mehr *) +(* zur Verfuegung, wird der ganze Index reorganisiert. Es ist garantiert,*) +(* dass der Index die maximale Anzahl von Satzeintraegen aufnehmen kann. *) + +INTVEC VAR indexpuffer; + + +PROC indexeintrag loeschen (DATEI VAR datei) : + + INT CONST + indexzeiger := datei. indexzeiger, + vorgaenger := index. vorgaenger, + nachfolger := index. nachfolger; + BOOL VAR moeglich; + delete (index. satzindex, datei. indexstelle); + index. eintraege DECR 1; + indizes zusammenlegen (datei, indexzeiger, nachfolger, moeglich); + IF NOT moeglich THEN + indizes zusammenlegen (datei, vorgaenger, indexzeiger, moeglich) + END IF; + indexzeiger justieren (datei) . + +index : + datei. index (indexzeiger) . + +END PROC indexeintrag loeschen; + +PROC indizes zusammenlegen (DATEI VAR datei, INT CONST zeiger, folgezeiger, + BOOL VAR moeglich) : + + moeglich := FALSE; + IF zeiger <> 0 AND folgezeiger <> 0 THEN + versuche zusammenzulegen + END IF . + +versuche zusammenzulegen : + INT CONST + eintraege a := index. eintraege, + eintraege b := folgeindex. eintraege; + IF zusammenlegbar THEN + wirklich zusammenlegen; + moeglich := TRUE + END IF . + +zusammenlegbar: + eintraege a + eintraege b <= dreiviertel maxeintrag OR + eintraege a = 0 OR eintraege b = 0 . + +wirklich zusammenlegen : + index. eintraege INCR folgeindex. eintraege; + indexverweise aendern (datei, folgeindex. satzindex, zeiger); + index. satzindex CAT folgeindex. satzindex; + folgeindex ausketten . + +folgeindex ausketten : + index. nachfolger := folgeindex. nachfolger; + IF index. nachfolger <> 0 THEN + datei. index (index. nachfolger). vorgaenger := zeiger + ELSE + datei. letzter index := zeiger + END IF; + folgeindex. nachfolger := datei. erster leerindex; + datei. erster leerindex := folgezeiger . + +index : + datei. index (zeiger) . + +folgeindex : + datei. index (folgezeiger) . + +END PROC indizes zusammenlegen; + +PROC indexzeiger justieren (DATEI VAR datei) : + + INT CONST aktueller satz := datei. satznr; + neue satzposition (datei, 1, 1, 1); + auf satz intern (datei, aktueller satz) + +END PROC indexzeiger justieren; + +PROC indexverweise aendern (DATEI VAR datei, INTVEC CONST satzindex, + INT CONST zeiger) : + + INT VAR i; + FOR i FROM 1 UPTO length (satzindex) DIV 2 REP + datei. ablage (satzindex ISUB i). indexblock := zeiger + END REP + +END PROC indexverweise aendern; + +PROC indexeintrag einfuegen (DATEI VAR datei, INT CONST eintrag) : + + INT VAR indexzeiger := datei. indexzeiger; + IF index. eintraege >= maxeintrag THEN + platz schaffen + END IF; + index. eintraege INCR 1; + insert (index. satzindex, datei. indexstelle, eintrag); + datei. satzzeiger := eintrag; + datei. ablage (eintrag). indexblock := indexzeiger . + +platz schaffen : + INT VAR neuer index := 0; + neuen indexblock besorgen; + IF neuer index <> 0 THEN + index aufsplitten + ELSE + index reorganisieren (datei) + END IF; + indexzeiger justieren (datei); + indexzeiger := datei. indexzeiger . + +neuen indexblock besorgen : + IF datei. erster leerindex <> 0 THEN + neuer index := datei. erster leerindex; + datei. erster leerindex := folgeindex. nachfolger + ELIF datei. indexblocks < maxindex THEN + datei. indexblocks INCR 1; + neuer index := datei. indexblocks; + folgeindex. satzindex := blockreservierung + END IF . + +index aufsplitten : + neuen block einketten; + splitpunkt bestimmen; + folgeindex. eintraege := index. eintraege - halbe eintraege; + split up (index. satzindex, folgeindex. satzindex, halbe eintraege + 1); + index. eintraege := halbe eintraege; + indexverweise aendern (datei, folgeindex. satzindex, neuer index) . + +neuen block einketten : + INT CONST alter nachfolger := index. nachfolger; + IF alter nachfolger <> 0 THEN + datei. index (alter nachfolger). vorgaenger := neuer index + ELSE + datei. letzter index := neuer index + END IF; + folgeindex. nachfolger := alter nachfolger; + folgeindex. vorgaenger := indexzeiger; + index. nachfolger := neuer index . + +splitpunkt bestimmen : + INT VAR halbe eintraege; + IF letzter block THEN + halbe eintraege := dreiviertel maxeintrag + ELSE + halbe eintraege := index. eintraege DIV 2 + 1 + END IF . + +letzter block : + alter nachfolger = 0 . + +index : + datei. index (indexzeiger) . + +folgeindex : + datei. index (neuer index) . + +END PROC indexeintrag einfuegen; + +PROC index reorganisieren (DATEI VAR datei) : + + INT VAR indexzeiger := 1; + REP + index auffuellen; + zum naechsten index + END REP . + +index auffuellen : + BOOL VAR moeglich; + REP + INT CONST nachfolger := index. nachfolger; + indizes zusammenlegen (datei, indexzeiger, nachfolger, moeglich) + UNTIL NOT moeglich END REP; + IF nachfolger = 0 THEN + LEAVE index reorganisieren + ELIF noch platz THEN + rest auffuellen + END IF . + +noch platz : + INT CONST platz := dreiviertel maxeintrag - index. eintraege; + platz > 0 . + +rest auffuellen : + split down (folgeindex. satzindex, indexpuffer, platz + 1); + folgeindex. eintraege DECR platz; + indexverweise aendern (datei, indexpuffer, indexzeiger); + index. satzindex CAT indexpuffer; + index. eintraege := dreiviertel maxeintrag . + +zum naechsten index : + indexzeiger := nachfolger . + +index : + datei. index (indexzeiger) . + +folgeindex : + datei. index (nachfolger) . + +END PROC index reorganisieren; + + +(************************* Sortierabfragen *******************************) + +TEXT VAR dez komma := ","; + +LET + sortmask = 1; + +TEXT PROC dezimalkomma : + + dez komma + +END PROC dezimalkomma; + +PROC dezimalkomma (TEXT CONST neues komma) : + + IF length (neues komma) <> 1 THEN + errorstop (nicht erlaubtes dezimalkomma) + ELSE + dez komma := neues komma + ENDIF + +END PROC dezimalkomma; + +INT PROC unsortierte saetze (EUDAT CONST datei) : + + datei. anz unsortierte + +END PROC unsortierte saetze; + +TEXT PROC sortierreihenfolge (EUDAT CONST datei) : + + datei. sortierfelder + +END PROC sortierreihenfolge; + +PROC aktueller satz unsortiert (DATEI VAR datei) : + + IF sortiert (datei) THEN + disable stop; + datei. ablage (datei. satzzeiger). attribut INCR sortmask; + datei. anz unsortierte INCR 1 + END IF + +END PROC aktueller satz unsortiert; + +PROC aktueller satz sortiert (DATEI VAR datei) : + + IF NOT sortiert (datei) THEN + disable stop; + datei. ablage (datei. satzzeiger). attribut DECR sortmask; + datei. anz unsortierte DECR 1 + END IF + +END PROC aktueller satz sortiert; + +BOOL PROC sortiert (DATEI CONST datei, INT CONST stelle) : + + (datei. ablage (stelle). attribut AND sortmask) = 0 + +END PROC sortiert; + +BOOL PROC sortiert (DATEI CONST datei) : + + sortiert (datei, datei. satzzeiger) + +END PROC sortiert; + + +(************************* Sortieren *************************************) + +(* Eine Datei kann in einer beliebigen Feldreihenfolge sortiert werden. *) +(* Dabei wird das Feldinfo beachtet. Wurden seit der letzten Sortierung *) +(* nur wenige Saetze geaendert (deren Plaetze in 'unsortierte' gespei- *) +(* chert sind), werden nur diese Saetze einsortiert. *) + +INTVEC VAR sortierinfo; + +TEXT VAR sortierfelder; + +TEXT VAR l, r; + + +PROC sortiere (EUDAT VAR datei) : + + sortierfelder := datei. sortierfelder; + IF sortierfelder = niltext THEN + standardbelegung + END IF; + sortiere intern (CONCR (datei)) . + +standardbelegung : + INT VAR i; + FOR i FROM 1 UPTO datei. felderzahl REP + sortierfelder CAT code (i) + END REP . + +END PROC sortiere; + +PROC sortiere (EUDAT VAR datei, TEXT CONST felder) : + + sortierfelder := felder; + sortiere intern (CONCR (datei)) + +END PROC sortiere; + +PROC sortiere intern (DATEI VAR datei) : + + IF datei. sortierfelder <> sortierfelder THEN + datei. sortierfelder := sortierfelder; + datei. anz unsortierte := datei. anz saetze + 1 + ELIF datei. anz unsortierte = 0 THEN + LEAVE sortiere intern + END IF; + sortierinfo := datei. feldinfo; + IF mehr als ein drittel THEN + komplett sortieren (datei); + datei. anz unsortierte := 0 + ELSE + einzeln sortieren (datei) + END IF; + auf satz intern (datei, 1) . + +mehr als ein drittel : + datei. anz saetze DIV datei. anz unsortierte < 3 . + +END PROC sortiere intern; + +PROC komplett sortieren (DATEI VAR datei) : + + INT VAR + satzzeiger, + satz := 1, + satz vorher; + + auf satz intern (datei, 1); + aktueller satz sortiert (datei); + satzzeiger := datei. satzzeiger; + WHILE noch satz vorhanden REP + zum naechsten satz; + satz richtig einsortieren; + cout (satz) + END REP; + disable stop; + index reorganisieren (datei); + neue satzposition (datei, 1, 1, 1) . + +noch satz vorhanden : + satz < datei. anz saetze . + +zum naechsten satz : + satz INCR 1; + auf satz intern (datei, satz); + satz vorher := satzzeiger; + satzzeiger := datei. satzzeiger . + +satz richtig einsortieren : + IF satz kleiner als vorgaenger THEN + satz einsortieren (datei, satz, satzzeiger); + satzzeiger := satz vorher + ELSE + aktueller satz sortiert (datei) + END IF . + +satz kleiner als vorgaenger : + datei. ablage (satz vorher). satz GROESSER + datei. ablage (satzzeiger). satz . + +END PROC komplett sortieren; + +PROC einzeln sortieren (DATEI VAR datei) : + + INT VAR i; + FOR i FROM 1 UPTO datei. anz satzeintraege REP + IF NOT sortiert (datei, i) THEN + satz einsortieren (datei, datei. anz saetze + 1, i); + cout (i) + END IF + END REP + +END PROC einzeln sortieren; + +PROC satz einsortieren (DATEI VAR datei, INT CONST satznr, satzzeiger) : + + stelle suchen; + an dieser stelle einfuegen . + +stelle suchen : + INT VAR + anfang := 1, + ende := satznr - 1, + mitte; + WHILE stelle nicht gefunden REP + intervall in der mitte halbieren; + teilintervall auswaehlen + END REP . + +stelle nicht gefunden : + anfang <= ende . + +intervall in der mitte halbieren : + mitte := (anfang + ende) DIV 2; + INT VAR vergleichssatz; + auf satz intern (datei, mitte); + IF NOT sortiert (datei) THEN + passenden vergleichssatz suchen + END IF; + vergleichssatz := datei. satzzeiger . + +passenden vergleichssatz suchen : + WHILE datei. satznr < ende REP + weiter intern (datei); + IF satz richtig THEN LEAVE passenden vergleichssatz suchen END IF + END REP; + WHILE datei. satznr > anfang REP + zurueck intern (datei); + IF satz richtig THEN LEAVE passenden vergleichssatz suchen END IF + END REP; + LEAVE stelle suchen . + +satz richtig : + sortiert (datei) . + +teilintervall auswaehlen : + IF zu vergleichender satz GROESSER datei. ablage (satzzeiger). satz THEN + ende := mitte - 1 + ELSE + anfang := mitte + 1 + END IF . + +zu vergleichender satz : + datei. ablage (vergleichssatz). satz . + +an dieser stelle einfuegen : + positioniere intern (datei, satzzeiger); + IF datei. satznr < anfang THEN anfang DECR 1 END IF; + disable stop; + aktueller satz sortiert (datei); + in hashkette ausketten; + indexeintrag loeschen (datei); + auf satz intern (datei, anfang); + indexeintrag einfuegen (datei, satzzeiger); + in hashkette einketten . + +in hashkette ausketten : + INT CONST h index := hashindex (aktueller satz); + hash ausketten (datei, h index) . + +in hashkette einketten : + INT VAR vorgaenger, nachfolger; + stelle in hashkette (datei, h index, vorgaenger, nachfolger); + hash einketten (datei, h index, vorgaenger, nachfolger) . + +aktueller satz : + datei. ablage (satzzeiger). satz . + +END PROC satz einsortieren; + +BOOL OP GROESSER (SATZ CONST links, rechts) : + + ungleiches feld suchen; + sortierrichtung feststellen; + SELECT sortierinfo ISUB vergleichsfeld OF + CASE 0 : din vergleich + CASE 1 : zahl vergleich + CASE 2 : datum vergleich + OTHERWISE text vergleich + END SELECT . + +ungleiches feld suchen : + INT VAR nr zeiger := 1; + WHILE nr zeiger < length (sortierfelder) REP + INT CONST vergleichsfeld := code (sortierfelder SUB nr zeiger); + feld lesen (links, vergleichsfeld, l); + feld lesen (rechts, vergleichsfeld, r); + SELECT sortierinfo ISUB vergleichsfeld OF + CASE 0 : din gleich + CASE 1 : zahl gleich + OTHERWISE text gleich + END SELECT; + nr zeiger INCR 2 + END REP; + LEAVE GROESSER WITH FALSE . + +sortierrichtung feststellen : + BOOL VAR aufsteigend; + IF (sortierfelder SUB (nr zeiger + 1)) = "-" THEN + aufsteigend := FALSE + ELSE + aufsteigend := TRUE + END IF . + +zahl gleich : + REAL VAR l wert, r wert; + wert berechnen (l, l wert); + wert berechnen (r, r wert); + IF l wert <> r wert THEN + LEAVE ungleiches feld suchen + END IF . + +din gleich : + IF NOT (l LEXEQUAL r) THEN + LEAVE ungleiches feld suchen + END IF . + +text gleich : + IF l <> r THEN + LEAVE ungleiches feld suchen + END IF . + +zahl vergleich : + IF aufsteigend THEN + l wert > r wert + ELSE + l wert < r wert + END IF . + +din vergleich : + IF aufsteigend THEN + l LEXGREATER r + ELSE + r LEXGREATER l + END IF . + +datum vergleich : + datum umdrehen (l); + datum umdrehen (r); + IF aufsteigend THEN + l > r + ELSE + l < r + END IF . + +textvergleich : + IF aufsteigend THEN + l > r + ELSE + l < r + END IF . + +END OP GROESSER; + +PROC wert berechnen (TEXT CONST zahl, REAL VAR wert) : + + LET ziffern = "0123456789"; + TEXT VAR komma := dez komma, text; + INT VAR stelle; + INT CONST laenge := length (zahl); + anfang bestimmen; + WHILE stelle <= laenge REP + zeichen untersuchen; + stelle INCR 1 + END REP; + wert := real (text) . + +anfang bestimmen : + stelle := pos (zahl, "0", "9", 1); + IF stelle = 0 THEN + wert := 0.0; LEAVE wert berechnen + ELIF pos (zahl, "-", 1, stelle) > 0 THEN + text := "-" + ELSE + text := niltext + END IF; . + +zeichen untersuchen: + TEXT CONST char := zahl SUB stelle; + IF pos (ziffern, char) > 0 THEN + text CAT char + ELIF char = komma THEN + text CAT "."; komma := niltext + END IF . + +END PROC wert berechnen; + +PROC datum umdrehen (TEXT VAR datum) : + + IF length (datum) <> 8 THEN + datum := niltext + ELSE + datum := subtext (datum, 7) + subtext (datum, 4, 5) + + subtext (datum, 1, 2) + END IF + +END PROC datum umdrehen; + + +(**************************** Reorganisieren *****************************) + +PROC reorganisiere (TEXT CONST dateiname) : + + EUDAT VAR datei 1, datei 2; + oeffne (datei 1, dateiname); + disable stop; + DATASPACE VAR ds := nilspace; + oeffne (datei 2, ds); + kopiere eudat (CONCR (datei 1), datei 2); + IF NOT is error THEN + forget (dateiname, quiet); + copy (ds, dateiname) + END IF; + forget (ds) + +END PROC reorganisiere; + +PROC kopiere eudat (DATEI VAR datei 1, EUDAT VAR datei 2) : + + enable stop; + kopiere saetze; + kopiere interna (datei 1, CONCR (datei 2)) . + +kopiere saetze : + auf satz intern (datei 1, 1); + auf satz (datei 2, 1); + WHILE NOT dateiende REP + satz einfuegen (datei 2, kopiersatz); + cout (datei 1. satznr); + weiter intern (datei 1); + weiter (datei 2) + END REP . + +dateiende : + datei 1. satznr > datei 1. anz saetze . + +kopiersatz : + datei 1. ablage (datei 1. satzzeiger). satz . + +END PROC kopiere eudat; + +PROC kopiere interna (DATEI VAR datei 1, datei 2) : + + datei 2. felderzahl := datei 1. felderzahl; + datei 2. feldnamen := datei 1. feldnamen; + datei 2. feldinfo := datei 1. feldinfo; + datei 2. sortierfelder := datei 1. sortierfelder; + datei 2. notizen (1) := datei 1. notizen (1); + datei 2. notizen (2) := datei 1. notizen (2); + datei 2. notizen (3) := datei 1. notizen (3) + +END PROC kopiere interna; + + +(************************* Notizen ***************************************) + +PROC notizen lesen (EUDAT CONST datei, INT CONST nr, TEXT VAR notiztext) : + + notiztext := datei. notizen (nr) + +END PROC notizen lesen; + +PROC notizen aendern (EUDAT VAR datei, INT CONST nr, TEXT CONST notiztext) : + + datei. notizen (nr) := notiztext + +END PROC notizen aendern; + +END PACKET eudas dateien; + |