/* kentta.h */ /*---------------------------------------------------------------------------- K E N T T A . H Tietueen yleinen kenttä ja siitä peritty joukko hyödyllisiä kenttiä. Tekijät: Vesa Lappalainen Ohjelmointikurssi 1996 Tehty: 07.01.1996/vl Muutettu: 14.01.1996/vl Mitä muutettu: + help_aihe Julkiset metodit: ----------------- string jonoksi() const = 0; - muutetaan kenttä merkkijonoksi cKenttavirhe sijoita(const char *s) cKenttavirhe sijoita(const string &st) cKenttavirhe sijoita(const cKentta &kentta); - sijoittaa merkkijonon tai kentan tähän kenttään. palauttaa joko KENTTA_OK tai sitten virheen josta selviää vakavuus ja itse virhe tekstinä. cKenttavirhe ota_seuraava(istream &is, const char *erotin); - ottaa tietovirrasta is seuraavan "palasen" eli johonkin erotinmerkkkin asti olevan jonon. Tämä ei voi ylittää rivirajaa, eli jos rivin loppu tulee vastaan, niin se laitetaan takaisin tietovirtaan. Kentästä poistetaan ylimääräiset tyhjät. int tyhjenna(istream &is) - kun kaikki kentät riviltä luettu, pitää tällä siirtyä "seuraavalle riville" ostream &operator<<(ostream &os,const cKentta &k); - tulostaa kentän tietovirtaan muunnos_funktio muunnos() const - palauttaa muunnosfunktion osoitteen. Muunnosfunktiolla tehdään kenttään sen oikeellisuutta vastaava muunnos. Muunnosfunktiota on voitava käyttää jokaisen painetun merkin jälkeen. Muunosfunktio voi esimerkiksi poistaa laittomat merkit jonosta. const char *help_aihe() const - paluttaa merkkijonon tämän kentän "context sensitive" hakusanasta. esim. "t_nimi" (t = topic). Luokkahierarkia: help-aihe ---------------- class cKentta NULL class cJonoKentta : public cKentta t_ok class cJono1isoksiKentta : public cJonoKentta t_alku_isoksi class cJonoIsoksiKentta : public cJonoKentta t_1_isoksi class cIntKentta : public cKentta t_int class cDoubleKentta : public cKentta t_double class cHetuKentta : public cJonoKentta t_hetu class cHetu1Kentta : public cHetuKentta t_hetu_1 class cNimiKentta : public cJonoKentta t_nimi class cNimi1Kentta : public cNimiKentta t_nimi_1 class cPuhKentta : public cJonoKentta t_puh class cPostinumeroKentta : public cJonoKentta t_postinumero class cVirheKentta : public cJonoKentta t_virhe Kenttään voidaan sijoittaa esim. merkkijono metodilla sijoita("kissa") Metodi palauttaa cKenttavirhe -luokan, jossa on virheen vakavuus. Vakavuus kysytään metodilla Taso(): KENTTA_OK, KENTTA_VAROITUS, // Kenttä muutettu, riittää ilmoitus näyttöön KENTTA_MUUTETTU_KYSY, // Kenttä muutettu, kysy uudelleen KENTTA_UUDELLEEN, // Kenttää ei muutettu, kysyttävä uudelleen KENTTA_OK_ONKO_AINOA, // Syntaksi OK, yksikäsitteisyys tarkistettava KENTTA_OK_VAROITA_MUUT, // Syntaksi OK, ei-yksikäsitteisyys varmistettava KENTTA_TUNTEMATON_VIRHE Lisäksi luokassa cKenttavirhe on virhettä vastaava teksti C-merkkijonona, joka voidaan kysyä metodilla Virhe(). Normaalien kenttien lisäksi voi olla vielä erikoiskenttiä, mutta niitä ei ole toteutettu vielä. Erikoiskenttiä olisivat esimerkiksi taulukkotyyppiset kentät. (ks. eKenttatyyppi) Kentältä voidaan myös kysyä metodilla muunnos() osoite muunnosfunktiolle, jolla kentästä poistetaan kenttään kuulumattomat merkit, muutetaan mahdollisesti kentän kirjaimia isoiksi ja pieniksi jne. Kenttä voidaan tarvittaessa muuttaa merkkijonoksi (string) metodilla jonoksi(). Kenttä voidaan tulostaa tietovirtaan esim. cout << kentta Kentta voidaan ottaa tietovirrasta metodilla kentta.ota_seuraava(cin,"|,") missä "|," on erotinjoukko, eli erottimena joko | tai , ----------------------------------------------------------------------------*/ #ifndef __KENTTA_H #define __KENTTA_H #include #include //using namespace std; using std::string; #include "muunnos.h" //#include "mjonot.h" #include "mjonotpp.h" //int ota_seuraava(istream &is, char *s, int max_koko, const char *erotin); //int tyhjenna(istream &is); //---------------------------------------------------------------------------- // Virhetasot: //---------------------------------------------------------------------------- typedef enum { KENTTA_OK, // Kenttä kaikin puolin kunnossa KENTTA_VAROITUS, // Kenttä muutettu, riittää ilmoitus näyttöön KENTTA_MUUTETTU_KYSY, // Kenttä muutettu, kysy uudelleen KENTTA_UUDELLEEN, // Kenttää ei muutettu, kysyttävä uudelleen KENTTA_OK_ONKO_AINOA, // Syntaksi OK, yksikäsitteisyys tarkistettava KENTTA_OK_VAROITA_MUUT, // Syntaksi OK, ei-yksikäsitteisyys varmistettava KENTTA_TUNTEMATON_VIRHE } eVirhetaso; //---------------------------------------------------------------------------- // Kenttätyypit: //---------------------------------------------------------------------------- typedef enum { KENTTA_NORMAALI, // Tavallinen yhden alkion kentta KENTTA_LISTA, // Monesta alkiosta koostuva kentta KENTTA_TUNTEMATON } eKenttatyyppi; //---------------------------------------------------------------------------- // Luokka virheelle: //---------------------------------------------------------------------------- class cKenttavirhe { eVirhetaso taso; const char *virhe; void alusta(eVirhetaso t=KENTTA_OK) { virhe = ""; taso = t; } void alusta(eVirhetaso t, const char *v) { virhe = v; taso = t; } public: cKenttavirhe(eVirhetaso t=KENTTA_OK) { alusta(t,""); } cKenttavirhe(eVirhetaso t,const char *v) { alusta(t,v); } const char *Virhe() { return virhe; } eVirhetaso Taso() { return taso; } }; //---------------------------------------------------------------------------- // Pari makroa kirjoitustyön pienentämiseksi: //---------------------------------------------------------------------------- #define VIRHE(t,v) cKenttavirhe((t),(v)) #define cKENTTA_OK cKenttavirhe(KENTTA_OK) //---------------------------------------------------------------------------- // // cKentta // ======= // // Abstrakti luokka yleiselle tietueen kentälle // Jokaiseen kenttään on tehtävä ainakin seuraavat metodit: // alusta(const char *) // - alustaa kentän merkkijonolla ja palauttaa jonkin // kenttavirheen tai KENTTA_OK // string jonoksi() // - muuttaa kentän merkkijonoksi // Lisäksi jos katsotaan tarpeelliseksi, kannattaa tehdä // muunnosfunktion osoitteen palauttava metodi: // muunnos_funktio muunnos() // - palauttaa funktion, jolla merkkijono muunnetaan vastaamaan // kenttään sallitua muotoa. Esimerkiksi jos kenttään sallitaan // vain numerot, voidaan palauttaa jono_numerot -funktion osoite // Myös sijoituksia voi tehdä: // =(string st) // =(int i) // =(long l) // =(double d) // =(const char *s) // ehkä tärkein sijoitus //---------------------------------------------------------------------------- class cKentta { protected: virtual cKenttavirhe alusta(const char *s) = 0; virtual int muunna_ja_vertaa(char *p, int maxp, const char *s, muunnos_funktio fun=NULL) const; public: virtual ~cKentta() {;} virtual string jonoksi() const = 0; virtual const char *help_aihe() const { return "NULL"; } cKenttavirhe sijoita(const char *s) { return alusta(s); } cKenttavirhe sijoita(const string &st) { return sijoita(st.c_str());} cKenttavirhe sijoita(const cKentta &kentta); friend std::ostream &operator<<(std::ostream &os,const cKentta &k); virtual muunnos_funktio muunnos() const { return NULL; } }; inline std::ostream &operator<<(std::ostream &os,const cKentta &k) { os << k.jonoksi(); return os; } inline cKenttavirhe cKentta::sijoita(const cKentta &kentta) { if ( this == &kentta ) return KENTTA_OK; return sijoita(kentta.jonoksi()); } inline int cKentta::muunna_ja_vertaa(char *p,int maxp,const char *s, muunnos_funktio fun) const // Sijoitetaan s jonoon p. Muutetaan p muunnoksella ja tutkitaan // muuttuiko muunnoksessa. Jos muuttui, palautetaan 1, muutoin 0 // Muunnosfunktiota fun käytetään tutkimisen jälkeen p:hen. // fun voi olla esim. poista_tyhjat tms. { if ( p == NULL ) return 0; kopioi_jono(p,maxp,s); if ( muunnos() ) muunnos()(p); int eri = onko_samat(p,s); if ( fun ) fun(p); return eri; } //---------------------------------------------------------------------------- // Tietueen kenttä merkkijonona //---------------------------------------------------------------------------- class cJonoKentta : public cKentta { protected: string jono; virtual cKenttavirhe alusta(const char *s) { jono = s; return KENTTA_OK; } virtual int sijoita_muuttuuko(const char *s,muunnos_funktio fun = NULL); public: cJonoKentta(const char *s=NULL) : jono(s?s:"") {;} virtual string jonoksi() const { return jono; } virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual const char *help_aihe() const { return "t_ok"; } }; inline int cJonoKentta::sijoita_muuttuuko(const char *s,muunnos_funktio fun) // Muunnetaan s muunnoksella ja sijoitetaan se jonoon ja tutkitaan // muuttuiko muunnoksessa. Jos muuttui, palautetaan 1, muutoin 0 // Jos fun == NULL (oletus), poistetaan vertailun jälkeen tyhjat { char apu[100]; if ( fun == NULL ) fun = poista_tyhjat; int eri = muunna_ja_vertaa(N_S(apu),s,fun); jono = apu; return eri; } //---------------------------------------------------------------------------- // Tietueen kenttä merkkijonona jonka 1. merkki isoksi //---------------------------------------------------------------------------- class cJono1isoksiKentta : public cJonoKentta { protected: virtual cKenttavirhe alusta(const char *s) { sijoita_muuttuuko(s); return KENTTA_OK; } public: cJono1isoksiKentta(const char *s=NULL) : cJonoKentta(s) {;} virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual muunnos_funktio muunnos() const { return jono_1_isoksi; } virtual const char *help_aihe() const { return "t_1_isoksi"; } }; //---------------------------------------------------------------------------- // Tietueen kenttä merkkijonona jonka kaikki merkit isoiksi //---------------------------------------------------------------------------- class cJonoIsoksiKentta : public cJonoKentta { protected: virtual cKenttavirhe alusta(const char *s) { sijoita_muuttuuko(s); return KENTTA_OK; } public: cJonoIsoksiKentta(const char *s=NULL) : cJonoKentta(s) {;} virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual muunnos_funktio muunnos() const { return jono_isoksi; } virtual const char *help_aihe() const { return "t_isoksi"; } }; //---------------------------------------------------------------------------- // Tietueen kenttä kokonaislukuna //---------------------------------------------------------------------------- class cIntKentta : public cKentta { protected: int i; virtual cKenttavirhe alusta(const char *s); public: cIntKentta(int ui = TYHJA_ARVO) { i = ui; } virtual string jonoksi() const { char s[20]; int_jonoksi(N_S(s),i,"%d"); return string(s); } virtual int operator=(int ui) { i = ui; return ui; } virtual operator int() const { return i; } virtual muunnos_funktio muunnos() const { return int_muunnos; } virtual const char *help_aihe() const { return "t_int"; } }; inline cKenttavirhe cIntKentta::alusta(const char *s) { char p[30]; int ero = muunna_ja_vertaa(N_S(p),s); i = jono_intiksi(p,"%d"); return ero ? VIRHE(KENTTA_MUUTETTU_KYSY,"Laittomia merkkejä!") : cKENTTA_OK; } //---------------------------------------------------------------------------- // Tietueen kenttä reaalilukuna //---------------------------------------------------------------------------- class cDoubleKentta : public cKentta { protected: double d; virtual cKenttavirhe alusta(const char *s); public: cDoubleKentta(int ud = TYHJA_ARVO) { d = ud; } virtual string jonoksi() const { char s[20]; double_jonoksi(N_S(s),d,"%4.2lf"); return string(s); } virtual double operator=(double ud) { d = ud; return ud; } virtual muunnos_funktio muunnos() const { return double_muunnos; } virtual const char *help_aihe() const { return "t_double"; } }; inline cKenttavirhe cDoubleKentta::alusta(const char *s) { char p[30]; int ero = muunna_ja_vertaa(N_S(p),s); d = jono_doubleksi(p,"%lf"); return ero ? VIRHE(KENTTA_MUUTETTU_KYSY,"Laittomia merkkejä!") : cKENTTA_OK; } //---------------------------------------------------------------------------- // Tietueen kenttä henkilötunnuksena //---------------------------------------------------------------------------- cKenttavirhe hetu_tarkistus(string &jono,const char *sa,int yks); //---------------------------------------------------------------------------- class cHetuKentta : public cJonoKentta { protected: virtual cKenttavirhe alusta(const char *s) { return hetu_tarkistus(jono,s,0); } public: virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual muunnos_funktio muunnos() const { return hetu_muunnos; } virtual const char *help_aihe() const { return "t_hetu"; } }; //---------------------------------------------------------------------------- // Tietueen kenttä henkilötunnuksena joita saa olla vain yksi kpl //---------------------------------------------------------------------------- class cHetu1Kentta : public cHetuKentta { protected: virtual cKenttavirhe alusta(const char *s) { return hetu_tarkistus(jono,s,1); } public: virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual const char *help_aihe() const { return "t_hetu_1"; } }; //---------------------------------------------------------------------------- // Tietueen kenttä nimenä //---------------------------------------------------------------------------- class cNimiKentta : public cJonoKentta { protected: virtual cKenttavirhe alusta(const char *s) { sijoita_muuttuuko(s); return KENTTA_OK; } public: virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual muunnos_funktio muunnos() const { return jono_alku_isoksi;} virtual const char *help_aihe() const { return "t_nimi"; } }; //---------------------------------------------------------------------------- // Tietueen kenttä nimenä joita mahdollisesti saa olla vain 1 kpl //---------------------------------------------------------------------------- class cNimi1Kentta : public cNimiKentta { protected: virtual cKenttavirhe alusta(const char *s) { sijoita_muuttuuko(s); return KENTTA_OK_VAROITA_MUUT; } public: virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual const char *help_aihe() const { return "t_nimi_1"; } }; //---------------------------------------------------------------------------- // Tietueen kenttä puhelinnumerona //---------------------------------------------------------------------------- class cPuhKentta : public cJonoKentta { protected: virtual cKenttavirhe alusta(const char *s); public: virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual muunnos_funktio muunnos() const { return puh_muunnos; } virtual const char *help_aihe() const { return "t_puh"; } }; inline cKenttavirhe cPuhKentta::alusta(const char *s) { if ( sijoita_muuttuuko(s) ) return VIRHE(KENTTA_MUUTETTU_KYSY,"Vääriä merkkejä!"); return KENTTA_OK; } //---------------------------------------------------------------------------- // Tietueen kenttä postinumerona //---------------------------------------------------------------------------- class cPostinumeroKentta : public cJonoKentta { protected: virtual cKenttavirhe alusta(const char *s); public: virtual const char *operator=(const char *s) { sijoita(s); return s; } virtual muunnos_funktio muunnos() const { return numerot_muunnos;} virtual const char *help_aihe() const { return "t_postinumero";} }; inline cKenttavirhe cPostinumeroKentta::alusta(const char *s) { if ( sijoita_muuttuuko(s) ) return VIRHE(KENTTA_MUUTETTU_KYSY,"Vääriä merkkejä!"); int len = jono.length(); if ( len != 5 && len != 0 ) return VIRHE(KENTTA_MUUTETTU_KYSY,"Postinumerossa täytyy olla 5 numeroa!"); return KENTTA_OK; } //---------------------------------------------------------------------------- // Tietueen kenttä virheenä //---------------------------------------------------------------------------- class cVirheKentta : public cJonoKentta { protected: virtual cKenttavirhe alusta(const char *s); public: cVirheKentta(const char *s): cJonoKentta(s) {;} virtual const char *help_aihe() const { return "t_virhe"; } }; inline cKenttavirhe cVirheKentta::alusta(const char *s) { cJonoKentta::alusta(s); return VIRHE(KENTTA_VAROITUS,"Kenttävirhe"); } #undef cKENTTA_OK #undef VIRHE #endif