// record.hpp : Datensatz im Arbeitsspeicher // 1995-08-19 Datensatz, Struktur und Manipulation im Arbeitsspeicher // Copyright 2011 Universitätsbibliothek Braunschweig, more see bottom // (Lesen und Speichern siehe ABASEW.CPP) // Klasse RECORD (c) UB Braunschweig 1995/2003 // Setzt die Klasse KONFIG voraus // Ein Objekt RECORD wird gebraucht, um einen Datensatz darzustellen // und zu manipulieren // Einlesen aus und Speichern in einer Datenbank leistet Klasse ABASE // Ein RECORD kann an ein Objekt EXET uebergeben werden zwecks Export // RECORD wird benoetigt von der Klasse EXET (und damit auch von den // erweiterten Klassen INDEX und ABASE. #ifndef __ALLEGRO #include "allegro.hpp" // globale Konstanten und Variablen #endif #ifndef __RECORD #define __RECORD #define WSPACE 64000 // max. Feldlaenge (vorher 32000) // bezieht sich auf das Eingabefeld; wieviel ein Satz verkraften kann, // steht auf einem anderen Blatt... // Ein Objekt der Klasse KONFIG wird gebraucht: #include "konfig.hpp" // ************* KLASSENBESCHREIBUNG class RECORD { //===========// public: // Variablen // %% Hinweise auf die aelteren DOS-Variablen //===========// CHAR *g ; // Basisadresse der Datenfelder [general data address] CHAR **ga ; // Adressenarray f.d. Datenfelder, ga[0] = g [general array for data] int *gi ; // Array der internen Nummern der Felder gemaess Konfiguration [general internal numbers of fields] // z.B. #u1 hat hier die Nr. 0, #00 die 2 int cri ; // Position der 1. Kat. d. aktuellen Satzes in ga[] [current rec index in ga; pos. of 1st field] // normal: 0, nur bei Untersaetzen waehrend Export >0 int gri ; // Anzahl Felder des Satzes CHAR *gend ; // Endadresse der Daten in g (hinter letztem Byte) [ g end address] int mri ; // markiertes Feld; Adresse: ga[mri] [marked rec index] // i.d.R. die #01, die mit Alt+m markiert wurde // Fuer Editor-Zwecke. Bleibt auf dem gewaehlten // Feld auch bei Verschiebungen per Ins/Del int Adn ; // logische Nr. der Datenbank (0,1,2,3) zu der der Satz gehoert %% Adb // -1 wenn rec nicht zu einer Datenbank gehoert // globale Variable ABASE Abase[Adn] ist Adresse des Db-Objekts int rFi ; // Nr. der .ALD-Datei d. Satzes %% filenmb long rOf ; // OffsetPosition innerhalb .ALD-Datei %% rad long rNr ; // Satznummer, 0 = neu %% recn int rLg ; // Satzlaenge in der Datei %% rlg int rSt ; // Status %% rstat // (0=neu,1=normal,2=reserviert,8=gesperrt,9=geloescht) KONFIG *kfg ; // pointer auf das zustaendige KONFIG-Objekt char schema; // Konfig.Buchstabe, z.B. a // Nur fuer die Indexierung (wird z.B. in Reserve() gefuellt: int rKx ; // Anzahl Schluessel %% okn CHAR *rKy[1000]; // Adressenliste der Schluessel %% oldkeys[] CHAR *rKbase; // Basisadresse fuer Schluessel // Platzzuteilung erfolgt in index.cpp char rKf[1000]; // flags: 0=key valid / 1=not valid %% okf // bei 1 muss der Schl. geloescht werden long rNa ; // additional, for #nra (nachgeladener Satz) $$981109 // Nur >0, wenn gerade einer nachgeladen wurde CHAR *Wsp2 ; // 2. Haelfte von Wspace, Hilfsvar f. UTF-Wandlung char editdate[48];// letztes Aenderungsdatum (z.B. f. a99 Reservespeicher) // $$20120118 48 statt 18 /* Am wichtigsten ist der Array ga[], der die Anfangsadressen der Datenfelder im Arbeitsspeicher enthält. Es kann darin mehrere aufeinanderfolgende Datensätze geben (z.B. bei Nachladungen). Ein weiterer (auch der erste) beginnt jeweils mit der Zeichenfolge 29 01, diese Zeichen stehen also i.d.R. unmittelbar vor der Zeichenfolge #00 des ersten Feldes. Ein hierarchischer Untersatz beginnt dagegen mit 29 02, darauf folgt "#01", bzw. mit 29 03, darauf folgt "#02", usw. Das jeweils erste Feld eines Satzes oder Untersatzes beginnt also nicht mit '#', sondern mit Code 29 und dem Hierarchiebyte. Das ist beim Umgang mit ga[] sehr wichtig. Der Array gi[] enthält die internen Nummern der Felder laut CFG, wobei #u1 und #u2 die Nummern 1 und 2 haben, #00 dann die 3 usw. Dieser Array dient der schnellen Suche nach einem Feld und der internen Sortierung (denn die CFG-Reihenfolge muss keine numerisch aufsteigende sein! */ //============// public: // Methoden // //============// // ************* Konstruktor: RECORD(KONFIG *cfg, unsigned int gsp=0, int gd=0, int wsp=0); // cfg = ein Objekt KONFIG, muss vorher angelegt werden // Defaults fuer folgende Werte werden aus CFG uebernommen, // wenn nicht angegeben oder 0 angegeben: // gsp = max. Groesse des Speichers fuer Felder, // gd = max. Zahl der Felder eines Satzes // wsp = max. Groesse eines Feldes (default WSPACE) // Fehler: Aerror enthaelt eine Meldung, sonst Aerror == "" // (Konstruktor kann kein "return xyz" machen) // Beispiel: KONFIG *kfg = new KONFIG("A","C:\\ALLEGRO\\DEMO"); // RECORD *satz = new RECORD(kfg); // Standard! // RECORD *rec = new RECORD(kfg,10000,0,2000); // RECORD *dummy = new RECORD(kfg,100,10,300); // Fuer Hilfszwecke kann es sinnvoll sein, kleine Werte zu nehmen, wenn // mit dem Objekt nicht wirklich viel zu tun ist // Destruktor ~RECORD(); // ***************** // Sonstige Methoden (weitere Hinweise siehe in record.cpp) // ------------------------------------------------------------ // Positionsnr. eines Feldes innerhalb des Array ga[] im RECORD bestimmen: int Pos(CHAR *, int md=0); // %% kat_pos(CHAR *); // return: interne Position der Kategorie im ga[]-Array // -1 wenn nicht vorhanden // Beispiel: i=rec->Pos("#123"); // Ergebnis: rec->ga[i] ist die Adresse des Feldes // und zwar des Zeichens '#' // md == 1 : ganzen hierarchischen Satz durchsuchen, incl. Untersaetze // 0 : nur aktuellen Satz ab Position cri, Untersaetze nicht // ------------------------------------------------------------ // absolute String-Adresse des Feldtextes bestimmen: CHAR *Adr(CHAR *,int md=0); // %% kat_adr(CHAR *); // return: Adresse des Feldtextes (erstes Textzeichen des Inhalts!) // NULL wenn Feld nicht vorhanden // Beispiel: adr=rec->Adr("#123"); // Ergebnis: adr ist die Adresse des Feldtextes (!) // also des Zeichens hinter #123 // adr-kfg->skt ist die Adresse von '#' // md wie bei Pos() // ------------------------------------------------------------ // absolute String-Adresse eines Unterfeldtextes bestimmen: // Adresse eines UnterFelds (z.B. AdrSf("#96a$u") // und auf Wunsch kopieren (z.B. AdrSf("#98a$u",kopie,10) // 10 zeichen // AdrSf("#98a$u",kopie) // ganzes Unterfeld // Achtung: dann muss kopie lang genug sein! CHAR *AdrSf(CHAR *ufd,CHAR *kopie=0, int lgth=0); // return: Adresse des ersten Zeichens des Unterfeldtextes von $u in #96a // NULL wenn nicht vorhanden // Beispiele: adr=AdrSf(#90$u) Text von $u in #90 // adr=AdrSf(#123$$); Text von #123 VOR allen Unterfeldern // ------------------------------------------------------------ // Ein Feld in den Datensatz einsortieren int Ins(CHAR *); // %% kat_ins(CHAR *); // return: Position, an der das Feld eingeordnet wurde // -1 wenn Feld fehlerhaft, Fehlermeldung in Aerror // z.B. unerlaubte Wiederholung, Feld nicht aenderbar // d.h. der Felddeskriptor in der CFG wird verwendet // Beispiel: rec->Ins("#123 Text"); // ------------------------------------------------------------ // Ein Feld aus dem Satz loeschen int Del(CHAR *); // %% rdelete(i,i+1); // return: Position, wo sich das Feld befand // komplettes Feld steht dann in Aerror, falls man es braucht // -1 wenn nicht gefunden (Aerror leer) // Beispiel: rec->Del("#123"); // ------------------------------------------------------------ // PartDelete : Mehrere Felder aus dem Satz loeschen int PartDel(int i ,int j); // %% rdelete(i,j); // loesche die Felder i bis j-1 // Bedingungen: i,j > 0, j>i, i,j<=rec->gri // Special case : j==-1 : from i to end of rec (= gri) // return: 0 if not possible, 1:done // Beispiele: i=rec->Pos("#81"); // j=rec->Pos("#90"); // PartDel(i,j+1); // Felder #81 bis incl. #90 loeschen // ------------------------------------------------------------ // Search+Replace innerhalb eines Satzes: CHAR *SrRp(CHAR *a,CHAR *b,int ,int ,int ); // srch (+repl) // suche a im Bereich b // field-specific srch&repl in current rec CHAR *FSrRp(CHAR *a,int); // md=1: repl 0:not // a="*#nn_abc_XYZ_" : Im Feld #nn die Sequenz abc durch XYZ ersetzen // Hierarchische Untersatze int SubPos(CHAR *); // Position eines Untersatzes bestimmen // und diesen zum aktuellen Satz machen int SubDel(CHAR *); // Untersatz loeschen ab angegebener Kategorie int SubDel(int ); // Untersatz loeschen ab einer Position int SubCopy(int, RECORD *, int, int md=0); // Untersatz kopieren int SubMove(int, RECORD *, int); // Untersatz verschieben int SubNxt(int); // naechsten Untersatz finden, ab Position int // return -1 wenn keiner mehr kommt, nicht-zyklisch int SubPre(int); // vorigen Untersatz finden, ab Position int // return -1 wenn es keinen Untersatz gibt, // zyklisch: wenn (0), dann Pos. des letzten // ======================================================================== int Reserve(); // Satz zum Bearbeiten reservieren // incl. blockieren und aktuelle Schluessel bestimmen int Release(); // wieder freigeben void Copy(RECORD *); // Inhalt aus anderem Satz kopieren void Empty(void); // reset rec as if new // UTF-8 in intern wandeln, u-Befehle normalerweise in Indexparam. void UTFcode(CHAR *ft, CHAR *gt); // ft (UTF) -> gt (Internal) // ======================================================================== private: CHAR *Wspace; // Workspace, Eingabetext landet hier // Hilfsfunktion zum Einordnen von Wspace in den Satz int ginst(int); // %% ginst(int); // %% das ist die alte Funktion aus acore.c, fuer die String-Array-Operation // ======================================================================== }; // end RECORD class #endif // zu #ifndef RECORD /* Copyright 2011 Universitätsbibliothek Braunschweig Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */