/****************************************************************************/ /* ** K E R H O E T S . C ** ** Kerhosta tietyn ehdon tyttvien jsenien etsiminen ** ** Aliohjelmat: ** onko_rajoissa - tutkii onko kentt sallittujen rajojen sisll ** lajittele - tekee permutaatiotaulukon valitun kentn ** mukaisesti ** etsi_kentat - etsii annetun maskin ehdon tyttvi jseni ** kysy_kentat_ja_etsi - interraktiivinen kysyminen, etsiminen, ** selaaminen, korjailu ja poisto ** laske_montako_muuta - etsii onko muita kuin valittua jsent ** korjaile_kenttia - antaa mahdollisuuden korjailla valit.kentti ** ** ** Tekijt: Vesa Lappalainen ** Ohjelmointikurssi 1991 ** Tehty: 13.11.1991 ** Muutettu: 17.11.1991/vl ** Mit muutettu: rakennetta siistitty ** listty lajittelu ** Muutettu: 23.11.1991/vl ** Mit muutettu: tyyppiksite yleistetty ** Muutettu: 24.12.1991/vl ** Mit muutettu: epyhtlhaku ** negatiivisten lukujen lajittelu korjattu ** tyhjn 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 lisparametri ** Muutettu: 18.12.1992/vl ** Mit muutettu: korjattu tietueen poistossa ollut vika ** eli poistettu viittaus nollatulla nykyjsenell ** vaihdettu Jarjestystyypin tietueen nimi ** kenttia -> indekseja ** kentat -> indeksit ** Muutettu: 4.12.1993/vl ** Mit muutettu: - laita_selaus_kohdalla korjattu siten, ettei ** viimeisen poisto nyt vr jsent ** - korjattu kenttien muuttamista ** - etsiminen silytt 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 kytettv tietue. */ int kentan_nro; /* Kentt jonka mukaan lajitellaan. */ Jasen_tyyppi **jasenet; /* Osoitin osoitintaulukon alkuun. */ } Vertaa_tyyppi; /* */ typedef struct { /* Avaimen muodostuksessa kytett 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 kytettv 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 jrjestystaulukko. */ ) /* ** Aliohjelmalla alustetaan avaimen muodostamisessa tarvittava taulukko. ** Tyhj, vlimerkit 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 keskenn! */ 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; /* Tiedonvlitys lajittele -> vertaile */ /****************************************************************************/ int /* -1 1. pienempi */ vertaile( /* 0 Yhtsuuria */ /* 1 1. suurempi */ const void *a ,/* s 1. verrattavan indeksi. */ const void *b /* s 2. verrattavan indeksi. */ ) /* ** Funktiolla verrataan kahta indeksin avulla annettua jsent 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 kentn mukaan lajitellaan */ ) /* ** Funktiolla lajitellaan jarj taulukko annetun kentn mukaan oikeaan ** jrjestykseen. Lajiteltava kentt valitaan kentan_nro mukaan. ** Mikli jarj.indekseja = 0, alustetaan taulukko 0 1 2 3 ** muuten kytetn olemassa olevaa numerointia. ** Ei viel jrjest AND ja OR etsimisen mukaan! ** ** Globaalit: Kytt vertaa -funktion kanssa yhteist aluetta VERTAA ** Kutsuu: qsort ** Algoritmi: Vlitetn 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-jseni 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 lukumr */ sizeof(jarj->indeksit[0]), /* Yksittisen alkion koko */ vertaile); /* Vertailualiohjelman nimi */ } /****************************************************************************/ int /* 0 = ei lydy muita joihin tsm */ laske_montako_muuta( /* muuten muiden tsmvien mr */ Kerho_tyyppi *kerho ,/* s Kerho josta etsitn */ int kentta ,/* s Kentt johon verrataan */ char *jono ,/* s Jono jota etsitn */ int kuka_ei ,/* s Henkil jota ei etsit. */ int *viimeinen ,/* t Indeksi viimeiseen lytyneeseen */ int *oliko_kuka_ei /* t Oliko se joka ei saa olla */ ) /* ** Funktiolla lasketaan montako muuta ehdon tsmlleen tyttv jsent ** kerhosta lytyy. Palautetaan parametrina mys viimeinen johon tsmsi. ** ** Algoritmi: Verrataan jokaista paitsi ei-etsittv. ----------------------------------------------------------------------------*/ { 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 tsm */ tutki_tasmaako( /* 0 = tsm */ Jasen_tyyppi *jasen ,/* s Tutkittva jsen */ char *ikentta ,/* s Kentt muutettuna isoiksi kirjaimeksi */ char *maski ,/* s Maski muutettuna isoiksi kirjaimeksi */ int knro /* s Kentn numero. */ ) /* ** Funktiolla tutkitaan onko annettu ehto voimassa. Ehdot: ** <, <= ,> , >= , !=, == ** Mikli 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 tsm */ onko_rajoissa( /* 0 = tsm */ Jasen_tyyppi *jasen ,/* s Tutkittva jsen */ char *kentta ,/* s Tutkittava kentt. */ int knro /* s Kentn 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 tsm */ break; case '&': if ( samat != 0 ) return 1; break; /* And:illa jatketaan viel */ } } } /****************************************************************************/ int /* */ etsi_indeksit( /* = lytyneiden indeksien lukumr */ Kerho_tyyppi *kerho ,/* s Kerho josta etsitn */ int kentta ,/* s Kentn numero, josta etsitn (tai AND,OR) */ Haku_tyyppi *maski ,/* s Arvot joiden mukaan etsitn. */ Jarjestys_tyyppi *etsi /* t Taulukko jonne lytyneet talletetaan */ ) /* ** Funktiolla etsitn maskin mukaisia kentti rekisterist. ** Palautetaan taulukossa niiden paikkojen indeksit, joista ** maski lytyi. Mikli kentt on OR etsitn TAI-toimintona kaikkia ** kentti (eli jos yksikin kentt tsm) ja mikli kentta==AND ** etsitn JA-toimintona (eli kaikkien kenttien tytyy tsmt). ** Jos maskin kentt on tyhj, ei kentt verrata lainkaan. ** Jos maskin kentt alkaa ~, niin vastaavan kentn tytyy olla tyhj. ** Mikli ketn ei lydy, laitetaan silti indeksit[0]=0, jotta siihen voidaan ** varmasti viitata. ** ** Kutsuu: jono_isoksi ** kopioi_jono, N_S ** wildmat ** Algoritmi: Kokeillaan jokaista paikkaa ja merkitn lytymt yls. ** 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 jsenet */ if (!kerho->jasenet[j]) continue; /* Ohitetaan NULL-osoittimet*/ samat=0; for (k=k1; k<=k2; k++) { /* Tarkistetaan kentt. */ if ( KK[0] != 0 && strchr(KK,KV[k]) == NULL && ( kentta == ETSI_AND ) || ( kentta == ETSI_OR ) ) continue; /* Jos ei ksiteltviss 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 vlitet. */ samat = !tutki_tasmaako(kerho->jasenet[j],isana,m,k); if ( samat && yksi_riittaa ) break; /* Yksi ja TAI lytyi */ if ( (!samat) && (!yksi_riittaa) ) break; /* JA ei lydy */ } 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 tytetn. */ ) /* ** Aliohjelmalla tytetn viesti muotoon: ** Valitse kent jonka mukaan etsitn (?=kenttlista uudell.) ** Mikli korjaus ja poisto on sallittu, listn viestiin viel ** ,\npoisto (P), korjailu (K) ** Samoin sallittujen kirjaimien joukkoon laitetaan kaikki kenttlistan ** 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 etsitn (?=kenttlista uudell.)"); selaus->vali = '\n'; /* Tytetn nppinlistaan nyt sallitut nppimet */ 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 nytt 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 kentn arvo oikeisiin ** rajoihin. Samalla muutetaan kerhon nykyjsen. ** 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 ) { /* Tm vain kun mitn 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 henkilit. ** Mikli painetaan muuta kuin + tai -, palautetaan painettu nppin. ** Painetuiksi sallitaan kuitenkin vain listassa olevat nppimet ** sek +, - ja RET. ** Aluksi tulostetaan kohdalla oleva henkil (mikli tllainen on olemassa). ** Tmn jlkeen tulostetaan viesti, johon listn mahdollisesti pern ** tieto + ja - kytst, mikli nm ovat olemassa. ** cr-lipulla tutkitaan halutaanko lyhyt vai pitk tulostus. ** Lyhyess tulostuksessa pyyhitn edellinen viesti pois ja nin ** selattavat saadaan tiiviimmin nyttn. ** ** Muuttuu: selaus->kohdalla ** kerho->nykyjasen ** kerho->rakenne ** Sytt: nppimist ** Tulostus: nyttn ** Kutsuu: tulosta_jasen ** kopioi_jono, N_S ** liita_jono ** odota_nappain ** Esimerkki: viesti = "Selaile" vali = ' ' ja on selattavia kump. suuntaan ** tulostaa kohdalla olevan jsenen 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 { /* Pyyhitn 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 { /* Estetn 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 eteenpin */ 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 taaksepin*/ 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 lytymis yms. tiedot laitetaan*/ int korj_poisto /* s Onko korjailu ja poisto sallittu */ ) /* ** Funktiolla tytetn nytlle tuleva kysymys ja sallitut nppimet sek ** tmn jlkeen annetaan selaus-funktion hoitaa tehtvi kunnes painetaan ** jotain muuta kuin + tai -. Mikli painetaan ? tulostetaan kenttlista ** ja jatketaan viel selailua kun lydettyjen lista on tyhjennetty. ** ** Muuttuu: etsi.selattavat ** Sytt: nppimist ** Tulostus: nyttn ** Kutsuu: tayta_viesti_ja_sallitut ** selaile ----------------------------------------------------------------------------*/ { char painettu; int i; for (i=0; iselattavat->indekseja; i++) /* Jotta paikka silyy */ if ( kerho->nykyjasen == selaus->selattavat->indeksit[i] ) selaus->kohdalla = i; /* Kyselln kunnes ei en haluta kenttlistaa. */ 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 = eponnistui */ varaa_jarjestys( /* 0 = onnistui */ Kerho_tyyppi *kerho ,/* s */ int koko ,/* s Taulukolle varattava koko */ Jarjestys_tyyppi *loytyi/* t */ ) /* ** Funktiolla varataan tilaa jrjestystaulukolle mikli max_koko=-1. ** tai tila ei riit. ** Samalla muut kentt alustetaan siten, ett on yksi lytynyt joka ** osoittaa nyky_jaseneen. ** Jos koko<=0, niin varataan tilaa kerhon jsenistn 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 = eponnistui */ etsi_indekseja( /* Lytyneiden indeksien lukumr. */ Kerho_tyyppi *kerho ,/* s,t Kerho josta etsitn */ int kentan_nro ,/* s Kentn numero, jonka mukaan etsitn */ Jarjestys_tyyppi *loytyi/* t Taulukko jonne lytyneet talletetaan. */ ) /* ** Funktiolla etsitn kerhosta kentst kentan_nro niit jseni, joilla ** ko. kentss on kerho->haku ehdon tyttvt tiedot. Jos kentn numero ** on JA tai TAI, niin koko tietueen tiedot kytetn hyvksi. ** Mikli lytyneit on yli yksi, tulostetaan lytyneiden lukumr. ** Voidaan kutsua mys alustamattomalla taulukolla, mikli sen max_koko=-1; ** tllin taulukko alustetaan ja varataan sille tarvittava permutaatio ** taulukko. ** ** Muuttuu: kerho->nykyjasen ** Tulostus: nytn ** Kutsuu: etsi_indeksit ----------------------------------------------------------------------------*/ { if (varaa_jarjestys(kerho,0,loytyi)) return -1; etsi_indeksit(kerho,kentan_nro,kerho->haku,loytyi); if ( loytyi->indekseja > 1 ) printf("Thn tsm %d tietuetta!\n",loytyi->indekseja); kerho->nykyjasen = loytyi->indeksit[0]; return loytyi->indekseja; } /****************************************************************************/ int /* -1 = eponnistui */ alusta_selaustaulukko( /* 0 = onnistui, */ Kerho_tyyppi *kerho ,/* s Kerho josta etsitn. */ Selaus_tyyppi *selaus ,/* t Alustettava taulukko. */ Jarjestys_tyyppi *loytyi/* s Kytettev jrjestystaulukko. */ ) /* ** Funktiolla varataan tilaa selaustaulukolle ja alustetaan se sisltmn ** vain kerhon nykyjsen. Mikli 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 jseni! */ if ( !kerho->haku ) { /* Onko hakumaskia ennestn? */ if ( !(kerho->haku = calloc(MAX_KENTTIA,sizeof(kerho->haku[0]))) ) return -1; /* 1. kerralla hakuehto laitetaan tyhjksi. calloc hoiti tmn! */ } 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 lytyneiden kenttien lukumr */ /* -2 = halutaan edelliseen menuun */ Kerho_tyyppi *kerho ,/* s,t Kerho josta etsitn. */ int korj_poisto ,/* s Onko korjailu ja poisto mukana (1=on, 0=ei)*/ Jarjestys_tyyppi **loytyi,/* s,t Taulukko, jonne lytyneet tulevat. */ int samahaku /* s Tuleeko sama hakukentt kuin ed. kerralla */ ) /* ** Funktiolla kysytn mink kentn mukaan etsitn, kysytn ** tiedot ja etsitn ehdot tyttvien kenttien indeksit. ** Nit voidaan sitten selata yls tai alas. Mys korjailu ** ja poisto on mahdollista, jos korj_poisto=1. ** Jos korj_poisto=2, niin tehdn vain etsiminen yhden kerran. ** Mikli loytyi==NULL, tehdn apumuuttujan avulla osoite ** globaaliin taulukkoon Loytyi. ** Mikli *loytyi==NULL, kytetn mys globaalia taulukkoa Loytyi, ** mutta palautetaan osoitin Loytyi-taulukkoon. ** Mikli ei ole NULL, pit 1:ll kutsukerralla olla alustettu ** loytyi.indekseja=-1 ** Tllin aliohjelma huolehtii tarvittavasta tilanvarauksesta ** taulukolle. Voidaan tietysti varata itsekin haluttu tila. ** Muiden kuin globaalin taulukon koko ei muutu automaattisesti. ** ** Sytt: Pttelt ** Tulostus: Nyttn ** 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 nppin nppimen */ int kentan_nro; /* Kun painettu nppin muutetaan kentn 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 nppint. Jos jokin kenttlistasta, kysytn */ /* sen kentn arvo ja etsitn. */ 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 mikn kenttlistasta. 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("Tyt 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("Tyt 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 = eponnistui */ kysy_arvot_kentille( /* 0 = onnistui */ Kerho_tyyppi *kerho ,/* s Kerho, jota ksitelln. */ Jasen_tyyppi *jasen /* s,t Mallijasen, johon tulee oletusarvot */ ) /* ** Kysytn arvot jonossa oleville kentille. ----------------------------------------------------------------------------*/ { char *p; int kentta,paluu; printf("Valitse arvot kentille: (" TYHJENNA_JONO" ->tyhjent kentn, tyhj->jtetn 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 tytt"); if ( paluu ) return paluu == 1; } return 0; } /****************************************************************************/ int /* 1 = eponnistui */ kysy_kentat_ja_arvot( /* 0 = onnistui */ Kerho_tyyppi *kerho ,/* s Kerho, jota ksitelln. */ Jasen_tyyppi *jasen ,/* s,t Mallijasen, johon tulee oletusarvot */ int kas_kentta /* s Mink ksittelytavan kentt? */ ) { if ( kysy_kas_kentat(kerho,kas_kentta) ) return 1; if ( kysy_arvot_kentille(kerho,jasen) ) return 1; return 0; } /****************************************************************************/ /* Aliohjelmien sisiset globaalit */ static char Kenttavalinnat[80]=""; /* Mahdollisten kenttien valinnat */ static Jasen_tyyppi Arvo_jasen = {NULL};/* Jsen jossa kenttien tyttarvot */ #define Kasiteltavat_kentat Arvo_jasen.rakenne->kas_kentat[MUUTOS] /****************************************************************************/ int /* */ korjailu_menu( /* = valitun toiminnan numero */ Jasen_tyyppi *jasen /* s Jsen, jonka mallitiedot tulostetaan */ ) /* ** Funktioilla tulostetaan korjailumenu muodossa: ** Valitse: ** 0 = ** 1 = valitse ksiteltvt kentt ** jsenmaksu = 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 pvalintaan\n" " 1 = valitse ksiteltvt kentt (%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 = tyt automaattisesti kentt 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. tytt, 3 = kyselev tytt */ Kerho_tyyppi *kerho ,/* s Kerho, jonka jseni tytetn. */ Jarjestys_tyyppi *loytyi/* s,t Lytyneiden taulukko */ ) /* ** Funktioilla tytetn kentti joko automaattisesti tai kysellen. ** Aluksi kysytn hakuehto ja etsitn ehdot tyttvt tietueet. ** Kentti tytetn kenttien nimien perusteella, eli vain sellaiset ** tietueet ksitelln, joissa on samanniminen kentt, jota ollaan ** tyttmss. Koska etsiminen ei tt tied, saattaa aluksi ** tulostua liian monta tietuetta. ** Nytn 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 kentll. */ if ( loytyi->indekseja == 0 ) { printf("Ehdon tyttvi tietueita ei lydy!\n"); goto uudestaan; } if ( valinta == 2 ) { if ( loytyi->indekseja == 1 ) printf("Tsm 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 Lytyneiden taulukko. */ ) /* ** Aliohjelmalla on mahdollista korjailla valittuja kentti. ** Aluksi tarkistetaan onko aliohjelmien sisisiss muuttujissa jo ** jrkevt arvot. Mikli 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 tyhjksi */ 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 kentn 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; } } }