/****************************************************************************/ /* ** K E R H O R A K . C ** ** Kerhon rakenteeseen oleellisesti liittyvi„ aliohjelmia ** ** Aliohjelmat: ** kentan_tyyppi - palauttaa kent„n tyypin ** kentan_osoite - palauttaa kent„n osoitteen ** kentan_koko - palauttaa kent„n koon tavuina ** kentta_jonoksi - palauttaa valitun kent„n merkkijonona ** jono_kentaksi - muuttaa merkkijonon kent„ksi ** tulosta_jasen - tulostaa j„senen valittuun tiedostoon ** poista_NULL - poistaa osoitintaulukosta NULL-osoittimet ** tulosta_kenttalista - tulostaa valittavaksi kaikki j„sentietueen ** kent„t ** alusta_jasen - alustaa j„senen kent„t„ tyhjiksi ** lisaa_jasen - lis„„ uuden j„senen rakenteeseen ** luo_jasentaulukko - luo j„senosoitintaulukon ** kysy_kentta - kysyy j„senen valitun kent„n tiedot ** kysy_jasenen_tiedot - kysyy j„senen kaikkien kenttien tiedot ** kysy_haku - kysyy yhden hakukent„n arvon ** kysy_hakutiedot - kysyy koko hakutaulukon tiedot ** poista_jasen - varmistaa ja poistaa valitun j„senen ** ** ** ** ** Yleinen tietorakenne on seuraava: ** ** ** Kerho_tyyppi Haku_tyyppi Jasen_tyyppi ** ------ ------- ** | | | | ** | 7 | |--->| | ** | 3 | | | | ** | | | ------- ------ ** | | | | | ** | o--+----| |---->| | ** | | jasenet | | | ------ ** | o--+------>|-----| | ------ | | ** ------ | o--+-----| | | ** |-----| |----->| | ** | o--+------------| ------ ------ ** |-----| | | ** | o--+--------------------------->| | ** |-----| | | ** | o--+--? ------ ** |-----| ** | o--+--? ** |-----| ** | o--+--? ** |-----| ** | o--+--? ** |-----| ** ** ** ** Tekij„t: Vesa Lappalainen ** Ohjelmointikurssi 1991 ** Tehty: 20.12.1991 ** Muutettu: 21.12.1991 ** Mit„ muutettu: lis„tty kysy_jasenen_tiedot ** Muutettu: 21.12.1991/vl ** Mit„ muutettu Tietojen oikeellisuustarkistukset ** kysy_jasenen_tiedot 2 uutta parametria ** Muutettu: 24.12.1991/vl ** Mit„ muutettu: Lis„tty etsimisess„ ja selailussa tarvittavia osia. ** Rakenteesta riippuvat vain tiedostot ** kerho.h ja kerhorak.h ** Muutettu: 23.12.1992/vl ** Mit„ muutettu: Korjattu painovirheit„. ** ** */ #include #include #include #include #include "mjonot.h" #include "kerho.h" #define OLET_ALKU 19 /* Oletuksen alkusarake */ #define VAKANEN 33 /* V„k„sen alkusarake */ char KENTTAVALINNAT[50] = "123456789ABCDEFGHIJ ?+-" NAP_KORJ_POISTO NAP_JA_TAI; /****************************************************************************/ Tyypit /* -1 = tuntematon kent„n numero */ kentan_tyyppi( /* muut = kent„n tyyppi */ int nro ,/* s Kent„n numero, jonka tyyppi halutaan. */ Jasen_tyyppi *jasen /* s J„sen, jonka kent„n tyyppi halutaan. */ ) /* ** Funktiolla palautetaan kent„n tyyppi. ** ----------------------------------------------------------------------------*/ { if (!jasen) return -1; switch (nro) { case NIMIKENTTA : return Tjono; case SOTUKENTTA : return Tsotu; case KATUKENTTA : return Tjono; case POSTINROKENTTA : return Tjono; case POSTIOSKENTTA : return Tjono; case KOTIPUHKENTTA : return Tjono; case TYOPUHKENTTA : return Tjono; case AUTOPUHKENTTA : return Tjono; case LIITTYMISKENTTA: return Tint ; case JMAKSUKENTTA : return Tdouble; case MAKSUKENTTA : return Tdouble; case LISATIETOJAKENTTA: return Tjono; default: return -1; } } /****************************************************************************/ void /* NULL = tuntematon kent„n numero */ *kentan_osoite( /* muut = osoitin kent„n alkuun */ int nro ,/* s Kent„n numero, jonka osoitin halutaan. */ Jasen_tyyppi *jasen /* s J„sen, jonka kent„n osoite halutaan */ ) /* ** Funktiolla palautetaan osoitin kent„n alkuun. ** ----------------------------------------------------------------------------*/ { if (!jasen) return NULL; switch (nro) { case NIMIKENTTA : return jasen->nimi; case SOTUKENTTA : return jasen->sotu; case KATUKENTTA : return jasen->katuosoite; case POSTINROKENTTA : return jasen->postinumero; case POSTIOSKENTTA : return jasen->postiosoite; case KOTIPUHKENTTA : return jasen->kotipuhelin; case TYOPUHKENTTA : return jasen->tyopuhelin; case AUTOPUHKENTTA : return jasen->autopuhelin; case LIITTYMISKENTTA: return &jasen->liittymisvuosi; case JMAKSUKENTTA : return &jasen->jmaksu; case MAKSUKENTTA : return &jasen->maksu; case LISATIETOJAKENTTA: return jasen->lisatietoja; default: return NULL; } } /****************************************************************************/ int /* 0 = tuntematon kent„n numero */ kentan_koko( /* muut = kent„n koko tavuina */ int nro ,/* s Kent„n numero, jonka koko halutaan. */ Jasen_tyyppi *jasen /* s J„sen, jonka kent„n koko halutaan. */ ) /* ** Funktiolla palautetaan kent„n koko tavuina. ** ----------------------------------------------------------------------------*/ { if (!jasen) return 0; switch (nro) { case NIMIKENTTA : return sizeof(jasen->nimi); case SOTUKENTTA : return sizeof(jasen->sotu); case KATUKENTTA : return sizeof(jasen->katuosoite); case POSTINROKENTTA : return sizeof(jasen->postinumero); case POSTIOSKENTTA : return sizeof(jasen->postiosoite); case KOTIPUHKENTTA : return sizeof(jasen->kotipuhelin); case TYOPUHKENTTA : return sizeof(jasen->tyopuhelin); case AUTOPUHKENTTA : return sizeof(jasen->autopuhelin); case LIITTYMISKENTTA: return sizeof(jasen->liittymisvuosi); case JMAKSUKENTTA : return sizeof(jasen->jmaksu); case MAKSUKENTTA : return sizeof(jasen->maksu); case LISATIETOJAKENTTA: return sizeof(jasen->lisatietoja); default: return -1; } } static char kentta_jonona[80]; /****************************************************************************/ char /* */ *kentta_jonoksi( /* = jonon osoite */ int kentta ,/* s Kentt„, joka muutetaan jonoksi */ Jasen_tyyppi *jasen /* s J„sen jonka kentt„ otetaan */ ) /* ** Funktiolla otetaan j„senen valittu kentt„ ja palautetaan se merkkijonona. ** Mik„li kyseess„ on tekstikentt„, palautetaan osoitin kent„n alkuun. ** Muussa tapauksessa kent„n arvo laitetaan staattiseen merkkijonoon ** jonka osoite palautetaan. Seuraavalla kutsulla t„m„n merkkijonon ** arvo muuttuu, joten mik„li tulos halutaan s„ilytt„„, pit„„ se heti kutsun ** j„lkeen kopioida jononkin toiseen muuttujaan. ** ** Globaalit: kentta_jonona ** Kutsuu: kentan_tyyppi ** kentan_osoite ** kopioi_jono ** Esimerkki: kopioi_jono(N_S(jono),kentta_jonona(5,jasen)); ----------------------------------------------------------------------------*/ { void *p; int tyyppi,i; double d; tyyppi = kentan_tyyppi(kentta,jasen); p = kentan_osoite(kentta,jasen); kentta_jonona[0]=0; /* Alustetaan tyhj„ksi. */ switch (tyyppi) { case Tsotu: case Tjono: return p; case Tint: i = *(int *)p; if ( i == TYHJA_ARVO ) break; sprintf(kentta_jonona,"%d",i); break; case Tdouble: d = *(double *)p; if ( d == TYHJA_ARVO ) break; sprintf(kentta_jonona,"%4.2lf",d); break; default: kopioi_jono(N_S(kentta_jonona),"VIRHE!"); break; } return kentta_jonona; } /****************************************************************************/ void /* */ jono_kentaksi( /* = jonon osoite, jos taytyy_kopioida==1 */ int kentta ,/* s Kentt„, joka muutetaan jonoksi */ Jasen_tyyppi *jasen ,/* t J„sen jonka kentt„ otetaan */ char *jono /* s Jono, joka muutetaan kent„ksi. */ ) /* ** Funktiolla muutetaan merkkijono valittuun kentt„„n arvoksi. ** ** Kutsuu: kentan_tyyppi ** kentan_osoite ** kentan_koko ** kopioi_jono ** Esimerkki: kopioi_jono(N_S(jono),kentta_jonona(5,jasen)); ----------------------------------------------------------------------------*/ { void *p; int tyyppi,i=TYHJA_ARVO; double d=TYHJA_ARVO; tyyppi = kentan_tyyppi(kentta,jasen); p = kentan_osoite(kentta,jasen); switch (tyyppi) { case Tsotu: case Tjono: kopioi_jono(p,kentan_koko(kentta,jasen),jono); return; case Tint: sscanf(jono,"%d",&i); *(int *)p = i; return; case Tdouble: sscanf(jono,"%lf",&d); *(double *)p = d; return; default: ; } } /****************************************************************************/ void tulosta_jasen( /* */ FILE *f ,/* s Tiedosto johon tulostetaan */ Jasen_tyyppi *jasen /* s Tulostettava j„sen */ ) /* ** Funktiolla tulostetaan j„sen valittuun tiedostoon. ** Mik„li numeerisessa kent„ss„ on tyhj„ arvo, ei sit„ tulosteta! ** ** Tulostus: tiedostoon f ** Kutsuu: kentta_jonoksi ** int_jonoksi,double_jonoksi ----------------------------------------------------------------------------*/ { char st[80]; fprintf(f," %s %s\n", jasen->nimi, jasen->sotu); fprintf(f," %s %s %s\n", jasen->katuosoite, jasen->postinumero, jasen->postiosoite); fprintf(f," k: %s t: %s a: %s\n",jasen->kotipuhelin, jasen->tyopuhelin, jasen->autopuhelin); fprintf(f," Liittynyt %s.",int_jonoksi(N_S(st),jasen->liittymisvuosi,"%d")); fprintf(f," J„senmaksu %s mk.", double_jonoksi(N_S(st),jasen->jmaksu,"%5.2lf")); fprintf(f," Maksettu %s mk\n", double_jonoksi(N_S(st),jasen->maksu,"%5.2lf")); fprintf(f," %s\n",jasen->lisatietoja); } /****************************************************************************/ int /* */ poista_NULL( /* 0 = poisto onnistui, 1 = ep„onnistui */ Kerho_tyyppi *kerho /* s Kerho josta NULL-osoittimet poistetaan. */ ) /* ** Funktiolla poistetaan NULL osoittimet listasta. ** ** Algoritmi: Lukuosoitin ja kirjoitusosoitin, joiden v„limatkaa ** kasvatetaan aina, kun l”ytyy poistettava. ----------------------------------------------------------------------------*/ { int j,k=0; for (j=0; jjasenia; j++) if ( kerho->jasenet[j] ) kerho->jasenet[k++] = kerho->jasenet[j]; kerho->jasenia = k; kerho->nykyjasen = 0; return 0; } /****************************************************************************/ void /* */ tulosta_kenttalista( /* */ char *lista /* s Kent„t, jotka tulostetaan n„ytt””n. */ ) /* ** Aliohjelmalla tulostetaan kentt„lista n„ytt””n. Vain ne kent„t ** tulostetaan, joiden valintakirjain on mukana listassa. ** ** Tulostus: N„ytt””n ** Kutsuu: ----------------------------------------------------------------------------*/ { if ( strchr(lista,'1') ) printf(" 1 = nimi\n"); if ( strchr(lista,'2') ) printf(" 2 = sotu\n"); if ( strchr(lista,'3') ) printf(" 3 = katuosoite\n"); if ( strchr(lista,'4') ) printf(" 4 = postinumero\n"); if ( strchr(lista,'5') ) printf(" 5 = postiosoite\n"); if ( strchr(lista,'6') ) printf(" 6 = kotipuhelin\n"); if ( strchr(lista,'7') ) printf(" 7 = ty”puhelin\n"); if ( strchr(lista,'8') ) printf(" 8 = autopuhelin\n"); if ( strchr(lista,'9') ) printf(" 9 = liittymisvuosi\n"); if ( strchr(lista,'A') ) printf(" A = j„senmaksu\n"); if ( strchr(lista,'B') ) printf(" B = maksettu maksu\n"); if ( strchr(lista,'C') ) printf(" C = lis„tietoja\n"); if ( strchr(lista,NAP_JA) ) printf(" %c = %s\n",NAP_JA,"JA ehto kaikille kentille"); if ( strchr(lista,NAP_TAI) ) printf(" %c = %s\n",NAP_TAI,"TAI ehto kaikille kentille"); printf(" "); } /****************************************************************************/ void /* */ alusta_jasen( /* */ Kerho_tyyppi *kerho ,/* s Kerho, jonka j„sen alustetaan. */ Jasen_tyyppi *jasen /* t Alustettava j„sen. */ ) /* ** Aliohjelmalla alustetaan j„senen tiedot kerhon nykyj„senen mukaan. ** Ne kent„t, jotka halutaan lis„yksess„ tyhjent„„, tyhjennet„„n. ** Mik„li kerhossa ei ole j„seni„, tyhjennet„„n kaikki kent„t! ** ** Globaalit: KENTAT ----------------------------------------------------------------------------*/ { int k; if ( kerho->nykyjasen >= kerho->jasenia ) for (k=0; kjasenet[kerho->nykyjasen]; jasen->nimi[0]=0; jasen->sotu[0]=0; jasen->autopuhelin[0]=0; jasen->lisatietoja[0]=0; } } /****************************************************************************/ int /* */ lisaa_jasen( /* 0 = onnistui 1 = ei onnistu */ Kerho_tyyppi *kerho ,/* s,t K„sitelt„v„ kerho */ Jasen_tyyppi *jasen /* s Lis„tt„v„ j„sen */ ) /* ** Funktiolla lis„t„„n uusi j„sen kerhoon. EI tarkisteta esiintyyk” ** nimi jo ennest„„n. Mik„li tilaa ei ole, yritet„„n allokoida uutta ** tilaa 50% maksimim„„r„„n n„hden lis„„. ** ** Algoritmi: Jos uudelle j„senelle saadaan varattua tilaa, lis„t„„n ** uuden paikan osoite taulukkoon jo kopioidaan tiedot ** uuteen paikkaan. ----------------------------------------------------------------------------*/ { Jasen_tyyppi *uusi_jasen,**uusi_tila; int uusi_koko; if ( kerho->jasenia >= kerho->max_jasenia ) { uusi_koko = 3*(kerho->max_jasenia)/2; uusi_tila = realloc(kerho->jasenet,uusi_koko*sizeof(Jasen_tyyppi *)); if ( !uusi_tila ) return 1; kerho->jasenet=uusi_tila; kerho->max_jasenia=uusi_koko; } uusi_jasen = malloc(sizeof(Jasen_tyyppi)); if ( uusi_jasen==NULL ) return 1; *uusi_jasen = *jasen; kerho->jasenet[kerho->jasenia]=uusi_jasen; kerho->nykyjasen=kerho->jasenia; kerho->jasenia++; return 0; } static char *EI_VOI_LUODA = "J„senist”lle ei saada varattua tilaa muistista!"; /****************************************************************************/ char /* NULL =onnistui */ *luo_jasentaulukko( /* muut = virheilmoitus merkkijonona */ Kerho_tyyppi *kerho ,/* t K„sitelt„v„ kerho */ int koko /* s Kerhon maksimij„senm„„r„. */ ) /* ** Funktiolla luodaan kerhoon tyhj„ osoitintaulukko j„senist””n. Mik„li ** j„sentaulukkoa ei voida luoda, palautetaan virheilmoitus. ** Mik„li taulukko saadaan luotua, alustetaan se NULL-osoittimilla. ----------------------------------------------------------------------------*/ { int i; kerho->jasenet = malloc(koko*(sizeof(Jasen_tyyppi *))); kerho->max_jasenia=koko; kerho->jasenia=0; kerho->haku=NULL; if (!kerho->jasenet) return EI_VOI_LUODA; for (i=0; ijasenet[i]=NULL; return NULL; } /****************************************************************************/ char /* "" jos v„„r„ kent„n nro */ *viesti( /* Kent„n numeroa nro vastaava viesti */ int nro /* Kent„n numero, jonka viesti halutaan. */ ) /* ** Funktiolla palautetaan haluttua kentt„„ vastaava kent„n kysymisess„ ** tarvittava viesti. ** ----------------------------------------------------------------------------*/ { switch (nro) { case 0: return "J„senen nimi" ; case 1: return "Sotu" ; case 2: return "Katuosoite" ; case 3: return "Postinumero" ; case 4: return "Postiosoite" ; case 5: return "Kotipuhelin" ; case 6: return "Ty”puhelin" ; case 7: return "Autopuhelin" ; case 8: return "Liittymisvuosi" ; case 9: return "J„senmaksu mk" ; case 10: return "Maksettu maksu mk"; case 11: return "Lis„tietoja" ; default: return "" ; } } /****************************************************************************/ int /* 1 = lopetetaan sy”tt” */ kysy_kentta( /* 0 = OK */ int nro ,/* s Luettavan kent„n numero */ char *jono ,/* t Jono johon kent„n vastaus luetaan. */ int max_koko ,/* s Jonon maksimi koko. */ Tarkistus_funktio f ,/* s Funktio, jolla jonon oikeellisuus tark. */ Tarkistus_tyyppi *tark /* s Tarkistusfunktion parametri */ ) /* ** Funktiolla luetaan vastaus kentt„„n. ** ** Globaalit: POIS (jono, jolla sy”tt” katkaistaan) ** Sy”tt”: p„„tteelt„ ** Tulostus: n„ytt””n ** Kutsuu: lue_jono_oletus ----------------------------------------------------------------------------*/ { char apu[80]; Tarkistus_tulos_tyyppi f_paluu; int paluu; tark->kentta = nro; kopioi_jono(N_S(apu),jono); do { paluu = lue_jono_oletus(viesti(nro),OLET_ALKU,VAKANEN,apu,N_S(apu)); if ( paluu < OLETUS ) return 1; poista_tyhjat(apu); if ( strcmp(apu,POIS)==0 ) return 1; if (!f) break; /* Jollei tarkistusfunktiota, niin kaikki kelpaa! */ f_paluu = f(tark,apu); if ( f_paluu == TARK_LOPETUS ) return 1; if ( f_paluu == TARK_PAL_OLET ) kopioi_jono(N_S(apu),jono); } while ( f_paluu != TARK_OK ); kopioi_jono(jono,max_koko,apu); return 0; } /****************************************************************************/ int /* 0 = hommat OK */ kysy_jasenen_tiedot( /* 1 = halutaan pois kysymyksest„ */ Kerho_tyyppi *kerho ,/* s Kerho johon j„sent„ kysyt„„n */ Jasen_tyyppi *jasen ,/* s,t T„ytett„v„n j„senen tiedot */ int kysymys_tyyppi /* s Sy”tt”, p„ivitys, lis„ys? */ ) /* ** Funktiolla kysell„„n j„senen tiedot. Oletusarvoina k„ytet„„n ** jasenen alkuper„isi„ tietoja. ** Mik„li jonoa luettaessa pit„„ poistua, lopetetaan kysymykset ** ja j„senen alkuper„iset tiedot s„ilyv„t. ** palautetaan 1. ** Numeeriset kent„t muutetaan merkkijonoiksi ennen kysymist„. ** ** Sy”tt”: p„„tteelt„ ** Tulostus: n„ytt””n ** Kutsuu: kysy_kentta ** jono_intiksi, int_jonoksi, jono_doubleksi, double_jonoksi ----------------------------------------------------------------------------*/ { #define LUE_KENTTA(jono,t_fun) \ if ( kysy_kentta(k++,N_S(jono),t_fun,&tarkistus) ) return 1; Jasen_tyyppi apu_jasen; Tarkistus_tyyppi tarkistus; char st[80]; int k=0; tarkistus.kerho = kerho; tarkistus.syotto_tyyppi = kysymys_tyyppi; tarkistus.jasen = &apu_jasen; apu_jasen=*jasen; LUE_KENTTA(apu_jasen.nimi ,t_nimi); LUE_KENTTA(apu_jasen.sotu ,t_sotu); LUE_KENTTA(apu_jasen.katuosoite ,t_katu); LUE_KENTTA(apu_jasen.postinumero,t_numeerinen); LUE_KENTTA(apu_jasen.postiosoite,t_isoksi); LUE_KENTTA(apu_jasen.kotipuhelin,t_puh); LUE_KENTTA(apu_jasen.tyopuhelin ,t_puh); LUE_KENTTA(apu_jasen.autopuhelin,t_puh); int_jonoksi(N_S(st),apu_jasen.liittymisvuosi,"%d"); LUE_KENTTA(st ,t_vuosi_1900); apu_jasen.liittymisvuosi = jono_intiksi(st,"%d"); double_jonoksi(N_S(st),apu_jasen.jmaksu,"%4.2lf"); LUE_KENTTA(st ,t_ok); apu_jasen.jmaksu = jono_doubleksi(st,"%lf"); double_jonoksi(N_S(st),apu_jasen.maksu,"%4.2lf"); LUE_KENTTA(st ,t_ok); apu_jasen.maksu = jono_doubleksi(st,"%lf"); LUE_KENTTA(apu_jasen.lisatietoja,t_ok ); *jasen = apu_jasen; return 0; #undef LUE_KENTTA } /****************************************************************************/ int /* 0 = kentt„ OK */ kysy_haku( /* 1 = halutaan poistua */ Haku_tyyppi *haku ,/* s,t T„ytett„v„ hakutietue */ int nro /* s Kysytt„v„ kentt„ */ ) /* ** Funktiolla kysyt„„n kent„n tiedot. Oletusarvoina k„ytet„„n ** kent„n alkuper„isi„ tietoja. ** Mik„li kentt„„n vastataan q, lopetetaan kysymykset ja ** palautetaan 1. ** ** Sy”tt”: p„„tteelt„ ** Tulostus: n„ytt””n ** Kutsuu: kysy_kentta ----------------------------------------------------------------------------*/ { Tarkistus_tyyppi tark; return kysy_kentta(nro,N_S(haku[nro]),t_ok,&tark); } /****************************************************************************/ int /* 0 = hommat OK */ kysy_hakutiedot( /* 1 = halutaan pois kysymyksest„ */ Haku_tyyppi *haku /* s,t T„ytett„v„ hakutaulukko */ ) /* ** Funktiolla kysell„„n hakutaulukon tiedot. Oletusarvoina taulukon ** alkuper„iset tiedot. ** Mik„li johonkin kentt„„n vastataan q, lopetetaan kysymykset ja ** palautetaan 1. ** ** Sy”tt”: p„„tteelt„ ** Tulostus: n„ytt””n ** Kutsuu: kysy_haku ----------------------------------------------------------------------------*/ { int k; printf("== tarkoittaa, ett„ kent„n TŽYTYY olla tyhj„\n"); for (k = 0; k < KENTTIA; k++) { if ( kysy_haku(haku,k) ) return 1; } return 0; } /****************************************************************************/ int /* */ poista_jasen( /* 0 = onnistui, 1 = ep„onnistui */ Kerho_tyyppi *kerho ,/* s,t Kerho josta poistetaan. */ int poistettava /* s Poistettavan j„senen numero */ ) /* ** Funktiolla poistetaan j„sen listasta. Poisto varmistetaan k„ytt„j„lt„. ** Listaan laitetaan j„senen paikalle NULL ja itse j„sen h„vitet„„n. ** ** Sy”tt”: P„„tteelt„ ** Tulostus: N„yt”lle ** Kutsuu: odota_nappain ----------------------------------------------------------------------------*/ { char vastaus; printf("Haluatko todellakin poistaa j„senen %s (k/E):", kerho->jasenet[poistettava]->nimi); vastaus=odota_nappain("KE",'E',VAIN_ISOT); printf("\n"); if ( vastaus=='E' ) return 1; free(kerho->jasenet[poistettava]); kerho->jasenet[poistettava]=NULL; printf("J„sen poistettu!\n"); return 0; }