/* 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: 20.01.1997 ** Mitä muutettu: + Otettu kerhosta jäsenistön osuus ** ** 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) ** ** string lisaa(const cJasen &jasen); ** - lisätään uusi jäsen. Jäsenestä tehdään kopio. Jos tila loppuu, ** yritetään kasvattaa tilaa. ** ** string 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 0:s jä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); ** ** string luo(const string &tied,const string &nimi, ** - luo jäsenistön uutta kerhoa varten, mahd. vanha talletetaan ** ** string lue(const string &tied); ** - luetaan uusi jäsenistö, mahd. vanha talletetaan ** ** string 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" using std::ifstream; using std::ofstream; //============================================================================ // Makrot: //============================================================================ //---------------------------------------------------------------------------- // Makro, jolla tutkitaan palauttiko kutsu v virheen vai ei ja jos // palautti, niin poistutaan aliohjelmasta palauttaen sama virhe. #define IF_ERR_RETURN(v) { string 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()); try { cJasen *uusi = new cJasen(jasen); alkiot[lkm] = uusi; lkm++; muutettu = 1; } catch ( std::bad_alloc ) { return EI_SAA_ALKIOTA; } return ""; } //---------------------------------------------------------------------------- string 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 ""; muutettu = 1; *(alkiot[i]) = uusi; return ""; } //---------------------------------------------------------------------------- string 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 ""; alkiot = (cJasen **)malloc( koko * (sizeof(cJasen *)) ); lkm = 0; max_lkm = 0; if ( alkiot == NULL ) return EI_VOI_LUODA; max_lkm = koko; return ""; } //---------------------------------------------------------------------------- string 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 ""; } //---------------------------------------------------------------------------- string 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; string rivi; cJasen uusi; while ( std::getline(f,rivi) ) { if ( rivi == "" || rivi[0] == ';' ) continue; uusi.setAsString(rivi); // f >> uusi; // vaatisi kunkin rivin olemisen täydellisenä, muuten OK! IF_ERR_RETURN(lisaa(uusi)); } muutettu = 0; return ""; } //---------------------------------------------------------------------------- string cJasenet::talleta(const string &tied) { if ( !muutettu ) return ""; string tiedosto(tied); if ( tied == "" ) tiedosto = tiedoston_nimi; ofstream f(tiedosto.c_str()); if ( !f ) return TIED_EI_AUKEA; f << koko_nimi << "\n"; f << max_lkm << "\n"; 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; } //---------------------------------------------------------------------------- void cJasenet::poista_ind(int ind) { if ( ulkona(ind) ) return; muutettu = 1; delete alkiot[ind]; for (int i=ind; ianna(a).kentta_avaimeksi(kentta); return jasenet->anna(a).kentta_jonoksi(kentta) < jasenet->anna(b).kentta_jonoksi(kentta); } }; #include //---------------------------------------------------------------------------- void cJasenet::etsi(cPermutaatio &loytyneet,int k,const string &jono) { for (int i=0; i