/****************************************************************************/ /* ** K E R H O L R A . C ** ** Kerhon rakenteen lukeminen tiedostosta. ** ** Rakennetiedoston muoto on seuraava: ** *|; Kerhon rakenne: *|#|Kent„n kysyminen |Kent„n nimi |pi|al|le|Tyyppi |form|tark.|mallitulostus| rajat % komentti *|;|-------------------------------------------------------------------------------------------- *|1|J„senen nimi |nimi |40|==|19|Tjono |%s|t_nimi| " %s" | % Nimi t„h„n *|2|Sotu |sotu |12|==|11|Tsotu |%s|t_sotu| " %s\n" *|3|Katuosoite |katuosoite |40| |15|Tjono |%s|t_katu| " %s" *|4|Postinumero |postinumero |6 | |05|Tjono |%s|t_numeerinen| " %s" *|5|Postiosoite |postiosoite |30| |15|Tjono |%s|t_isoksi| " %s\n" *|6|Kotipuhelin |kotipuhelin |15| |11|Tjono |%s|t_puh| " k: %s" *|7|Ty”puhelin |ty”puhelin |15|==|11|Tjono |%s|t_puh| " t: %s" *|8|Autopuhelin |autopuhelin |15|==|11|Tjono |%s|t_puh| " a: %s\n" *|9|Liittymisvuosi |liittymisvuosi | 2|93|04|Tint |%d|t_vuosi_1900| " Liittynyt %s." | ">1990" *|A|J„senmaksu mk |j„senmaksu | 4| |06|Tdouble|%6.2lf|t_ok| " J„senmaksu %s mk." *|B|Maksettu maksu mk |maksettu maksu | 4| |06|Tdouble|%6.2lf|t_ok| " Maksettu %s mk\n" *|C|Lis„tietoja |lis„tietoja |80| |30|Tjono |%s|t_ok| " %s\n" *|##Menu: ####################################################################################### *|"012345" *|"\n\n\n\n\n" *|"J„senrekisteri\n" *|"==============\n" *|"\n" *|"Kerhossa %s on %d j„sent„.\n" *|"\n" *|"Valitse:\n" *|" 0 = lopetus\n" *|" 1 = lis„„ uusi j„sen\n" *|" 2 = etsi j„senen tiedot\n" *|" 3 = tulosteet\n" *|" 4 = tietojen korjailu\n" *|" 5 = p„ivit„ j„senmaksuja\n" *|" :" *|##Lis„yksen otsikko: ############################################################## *|19 33 *|"\n" *|"J„seni„ on nyt %d.\n" *|"Anna uusi nimi muodossa sukunimi etunimi etunimi\n" *|################################################################################### ** ** Huom! Itse kentti„ selitt„v„l„ rivill„ erotinmerkkin„ on |, paitsi ** viimeisess„ kohdassa, jossa erotin on % (koska rajoissa voi olla TAI eli |) ** ** Kenttien selityksess„ sarakkeet ovat: **-------------------------------------- ** 1. # = Kent„n pikavalintakirjain; varo varattuja ** kirjaimia kuten K=korjaus, P=poisto, ?=avustus ** |=TAI-haku, &=JA-haku ** Kirjainten ei tarvitse olla j„rjestyksess„! ** 2. Kent„n kysyminen = Kentt„„ kysytt„ess„ tuleva merkkijono ** 3. Kent„n nimi = Kent„n nimi er„iss„ tulostuksissa ja mallirivill„ ** talletuksessa (talletuksessa nimi katkeaa) ** 4. pi = kent„n pituus jos tyypiss„ ei ole erikseen pituutta ** Jos kent„n tyyppiin liittyy pituus, voittaa se t„m„n ** m„„rityksen (ei siis tarvitse tiet„„ onko int 2 vai 4 tavua) ** 5. al = kent„n alustus uutta lis„tt„ess„ ** == tyhjennet„„n kent„n oletusarvo ** (tyhj„) k„ytet„„n edellisen arvoa oletuksena ** muut k„ytet„„n t„t„ arvoa oletuksena ** 6. le = kent„n leveys talletettaessa tiedostoon, jos kentt„ ** tarvitsee enemm„n leveytt„, k„ytet„„n enemm„n, mutta ** sarakkeet sotkeutuvat (eli eiv„t ole kauniita) ** 7. Tyyppi = kent„n tyyppi ** "Tint", "Tdouble", "Tjono", "Tsotu", "Tarvo" ** tarkista taulukko TYYPIT t„ss„ tiedostossa ** 8. form = k„ytett„v„ formaatti kun numeerisia kentti„ muutetaan ** merkkijonoiksi ** "%6.2lf" -> " 5.00" jos kentt„ Tdouble ja 5 ** 9. tark. = k„ytett„v„ tarkistusfunktio ** kelpaavat nimet ks. kerhotar.c * esim. t_ok, t_sotu ** 10. mallitulostus = kent„n tulostuksen formaatti ** 12345678901234567890 ** " Tulos: %s" -> " Tulos: 5.00" ** " Tulos: %10s" -> " Tulos: 5.00" ** " Tulos: %-10s"-> " Tulos: 5.00 " ** " Tulos:" -> " Tulos:" ** Huom! %s:i„ saa olla liian v„h”n muttei liikaa! ** 11. rajat = ehdot sy”t”n oikeellisuudelle ** ">=0&<=5" -> sy”t”n t„ytyy olla 0 ja 5 v„l. ** "Mat|Fys|Kem" -> sy”t”n t„ytyy olla jokin em. ** "A*|B?" -> t„ytyy alkaa A:lla tai olla ** B ja jokin tasan yksi muu merkki ** 12 komentti = vapaavalintaista teksti„, joka ei tule mihink„„n ** ** Valikko ja otsikot: **-------------------- ** Tiedoston kaksi viimeist„ osaa kuvaavat p„„valikkoa ja ** lis„yksen otsikoksi tulevaa teksti„. Mik„li n„it„ ** osia ei ole, tulee niille oletusarvot. ** Menu 1. rivi on menun valintakirjaimet ** %s korvautuu rekisterin koko nimell„ ** %d tietueiden t„m„n hetkisell„ lukum„„r„ll„ ** Lis„yksen otsikon kentt„ 1. rivi on vasemman sulun ja > paikka ** kysymyksess„ "Sotu (010271-1234) >" ** %d korvautuu tietueiden m„„r„ll„ ** ** Tiedoston loppuosa voidaan kirjoittaa my”s ilman "-merkkej„ ja ** t„ll”in uusi rivi merkitsee aina rivinvaihtoa. ** ** Aliohjelmat: ** lue_rakennetiedosto - lukee annetun nimisest„ tiedostosta rakenteen ** kysy_rakenne - kysyy uuden rakenteen ** rakenteen_nro - rakenteen numero nimen perusteella ** talleta_kaikki_rakenne_optiot - optiotiedoston k„s. kutsu ** rakenteen_vaihto_sallittu - onko sallittua vaihtaa rakennetta? ** ** ** Tekij„t: Vesa Lappalainen ** Ohjelmointikurssi 1991 ** Tehty: 26.12.1991 ** Muutettu: 27.12.1991 ** Mit„ muutettu: Sallii useita rakenteita. ** Mik„li rakenne on jo luettu, palautetaan ** vanhan rakenteen osoite. ** Muutettu: 28.12.1991 ** Mit„ muutettu: My”s menu luetaan rakennetiedostosta. ** Muutettu: 18.12.1993 ** Mit„ muutettu: - Sy”t”n rajat rakennetiedostoon. ** - optioiden talletus ** ** */ #include #include #include #include #include "mjonot.h" #include "kerho.h" /****************************************************************************/ /* ** Aputyypit lukujen sijoittumisen tutkimiseksi tietueessa, eli ** tuleeko systeemiss„ tietyn tyyppiset luvut mielivaltaisiin ** osoitteisiin, parillisiin osoitteisiin, 4:ll„ jaollisiin os. ** jne.. ** */ typedef struct { char hopo; char jono[10]; } CHAR_tyyppi; typedef struct { char hopo; int luku; } INT_tyyppi; typedef struct { char hopo; double luku; } DOUBLE_tyyppi; /****************************************************************************/ /* ** Tunnetut tietotyypit: */ typedef struct { char *nimi; Tyypit tyyppi; int koko; int jaollisuus; /* Sijoittuminen 1,2,4 jaoll. osoitteisiin */ } Tyypit_tyyppi; static Tyypit_tyyppi TYYPIT[] = { {"Tjono", Tjono, 0, offsetof(CHAR_tyyppi ,jono)}, {"Tsotu", Tsotu, 12, offsetof(CHAR_tyyppi ,jono)}, {"Tint", Tint, sizeof(int) ,offsetof(INT_tyyppi ,luku)}, {"Tdouble",Tdouble,sizeof(double),offsetof(DOUBLE_tyyppi,luku)}, {"Tarvo", Tarvo, sizeof(double),offsetof(DOUBLE_tyyppi,luku)}, {NULL , 0, 0 ,0 } }; #if 0 /****************************************************************************/ static char * /* "NULL" = tyypille ei ole nime„ */ tyypin_nimi( /* muut = tyyppi„ vastaava nimi */ Tyypit tyyppi /* s Tyyppi, jolle nime„ etsit„„n */ ) /* Funktiolla palautetaan tyyppi„ vastaava nimi ** Esim. Tint -> "Tint" ----------------------------------------------------------------------------*/ { int i; for (i=0; TYYPIT[i].nimi; i++) if ( TYYPIT[i].tyyppi == tyyppi ) return TYYPIT[i].nimi; return "NULL"; } #endif /****************************************************************************/ static int /* -1 = nime„ vastaavaa tyyppi„ ei ole */ tyypin_nro( /* muut = nime„ vastaavan tyypin indeksi */ const char *nimi /* s Tyypin nimi, jolle tyyppi„ etsit„„n. */ ) /* Funktiolla palautetaan tyypin nime„ vastaava tyyppi ** Esim. "Tint" -> indeksi Tint (2) ** "Tin*" -> indeksi Tint (2) - jokerit kelpaavat ** "TINT" -> indeksi Tint (2) - isoilla ja pienill„ ei v„li„ ----------------------------------------------------------------------------*/ { int i; for (i=0; TYYPIT[i].nimi; i++) if ( onko_samat(TYYPIT[i].nimi,nimi) == 0 ) return i; return -1; } /****************************************************************************/ /* ** Ennest„„n luetut rakenteet: */ #define MAX_RAKENTEITA 50 static RAKENTEITA = 0; static Rakenne_tyyppi *RAKENTEET[MAX_RAKENTEITA] = {NULL}; /****************************************************************************/ char /* */ *muuta_erikoismerkit( /* muutettu jono. */ char *jono /* s,t Muutettava jono */ ) /* ** Funktiolla muutetaan kaikki jonossa olevat erikoismerkit. ** Toimii toistaiseksi vain " \" ja \n merkeille. ** Tiedostosta luettu \n on todellakin kaksi eri merkki„ \ ja n ** eik„ rivinvaihto kuten ohjelmaan kirjoitettuna. Siksi n„m„ ** yhdistelm„t korvataan vastaavalla oikealla merkill„. ** ** Muuttuu: jono ** Esimerkki: jono= "aaa" "bbb" -> jono=aaabbb ** jono= "aaaaaaa c -> jono=aaaaaaa c ----------------------------------------------------------------------------*/ { char *p,*a; while ( (p = strstr(jono,"\\n")) != NULL ) { memmove(p,p+1,strlen(p+1)+1); *p = '\n'; } while ( (p = strstr(jono,"\\\"")) != NULL ) { /* \" -> 0xff tilap„isesti */ memmove(p,p+1,strlen(p+1)+1); *p = 0xff; } /* Nyt jos l”ytyy lainausmerkkej„, niin kaikki ne ja niiden ulkop.osa pois*/ a = jono; p = strchr(a,'\"'); while ( p ) { memmove(a,p+1,strlen(p+1)+1); /* Pois 1. " ja sit„ ed. osa */ p = strchr(a,'\"'); if (!p) break; a = p; /* 2. " */ p = strchr(a+1,'\"'); /* L”ytyyk” viel„ " */ if ( !p ) *a=0; /* Jollei, niin katkaistaan 2. " kohdalta*/ } p = jono; while ( (p = strchr(p,0xff)) != NULL ) *p = '\"'; /* \" merkit. " takaisin*/ return jono; } static char *EI_AUKEA = "Rakennetiedostoa ei saada avatuksi!"; static char *EI_TILAA = "Rakenteelle ei saada varatuksi tilaa!"; static char *LIIAN_ISO = "Rakenteesta tulee liian iso!"; static char *VAARIN = "Rakennetiedoston muoto on v„„rin!"; static char *TUN_TYYPPI = "Tuntematon tyyppi!"; static char *TUN_FUNKTIO = "Tuntematon funktio!"; static char *LIIKAA_KENTTIA = "Liian monta kentt„„!"; static char *LIIAN_MONTA = "Liian monta rakennetta k„yt”ss„!"; /****************************************************************************/ char /* muut = virheilmoitus */ *lisaa_rakenne_rivi( /* NULL = onnistui */ Rakenne_tyyppi *rakenne,/* s,t Rakenne, jonne rivi lis„t„„n. */ char *rivi /* s Lis„tt„v„ rivi */ ) /* ** Funktiolla tutkitaan ja lis„t„„n rakenteeseen uusi kentt„. Rivi on t„m„n ** tiedoston alussa annettua muotoa. sotu, int ja double kenttien koosta ** ei v„litet„, vaan niiden koko on 12,sizeof(int),sizeof(double). ** ** Muuttuu: rivi ** Tulostus: n„ytt””n virheilmoitus ** Kutsuu: palanen ** tee_jono ** onko_samat ----------------------------------------------------------------------------*/ { #define OSA(rivi) palanen(rivi,"|",&j); if ( j<0 ) return VAARIN #define OTA_INT(p,i) i=-1; sscanf(p,"%d",&i); if ( i<0 ) return VAARIN char *p; int j,i,koko; Kentta_tyyppi kentta; if ( rakenne->kenttia >= MAX_KENTTIA ) return LIIKAA_KENTTIA; p = OSA(rivi); rakenne->kenttavalinnat[rakenne->kenttia]=p[0]; p = OSA(NULL); kentta.hopute = tee_jono(poista_tyhjat(p)); p = OSA(NULL); kentta.nimi = tee_jono(poista_tyhjat(p)); p = OSA(NULL); OTA_INT(p,i); koko = i; p = OSA(NULL); kentta.alustus = tee_jono(muuta_erikoismerkit(poista_tyhjat(p))); p = OSA(NULL); OTA_INT(p,i); kentta.mpit = i; p = OSA(NULL); if ( ( i = tyypin_nro(p) ) < 0 ) return TUN_TYYPPI; kentta.tyyppi = TYYPIT[i].tyyppi; if ( TYYPIT[i].koko ) koko = TYYPIT[i].koko; kentta.koko = koko; kentta.alku = rakenne->koko; while ( kentta.alku % TYYPIT[i].jaollisuus != 0 ) kentta.alku++; rakenne->koko = kentta.alku + koko; if ( rakenne->koko > sizeof(Jasen_tyyppi) ) return LIIAN_ISO; p = OSA(NULL); kentta.format = tee_jono(muuta_erikoismerkit(p)); p = OSA(NULL); if ( ( kentta.tark_fun = tarkistus_fun(p) ) == NULL ) return TUN_FUNKTIO; p = OSA(NULL); rakenne->mallitulostus[rakenne->kenttia] = tee_jono(muuta_erikoismerkit(p)); p = palanen(NULL,"%",&j); kentta.rajat = tee_jono(muuta_erikoismerkit(p)); rakenne->kentat[rakenne->kenttia++] = kentta; return NULL; #undef ETSI #undef OTA_INT #undef OSA } /****************************************************************************/ int /* -1 =ei l”ydy */ rakenteen_nro( /* muut = rakenteen nro */ char *nimi /* s Rakenteen tiedostonimi, jota etsit„„n. */ ) /* ** Funktiolla etsit„„n l”ytyyk” rakenteen nime„. ** ** Globaalit: RAKENTEITA, RAKENTEET ----------------------------------------------------------------------------*/ { int r; for (r = 0; r < RAKENTEITA; r++ ) { /* L”ytyyk” ennest„„n? */ if ( onko_samat(RAKENTEET[r]->tiedoston_nimi,nimi)==0 ) return r; } return -1; } /****************************************************************************/ int /* 1 = ep„onnistui */ lue_isojono( /* 0 = onnistui */ FILE *f ,/* s tiedosto, josta luetaan */ char *jono ,/* t Jono, johon luetaan */ int max_koko ,/* s */ char lopetus /* s Merkki rivin alussa, johon lopetetaan. */ ) /* ** Funktiolla luetaan tiedostosta rivej„ kunnes tulee vastaa lopetus. ** Rivit kootaan yhdeksi isoksi merkkijonoksi. ** ** Sy”tt”: tiedostosta ----------------------------------------------------------------------------*/ { char rivi[MAX_RIVI]; jono[0] = 0; while ( !feof(f) ) { /* Luetaan menun otsikko */ if ( f_lue_jono(f,N_S(rivi)) < OLETUS ) continue; if (rivi[0]==lopetus) break; liita_jono(jono,max_koko,rivi); liita_jono(jono,max_koko,"\n"); } return ( jono[0]==0 ); } /****************************************************************************/ char /* muut = virheilmoitus */ *lue_rakennetiedosto( /* NULL = onnistui */ Kerho_tyyppi *kerho ,/* t Kerho, johon rakenne luetaan. */ char *tiedosto /* s Luettavan tiedoston nimi */ ) /* ** Funktiolla luetaan uusi rakenne kerhoon. Rakenteesta ei saa muodostua ** isompi kuin Jasen_tyypin koko! Mik„li rakenne l”ytyy ennest„„n, k„ytet„„n ** vanhaa. Ensimm„isell„ kutsulla oletusrakenne talletetaan. ** ** Tulostus: virheilmoitus n„ytt””n ** Kutsuu: poista_alkutyhjat ** kopioi_jono ** lisaa_rakenne_rivi ----------------------------------------------------------------------------*/ { FILE *f; static char *p,*viesti,jono[MAX_RAKENNERIVI],osa[70],isojono[2000]; int r; if ( !RAKENTEITA ) { lue_rakenne_optiot(kerho->rakenne); RAKENTEET[0] = kerho->rakenne; RAKENTEITA++; } if ( tiedosto[0] == 0 ) return NULL; r = rakenteen_nro(tiedosto); if ( r >= 0 ) { kerho->rakenne = RAKENTEET[r]; return NULL; } if ( RAKENTEITA >= MAX_RAKENTEITA ) return LIIAN_MONTA; viesti = NULL; f = fopen(tiedosto,"rt"); if (!f) return EI_AUKEA; kerho->rakenne = calloc(1,sizeof(Rakenne_tyyppi)); if (!kerho->rakenne) { fclose(f); return EI_TILAA; } kerho->rakenne->kentat = calloc(MAX_KENTTIA,sizeof(Kentta_tyyppi)); kerho->rakenne->kenttia = 0; kerho->rakenne->koko = offsetof(Jasen_tyyppi,nimi); kerho->rakenne->mallirivi = NULL; kerho->rakenne->tiedoston_nimi = tee_jono(tiedosto); kerho->rakenne->kommentti = NULL; kerho->rakenne->paamenu = NULL; kerho->rakenne->menu_valinnat = NULL; kerho->rakenne->lisays_otsikko = NULL; kerho->rakenne->rak_nro = RAKENTEITA; p = strchr(tiedosto,'.'); if ( p ) *p = 0; kopioi_jono(N_S(kerho->rakenne->nimi),tiedosto); if ( p ) *p = '.'; if (!kerho->rakenne->kentat) return EI_TILAA; if (!kerho->rakenne->tiedoston_nimi) return EI_TILAA; kerho->rakenne->mallitulostus = calloc(MAX_KENTTIA,sizeof(char *)); if (!kerho->rakenne->mallitulostus) return EI_TILAA; kerho->rakenne->kenttavalinnat = calloc(MAX_KENTTIA,1); if (!kerho->rakenne->kenttavalinnat) return EI_TILAA; kerho->rakenne->olet_alku = RAKENTEET[0]->olet_alku; kerho->rakenne->vakanen = RAKENTEET[0]->vakanen ; while (!feof(f)) { /* Luetaan rakenne */ if ( f_lue_jono(f,N_S(jono)) <= OLETUS ) continue; poista_alkutyhjat(jono); if ( jono[0] == 0 ) continue; if ( jono[0] == ';') { /* Otetaan 1. kommentti talteen */ if (kerho->rakenne->kommentti) continue; kerho->rakenne->kommentti = tee_jono(jono); continue; } if (jono[0]=='#') break; kopioi_jono(N_S(osa),jono); viesti = lisaa_rakenne_rivi(kerho->rakenne,jono); if ( viesti ) { printf("RAKENNE: %s\n",osa); goto talleta_rakenne; } } if ( f_lue_jono(f,N_S(jono)) > OLETUS ) kerho->rakenne->menu_valinnat = tee_jono(muuta_erikoismerkit(jono)); if ( !lue_isojono(f,N_S(isojono),'#') ) kerho->rakenne->paamenu = tee_jono(muuta_erikoismerkit(isojono)); if ( f_lue_jono(f,N_S(jono)) > OLETUS ) sscanf(jono,"%d %d",&kerho->rakenne->olet_alku,&kerho->rakenne->vakanen); if ( !lue_isojono(f,N_S(isojono),'#') ) kerho->rakenne->lisays_otsikko = tee_jono(muuta_erikoismerkit(isojono)); talleta_rakenne: if (!kerho->rakenne->kommentti) kerho->rakenne->kommentti =";"; if (!kerho->rakenne->paamenu) kerho->rakenne->paamenu = RAKENTEET[0]->paamenu; if (!kerho->rakenne->menu_valinnat) kerho->rakenne->menu_valinnat = RAKENTEET[0]->menu_valinnat; if (!kerho->rakenne->lisays_otsikko) kerho->rakenne->lisays_otsikko = RAKENTEET[0]->lisays_otsikko; RAKENTEET[RAKENTEITA++] = kerho->rakenne; fclose(f); lue_rakenne_optiot(kerho->rakenne); return viesti; } static char rakennevalinnat[80]="123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /****************************************************************************/ Rakenne_tyyppi /* NULL = rakennetta ei haluta muuttaa! */ *kysy_rakenne(void) /* Valitun rakenteen osoite */ /* ** Funktiolla kysyt„„n mit„ rakennetta k„ytet„„n, ja palautetaan ** osoitin t„h„n rakenteeseen. Kutsuvan ohjelman pit„„ toimia siten, ** ett„ paluuarvon ollessa NULL, ei rakennetta muuteta! ** ** Globaalit: RAKENTEET, RAKENTEITA ** Sy”tt”: n„pp„imist”lt„ ** Tulostus: n„ytt””n ** Kutsuu: kopioi_jono, liita_jono ** odota_nappain ----------------------------------------------------------------------------*/ { int r; char kommentti[40],tnimi[30],valinnat[80],nappain; if ( RAKENTEITA < 2 ) return NULL; printf("\n\nValitse k„ytett„v„ rakenne:\n"); printf(" 0 = rakennetta ei muuteta\n"); for (r=0; rkommentti+1); kopioi_jono(N_S(tnimi), RAKENTEET[r]->tiedoston_nimi); printf(" %c = %-30s %-40s\n",rakennevalinnat[r],tnimi,kommentti); } printf(" :"); kopioi_jono(valinnat,RAKENTEITA+1,rakennevalinnat); liita_jono(N_S(valinnat),"0"); nappain = odota_nappain(valinnat,'0',VAIN_ISOT); printf("\n"); if (nappain=='0') return NULL; r = (int) (strchr(valinnat,nappain) - valinnat); return RAKENTEET[r]; } /****************************************************************************/ int /* -1 = ep„onnistui */ talleta_kaikki_rakenne_optiot( /* 0 = onnistui */ void /* */ ) /* ----------------------------------------------------------------------------*/ { int r; int paluu = 0; for (r=0; r= 2 ); }