/****************************************************************************/ /* ** K E R H O E T S . C ** ** Kerhosta tietyn ehdon t„ytt„vien j„senien etsiminen ** ** Aliohjelmat: ** onko_rajoissa - tutkii onko kentt„ sallittujen rajojen sis„ll„ ** lajittele - tekee permutaatiotaulukon valitun kent„n ** mukaisesti ** etsi_kentat - etsii annetun maskin ehdon t„ytt„vi„ j„seni„ ** kysy_kentat_ja_etsi - interraktiivinen kysyminen, etsiminen, ** selaaminen, korjailu ja poisto ** laske_montako_muuta - etsii onko muita kuin valittua j„sent„ ** korjaile_kenttia - antaa mahdollisuuden korjailla valit.kentti„ ** ** ** Tekij„t: Vesa Lappalainen ** Ohjelmointikurssi 1991 ** Tehty: 13.11.1991 ** Muutettu: 17.11.1991/vl ** Mit„ muutettu: rakennetta siistitty ** lis„tty lajittelu ** Muutettu: 23.11.1991/vl ** Mit„ muutettu: tyyppik„site yleistetty ** Muutettu: 24.12.1991/vl ** Mit„ muutettu: ep„yht„l”haku ** negatiivisten lukujen lajittelu korjattu ** tyhj„n sotun lajittelu korjattu ** Muutettu: 28.12.1991/vl ** Mit„ muutettu: yleisempi tietorakenne ** Muutettu: 29.12.1991/vl ** Mit„ muutettu: valittujen kenttien korjailu ** kysy_kentat_ja_etsi, 1 lis„parametri ** Muutettu: 18.12.1992/vl ** Mit„ muutettu: korjattu tietueen poistossa ollut vika ** eli poistettu viittaus nollatulla nykyj„senell„ ** vaihdettu Jarjestystyypin tietueen nimi„ ** kenttia -> indekseja ** kentat -> indeksit ** Muutettu: 4.12.1993/vl ** Mit„ muutettu: - laita_selaus_kohdalla korjattu siten, ettei ** viimeisen poisto n„yt„ v„„r„„ j„sent„ ** - korjattu kenttien muuttamista ** - etsiminen s„ilytt„„ paikan uudelleen tultaessa ** - selauksen lyhyt muoto ** */ #include #include #include #include "mjonot.h" #include "kerho.h" #include "help.h" #define MERKKEJA 256 #define EI_KENTTAA "\177" /****************************************************************************/ /* ** T i e t o t y y p i t */ typedef struct { /* Lajittelussa apuna k„ytett„v„ tietue. */ int kentan_nro; /* Kentt„ jonka mukaan lajitellaan. */ Jasen_tyyppi **jasenet; /* Osoitin osoitintaulukon alkuun. */ } Vertaa_tyyppi; /* */ typedef struct { /* Avaimen muodostuksessa k„ytett„ tyyppi */ int alustettu; /* Onko taulukko alustettu vai ei. */ char avainarvo[MERKKEJA]; /* Miten kukin kirjain muuttuu */ } Jarjestys_avain_tyyppi; /* /****************************************************************************/ /* ** G l o b a a l i t muuttujat */ static Jarjestys_avain_tyyppi JARJESTYS = {0,""}; /* Avaimen muodostuksessa k„ytett„v„ taul. */ /****************************************************************************/ /* ** A L I O H J E L M A T */ #define A_1(mika,miksi) j->avainarvo[(unsigned char)mika] = miksi #define A_A(mi,mp,miksi) A_1(mi,miksi); A_1(mp,miksi) /****************************************************************************/ void /* */ alusta_jarjestys( /* */ Jarjestys_avain_tyyppi *j /* s,t Alustettava j„rjestystaulukko. */ ) /* ** Aliohjelmalla alustetaan avaimen muodostamisessa tarvittava taulukko. ** Tyhj„, v„limerkit ja tuntemattomat = 0x20 ** '0' = 0x30 ... '9' = 0x39 ** 'A' = 0x41 ... 'Z' = 0x5a ** '�' = 0x5b ... ** ** ----------------------------------------------------------------------------*/ { int i; if (j->alustettu) return; j->alustettu = 1; for (i=0; iavain); if (i<20) { printf("TEE AVAIN: Liian pieni avainkentt„!\n"); return; } tyyppi = kentan_tyyppi(kentan_nro,jasen); p = kentan_osoite(kentan_nro,jasen); switch (tyyppi) { case Tjono: kopioi_jono(N_S(jasen->avain),p); poista_tyhjat(jasen->avain); for (a=(unsigned char *)jasen->avain; *a; a++) { *a = JARJESTYS.avainarvo[*a]; } poista_tyhjat(jasen->avain); return; case Tsotu: kopioi_jono(N_S(s),p); liita_jono(N_S(s)," "); kopioi_jono(N_S(jasen->avain),s); jasen->avain[0] = s[4]; /* Vaihdetaan pv ja vuosi kesken„„n! */ jasen->avain[1] = s[5]; jasen->avain[4] = s[0]; jasen->avain[5] = s[1]; return; case Tint: i = *(int *)p; sprintf(jasen->avain,"%+05d",i); if ( jasen->avain[0] == '-' ) jasen->avain[0]='+'-1; /* jotta - < + */ return; case Tarvo: case Tdouble: d = *(double *)p; sprintf(jasen->avain,"%+015.7lf",d); if ( jasen->avain[0] == '-' ) jasen->avain[0]='+'-1; /* jotta - < + */ return; default: /* Avain, joka menee lajittelussa viimeiseksi! */ kopioi_jono(N_S(jasen->avain),EI_KENTTAA); return; } } static Vertaa_tyyppi VERTAA; /* Tiedonv„litys lajittele -> vertaile */ /****************************************************************************/ int /* -1 1. pienempi */ vertaile( /* 0 Yht„suuria */ /* 1 1. suurempi */ const void *a ,/* s 1. verrattavan indeksi. */ const void *b /* s 2. verrattavan indeksi. */ ) /* ** Funktiolla verrataan kahta indeksin avulla annettua j„sent„ toisiinsa. ** Verrattava kentt„ katsotaan globaalista muuttujasta VERTAA.kentan_nro. ** ** Globaalit: VERTAA ----------------------------------------------------------------------------*/ { return (strcmp( VERTAA.jasenet[*(int *)a]->avain, VERTAA.jasenet[*(int *)b]->avain )); } /****************************************************************************/ void /* */ lajittele( /* */ /* */ Kerho_tyyppi *kerho ,/* s Lajiteltava kerho */ Jarjestys_tyyppi *jarj ,/* s,t Lajiteltava permutaatiotaulukko */ int kentan_nro /* s Mink„ kent„n mukaan lajitellaan */ ) /* ** Funktiolla lajitellaan jarj taulukko annetun kent„n mukaan oikeaan ** j„rjestykseen. Lajiteltava kentt„ valitaan kentan_nro mukaan. ** Mik„li jarj.indekseja = 0, alustetaan taulukko 0 1 2 3 ** muuten k„ytet„„n olemassa olevaa numerointia. ** Ei viel„ j„rjest„ AND ja OR etsimisen mukaan! ** ** Globaalit: K„ytt„„ vertaa -funktion kanssa yhteist„ aluetta VERTAA ** Kutsuu: qsort ** Algoritmi: V„litet„„n permutaatiotaulukko qsort aliohjelmalle ----------------------------------------------------------------------------*/ { int j,ind,max_ind; char eka_kentta[40]; if ( (kentan_nro < 0) || !jarj->jarjesta ) return; /* Permutaation alustus tarvittaessa. */ if ( jarj->indekseja == 0 ) { max_ind = jarj->max_koko; if ( max_ind > kerho->jasenia ) max_ind = kerho->jasenia; ind = 0; for (j=0; jjasenet[j] ) /* NULL-j„seni„ ei laiteta */ jarj->indeksit[ind++] = j; jarj->indekseja = ind; } for (j=0; jindekseja; j++) { /* Avaimeksi kentta+"nimi" */ tee_avain(0,kerho->jasenet[jarj->indeksit[j]]); kopioi_jono(N_S(eka_kentta),kerho->jasenet[jarj->indeksit[j]]->avain); tee_avain(kentan_nro,kerho->jasenet[jarj->indeksit[j]]); liita_jono(N_S(kerho->jasenet[jarj->indeksit[j]]->avain),eka_kentta); } VERTAA.kentan_nro = kentan_nro; VERTAA.jasenet = kerho->jasenet; qsort( (void *)(jarj->indeksit), /* Lajiteltava taulukko */ jarj->indekseja, /* Taulukon alkioiden lukum„„r„ */ sizeof(jarj->indeksit[0]), /* Yksitt„isen alkion koko */ vertaile); /* Vertailualiohjelman nimi */ } /****************************************************************************/ int /* 0 = ei l”ydy muita joihin t„sm„„ */ laske_montako_muuta( /* muuten muiden t„sm„„vien m„„r„ */ Kerho_tyyppi *kerho ,/* s Kerho josta etsit„„n */ int kentta ,/* s Kentt„ johon verrataan */ char *jono ,/* s Jono jota etsit„„n */ int kuka_ei ,/* s Henkil” jota ei etsit„. */ int *viimeinen ,/* t Indeksi viimeiseen l”ytyneeseen */ int *oliko_kuka_ei /* t Oliko se joka ei saa olla */ ) /* ** Funktiolla lasketaan montako muuta ehdon t„sm„lleen t„ytt„v„„ j„sent„ ** kerhosta l”ytyy. Palautetaan parametrina my”s viimeinen johon t„sm„si. ** ** Algoritmi: Verrataan jokaista paitsi ei-etsitt„v„„. ----------------------------------------------------------------------------*/ { int j,montako=0; *viimeinen = -1; *oliko_kuka_ei = 0; for (j=0; jjasenia; j++) { if ( strcmp(jono,kentta_jonoksi(kentta,kerho->jasenet[j]) ) == 0 ) { if ( j == kuka_ei ) *oliko_kuka_ei = 1; else { montako++; *viimeinen = j; } } } return montako; } /****************************************************************************/ typedef enum { YHT, ERIS, PIEN, PIENYHT, SUUR, SUURYHT } Vertailu_oper_tyyppi; typedef struct { char *ehto; int pit; Vertailu_oper_tyyppi kasky; } Vertailu_tyyppi; static Vertailu_tyyppi EHDOT[] = { { "" , 0, YHT}, { "==", 2, YHT}, { "!=", 2, ERIS}, { "<=", 2, PIENYHT}, { "<" , 1, PIEN}, { ">=", 2, SUURYHT}, { ">" , 1, SUUR}, { NULL, 0, YHT} }; /****************************************************************************/ int /* 1 = ei t„sm„„ */ tutki_tasmaako( /* 0 = t„sm„„ */ Jasen_tyyppi *jasen ,/* s Tutkittva j„sen */ char *ikentta ,/* s Kentt„ muutettuna isoiksi kirjaimeksi */ char *maski ,/* s Maski muutettuna isoiksi kirjaimeksi */ int knro /* s Kent„n numero. */ ) /* ** Funktiolla tutkitaan onko annettu ehto voimassa. Ehdot: ** <, <= ,> , >= , !=, == ** Mik„li ehtoa ei ole annettu, tulkitaan ehto tavalliseksi ** wildmat vertailuksi. ** ** Globaalit: EHDOT ** Muuttuu: jasen->avain ** Kutsuu: kentta_jonoksi ** jono_kentaksi ** wildmat ** Esimerkki: ikentta "20", maski "<=50" -> 0 ----------------------------------------------------------------------------*/ { int i,tulos,ehto_ind=0; char *m; Jasen_tyyppi mjasen,kjasen; char ik[80]; if ( ikentta == NULL ) { kopioi_jono(N_S(ik),kentta_jonoksi(knro,jasen)); jono_isoksi(ik); ikentta = ik; } mjasen.rakenne = jasen->rakenne; kjasen = *jasen; if ( knro >= jasen->rakenne->kenttia ) return 1; for (i=1; EHDOT[i].ehto; i++) if ( strstr(maski,EHDOT[i].ehto) == maski ) { ehto_ind = i; break; } m = maski+EHDOT[ehto_ind].pit; switch ( EHDOT[ehto_ind].kasky ) { case YHT: return wildmat(ikentta,m); case ERIS: return !wildmat(ikentta,m); case PIEN: case PIENYHT: case SUUR: case SUURYHT: jono_kentaksi(knro,&mjasen,m); jono_kentaksi(knro,&kjasen,ikentta); tee_avain(knro,&mjasen); tee_avain(knro,&kjasen); tulos = strcmp(kjasen.avain,mjasen.avain); switch ( EHDOT[ehto_ind].kasky ) { case PIEN: return !(tulos<0); case PIENYHT: return !(tulos<=0); case SUUR: return !(tulos>0); case SUURYHT: return !(tulos>=0); } default: return 1; } } /****************************************************************************/ int /* 1 = ei t„sm„„ */ onko_rajoissa( /* 0 = t„sm„„ */ Jasen_tyyppi *jasen ,/* s Tutkittva j„sen */ char *kentta ,/* s Tutkittava kentt„. */ int knro /* s Kent„n numero. */ ) /* ** Funktiolla tutkitaan onko annettu kentt„ annetuissa rajoissa. ** Rajat esim: ">=0 & <=3" tai "a*" | "b*" ----------------------------------------------------------------------------*/ { int l,j,samat; char rajat[80],*ra,ikentta[80],*p,*r=jasen->rakenne->kentat[knro].rajat; kopioi_jono(N_S(ikentta),kentta); kopioi_jono(N_S(rajat),r); if ( rajat[0] == 0 ) return 0; if ( kentta[0] == 0 ) return 0; jono_isoksi(rajat); jono_isoksi(ikentta); ra = rajat; while ( 1 ) { p = palanen(ra,"&|",&j); ra = NULL; l = strlen(p); poista_alkutyhjat(p); samat = tutki_tasmaako(jasen,ikentta,p,knro); if ( j <= 0 ) return samat; /* Rajat loppuivat! */ switch ( r[(int)(l+(p-rajat))] ) { /* Yhdistetyn ehdon merkki */ case '|': if ( samat == 0 ) return 0; /* Or:illa kaikki t„sm„„ */ break; case '&': if ( samat != 0 ) return 1; break; /* And:illa jatketaan viel„ */ } } } /****************************************************************************/ int /* */ etsi_indeksit( /* = l”ytyneiden indeksien lukum„„r„ */ Kerho_tyyppi *kerho ,/* s Kerho josta etsit„„n */ int kentta ,/* s Kent„n numero, josta etsit„„n (tai AND,OR) */ Haku_tyyppi *maski ,/* s Arvot joiden mukaan etsit„„n. */ Jarjestys_tyyppi *etsi /* t Taulukko jonne l”ytyneet talletetaan */ ) /* ** Funktiolla etsit„„n maskin mukaisia kentti„ rekisterist„. ** Palautetaan taulukossa niiden paikkojen indeksit, joista ** maski l”ytyi. Mik„li kentt„ on OR etsit„„n TAI-toimintona kaikkia ** kentti„ (eli jos yksikin kentt„ t„sm„„) ja mik„li kentta==AND ** etsit„„n JA-toimintona (eli kaikkien kenttien t„ytyy t„sm„t„). ** Jos maskin kentt„ on tyhj„, ei kentt„„ verrata lainkaan. ** Jos maskin kentt„ alkaa ~, niin vastaavan kent„n t„ytyy olla tyhj„. ** Mik„li ket„„n ei l”ydy, laitetaan silti indeksit[0]=0, jotta siihen voidaan ** varmasti viitata. ** ** Kutsuu: jono_isoksi ** kopioi_jono, N_S ** wildmat ** Algoritmi: Kokeillaan jokaista paikkaa ja merkit„„n l”ytym„t yl”s. ** Isot ja pienet kirjaimet samaistetaan. ----------------------------------------------------------------------------*/ { #define KK kerho->jasenet[j]->rakenne->kas_kentat[SYOTTO] #define KV kerho->jasenet[j]->rakenne->kenttavalinnat char isana[MAX_RIVI],*m; int j,k,k1=kentta,k2=kentta,samat,yksi_riittaa=1; if ( kentta==ETSI_AND || kentta==ETSI_OR ) { k1=0; k2=K_KENTTIA-1; } etsi->indekseja=0; etsi->indeksit[0]=0; if ( kentta == ETSI_AND ) yksi_riittaa=0; /* Muille paitsi ANDille */ for (k=k1; k<=k2; k++) jono_isoksi(maski[k]); for (j=0; jjasenia; j++) { /* Tutkitaan kaikki j„senet */ if (!kerho->jasenet[j]) continue; /* Ohitetaan NULL-osoittimet*/ samat=0; for (k=k1; k<=k2; k++) { /* Tarkistetaan kent„t. */ if ( KK[0] != 0 && strchr(KK,KV[k]) == NULL && ( kentta == ETSI_AND ) || ( kentta == ETSI_OR ) ) continue; /* Jos ei k„sitelt„viss„ kentiss„, niin jatketaan. */ kopioi_jono(N_S(isana),kentta_jonoksi(k,kerho->jasenet[j])); jono_isoksi(isana); m = maski[k]; if (!*m) continue; /* Tyhjist„ kentist„ ei v„litet„. */ samat = !tutki_tasmaako(kerho->jasenet[j],isana,m,k); if ( samat && yksi_riittaa ) break; /* Yksi ja TAI l”ytyi */ if ( (!samat) && (!yksi_riittaa) ) break; /* JA ei l”ydy */ } if ( samat ) { etsi->indeksit[etsi->indekseja++]=j; if ( etsi->indekseja>=etsi->max_koko ) break; } } if ( etsi->indekseja > 1 ) lajittele(kerho,etsi,k1); return etsi->indekseja; #undef KK #undef KV } /****************************************************************************/ void /* */ tayta_viesti_ja_sallitut( /* */ Kerho_tyyppi *kerho ,/* s Kerho, josta viesti halutaan. */ int korj_poisto ,/* s Onko korjaus ja poisto mukana? (0=ei, 1=on)*/ Selaus_tyyppi *selaus /* s,t Paikka jonne tiedot t„ytet„„n. */ ) /* ** Aliohjelmalla t„ytet„„n viesti muotoon: ** Valitse kent„„ jonka mukaan etsit„„n (?=kentt„lista uudell.) ** Mik„li korjaus ja poisto on sallittu, lis„t„„n viestiin viel„ ** ,\npoisto (P), korjailu (K) ** Samoin sallittujen kirjaimien joukkoon laitetaan kaikki kentt„listan ** mukaiset kirjaimet sek„ ? J T (lista, JA, TAI) ja tarvittaessa P ja/tai K. ** ** Muuttuu: selaus->viesti ** selaus->sallitut ** Kutsuu: kopioi_jono, N_S ** liita_jono ----------------------------------------------------------------------------*/ { char viestin_jatko[80]; kopioi_jono(N_S(selaus->viesti), "Valitse kentt„ jonka mukaan etsit„„n (?=kentt„lista uudell.)"); selaus->vali = '\n'; /* T„ytet„„n n„pp„inlistaan nyt sallitut n„pp„imet */ kopioi_jono(N_S(selaus->sallitut),kerho->rakenne->kenttavalinnat); if ( strlen(selaus->sallitut) > K_KENTTIA ) selaus->sallitut[K_KENTTIA]=0; /* Poistetaan listasta ylim. kirjaimet */ liita_jono(N_S(selaus->sallitut),NAP_JA_TAI); liita_jono(N_S(selaus->sallitut),NAP_AINA_SALLITUT); /* Jos korj ja poisto sallittu ja on joku jota n„ytt„„ ruudussa. */ if ( korj_poisto==KORJAILU && selaus->selattavat->indekseja>0 ) { sprintf(viestin_jatko,",\n%c = poisto, %c = korjailu", NAP_POISTO, NAP_KORJ); liita_jono(N_S(selaus->viesti),viestin_jatko); liita_jono(N_S(selaus->sallitut),NAP_KORJ_POISTO); selaus->vali = ' '; } } /****************************************************************************/ void /* */ laita_selaus_kohdalla( /* */ Kerho_tyyppi *kerho ,/* s Selailtavan kerho tiedot. */ Selaus_tyyppi *selaus /* s,t Selattavat tiedot. */ ) /* ** Aliohjelmalla laitetaan selaus-tietueen kohdalla kent„n arvo oikeisiin ** rajoihin. Samalla muutetaan kerhon nykyj„sen. ** Muuttuu: selaus->kohdalla ** kerho->nykyjasen ----------------------------------------------------------------------------*/ { if ( selaus->kohdalla < 0 ) selaus->kohdalla = 0; if ( selaus->kohdalla >= selaus->selattavat->indekseja ) selaus->kohdalla = selaus->selattavat->indekseja - 1; /* korj. 4.12.93 */ if ( selaus->selattavat->indekseja <= 0 ) { /* T„m„ vain kun mit„„n ei ole*/ /* selaus->selattavat->indekseja = 0; */ selaus->kohdalla = 0; selaus->selattavat->indeksit[0] = 0; } kerho->nykyjasen = selaus->selattavat->indeksit[selaus->kohdalla]; } /****************************************************************************/ char /* */ selaile( /* Viimeksi painettu merkki (paitsi + tai -) */ Kerho_tyyppi *kerho ,/* s Selailtavan kerho tiedot. */ Selaus_tyyppi *selaus ,/* s,t Selattavat tiedot. */ int korj_poisto /* s Onko korjailu ja poisto sallittu */ ) /* ** Funktiolla selataan selaus-listassa olevia henkil”it„. ** Mik„li painetaan muuta kuin + tai -, palautetaan painettu n„pp„in. ** Painetuiksi sallitaan kuitenkin vain listassa olevat n„pp„imet ** sek„ +, - ja RET. ** Aluksi tulostetaan kohdalla oleva henkil” (mik„li t„llainen on olemassa). ** T„m„n j„lkeen tulostetaan viesti, johon lis„t„„n mahdollisesti per„„n ** tieto + ja - k„yt”st„, mik„li n„m„ ovat olemassa. ** cr-lipulla tutkitaan halutaanko lyhyt vai pitk„ tulostus. ** Lyhyess„ tulostuksessa pyyhit„„n edellinen viesti pois ja n„in ** selattavat saadaan tiiviimmin n„ytt””n. ** ** Muuttuu: selaus->kohdalla ** kerho->nykyjasen ** kerho->rakenne ** Sy”tt”: n„pp„imist” ** Tulostus: n„ytt””n ** Kutsuu: tulosta_jasen ** kopioi_jono, N_S ** liita_jono ** odota_nappain ** Esimerkki: viesti = "Selaile" vali = ' ' ja on selattavia kump. suuntaan ** tulostaa kohdalla olevan j„senen tiedot ja ** "Selaile, seuraava (+), edellinen (-):" ----------------------------------------------------------------------------*/ { int i,suunta=0,cr=1; char painettu,vali,*p,pilkku; char sallitut[80]; char apu[80],viesti[80]; viesti[0]=0; while (1) { selaus->kohdalla += suunta; laita_selaus_kohdalla(kerho,selaus); if ( suunta != 0 ) kerho->rakenne = kerho->jasenet[kerho->nykyjasen]->rakenne; tayta_viesti_ja_sallitut(kerho,korj_poisto,selaus); pilkku = ','; if ( selaus->selattavat->indekseja > 0 ) {/* Jos joku on kohdalla, tulos*/ if ( cr ) printf("\n"); else { /* Pyyhit„„n edellinen rivi pois */ for (i=strlen(viesti);i>=0; i--) printf("\b"); for (i=strlen(viesti);i>=0; i--) printf(" "); for (i=strlen(viesti);i>=0; i--) printf("\b"); } if ( cr ) printf("\ #%03d -------------------------------------------------------------------------\n", kerho->nykyjasen+1); tulosta_jasen(stdout,kerho->jasenet[kerho->nykyjasen]); if (cr ) printf("\ ------------------------------------------------------------------------------\n"); } viesti[0]=0; if ( ( p = strchr(selaus->viesti,'\n') ) != NULL ) { /* \n kohdalta poik*/ kopioi_jono(N_S(viesti),p+1); p[1] = 0; } if ( cr ) printf("%s",selaus->viesti); else { /* Estet„„n ei-cr tapauksessa liiat pilkut ja rivinvaihdot */ if ( viesti[0] == 0 ) pilkku = ' '; selaus->vali = ' '; } vali = selaus->vali; kopioi_jono(N_S(sallitut),selaus->sallitut); /* Jos voidaan selata eteenp„in */ if ( selaus->kohdalla < selaus->selattavat->indekseja-1 ) { sprintf(apu,"%c%c%c = seuraava (%d)",pilkku, vali,NAP_SEURAAVA,selaus->selattavat->indekseja-selaus->kohdalla-1); liita_jono(N_S(sallitut),NAP_SEUR_LOPPU); liita_jono(N_S(viesti),apu); vali = ' '; pilkku = ','; } if ( selaus->kohdalla > 0 ) { /* Jos voidaan selata taaksep„in*/ sprintf(apu,"%c%c%c = edellinen (%d)",pilkku, vali,NAP_EDELLINEN,selaus->kohdalla); liita_jono(N_S(sallitut),NAP_EDEL_ALKU); liita_jono(N_S(viesti),apu); } printf("%s:",viesti); painettu=odota_nappain(sallitut,NAP_RET,VAIN_ISOT); suunta = 0; switch (painettu) { case NAP_EDELLINEN: suunta = -1; break; case NAP_SEURAAVA: suunta = 1; break; case NAP_ALKUUN: selaus->kohdalla=0; break; case NAP_LOPPUUN: selaus->kohdalla=selaus->selattavat->indekseja-1; break; default : return painettu; } cr = ( kerho->jasenet[kerho->nykyjasen]->rakenne->poista_cr == 0 ); } } /****************************************************************************/ char /* */ selaile_ja_odota_valinta( /* */ Kerho_tyyppi *kerho ,/* s Selailtava kerho */ Selaus_tyyppi *selaus ,/* s,t Tietue jonne l”ytymis yms. tiedot laitetaan*/ int korj_poisto /* s Onko korjailu ja poisto sallittu */ ) /* ** Funktiolla t„ytet„„n n„yt”lle tuleva kysymys ja sallitut n„pp„imet sek„ ** t„m„n j„lkeen annetaan selaus-funktion hoitaa teht„vi„ kunnes painetaan ** jotain muuta kuin + tai -. Mik„li painetaan ? tulostetaan kentt„lista ** ja jatketaan viel„ selailua kun l”ydettyjen lista on tyhjennetty. ** ** Muuttuu: etsi.selattavat ** Sy”tt”: n„pp„imist” ** Tulostus: n„ytt””n ** Kutsuu: tayta_viesti_ja_sallitut ** selaile ----------------------------------------------------------------------------*/ { char painettu; int i; for (i=0; iselattavat->indekseja; i++) /* Jotta paikka s„ilyy */ if ( kerho->nykyjasen == selaus->selattavat->indeksit[i] ) selaus->kohdalla = i; /* Kysell„„n kunnes ei en„„ haluta kentt„listaa. */ do { painettu = selaile(kerho,selaus,korj_poisto); printf("%c\n",painettu); if ( painettu == '?' ) { printf("\n\n"); tulosta_kenttalista(kerho,selaus->sallitut); printf("\n"); if ( selaus->selattavat->indekseja > 0 ) selaus->selattavat->indekseja = 0;/* Jottei lista rullaa pois kuvast*/ } } while ( painettu == '?' ); return painettu; } static Jarjestys_tyyppi Loytyi = {-1,0} /*,NULL}*/; /****************************************************************************/ int /* -1 = ep„onnistui */ varaa_jarjestys( /* 0 = onnistui */ Kerho_tyyppi *kerho ,/* s */ int koko ,/* s Taulukolle varattava koko */ Jarjestys_tyyppi *loytyi/* t */ ) /* ** Funktiolla varataan tilaa j„rjestystaulukolle mik„li max_koko=-1. ** tai tila ei riit„. ** Samalla muut kent„t alustetaan siten, ett„ on yksi l”ytynyt joka ** osoittaa nyky_jaseneen. ** Jos koko<=0, niin varataan tilaa kerhon j„senist”n verran. ** Jos loytyi osoittaa globaaliin taulukkoon Loytyi, niin kokoa ** kasvatetaan tarvittaessa. ** ----------------------------------------------------------------------------*/ { if ( koko <= 0 ) koko = kerho->jasenia; if ( loytyi->max_koko == -1 || ( koko > loytyi->max_koko && loytyi==&Loytyi) ) { if ( loytyi->max_koko == -1 ) loytyi->indeksit = NULL; /* realloc !!! */ if ( !(loytyi->indeksit = realloc(loytyi->indeksit,sizeof(int)*koko)) ) return -1; loytyi->max_koko = koko; loytyi->indekseja = 1; loytyi->indeksit[0] = kerho->nykyjasen; loytyi->jarjesta = 1; } return 0; } /****************************************************************************/ int /* -1 = ep„onnistui */ etsi_indekseja( /* L”ytyneiden indeksien lukum„„r„. */ Kerho_tyyppi *kerho ,/* s,t Kerho josta etsit„„n */ int kentan_nro ,/* s Kent„n numero, jonka mukaan etsit„„n */ Jarjestys_tyyppi *loytyi/* t Taulukko jonne l”ytyneet talletetaan. */ ) /* ** Funktiolla etsit„„n kerhosta kent„st„ kentan_nro niit„ j„seni„, joilla ** ko. kent„ss„ on kerho->haku ehdon t„ytt„v„t tiedot. Jos kent„n numero ** on JA tai TAI, niin koko tietueen tiedot k„ytet„„n hyv„ksi. ** Mik„li l”ytyneit„ on yli yksi, tulostetaan l”ytyneiden lukum„„r„. ** Voidaan kutsua my”s alustamattomalla taulukolla, mik„li sen max_koko=-1; ** t„ll”in taulukko alustetaan ja varataan sille tarvittava permutaatio ** taulukko. ** ** Muuttuu: kerho->nykyjasen ** Tulostus: n„yt””n ** Kutsuu: etsi_indeksit ----------------------------------------------------------------------------*/ { if (varaa_jarjestys(kerho,0,loytyi)) return -1; etsi_indeksit(kerho,kentan_nro,kerho->haku,loytyi); if ( loytyi->indekseja > 1 ) printf("T„h„n t„sm„„ %d tietuetta!\n",loytyi->indekseja); kerho->nykyjasen = loytyi->indeksit[0]; return loytyi->indekseja; } /****************************************************************************/ int /* -1 = ep„onnistui */ alusta_selaustaulukko( /* 0 = onnistui, */ Kerho_tyyppi *kerho ,/* s Kerho josta etsit„„n. */ Selaus_tyyppi *selaus ,/* t Alustettava taulukko. */ Jarjestys_tyyppi *loytyi/* s K„ytettev„ j„rjestystaulukko. */ ) /* ** Funktiolla varataan tilaa selaustaulukolle ja alustetaan se sis„lt„m„„n ** vain kerhon nykyj„sen. Mik„li tilaa ei saada, palautetaan -1. ** Selaustaulukko pit„„ muistaa vapauttaa kutsulla: ** free(selaus->selattavat.indeksit); ** ** Kutsuu: malloc ----------------------------------------------------------------------------*/ { if ( !kerho->jasenia ) return -1; /* Turha etsi„ jollei ole j„seni„! */ if ( !kerho->haku ) { /* Onko hakumaskia ennest„„n? */ if ( !(kerho->haku = calloc(MAX_KENTTIA,sizeof(kerho->haku[0]))) ) return -1; /* 1. kerralla hakuehto laitetaan tyhj„ksi. calloc hoiti t„m„n! */ } if (varaa_jarjestys(kerho,0,loytyi)) return -1; selaus->kohdalla = 0; selaus->selattavat = loytyi; return 0; } /****************************************************************************/ int /* -1 = etsiminen ei onnistu */ kysy_kentat_ja_etsi( /* Muuten l”ytyneiden kenttien lukum„„r„ */ /* -2 = halutaan edelliseen menuun */ Kerho_tyyppi *kerho ,/* s,t Kerho josta etsit„„n. */ int korj_poisto ,/* s Onko korjailu ja poisto mukana (1=on, 0=ei)*/ Jarjestys_tyyppi **loytyi,/* s,t Taulukko, jonne l”ytyneet tulevat. */ int samahaku /* s Tuleeko sama hakukentt„ kuin ed. kerralla */ ) /* ** Funktiolla kysyt„„n mink„ kent„n mukaan etsit„„n, kysyt„„n ** tiedot ja etsit„„n ehdot t„ytt„vien kenttien indeksit. ** N„it„ voidaan sitten selata yl”s tai alas. My”s korjailu ** ja poisto on mahdollista, jos korj_poisto=1. ** Jos korj_poisto=2, niin tehd„„n vain etsiminen yhden kerran. ** Mik„li loytyi==NULL, tehd„„n apumuuttujan avulla osoite ** globaaliin taulukkoon Loytyi. ** Mik„li *loytyi==NULL, k„ytet„„n my”s globaalia taulukkoa Loytyi, ** mutta palautetaan osoitin Loytyi-taulukkoon. ** Mik„li ei ole NULL, pit„„ 1:ll„ kutsukerralla olla alustettu ** loytyi.indekseja=-1 ** T„ll”in aliohjelma huolehtii tarvittavasta tilanvarauksesta ** taulukolle. Voidaan tietysti varata itsekin haluttu tila. ** Muiden kuin globaalin taulukon koko ei muutu automaattisesti. ** ** Sy”tt”: P„„ttelt„ ** Tulostus: N„ytt””n ** Kutsuu: ks. alla ----------------------------------------------------------------------------*/ { #define RETURN(n) { selaus.selattavat->indekseja = n; goto pois; } Jarjestys_tyyppi *loyt=NULL; static Selaus_tyyppi selaus; static int ed_haku=0; int poistettuja=0; char painettu; /* Viimeksi painettu n„pp„in n„pp„imen„ */ int kentan_nro; /* Kun painettu n„pp„in muutetaan kent„n nroksi */ if ( loytyi == NULL ) loytyi = &loyt; if ( *loytyi == NULL ) *loytyi = &Loytyi; if ( alusta_selaustaulukko(kerho,&selaus,*loytyi) ) return -1; if ( korj_poisto == VAIN_ETSI ) selaus.selattavat->indekseja = -2; if ( samahaku && ed_haku ) { painettu = ed_haku; goto etsi; } while ( (painettu = selaile_ja_odota_valinta(kerho,&selaus,korj_poisto) ) != NAP_RET ) { /* Tutkitaan painettua n„pp„int„. Jos jokin kentt„listasta, kysyt„„n */ /* sen kent„n arvo ja etsit„„n. */ etsi: kentan_nro = paikka(kerho->rakenne->kenttavalinnat,painettu); if ( 0 <= kentan_nro && kentan_nro < K_KENTTIA ) { ed_haku = painettu; if ( samahaku == 2 ) kerho->haku[kentan_nro][0] = 0; if ( kysy_haku(kerho,kerho->haku,kentan_nro) == 1 ) RETURN(-1); if ( kerho->haku[kentan_nro][0] == 0 ) RETURN(-2); etsi_indekseja(kerho,kentan_nro,*loytyi); selaus.kohdalla=0; } else /* Ei mik„„n kentt„listasta. Onko jokin muu tunnettu? */ switch (painettu) { case NAP_KORJ : printf("Korjaa tietoja tarvittaessa!\n"); if ( kysy_jasenen_tiedot(kerho,kerho->jasenet[kerho->nykyjasen],PAIVITYS) ) RETURN(-1); break; case NAP_POISTO: if ( !poista_jasen(kerho,kerho->nykyjasen) ) { /* selaustaulukko pit„„ korjata! */ if ( --selaus.selattavat->indekseja >0 ) memmove( selaus.selattavat->indeksit + selaus.kohdalla, selaus.selattavat->indeksit + selaus.kohdalla+1, sizeof(selaus.selattavat->indeksit[selaus.kohdalla])* (selaus.selattavat->indekseja - selaus.kohdalla) ); poistettuja++; } break; case NAP_JA: printf("T„yt„ JA-hakuehdot:\n"); if ( kysy_hakutiedot(kerho,kerho->haku) ) RETURN(-1); etsi_indekseja(kerho,ETSI_AND,*loytyi); selaus.kohdalla=0; break; case NAP_TAI: printf("T„yt„ TAI-hakuehdot:\n"); if ( kysy_hakutiedot(kerho,kerho->haku) ) RETURN(-1); etsi_indekseja(kerho,ETSI_OR,*loytyi); selaus.kohdalla=0; break; case NAP_VAIHD_RAK: { Rakenne_tyyppi *rakenne; rakenne = kysy_rakenne(); if ( rakenne == NULL ) RETURN(-1); kerho->rakenne = rakenne; continue; } default : continue; } if ( korj_poisto == VAIN_ETSI ) break; } pois: if (poistettuja) { poista_NULL(kerho); (*loytyi)->indekseja = 1; (*loytyi)->indeksit[0] = kerho->nykyjasen; } return selaus.selattavat->indekseja; #undef RETURN } /****************************************************************************/ int /* 1 = ep„onnistui */ kysy_arvot_kentille( /* 0 = onnistui */ Kerho_tyyppi *kerho ,/* s Kerho, jota k„sitell„„n. */ Jasen_tyyppi *jasen /* s,t Mallijasen, johon tulee oletusarvot */ ) /* ** Kysyt„„n arvot jonossa oleville kentille. ----------------------------------------------------------------------------*/ { char *p; int kentta,paluu; printf("Valitse arvot kentille: (" TYHJENNA_JONO" ->tyhjent„„ kent„n, tyhj„->j„tet„„n alkup. arvo)\n"); for (p=jasen->rakenne->kas_kentat[MUUTOS]; *p; p++) { kentta = paikka(jasen->rakenne->kenttavalinnat,*p); if ( kentta < 0 ) continue; paluu = kysy_yksi_kentta(kerho,jasen,kentta,0,"Kenttien t„ytt”"); if ( paluu ) return paluu == 1; } return 0; } /****************************************************************************/ int /* 1 = ep„onnistui */ kysy_kentat_ja_arvot( /* 0 = onnistui */ Kerho_tyyppi *kerho ,/* s Kerho, jota k„sitell„„n. */ Jasen_tyyppi *jasen ,/* s,t Mallijasen, johon tulee oletusarvot */ int kas_kentta /* s Mink„ k„sittelytavan kent„t? */ ) { if ( kysy_kas_kentat(kerho,kas_kentta) ) return 1; if ( kysy_arvot_kentille(kerho,jasen) ) return 1; return 0; } /****************************************************************************/ /* Aliohjelmien sis„iset globaalit */ static char Kenttavalinnat[80]=""; /* Mahdollisten kenttien valinnat */ static Jasen_tyyppi Arvo_jasen = {NULL};/* J„sen jossa kenttien t„ytt”arvot */ #define Kasiteltavat_kentat Arvo_jasen.rakenne->kas_kentat[MUUTOS] /****************************************************************************/ int /* */ korjailu_menu( /* = valitun toiminnan numero */ Jasen_tyyppi *jasen /* s J„sen, jonka mallitiedot tulostetaan */ ) /* ** Funktioilla tulostetaan korjailumenu muodossa: ** Valitse: ** 0 = ** 1 = valitse k„sitelt„v„t kent„t ** j„senmaksu = 45.00 ** maksettu maksu = ** 2 = ... ** ** Siten odotetaan ja palautetaan tehty valinta. ** ** Globaalit: Kenttavalinnat ** Kasiteltavat_kentat ----------------------------------------------------------------------------*/ { char *p,*kj; int valinta,kentta; printf( "\n" "Valitse: \n" " ? = avustus\n" " 0 = takaisin p„„valintaan\n" " 1 = valitse k„sitelt„v„t kent„t (%s)\n",Kasiteltavat_kentat); for (p=Kasiteltavat_kentat; *p; p++) { kentta=paikka(Kenttavalinnat,*p); if ( 0 <= kentta && kentta < jasen->rakenne->kenttia ) { kj = kentta_jonoksi(kentta,jasen); if ( kj[0] ) printf("%8c : %-18s = %s\n",*p,jasen->rakenne->kentat[kentta].nimi,kj); } } printf( " 2 = t„yt„ automaattisesti kent„t edell„ valituilla arvoilla\n" " 3 = kysy yksitellen kenttien arvoja\n" " :"); valinta=paikka("?0123456789",odota_nappain("?0123",'0',VAIN_ISOT))-1; printf("%d\n",valinta); return valinta; } /****************************************************************************/ int /* -1 = halutaan kokonaan pois */ tayta_kentat( /* 0 = onnistui */ /* -2 = edelliseen menuun */ int valinta ,/* s 2 = autom. t„ytt”, 3 = kyselev„ t„ytt” */ Kerho_tyyppi *kerho ,/* s Kerho, jonka j„seni„ t„ytet„„n. */ Jarjestys_tyyppi *loytyi/* s,t L”ytyneiden taulukko */ ) /* ** Funktioilla t„ytet„„n kentti„ joko automaattisesti tai kysellen. ** Aluksi kysyt„„n hakuehto ja etsit„„n ehdot t„ytt„v„t tietueet. ** Kentti„ t„ytet„„n kenttien nimien perusteella, eli vain sellaiset ** tietueet k„sitell„„n, joissa on samanniminen kentt„, jota ollaan ** t„ytt„m„ss„. Koska etsiminen ei t„t„ tied„, saattaa aluksi ** tulostua liian monta tietuetta. ** N„yt”n tulostus hieman vaihtelee sen mukaan, onko valinta 2 vai 3. ** ** Globaalit: Kenttavalinnat ** Kasiteltavat_kentat ** Arvo_jasen ----------------------------------------------------------------------------*/ { static Jasen_tyyppi apu_jasen, *jasen; int j,kentta,paluu; char *p; int samahaku = 0; uudestaan: viiva(); paluu = kysy_kentat_ja_etsi(kerho,VAIN_ETSI,&loytyi,samahaku); if ( paluu < 0 ) return paluu; samahaku = 2; /* Jatkossa hakeminen samalla kent„ll„. */ if ( loytyi->indekseja == 0 ) { printf("Ehdon t„ytt„vi„ tietueita ei l”ydy!\n"); goto uudestaan; } if ( valinta == 2 ) { if ( loytyi->indekseja == 1 ) printf("T„sm„„ vain yksi tietue!\n"); printf("Muutetaanko (K/e)?"); if ( !kylla_vastaus() ) goto uudestaan; printf("Odota hetki..."); } for (j=0; jindekseja; j++) { kerho->nykyjasen = loytyi->indeksit[j]; /* Tarkistuksen takia! */ jasen = kerho->jasenet[loytyi->indeksit[j]]; memcpy(&apu_jasen,jasen,jasen->rakenne->koko); if ( valinta == 3 ) { printf( "---------------------------------------------------------------------------\n"); tulosta_jasen(stdout,jasen); } for (p=Kasiteltavat_kentat; *p; p++) { kentta = paikka(Kenttavalinnat,*p); if ( kentta < 0 ) continue; kentta = sijoita_kentta(&apu_jasen,&Arvo_jasen,kentta); if ( kentta < 0 ) continue; if ( valinta == 3 ) { paluu = kysy_yksi_kentta(kerho,&apu_jasen,kentta,1,""); if ( paluu == 1 ) return 1; if ( paluu == -1 ) break; } } if ( memcmp(jasen,&apu_jasen,jasen->rakenne->koko) ) { memcpy(jasen,&apu_jasen,apu_jasen.rakenne->koko); kerho->muutettu = 1; } } if ( valinta == 2 ) printf("Tiedot muutettu!\n\n"); else goto uudestaan; return 0; } /****************************************************************************/ void /* */ korjaile_kenttia( /* */ Kerho_tyyppi *kerho ,/* s,t Kerho, jonka tietueita korjaillaan. */ Jarjestys_tyyppi **loytyi/* s,t L”ytyneiden taulukko. */ ) /* ** Aliohjelmalla on mahdollista korjailla valittuja kentti„. ** Aluksi tarkistetaan onko aliohjelmien sis„isiss„ muuttujissa jo ** j„rkev„t arvot. Mik„li on tulostetaan menu, ja toimitaan sen mukaan. ** loytyi ks. kysy_kentat_ja_etsi ** ** Globaalit: Kenttavalinnat ** Kasiteltavat_kentat ** Arvo_jasen ** Kutsuu: kysy_kas_kentat ** kopioi_jono ** kysy_kentat_ja_etsi ** korjailu_menu ** tayta_kentat ** ----------------------------------------------------------------------------*/ { int valinta,nyky; Jarjestys_tyyppi *loyt=NULL; if ( !kerho->jasenia ) return; if ( loytyi == NULL ) loytyi = &loyt; if ( *loytyi == NULL ) *loytyi = &Loytyi; if ( Arvo_jasen.rakenne != kerho->jasenet[kerho->nykyjasen]->rakenne || kerho->rakenne->kas_kentat[MUUTOS][0] == 0 ) { nyky = kerho->nykyjasen; kerho->nykyjasen = kerho->jasenia; /* Jotta alustaa tyhj„ksi */ alusta_jasen(kerho,&Arvo_jasen); kerho->nykyjasen = nyky; kopioi_jono(N_S(Kenttavalinnat),Arvo_jasen.rakenne->kenttavalinnat); if ( kysy_kentat_ja_arvot(kerho,&Arvo_jasen,MUUTOS) ) return; } while (1) { valinta = korjailu_menu(&Arvo_jasen); switch ( valinta ) { case 0: return; case -1: help_hakemisto("Tietyn kent„n korjailu"); break; case 1: if ( kysy_kentat_ja_arvot(kerho,&Arvo_jasen,MUUTOS) ) return; break; case 2: case 3: if ( tayta_kentat(valinta,kerho,*loytyi) == -1 ) return; break; } } }