/* * Name : database.cpp * Aufgabe : Implementierung der Datenbank * Version : $Revision: 1.2 $ * Datum : $Date: 2000/01/25 23:07:13 $ * Beschreibung : Komfortables Durchsuchen der Heise-Register-Datei * * Copyright (C) 1998 Alexander Bednarz * Martin Habbecke * * 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 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include "database.h" #include "found.h" #include "searchmask.h" #include "entry.h" /* Initialisierung: Nur Filename kopieren */ Database::Database( QString const & newname ) : QObject(), filename( newname ) { } /* Starten einer Suche */ // Durfuehren einer Suche in der Datei // anzahl zurueckgeben // Found *, weil wir ja sowieso dynamisch angelegt, daher haben wir ja nen Zeiger // found wurde im Toplevel angelegt // ich gehe davon aus, dass found leer is, und is bereit fuers einfuegen int Database::search(Found * found, SearchMask & s) { FILE * in = fopen( filename, "r" ); // Datei oeffnen // TODO: Auf Fehler pruefen Entry e; // Ein Eintrag, der dann gelesen und verglichen wird int anz = 0; // Anzahl der gef. Eintraege /* Endposition des Files bestimmen */ fseek( in, 0, SEEK_END ); long endpos = ftell( in ); fseek( in, 0, SEEK_SET ); /* Flag zur Vortsetzung der Suche setzen */ continueSearch = true; long searchCount = 0; // SuchMaske fuer die Suche vorbereiten s.parse(); while ( e.read( in ) && continueSearch ) { /* Alle 10 Eintraege den Progressbar weitersetzen */ if ( !(++searchCount % 20) ) { emit databasePosition( ftell( in ) * 100 / endpos ); /* Events bearbeiten -> ProgressBar updaten */ kapp->processEvents(); } if ( e.compare( s ) == Entry::GLEICH ) { // cout << "Eintrag ist gleich; bei: " << ftell( in ) << endl; found->append( e ); anz++; } } // cout << "Letzter Entry e: " << endl; // cout << "Schlagwoerter: " << e.Schlagwoerter() << endl; // Datei schliessen fclose( in ); // Und gefundenen vektor vorsortieren found->sort( Found::JAHR_DOWN ); return anz; } // Test, ob File filename eine gueltige Registerdatei ist. // - gibt es sie ueberhaupt? // - kann sie geoeffnet werden? // - richtiger Syntax? // sollte VOR dem Constructen eines Database Objects aufgerufen werden // statische Memberfunction bool Database::isValid( char const * filename ) { bool ret = true; // davon ausgehen, dass es valid ist // Existiert? ret = QFileInfo( filename ).exists(); if (!ret) return false; // Oeffnenbar? (das ist ein Deutsch, ne??? :) FILE * test = fopen( filename, "r" ); if ( test == NULL ) return false; // Syntax // 5. Zeile darf nur Ziffern enthalten // 7. Zeile: 1. Zeichen e {'c', 'i', 'e', 'g'}, 2 Ziffern char line[261]; for( int i = 1; i <= 5; i++ ) fgets( line, 260, test ); // bis zur 5. Zeile gelesen // nur spaces und Ziffern erlaubt char *c = line; while ( *c ) { if ( !isspace( *c ) && !isdigit( *c ) ) ret = false; c++; } if (!ret) { fclose( test ); return false; } // 2 weitere Zeilen, bis zur 7. Zeile lesen fgets( line, 260, test ); fgets( line, 260, test ); // 1. Zeichen in {'c', 'i', 'e', 'g'} ? switch ( line[0] ) { case 'c': case 'i': case 'e': case 'g': break; default: ret = false; // es war nicht drin } if (!ret) { fclose( test ); return false; } // 2. und 3. Zeichen duerfen nur Ziffern sein if ( !isdigit( line[1] ) || !isdigit( line[2] ) ) ret = false; if (!ret) { fclose( test ); return false; } // -> gueltige Datei! return true; } /* Anhaengen einer Update-Datei an eine geoeffnete Registerdatei */ // *.CTI int Database::append(QString & appendName) { // MagazinTyp und Ausgabe und Jahrgang des ersten anzuhaengenden Entries feststellen FILE * f = fopen( appendName, "r" ); Entry a; a.read( f ); fclose( f ); // Ausgabe und Jahrgang des letzten Entries // des entsprechenden MagazinTyp feststellen // Dazu: gesamte Datei durchlesen, und letzten Eintrag dieses Typs merken f = fopen( filename, "r" ); // Entry fuer den alten, gefundenen letzten Eintrag entsprechenden Typs Entry old; // Markierung setzen, um zu erkennen, falls kein Entry entsprechenden Typs gefunden wird old.Ausgabe( "#" ); Entry dummy; while ( dummy.read( f ) ) { // Nur, wenn der Typ gleich ist, dann kopieren if ( dummy.Zeitschrift() == a.Zeitschrift() ) { old = dummy; } } fclose( f ); // Wurde ueberhaupt ein Eintrag entsprechenden Typs gefunden? if (old.Ausgabe()[0] == '#') { QMessageBox::warning( 0, "KHeisePro - Meldung", "Es wurden keine alten Registereinträge entsprechenden Typs gefunden.\n" "Also werden alle neuen Daten angehängt!" ); } else { // Es wurde ein Eintrag entsprechenden Typs gefunden, also ... // Ueberpruefen, ob anzuhaengender File, auch wirklich neuere Daten enthaelt? int aj = atoi( a.Jahrgang() ); int oj = atoi( old.Jahrgang() ); int aa = atoi( a.Ausgabe() ); int oa = atoi( old.Ausgabe() ); // Y2K Workaround von Erik Hansen [erikh@cs.tu-berlin.de] (Dank!) if (aj < 81) { aj = aj + 100; }; if ( ( aj < oj ) || ( aj == oj && aa <= oa ) ) { // neuer Jahrgang ist aelter oder // jahrgang gleich, aber ausgabe aelter QMessageBox::warning( 0, "KHeisePro - Meldung", "Die anzuhängenden Daten sind nicht neuer als die im aktuellen Register.\n" "Die Daten werden nicht angehängt!" ); return 0; } } // Daten anhaengen f = fopen( filename, "a" ); // Register oeffnen FILE * g = fopen( appendName, "r" ); // append oeffnen char line[260]; while ( fgets( line, 260, g ) ) { fputs( line, f ); } fclose( f ); fclose( g ); // Feedback QMessageBox::information( 0, "KHeisePro - Meldung", "Die Daten wurden erfolgreich angehängt!" ); return 1; } /* Slot: Abbruch einer laufenden Suche */ void Database::abortSearch( void ) { continueSearch = false; // cout << "SEARCH ABORTED" << endl; } #ifdef auskommentiert bool Database::recode() { FILE * in = fopen( filename, "r" ); char tmp[L_tmpnam]; // Platz fuer Temp-Filename FILE * out= fopen( tmpnam( tmp ), "w" ); // Einen kompletten Satz an Entry einfuegen, um einfacher ueberlesen zu koennen fprintf( out, "# KHeisePro - %s\n", VERSION ); fprintf( out, "# Recoded am %s\n", (const char *) QDateTime::currentDateTime().toString() ); fprintf( out, "#\n#\n#\n#\n#\n#\n#\n" ); int c; int outc; while ( (c = fgetc( in ) ) != EOF ) { switch( (char) c ) { case '\201': outc = 'ü'; break; case '\204': outc = 'ä'; break; case '\224': outc = 'ö'; break; case '\216': outc = 'Ä'; break; case '\231': outc = 'Ö'; break; case '\232': outc = 'Ü'; break; case '\236': case '\341': outc = 'ß'; break; case '\335': outc = '§'; break; case '\015': continue; // CR case '\032': continue; // ^Z default: outc = c; } fputc( outc, out ); } fclose( in ); fclose( out ); return true; } #endif // auskommentiert #include "database.moc"