HTML asiakas

Sain valmiiksi uuden version käyttöliittymästä. Rutiini on aika pitkä, joten ajattelin käydä sen läpi vähän yksityiskohtaisemmin kuin edelliset koodinpätkät.

Kaikki oikeudet tietenkin pidätetään. Viimeinen versio ohjelmasta löytyy seuraavasta linkistä: moijari.com:5002

Linkissä on muuten tämä uusi versio, toivotaan, ettei se kaatuile… Linkissä on edellisen postin sisään lokkaantuminen. Anna käyttäjätunnukseksi testi ja salasanaksi testaus.

Edit: Lisätty save nappula jatkon tekstiin ja koodiin. Lisätty loppuun otsakkeen ja rivien tulostusrutiinit.

Rutiini käy läpi seuraavat vaiheet

  • nappuloiden käsittely
  • HTML otsakkeen tulostus (HTTP/1.0, Location, Server, Date jne.)
  • terttu sanan valikon tulostus
  • ylärivin nappuloiden tulostus
  • vierasavainten käsittely (aiemmassa postissa)
  • Save nappulan rutiini
  • otsakeiden kenttien luku tertusta
  • rivien kenttien tietojen luku tertusta
  • Fetch nappulan käsittely ensimmäinen käsittely
  • Prev ja Next nappuloiden endimmäinen käsittely
  • Submit, Display, Change ja Save nappuloiden käsittely
  • Fetch, Prev ja Next nappuloiden toinen yhteinen osa
  • tulosta otsake
  • tulosta rivit
  • vapauta käytetyt muistialueet.

Koodissa on vähän enemmän kommentteja kun tavallisesti. Ohjelman viimeinen versio linkki toimii taas. Vierasavainten käsittelypostissa mainitut muutokset löytyy kappaleessa eivät ole vielä paikallaan.

