diff options
| -rw-r--r-- | server/src/Makefile.am | 3 | ||||
| -rw-r--r-- | server/src/database.cc | 20 | ||||
| -rw-r--r-- | server/src/macro.h | 58 | ||||
| -rw-r--r-- | server/src/macro_parser.cc | 170 | ||||
| -rw-r--r-- | server/src/macro_parser.h | 36 | ||||
| -rw-r--r-- | server/src/server.cc | 76 | ||||
| -rw-r--r-- | server/src/transaction.h | 2 | ||||
| -rw-r--r-- | server/src/xmlparser.cc | 8 | ||||
| -rw-r--r-- | server/xml/Makefile.am | 6 | ||||
| -rw-r--r-- | server/xml/example.xml | 56 | ||||
| -rw-r--r-- | server/xml/patient.xml | 10 | 
11 files changed, 354 insertions, 91 deletions
| diff --git a/server/src/Makefile.am b/server/src/Makefile.am index ac5ed0a..43fa560 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -11,6 +11,7 @@ pracrod_SOURCES = \  	configuration.cc \  	exception.cc \  	log.cc \ +	macro_parser.cc \  	server.cc \  	tcpsocket.cc \  	tostring.cc \ @@ -23,6 +24,8 @@ EXTRA_DIST = \  	debug.h \  	exception.h \  	log.h \ +	macro.h \ +	macro_parser.h \  	server.h \  	tcpsocket.h \  	tostring.h \ diff --git a/server/src/database.cc b/server/src/database.cc index 1d4915e..1a48925 100644 --- a/server/src/database.cc +++ b/server/src/database.cc @@ -62,7 +62,7 @@ int Database::post(Transaction &transaction)          commit.macro + "', '" +           commit.version + "', '" +           now + "', '" +  -        commit.user + "')"; +        transaction.user + "')";        W.exec(sql);        // Insert field entries @@ -124,21 +124,21 @@ CREATE DATABASE pracro  CREATE TABLE transactions  ( -  "cpr" varchar(255), -  "transaction" varchar(255), -  "makro" varchar(255), -  "version" varchar(255), -  "timestamp" varchar(255), -  "user" varchar(255) +  "cpr" varchar(11), +  "transaction" text, +  "makro" text, +  "version" text, +  "timestamp" bigint, +  "user" text  )   WITH OIDS;  ALTER TABLE transactions OWNER TO pracro;  CREATE TABLE fields  ( -  "transaction" varchar(255), -  "name" varchar(255), -  "value" varchar(255) +  "transaction" text, +  "name" text, +  "value" text  )   WITH OIDS;  ALTER TABLE fields OWNER TO pracro; diff --git a/server/src/macro.h b/server/src/macro.h new file mode 100644 index 0000000..af9749d --- /dev/null +++ b/server/src/macro.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            macro.h + * + *  Mon Sep 24 10:51:43 CEST 2007 + *  Copyright 2007 Bent Bisballe Nyeng, Lars Bisballe Jensen and Peter Skaarup + *  deva@aasimon.org, elsenator@gmail.com and piparum@piparum.dk + ****************************************************************************/ + +/* + *  This file is part of Pracro. + * + *  Pracro is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  Pracro is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with Pracro; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#ifndef __PRACRO_MACRO_H__ +#define __PRACRO_MACRO_H__ + +#include <string> +#include <vector> + +class WidgetProperty { +public: +  std::string name; +  std::string value; +}; +typedef std::vector< WidgetProperty > WidgetPropertyList;  + +class Widget; +typedef std::vector< Widget > WidgetList;  + +class Widget { +public: +  std::string type; +  WidgetPropertyList properties; +  WidgetList widgets; +}; + +class Macro { +public: +  std::string name; +  std::string version; + +  WidgetList widgets; +}; + +#endif/*__PRACRO_MACRO_H__*/ diff --git a/server/src/macro_parser.cc b/server/src/macro_parser.cc new file mode 100644 index 0000000..c317482 --- /dev/null +++ b/server/src/macro_parser.cc @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            macro_parser.cc + * + *  Mon Sep 24 10:49:55 CEST 2007 + *  Copyright 2007 Bent Bisballe Nyeng, Lars Bisballe Jensen and Peter Skaarup + *  deva@aasimon.org, elsenator@gmail.com and piparum@piparum.dk + ****************************************************************************/ + +/* + *  This file is part of Pracro. + * + *  Pracro is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  Pracro is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with Pracro; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#include "macro_parser.h" + +// For XML +#include <config.h> + +// For open, read and close +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <stdio.h> +#include <string.h> +#include <expat.h> + +#include <string> +#include <map> + +class MacroParser { +public: +  Macro *macro; +  std::vector< Widget* > stack; +  bool done; +}; + +static void start_hndl(void *p, const char *el, const char **attr) +{ +  MacroParser *parser = (MacroParser*)XML_GetUserData(p); + +  printf("Start tag [%s]\n", el); + +  // Convert to comfy C++ values... +  std::string name = el; +  std::map< std::string, std::string > attributes; + +  while(*attr) { +    std::string at_name = *attr; +    attr++; +    std::string at_value = *attr; +    attr++; + +    attributes.insert(make_pair(at_name, at_value)); +  } + +  // Do something reasonable with them... + +  if(name == "include") { + +    Macro inc; +    parse_macro(attributes["name"], inc); + +    WidgetList::iterator w = inc.widgets.front().widgets.begin(); +    while(w != inc.widgets.front().widgets.end()) { +      parser->stack.back()->widgets.push_back(*w); +      w++; +    } + +    return; // Don't do further parsing of this tag. +  } + +  Widget widget; +  widget.type = name; + +  Widget *wp; + +  if(parser->stack.size() > 0) {// We only pushback the child if there is a parent. +    parser->stack.back()->widgets.push_back(widget); +    wp = &parser->stack.back()->widgets.back(); +  } else { +    parser->macro->widgets.push_back(widget); +    wp = &parser->macro->widgets.back(); +  } +  parser->stack.push_back(wp); + +  std::map< std::string, std::string >::iterator i = attributes.begin(); +  while(i != attributes.end()) { +    WidgetProperty prop; +    prop.name = i->first; +    prop.value = i->second; + +    wp->properties.push_back(prop); + +    i++; +  } +} + +static void end_hndl(void *p, const char *el) +{ +  MacroParser *parser = (MacroParser*)XML_GetUserData(p); +  +  printf("End tag [%s]\n", el); + +  if(std::string("include") != el) parser->stack.pop_back(); + +  if(!strcmp(el, "macro")) parser->done = true; +} + +void parse_macro(std::string name, Macro ¯o) +{ + +  XML_Parser p = XML_ParserCreate(NULL); +  if (! p) { +    fprintf(stderr, "Couldn't allocate memory for parser\n"); +    // throw Exception(...); +    return; +  } + +  MacroParser parser; +  parser.macro = ¯o; +  parser.done = false; + +  XML_SetUserData(p, &parser); +  XML_UseParserAsHandlerArg(p); +  XML_SetElementHandler(p, start_hndl, end_hndl); + +  std::string macrofile = std::string(XML) + "/" + name + ".xml"; +  int fd = open(macrofile.c_str(), O_RDONLY); + +  if(fd == -1) { +    printf("Cannot open file \"%s\"...", macrofile.c_str()); +    printf("failed!\n"); +    return; +  } + +  while(!parser.done) { +    char buf[32]; +    int len; + +    memset(buf, 0, sizeof(buf)); +    len = read(fd, buf, sizeof(buf) - 1); + +    parser.done = len == 0; + +    if (! XML_Parse(p, buf, len, parser.done)) { +      fprintf(stderr, "Parse error at line %d:\n%s\n", +	      XML_GetCurrentLineNumber(p), +	      XML_ErrorString(XML_GetErrorCode(p))); +      // throw Exception(...); +      return; +    } +  } + +  //  printf("%d requests\n", transaction.requests.size()); +} diff --git a/server/src/macro_parser.h b/server/src/macro_parser.h new file mode 100644 index 0000000..9f701d4 --- /dev/null +++ b/server/src/macro_parser.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + *            macro_parser.h + * + *  Mon Sep 24 10:49:55 CEST 2007 + *  Copyright 2007 Bent Bisballe Nyeng, Lars Bisballe Jensen and Peter Skaarup + *  deva@aasimon.org, elsenator@gmail.com and piparum@piparum.dk + ****************************************************************************/ + +/* + *  This file is part of Pracro. + * + *  Pracro is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  Pracro is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with Pracro; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. + */ +#ifndef __PRACRO_MACRO_PARSER_H__ +#define __PRACRO_MACRO_PARSER_H__ + +#include <string> + +#include "macro.h" + +void parse_macro(std::string name, Macro ¯o); + +#endif/*__PRACRO_MACRO_PARSER_H__*/ diff --git a/server/src/server.cc b/server/src/server.cc index 24f55ef..064d8b9 100644 --- a/server/src/server.cc +++ b/server/src/server.cc @@ -26,9 +26,6 @@   */  #include "server.h" -// For XML -#include <config.h> -  #include "tcpsocket.h"  #include <errno.h> @@ -40,40 +37,33 @@  #include "configuration.h" -// For open, read and close -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -  #include "transaction.h"  #include "xmlparser.h"  #include "database.h" -/** -\section{Data transmission} -En transmission består af en række deltransmissioner som afhænger af -brugerens handling. -\begin{itemize} -\item Klienten beder om en XMLMakro by-name. -\item Serveren genererer makroen og sender den til klienten i en XML -      stream. Forbindelsen lukkes efter end overførsel. -\item Brugeren udfylder input felterne og trykker på ``commit'' eller -      ``abort'' knappen. -\item Hvis der blev trykket ``abort'' lukkes vinduet. -\item Hvis der blev trykket ``commit'' genereres et XML dokument på -      klienten indeholdene alle input felternes navne og deres tilhørende -      værdier. -\item Dette XML dokument sendes til serveren via en nyoprettet forbindelse. -\item Serveren producerer en plaintext klump som repræsenterer -\item Teksten sendes til klienten som appender til den PC-Praxis -      journalfilen. -\item Klienten svarer til serveren at alt gik godt (eller det modsatte) og -      makrovinduet lukkes. -\item Serveren lagrer dataene i en database hvis det gik godt. -\end{itemize} -*/ +#include "macro.h" +#include "macro_parser.h" + +static void send_macro_widget(Widget &widget, TCPSocket &socket, std::string tabs) +{ +  socket.write(tabs + "<" + widget.type); +  WidgetPropertyList::iterator p = widget.properties.begin(); +  while(p != widget.properties.end()) { +    WidgetProperty &property = *p; +    socket.write(" " + property.name + "=\"" + property.value + "\""); +    p++; +  } +  socket.write(">\n"); + +  WidgetList::iterator w = widget.widgets.begin(); +  while(w != widget.widgets.end()) { +    send_macro_widget(*w, socket, tabs + "  "); +    w++; +  } +  socket.write(tabs + "</" + widget.type + ">\n"); +} +  static void connection(TCPSocket &socket)  {    printf("Got connection...\n"); @@ -91,24 +81,14 @@ static void connection(TCPSocket &socket)      printf("Handling request for \"%s\"...", request.macro.c_str()); -    // Now handle the request. -    char outbuf[3]; -    int bytes; - -    std::string macro = std::string(XML) + "/" + request.macro + ".xml"; - -    int fd = open(macro.c_str(), O_RDONLY); -    if(fd == -1) { -      printf("Cannot open file \"%s\"...", macro.c_str()); -      printf("failed!\n"); -      i++; -      continue; -    } +    Macro macro; +    parse_macro(request.macro, macro); -    while((bytes = read(fd, outbuf, sizeof(outbuf))) ) { -      socket.write(outbuf, bytes); +    WidgetList::iterator w = macro.widgets.begin(); +    while(w != macro.widgets.end()) { +      send_macro_widget(*w, socket, "  "); +      w++;      } -    close(fd);      printf("done.\n"); diff --git a/server/src/transaction.h b/server/src/transaction.h index 04d83b3..97bb556 100644 --- a/server/src/transaction.h +++ b/server/src/transaction.h @@ -48,7 +48,6 @@ typedef std::vector< Field > Fields;  class Commit {  public: -  std::string user;    std::string macro;    std::string version;    Fields fields; @@ -58,6 +57,7 @@ typedef std::vector< Commit > Commits;  class Transaction {  public: +  std::string user;    std::string cpr;    std::string version; diff --git a/server/src/xmlparser.cc b/server/src/xmlparser.cc index d4a6bd8..31ffbed 100644 --- a/server/src/xmlparser.cc +++ b/server/src/xmlparser.cc @@ -33,9 +33,9 @@  #include <string>  #include <map> -bool done = false; +static bool done = false; -void start_hndl(void *p, const char *el, const char **attr) +static void start_hndl(void *p, const char *el, const char **attr)  {    Transaction *transaction = (Transaction*)XML_GetUserData(p); @@ -63,6 +63,7 @@ void start_hndl(void *p, const char *el, const char **attr)    // Do something reasonable with them...    if(name == "pracro") { +    transaction->user = attributes["user"];      transaction->cpr = attributes["cpr"];      transaction->version = attributes["version"];    } @@ -75,7 +76,6 @@ void start_hndl(void *p, const char *el, const char **attr)    if(name == "commit") {      Commit c; -    c.user = attributes["user"];      c.macro = attributes["macro"];      c.version = attributes["version"];      transaction->commits.push_back(c); @@ -90,7 +90,7 @@ void start_hndl(void *p, const char *el, const char **attr)  } -void end_hndl(void *p, const char *el) +static void end_hndl(void *p, const char *el)  {    //  printf("End tag [%s]\n", el);    if(!strcmp(el, "pracro")) done = true; diff --git a/server/xml/Makefile.am b/server/xml/Makefile.am index 3ad491e..0e86339 100644 --- a/server/xml/Makefile.am +++ b/server/xml/Makefile.am @@ -1,7 +1,9 @@  EXTRA_DIST = \ -	example.xml +	example.xml \ +	patient.xml  xmldir = $(datadir)/xml  xml_DATA = \ -	example.xml +	example.xml \ +	patient.xml diff --git a/server/xml/example.xml b/server/xml/example.xml index 3e31f56..60068ca 100644 --- a/server/xml/example.xml +++ b/server/xml/example.xml @@ -1,27 +1,31 @@ -  <macro name="fundus" version="1.0"> -    <window name="mainwindow" -            caption="Fundus" -            width="800" -            height="600" -            layout="vbox"> -      <include name="patient"/> -      <frame name="spl_frame" caption="Spl:" layout="vbox"> -	<textedit name="spl_note" value="PÃ¥ begge sider alderssvarende forhold. Der er let katarakt, som dog ikke er operationskrævende."/> +<?xml version="1.0" encoding="UTF-8"?> +<macro name="fundus" version="1.0"> +  <window name="mainwindow" +          caption="Fundus" +          width="500" +          height="500" +          layout="vbox"> +    <include name="patient"/> +    <frame name="spl_frame" caption="Spl:" layout="vbox"> +      <textedit name="spl_note" regexp=".*" value="PÃ¥ begge sider alderssvarende forhold. Der er let katarakt, som dog ikke er operationskrævende."/> +    </frame> +    <frame name="linse_frame" caption="Linse:" layout="vbox"> +      <lineedit name="linse" regexp="[0-9]{5}" value="90-D linse"/> +      <textedit name="linse_note" regexp=".*" value="Der findes centrale atrofiske forandringer."/> +    </frame> +    <frame name="swelling_frame" layout="hbox"> +      <label name="swelling" caption="Der findes central hævelse med:"/> +      <frame name="swelling_radios" layout="vbox"> +	<radiobuttons name="radio" layout="vbox"> +          <item caption="Randblødning" value="rand"/> +	  <item caption="Exsudater" value="exsudater"/> +	  <item caption="Blahblah" value="blabla"/> +        </radiobuttons>        </frame> -      <frame name="linse_frame" caption="Linse:" layout="vbox"> -	<lineedit name="linse" caption="90-D linse"/> -	<textedit name="linse_note" value="Der findes centrale atrofiske forandringer."/> -      </frame> -      <frame name="swelling_frame" layout="hbox"> -	<label name="swelling" caption="Der findes central hævelse med:"/> -	<frame name="swelling_radios" layout="vbox"/> -	  <radiobutton name="radio1" caption="Randblødning"/> -	  <radiobutton name="radio2" caption="Exsudater"/> -	</frame> -      </frame> -      <frame name="buttons" layout="hbox"> -	<button name="cancel" caption="Annuller"/> -	<button name="commit" caption="Godkend"/> -      </frame> -    </window> -  </macro> +    </frame> +    <frame name="buttons" layout="hbox"> +      <button name="cancel" caption="Annuller" action="cancel"/> +      <button name="commit" caption="Godkend" action="commit"/> +    </frame> +  </window> +</macro> diff --git a/server/xml/patient.xml b/server/xml/patient.xml new file mode 100644 index 0000000..751f8f0 --- /dev/null +++ b/server/xml/patient.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<macro name="patient" version="1.0"> +  <frame name="cpr_frame" caption="CPR" layout="vbox"> +    <lineedit name="patient_cpr" regexp="\d{6}-{0,1}\d{4}" value=""/> +  </frame> +  <frame name="name_frame" caption="Navn:" layout="vbox"> +    <lineedit name="patient_navn" regexp=".+" value=""/> +    <textedit name="patient_note" regexp=".*" value=""/> +  </frame> +</macro> | 
