/* jasenet.cpp */ /****************************************************************************/ /* ** J A S E N E T . C P P ** ** J„senet-luokan toteutus ** ** Tekij„t: Vesa Lappalainen ** Ohjelmointikurssi 1991 ** Tehty: 20.12.1991 ** Muutettu: 09.12.1995 ** Mit„ muutettu: Muutettu C++ luokaksi ** Muutettu: 10.12.1995 ** Mit„ muutettu: + Laitettu tiedoston lukeminen ja kirjoittaminen ** toimivaksi (ks. metodit lue_tiedostosta ja talleta) ** + J„senen lis„ys kasvattaa taulukon kokoa, mik„li ** tila loppuu (ks. lisaa) ** Muutettu: 11.01.1996 ** Mit„ muutettu: + Lis„tt„v„n j„senen rekister”inti ** + laske montako muuta ** + tiedoston lukemisessa tyhj„t rivit eiv„t en„„ ** haittaa ** Muutettu: 20.01.1997 ** Mit„ muutettu: + Otettu kerhosta j„senist”n osuus ** Muutettu: 04.03.1997 ** Mit„ muutettu: + Korjattu viallinen anna tapauksessa jossa lkm==0 ** + Korjattu kommenttien k„sittely toimivaksi tiedoston ** lukemisessa ** ** Public-metodeja: ** ================ ** ** Metodit palauttavat yleens„ virheen merkkijonona, joka voidaan ** suoraan tulostaa. Jos virhett„ ei tapahdu, palautetaan NULL. ** ** cJasenet(int koko=0) ** - j„senit”n luominen, jos koko = 0, ei luoda j„sentaulukkoa ** ** ~cJasenet() ** - j„senist„n h„vitt„minen, jos j„senist”„ ei ole talletettu, talletetaan ** viimeist„„n nyt (mahd. virheilmoitus harakoille) ** ** const char *lisaa(const cJasen &jasen); ** - lis„t„„n uusi j„sen. J„senest„ tehd„„n kopio. Jos tila loppuu, ** yritet„„n kasvattaa tilaa. ** ** const char *korvaa(int i,const cJasen &jasen); ** - korvataan i:s j„sen uudella. Jos i v„„rin, ei tehd„ mit„„n (pal 1). ** ** const cJasen &anna(int i) const ** - otetaan kerhosta i:s j„sen. Jos i v„„rin, otetaan viim. j„sen. ** Jollei ole viimeist„k„„n, palautetaan virhej„sen. ** Kerholaisia voidaan muuttaa, kun otetaan j„senest„ kopio ** anna-metodilla, muutetaan kopion tietoja ja laitetaan takaisin ** korvaa-metodilla: ** cJasen jasen(kerho.anna(i)); ** - muuta jasenta ** kerho.korvaa(i,jasen); ** ** const char *luo(const string &tied,const string &nimi, ** - luo j„senist”n uutta kerhoa varten, mahd. vanha talletetaan ** ** const char *lue(const string &tied); ** - luetaan uusi j„senist”, mahd. vanha talletetaan ** ** const char *talleta(const string &tied=""); ** - talletetaan j„sensist„. Jos tied=="", k„ytet„„n luettaessa ** annettua nimi„. ** ** const string &Koko_nimi() const ** - palauttaa tiedoston koko nimen. ** ** int Lkm() const ** - palauttaa j„senm„„r„n ** ** const string &Tiedoston_nimi() const ** - paluttaa viimeksi k„ytetyn tiedoston nimen ** ** int Muutettu() const ** - palauttaa 1, mik„li j„senist”„ on muutettu talletusten j„lkeen ja ** 0 muuten. ** ** int cJasenet::TeeBak(const string &bak_tark) ** - palauttaa 0, mik„li tiedoston muuttaminen bak-tiedostoksi onnistuu ** 1 muuten. ** ** int laske_montako_muuta(const cJasen &jasen, int k,int &kuka) ** - laskee monellako j„senell„ on kent„ss„ k samat tiedot ** kuin jasenella. Palautetaan my”s viimeinen ko. j„sen. ** --------------------------------------------------------------------------- ** ** Tietorakenne on seuraava: ** ========================= ** ** ** cJasenet cJasen ** ------ ** | | ------ ** | | | | ** | 7 | max |---->| | ** | 3 | alkiot | | | ------ ** | o--+------>|-----| | ------ | | ** ------ | o--+-----| | | ** |-----| |----->| | ** | o--+------------| ------ ------ ** |-----| | | ** | o--+--------------------------->| | ** |-----| | | ** | o--+--? ------ ** |-----| ** | o--+--? ** |-----| ** | o--+--? ** |-----| ** | o--+--? ** |-----| ** ** ** J„senet ei tied„ j„seniens„ ominaisuuksia. ** J„senist” pit„„ huolta siit„, onko j„senet muuttunut, eli tarvitseeko se ** talletusta vaiko ei. ** Tiedoston muoto, ks. lue_tiedostosta - metodi ** */ #include #include #include "mjonotpp.h" #include "jasenet.h" //============================================================================ // Makrot: //============================================================================ //---------------------------------------------------------------------------- // Makro, jolla tutkitaan palauttiko kutsu v virheen vai ei ja jos // palautti, niin poistutaan aliohjelmasta palauttaen sama virhe. #define IF_ERR_RETURN(v) { const char *virhe=(v); if ( virhe ) return virhe; } //============================================================================ // Virheilmoitukset: //============================================================================ static const char *EI_VOI_LUODA = "Taulukolle ei saada varattua tilaa muistista!"; static const char *LIIKAA_ALKIOITA = "Liikaa alkioita, ei voi lis„t„!"; static const char *EI_SAA_ALKIOTA = "Ei saada tilaa uudelle alkiolle muistista!"; static const char *EI_NIMEA = "Ei koko nime„ tiedostossa!"; static const char *EI_MAXKOKOA = "Ei maksimikokoa tiedoston alussa!"; static const char *TIED_EI_AUKEA = "Tiedosto ei aukea!"; static const char *OTS_EI_KIRJ = "Otsikkotietoja ei voi kirjoittaa!"; static const char *ALKIO_EI_KIRJ = "Alkiota ei voi kirjoittaa!"; static const char *LAITON_INDEKSI = "Laiton indeksi!"; static const char *EI_REKISTEROITY= "Alkiota ei ole rekister”ity!"; //============================================================================ // Private -metodeja: //============================================================================ //---------------------------------------------------------------------------- void cJasenet::poista_taulukko() { if ( max_lkm > 0 ) free(alkiot); max_lkm = 0; } //---------------------------------------------------------------------------- void cJasenet::poista_alkiot() { for (int i=0; i= max_lkm ) IF_ERR_RETURN(kasvata_kokoa()); cJasen *uusi = new cJasen(jasen); if ( uusi == NULL ) return EI_SAA_ALKIOTA; alkiot[lkm] = uusi; lkm++; muutettu = 1; return NULL; } //---------------------------------------------------------------------------- const char *cJasenet::korvaa(int i,const cJasen &uusi) /* ** Korvataan paikassa i oleva j„sen uudella j„senell„. ** Vain rekister”ityneet j„senet hyv„ksyt„„n. ** Jos samat tiedot kuin vanhalla j„senell„, ei korvata. ----------------------------------------------------------------------------*/ { if ( ulkona(i) ) return LAITON_INDEKSI; if ( alkiot[i]->sama_rekisteri(uusi) == 0 ) return EI_REKISTEROITY; if ( *(alkiot[i]) == uusi ) return NULL; muutettu = 1; *(alkiot[i]) = uusi; return NULL; } //---------------------------------------------------------------------------- const char *cJasenet::luo_taulukko(int koko) /* ** Luodaan j„sentaulukko valitun kokoiseksi. Jos j„sentaulukko on ennest„„n ** on siell„ on se parasta poistaa. ** Luomisessa k„ytet„„n malloc-funktiota, jotta koon muuttaminen on ** jatkossa helpompaa realloc-funktiolla. (ks. lisaa-metodi). ----------------------------------------------------------------------------*/ { poista_kaikki(); if ( koko <= 0 ) return NULL; alkiot = (cJasen **)malloc( koko * (sizeof(cJasen *)) ); lkm = 0; max_lkm = 0; if ( alkiot == NULL ) return EI_VOI_LUODA; max_lkm = koko; return NULL; } //---------------------------------------------------------------------------- const char *cJasenet::luo(const string &tied,const string &nimi,int max_koko) /* ** Luodaan uusi j„senist” valitulla tiedoston nimell„ ja j„senist”n nimell„. ** Taulukon yl„rajaksi luodaan max_jas. ----------------------------------------------------------------------------*/ { IF_ERR_RETURN(luo_taulukko(max_koko)); tiedoston_nimi = tied; koko_nimi = nimi; muutettu = 1; return NULL; } //---------------------------------------------------------------------------- const char *cJasenet::lue_tiedostosta(const string &tied) /* ** Luetaan tiedostosta j„senist”n tiedot. ** ** Metodit olettavat tiedoston olevan seuraavaa muotoa: ** **Kelmien kerho ry **50 **; Kenttien j„rjestys tiedostossa on seuraava: **id|sukunimi etunimi |sotu |katuosoite |postinumero|postiosoite|koti... **1|Ankka Aku |010245-123U|Ankkakuja 6 |12345 |ANKKALINNA |12-1... **2|Susi Sepe |020347-123T| |12555 |Per„mets„ | ... **3|Ponteva Veli |030455-3333| |12555 |Per„mets„ | ... ** ** ** Tiedoston 3. rivilt„ alkaen olevat kommenttirivit (merkitty ;) unohdetaan. ** ** Taulukon yl„rajaksi luodaan tiedosta 2. rivilt„ luettu max_koko. ----------------------------------------------------------------------------*/ { ifstream f(tied.c_str()); if ( !f ) return TIED_EI_AUKEA; string nimi; lue_rivi(f,nimi); if ( !f ) return EI_NIMEA; int max_koko; lue_rivi(f,max_koko); if ( !f ) return EI_MAXKOKOA; IF_ERR_RETURN(luo_taulukko(max_koko)); tiedoston_nimi = tied; koko_nimi = nimi; int tunniste; cJasen jasen; while ( f ) { tunniste = f.get(); if ( tunniste == 0 || tunniste == '\n' ) continue; if ( tunniste == ';' ) { f.ignore(1000,'\n'); continue; } if ( tunniste == EOF ) break; // Ei kai ole mahdollista??? f.putback(char(tunniste)); f >> jasen; // vaatii kunkin rivin k„sittelemisen t„ydellisen„, muuten OK! if ( !jasen.tyhja() ) IF_ERR_RETURN(lisaa(jasen)); } muutettu = 0; return NULL; } //---------------------------------------------------------------------------- const char *cJasenet::talleta(const string &tied) { if ( !muutettu ) return NULL; string tiedosto(tied); if ( tied == "" ) tiedosto = tiedoston_nimi; ofstream f(tiedosto.c_str()); if ( !f ) return TIED_EI_AUKEA; f << koko_nimi << endl; f << max_lkm << endl; if ( !f ) return OTS_EI_KIRJ; for (int i=0; ikentta_jonoksi(k) == kentta && alkiot[i]->sama_rekisteri(jasen) == 0 ) { samoja++; kuka = i; } } return samoja; }