void html_sovellus(char *sovellus)
{
  int comp;
  char temps[512];
  unsigned char *criteria;

  unsigned char *bonesheaderdata,*bonesheaderdatacriteria;
  unsigned char *boneslinesdata,*boneslinesdatacriteria;
  unsigned char *memberid[64];
  unsigned char timebuf[128];
  unsigned char *ucp;
  time_t now;

  struct set *setheaderfields, *sethf;
  struct set *setlinesfields, *setlf;
  struct set *setheaderdata, *sethd;
  struct set *setscreendata, *setsd;
  struct set *setlinesdata, *setld;
  struct set *setprev,*setnext;

  bonesheaderdatacriteria=NULL;
  boneslinesdatacriteria=NULL;
  setheaderfields=NULL, sethf=NULL;
  setlinesfields=NULL, setlf=NULL;
  setheaderdata=NULL, sethd=NULL;
  setscreendata=NULL, setsd=NULL,
  setlinesdata=NULL, setld=NULL;
  setprev=NULL,setnext=NULL;

  *func='\0';

  ; luetaan parametreistä func parametri
  set_get_element("func",&comp,func,htmlparams);

  if(*func=='\0') {
    strcpy(func,"");
  }

  if(!strcmp(func,"Terttu"))
    strcpy(func,"");
  ; Nappuloiden käsittely

  if(!exists_session_var("mode"))
    strcpy(mode,"Display");
  else {
    ucp=NULL;
    get_session_var("mode",&ucp);
    strcpy(mode,ucp);
  }

  ; Func kentässä on ylärivin nappulan toiminnon nimi
  ; (Fetch, Prev, Next, Display, Change, Save jne.)
  ; Mode kentän mukaan otsakkeen ja rivien tulostuksessa
  ; tulostetaan vain katselu(Display) tai muuttelu(Change)
  ; kenttiä. Lisäksi mode vaikuttaa siihen tulostetaanko
  ; rivit lohkoon ylimääräisiä rivejä rivien lisäystä
  ; varten.
  ;
  ; Suomeksi:
  ;
  ; Fetch, Prev ja Next nappulat antavat katselunäytön,
  ; muuttaaksesi tietoja voit painaa Change nappulaa.
  ;
  ; Submit, Reset ja Save eivät vaikuta näyttömuotoon,
  ; eli jos olit ennen nappulaa muuttamassa, näyttö
  ; säilyy muutosmoodissa, jos olit display moodissa,
  ; näyttö säilyy muuttelumoodissa.
  ;
  ; Display ja change nappulat vaikuttavat vain
  ; näyttötilaan (katselu, muutos).
  ;
  ; Fetch, Prev ja Next nappulat lukevat tietoja
  ; tertusta. Ja muuttavat näyttötilaksi katselutilan
  ;
  ; Save nappula kutsuu skk_save rutiinia, joka lisää
  ; nappulan lokin loppuun(nyt). Muut rutiinin
  ; tehtävät on vielä auki 
  ;
  if(!strcmp(func,"Fetch")) {
    strcpy(mode,"Display");
  } else if(!strcmp(func,"Prev") ) {
    strcpy(mode,"Display");
  } else if(!strcmp(func,"Next") ) {
    strcpy(mode,"Display");
  } else if(!strcmp(func,"Submit")) {
    /* ei vaikuta modeen */
  } else if(!strcmp(func,"Reset")) {
  } else if(!strcmp(func,"Display") ) {
    strcpy(mode,"Display");
  } else if(!strcmp(func,"Change")) {
    strcpy(mode,"Change");
  } else if(!strcmp(func,"Save")) {
    /* Save ei vaikuta näyttöön */     
  }

  if(mode==NULL) {
    strcpy(mode,"Display");
    set_session_var("mode",mode);
  } else 
    set_session_var("mode",mode);

  ; Tulostetaan html otsake. Html otsakkeessa
  ; ensimmäisessä osassa on html:n rivien lukumäärä.
  ; Tämän takia ensimmäinen ja toinen osa tulostetaan
  ; erikseen (html1 ja html2 muuttujat). html_printf
  ; löytyy aiemmasta postista.

  html=html1;
  html[0]='\0';

  html_printf("HTTP/1.0 200 OK\r\n");
  html_printf("Location: \r\n");
  html_printf("Server: %s\r\n",programname);
  now = time(NULL);
  strftime(timebuf, sizeof(timebuf), HTMLTIMEFORMAT, gmtime(&now));

  html_printf("Date: %s\r\n",timebuf);

  html=html2;
  html[0]='\0';
  html_printf("\n<!DOCTYPE html>\r\n");
  html_printf("<html lang=\"fi\">");

  html_printf("<head>");
  html_printf("<meta charset=\"UTF-8\">");
  html_printf("<title>Terttu</title>",clientname);
  html_printf("<meta name=\"author\" content=\"Jari Kuivaniemi\">");
  html_printf("<link href=\"terttu.css\" rel=\"stylesheet\" type=\"text/css\">");
#ifdef OLD1
  html_printf("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=\"UTF-8\">");
#endif
  html_printf("</head>");
  html_printf("<body>");
  html_printf("<form action=\"%s\" method=\"post\">",sovellus);
  html_printf("<input type=\"hidden\" name=\"sessionid\" value=\"%s\">",sessionid);

  html_printf("<nav>");
  html_printf("<ul>");
  html_printf("<li>Terttu");
  html_printf("<ul>");

  ; Tulostaa terttu sanan valikon.

  html_sovellus_menu();

  html_printf("</ul></li>");

  ; Tulostaa ylärivin nappulat

  html_print_buttons();

  html_printf("</ul>");
  html_printf("</nav>");

  html_printf("<table border=\"0\">");
  html_printf("<td>");

  ; Selvittää foreign key yhteydet ja täyttää kentät.
  
  set_find_foreigns(sovellus,setscreen); /* JariK 20150920 */

  ; Save nappula suorittaa skk_save rutiinin. Lisäksi
  ; tarvitaan varmaankin tarkistuksia tiedoille (katso
  ; set_find_foreigns / tietovirrat.
  ;
  ; Aluksi Save nappi kirjoittaa tietueet lokiin, jossa
  ; sama tieto voi olla ajallisesti eri aikoina useampaan
  ; kertaan. skk_fetch:stä ilmeisesti tulee uusi versio,
  ; joka lukee lokia. Ilmeisesti viimeisin versio valitaan
  ; näytölle. Jatkossa poimintaehdosta (esim
  ; asiakasnumero=1000) voisi muodostaa tiiviste-
  ; merkkijonon, jonka nimiseen tiedostoon kaikki
  ; asiakasta tai muuta objektia koskevat tiedot
  ; laitetaan. Asiakasluettelo (kaikki tietueet,
  ; joissa on asiakasnumero kenttä) voisi olla
  ; saatavilla pelkästä 'asiakasnumero' tiivistettynä
  ; sanasta tehdystä tiedostosta.
  ;

  if(!strcmp(func,"Save")) {                                                                                                                    
    skk_save(setscreen);                                                                                                                        
  }
  ; Haetaan otsakkeen kenttien nimet ja muodostetaan
  ; otsakkeen hakuun käytettävä lause (bonesheaderdata)

  rowid=0;

  sprintf(temps,"'sovellus'=\"%s\", 'chapter'=\"header\", 'memberid', 'memberlength'",sovellus); /* Added memberlength. JariK 20140209 */

  skk_fetch2(&setheaderfields,temps,skk);

  bonesheaderdata=NULL;

  sethf=setheaderfields;
  while(sethf!=NULL) {
    set_get_element("memberid",&comp,memberid,sethf->data);
    set_add_element(&bonesheaderdata,memberid); /* Collect fieldnames to fieldsh */
    sethf=sethf->next;
  }

  ; Haetaan rivikenttien nimet ja muodostetaan rividatan
  ; hakuun tarvittava lause.
  sprintf(temps,"'sovellus'=\"%s\", 'chapter'=\"lines\", 'memberid', 'memberlength'",sovellus); /* JariK 20140127 */

  skk_fetch3(&setlinesfields,temps,skk); /* Changed to version 2. JariK 20140214 to version 3. JariK 20140303 */

  boneslinesdata=NULL;

  setlf=setlinesfields; /* sovellus, chapter="header", memberid */
  while(setlf!=NULL) {
    set_get_element("memberid",&comp,memberid,setlf->data);
    set_add_element(&boneslinesdata,memberid); /* Collect fieldnames to fieldsh */
    setlf=setlf->next;
  }

  ; Tämä on fetch nappulan ensimmäinen vaihe. Fetch
  ; nappula lukee näytön otsakkeen kenttien arvot.
  ;
  ; Arvoja käytetään fetch, prev ja next nappuloiden
  ; valikoimien otsaketietueiden valinnassa.
  ; Fetch tallettaa kenttien arvot istuntomuuttujan
  ; findmatch arvoksi.
  ;
  ; Lopuksi Fetchissä luetaan tuo otsakeketju ja
  ; palautetaan ketjun ensimmäinen otsikko sethd
  ; muuttujassa.
  if(!strcmp(func,"Fetch")) { /* JariK 20140220 */

    setscreendata=NULL;

    /* skkuser contains fields filled by user (see parameter reading)
     * fieldsh contains names of header fields.
     */
    skk_fetch_sets(&setscreendata,bonesheaderdata,setscreen);

    setsd=setscreendata;
    criteria=NULL;
    while(setsd!=NULL) {
      set_copy_filled(&criteria,setsd->data);
      setsd=setsd->next;
    }

    if(setscreendata!=NULL) /* Free also. JariK 20140221 */
      set_free(setscreendata);
    setscreendata=NULL;

    bonesheaderdatacriteria=NULL;
    set_copy_all(&bonesheaderdatacriteria,criteria);
    set_copy_all(&bonesheaderdatacriteria,bonesheaderdata);
     
    set_session_var("findmatch",bonesheaderdatacriteria);

    if(criteria!=NULL)
      free(criteria);
    criteria=NULL;

    setheaderdata=NULL;
    skk_fetch_sets(&setheaderdata,bonesheaderdatacriteria,skk->first);
    
    sethd=setheaderdata;
  }

  ; Prev ja next nappulat lukevat näytöltä tämän hetkisen
  ; otsake tietueen kentät. Seuraavaksi hartaan Fetchin
  ; saamat valintakriteerit findmatch ympäristö-
  ; muuttujasta. Sitten luetaan valintakriteerien
  ; mukaiset tiedot tertusta. Seuraavaksi 

  if((!strcmp(func,"Prev") || /* JariK 20140223 */
     !strcmp(func,"Next")) &&
     exists_session_var("findmatch")) { /* JariK 20140223 */

    skk_fetch_sets(&setscreendata,bonesheaderdata,setscreen); /* Ennen set_fetch. JariK 20150920 */

    setsd=setscreendata;
    criteria=NULL;
    while(setsd!=NULL) {
      set_copy_filled(&criteria,setsd->data);
      setsd=setsd->next;
    }

    if(setsd!=NULL)
      set_free(setsd);
    setsd=NULL;

    /* Luetaan fetchin tallettama kenttä, joka sisältää
     * otsakkeen kentät fetchin painamisen ajalta.
     * Esim selaa asiakkaan tilauksia jos asiakasnumero
     * on täytetty.
     */
    get_session_var("findmatch",&bonesheaderdatacriteria);

    setheaderdata=NULL;
    skk_fetch_sets(&setheaderdata,bonesheaderdatacriteria,skk->first);
    
    setnext=setheaderdata; /* has next row. JariK 20140226 */
    sethd=NULL; /* has new current row. JariK 20140226 */
    setprev=NULL; /* has previous row. JariK 20140226 */
    
    while(setnext!=NULL) {
      ; Kun arvot mätsäävät ruudulla prev tai next
      ; nappulan painamisen aikana olleisiin tietoihin,
      ; näytetään seuraavaksi joko tätä tietuetta edeltävä
      ; tai seuraava otsikko.
      if(!set_match2(setnext->data,criteria)) {
        if(!strcmp(func,"Prev")) {
          if(setprev!=NULL) {
            sethd=setprev;
          } else {
            sethd=setnext;
          }
          break;
        } else if(!strcmp(func,"Next")) {
          if(setnext->next!=NULL) {
            sethd=setnext->next;
          } else {
            sethd=setnext;
          }
          break;
        }
      }
      setprev=setnext;
      setnext=setnext->next;
    }
    /* Ei mätsäävää tietuetta, otetaan eka (esim fetch, reset, next) 20150929 JariK */
    if(sethd==NULL) 
      sethd=setheaderdata;
  }

  ; Submit, Change, Display ja Save nappuloilla luetaan
  ; vain ruudulla olevat tiedot uudestaan
  ; tulostettavaksi.
  if(!strcmp(func,"Submit") ||
     !strcmp(func,"Change") ||
     !strcmp(func,"Display") ||
     !strcmp(func,"Save") ) {

    setheaderdata=NULL;
    skk_fetch_sets(&setheaderdata,bonesheaderdata,setscreen);

    setlinesdata=NULL;
    skk_fetch_sets(&setlinesdata,boneslinesdata,setscreen);

    setld=setlinesdata;
  }

  if(!strcmp(func,"Fetch") ||
     !strcmp(func,"Prev") ||
     !strcmp(func,"Next")) {
    boneslinesdatacriteria=NULL;
    if(sethd!=NULL)
      set_copy_all(&boneslinesdatacriteria,sethd->data);
    set_copy_all(&boneslinesdatacriteria,boneslinesdata);

    setlinesdata=NULL;
    skk_fetch_sets(&setlinesdata,boneslinesdatacriteria,skk->first);

    setld=setlinesdata;
  }

  sethf=setheaderfields; /* sovellus, chapter="header", memberid */

  if(setheaderfields!=NULL)
    html_print_header(sethd,setheaderfields,mode); /* Ennen sethd->data */

  setlf=setlinesfields; /* sovellus, chapter="lines", memberid */
  setld=setlinesdata;

  html_print_lines(setld, setlinesfields,mode);

  html_printf("</td>");
  html_printf("</tr>");
  html_printf("</table>");

  set_debug_foreigns(sovellus,setscreen);

  html_printf("</body>");
  html_printf("</form>");
  html_printf("</html>");
  html_printf("\n\n");

  ; Vapautetaan käytössä olleet muistialueet

  if(bonesheaderdata!=NULL)
    free(bonesheaderdata);
  bonesheaderdata=NULL;

  if(bonesheaderdatacriteria!=NULL)
    free(bonesheaderdatacriteria);
  bonesheaderdatacriteria=NULL;

  if(setheaderfields!=NULL)
    set_free(setheaderfields);
  setheaderfields=NULL;

  if(setlinesfields!=NULL)
    set_free(setlinesfields);
  setlinesfields=NULL;

  if(setheaderdata!=NULL)
    set_free(setheaderdata);
  setheaderdata=NULL;

  if(setlinesdata!=NULL)
    set_free(setlinesdata);
  setlinesdata=NULL;
}

int html_print_header(struct set *set, struct set *setheaderfields,char *mode)
{
  struct set *sethf;

  html_printf("<div id=\"header\">");
  html_printf("<table border=\"0\">");
  sethf=setheaderfields;

  ; Tulostetaan kentän nimi arvopareja kaikille
  ; otsakkeen kentille.

  while(sethf!=NULL) {
    html_printf("<tr>");
    html_printf("<td>");
    html_print_fieldname(set,sethf->data,mode);
    html_printf("</td><td>");
    html_print_fieldvalue(set,sethf->data,mode);
    html_printf("</td>");
    sethf=sethf->next;
    html_printf("</tr>");
  }
  html_printf("</table>");
  html_printf("</div>");
}

int html_print_lines(struct set *setlinesdata, struct set *setlinesfields,char *mode)
{
  int comp,lines;
  char memberid[64],memberlength[10],value[128];
  struct set *setlf;
  struct set *setld;

  html_printf("<div id=\"lines\">");
  html_printf("<table border=\"0\">");
  html_printf("<tr>");

  ; Tulostetaan kentän nimet taulukon yläriville.

  setlf=setlinesfields;
  while(setlf!=NULL) {
    set_get_element("memberid",&comp,memberid,setlf->data);

    html_printf("<td>");
    html_printf("%s",memberid); /* Little bugfix JariK 31012014 */
    html_printf("</td>");
    setlf=setlf->next;
  }
  html_printf("</tr>");

  rowid++;

  lines=0;

  ; Selataan rividata läpi, ja kirjoitetaan yksi rivi
  ; joka tietueelle.

  setld=setlinesdata;
  while(setld!=NULL) {
    html_printf("<tr>");

    ; Tulostetaan riville kaikki kentät.

    setlf=setlinesfields;
    while(setlf!=NULL) {
      set_get_element("memberid",&comp,memberid,setlf->data); /* Get fieldname */
      set_get_element("memberlength",&comp,memberlength,setlf->data);
      set_get_element(memberid,&comp,value,setld->data); /* Get data */
      html_printf("<td>");
      html_printf("<input type=\"text\" value=\"%s\" name=\"%s%c%d\" size=\"%s\"  id=\"programbuttonlines\"",
                  value,memberid,rowidchar,rowid,memberlength);
      if(mode !=NULL && !strcmp(mode,"Display"))
        html_printf(" readonly");
      html_printf(">",
                  value,memberid,rowidchar,rowid,memberlength);
      html_printf("</td>");
      setlf=setlf->next;
    }
    html_printf("</tr>");

    rowid++;
    lines++;
    setld=setld->next;
  }

  ; Muuttelu tilassa tulostetaan tyhjiä rivejä, niin
  ; että kokonaisrivien määrä on 10 (esim 1 täytetty
  ; ja 9 tyhjää. Yli kymmenen rivin tapahtumissa oli
  ; ajatus että tulostetaan vain yksi ylimääräinen
  ; rivi. Kun se täytetään enter tuo uuden tyhjän rivin.
  ; sitä ei ole tässä.

  if(mode!=NULL && !strcmp(mode,"Change")) {
    while(lines<10) {
      html_printf("<tr>");
      setlf=setlinesfields;
      while(setlf!=NULL) {
        set_get_element("memberid",&comp,memberid,setlf->data); /* Get fieldname */
        set_get_element("memberlength",&comp,memberlength,setlf->data);
        html_printf("<td>");
        html_printf("<input type=\"text\" value=\"\" name=\"%s%c%d\" size=\"%s\"  id=\"programbuttonlines\">",
                    memberid,rowidchar,rowid,memberlength);
        html_printf("</td>");
        setlf=setlf->next;
      }
      html_printf("</tr>");

      rowid++;
      lines++;
    }
  }
}

int html_print_fieldname(struct set *set, char *sethf,char *mode)
{
  int comp;
  char memberid[64];

  ; Tulostetaan kentän nimi.

  set_get_element("memberid",&comp,memberid,sethf);
  html_printf("%s",memberid);
}

int html_print_fieldvalue(struct set *set, char *setf,char *mode)
{
  int comp;
  char memberid[64],memberlength[10],value[128];

  set_get_element("memberid",&comp,memberid,setf);
  set_get_element("memberlength",&comp,memberlength,setf);

  ; Tulostetaan kentän arvo. Tässä tehdään input lause
  ; syöttöluukkua varten. Lisäksi iffi näyttökentälle.

  *value='\0';
  if(set!=NULL && set->data!=NULL)
    set_get_element(memberid,&comp,value,set->data); /* Added data to header. JariK 20140216 */
  html_printf("<input type=\"text\" value=\"%s\" name=\"%s%c%d\" size=\"%s\" id=\"programbuttonheader\"",
      value,memberid,rowidchar,rowid,memberlength);
  if(mode !=NULL && !strcmp(mode,"Display"))
    html_printf(" readonly");
  html_printf("><br>");
}