summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/Action.h57
-rw-r--r--include/Confirm.h33
-rw-r--r--include/Exceptions.h86
-rw-r--r--include/Form.h41
-rw-r--r--include/Handle.h51
-rw-r--r--include/HttpServ.h44
-rw-r--r--include/Input.h26
-rw-r--r--include/Makefile.am2
-rw-r--r--include/Menu.h35
-rw-r--r--include/Message.h32
-rw-r--r--include/Output.h26
-rw-r--r--include/Socket.h55
-rw-r--r--include/String.h89
-rw-r--r--include/Table.h36
-rw-r--r--include/Variables.h46
-rw-r--r--include/template.h8
16 files changed, 667 insertions, 0 deletions
diff --git a/include/Action.h b/include/Action.h
new file mode 100644
index 0000000..e9edf27
--- /dev/null
+++ b/include/Action.h
@@ -0,0 +1,57 @@
+#ifndef __ACTION_H__
+#define __ACTION_H__
+#ifdef __cplusplus
+
+#include "Exceptions.h"
+#include "Handle.h"
+#include "Variables.h"
+
+/*
+ * La classe Action defini les actions HTTP possibles.
+ * Le constructeur indique l'URL de l'action. Si aucune URL n'est specifiee,
+ * alors une URL aléatoire sera générée.
+ *
+ * Lors de la construction d'une Action, elle sera rajoutée dans une liste chaînée
+ * interne à la classe. De ce fait, la fonction Look4URL recherchera une Action
+ * associée a une URL donnée en paramètre dans la liste chaînée. Le destructeur
+ * va remettre en place la liste chaînée.
+ *
+ * Les dérivés doivent surcharger la méthode Do, qui recevra les variables transportées
+ * par l'action (si nous avions une méthode POST juste avant) et le handle d'écriture
+ * vers le socket HTTP. Ils devront aussi surcharger GetTitle, qui sert à écrire le
+ * titre de la page HTML dans les méthodes SendHead et SendFoot. Ces deux méthodes sont
+ * d'ailleurs surchargeables, pour créer de nouvelles skins HTML dans des classes dérivées.
+ *
+ * La méthode ShowButton sert à afficher un bouton sur la page. Par défaut, ce bouton reviendra
+ * vers la page principale.
+ *
+ * Une action peut être "temporaire", c'est à dire accessible uniquement une seule fois.
+ * Dans ce cas, après création, il faut faire appel à la méthode CleanUp, et la méthode
+ * Do devra terminer par un appel a Accessed, afin de supprimer cette Action.
+ */
+
+class Action : public Base {
+ public:
+ Action(const String & = "");
+ virtual ~Action();
+ Action * Look4URL(const String &);
+ virtual void Do(Variables *, Handle *) = 0;
+ virtual void SendHead(Handle *);
+ virtual void SendFoot(Handle *);
+ virtual void ShowButton(Handle *, const String & = " Ok ", const String & = "start");
+ virtual String GetTitle(void) = 0;
+ String GetURL(void);
+ void CleanUp(void);
+ protected:
+ void Accessed(void);
+ private:
+ static Action * start;
+ Action * next, * prev;
+ String URL;
+ bool hastoclean, accessed;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Confirm.h b/include/Confirm.h
new file mode 100644
index 0000000..b56e0d2
--- /dev/null
+++ b/include/Confirm.h
@@ -0,0 +1,33 @@
+#ifndef __CONFIRM_H__
+#define __CONFIRM_H__
+#ifdef __cplusplus
+
+#include "Exceptions.h"
+#include "Action.h"
+#include "String.h"
+
+/*
+ * Cette classe sert à afficher une boîte de dialogue de confirmation.
+ * Constructeur:
+ * - titre = titre de la boite de dialogue
+ * - msg = message a afficher
+ * - url = url de cette boite
+ * - yes = action a effectuer si on clique sur Oui
+ * - no = action a effectuer si on clique sur Non.
+ */
+
+class Confirm : public Action {
+ public:
+ Confirm(const String & titre, const String & msg, const String & url, Action * yes, Action * no = 0);
+ virtual ~Confirm() { }
+ virtual String GetTitle();
+ virtual void Do(Variables *, Handle *);
+ private:
+ String tit, msg;
+ Action * NYes, * NNo;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Exceptions.h b/include/Exceptions.h
new file mode 100644
index 0000000..34c1155
--- /dev/null
+++ b/include/Exceptions.h
@@ -0,0 +1,86 @@
+#ifndef __EXCEPTIONS_H__
+#define __EXCEPTIONS_H__
+#ifdef __cplusplus
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stddef.h>
+
+/*
+ * Gère les exceptions du système. Le programme principal devrait tenter
+ * de les récupérer afin de les afficher.
+ * GeneralExecption: exception de base. Construite sur une string.
+ * MemoryException: plus assez de mémoire. Construit une string sur la taille mémoire
+ * qui a fait défaut.
+ * IOException: erreur de lecture/écriture. Construite sur le nombre d'octets
+ * et sur l'opération qui a générée l'erreur.
+ * IOGeneral: erreur générale sur une opération IO (erreur à l'ouverture notemment)
+ * IOInternal: erreur interne du programme. En particulier, le programme
+ * a voulu lire ou écrire alors que le Handle n'était pas prévu pour.
+ *
+ * Nous définissons les fonctions xmalloc, xfree et xstrdup. Elles devraient être
+ * utilisées en lieu et place des fonctions malloc, free et strdup. La fonction realloc
+ * étant désapréciée, elle n'est pas surchargée.
+ */
+
+// Impossible de surcharger free(void *). Les compilateurs
+// refuseront de passer un char * par exemple.
+#define free(p) xfree((void*)p)
+
+// On prédéfinit la classe String, pour éviter
+// les deadlocks de compilation...
+class String;
+
+class Base {
+ public:
+ char * strdup(const char *) const;
+ void * malloc(ssize_t) const;
+/* void * operator new(size_t);
+ void * operator new(size_t, void *); */
+};
+
+class GeneralException : public Base{
+ public:
+ GeneralException(String);
+ GeneralException(const GeneralException &);
+ ~GeneralException();
+ char * GetMsg();
+ protected:
+ GeneralException();
+ char * msg;
+ static char t[BUFSIZ];
+};
+
+class MemoryException : public GeneralException {
+ public:
+ MemoryException(ssize_t);
+};
+
+enum op_t {
+ IO_WRITE = 1,
+ IO_READ
+};
+
+class IOException : public GeneralException {
+ public:
+ IOException(String, op_t, ssize_t);
+};
+
+class IOGeneral : public GeneralException {
+ public:
+ IOGeneral(String);
+};
+
+class IOInternal : public GeneralException {
+ public:
+ IOInternal(String, op_t);
+};
+
+char * xstrdup(const char *) throw (MemoryException);
+void * xmalloc(ssize_t) throw (MemoryException);
+void xfree(void *&);
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Form.h b/include/Form.h
new file mode 100644
index 0000000..8a35898
--- /dev/null
+++ b/include/Form.h
@@ -0,0 +1,41 @@
+#ifndef __FORM_H__
+#define __FORM_H__
+#ifdef __cplusplus
+
+#include "Exceptions.h"
+#include "Action.h"
+#include "String.h"
+/*
+ * Cette classe sert à afficher un formulaire de saisie.
+ * Constructeur:
+ * - titre = titre de la page
+ * - url = url de ce formulaire
+ * - inv = invite du formulaire
+ * - names = liste des noms des variables pour chaque champs
+ * - invs = liste des invites pour chaque champs
+ * - defaults = listes des valeurs par defaut pour chaque champs
+ * - lists = liste des listes de valeurs pour les menus deroulants. Si une liste déroulante = 0,
+ * alors il s'agira d'un champ de saisie manuel.
+ * - descs = liste des listes de descriptions pour les menus deroulants.
+ * - nb = nombre de champs
+ * - ok = Action a effectuer lorsque l'on clique sur le bouton Ok.
+ */
+
+class Form : public Action {
+ public:
+ Form(const String & titre, const String & url, const String & inv,
+ String * names, String * invs, String * defaults, String ** lists, String ** descs,
+ int nb, Action * ok = 0);
+ virtual ~Form() { }
+ virtual String GetTitle();
+ virtual void Do(Variables *, Handle *);
+ private:
+ String tit, iv, * nms, * ivs, * defs, ** lsts, ** dscs;
+ int n;
+ Action * Next;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Handle.h b/include/Handle.h
new file mode 100644
index 0000000..cec51c7
--- /dev/null
+++ b/include/Handle.h
@@ -0,0 +1,51 @@
+#ifndef __HANDLE_H__
+#define __HANDLE_H__
+#ifdef __cplusplus
+
+#include <unistd.h>
+#include <iostream.h>
+#include "String.h"
+#include "Exceptions.h"
+
+/*
+ * Pour les classes qui vont deriver: le constructeur Handle(int) specifie
+ * le handle a stocker. De meme, GetHandle sert a lire le handle stocke.
+ *
+ * Les operateurs >> et << ne fonctionnent qu'avec des String. Vu que la
+ * classe String possede des constructeurs pour tous les types utiles, cela
+ * ne posera pas de problemes. >> va lire une ligne en supprimant les caractères
+ * '\n' des fins de lignes et en ignorant '\r'.
+ *
+ * Les fonctions read et write sont les memes que les fonctions systeme read
+ * et write.
+ *
+ * Les booleens CanRead et CanWrite indiquent si le handle peut lire ou ecrire.
+ *
+ * GetName donne le nom associe au handle. (nom de fichier ou autre)
+ */
+
+class Handle : public Base {
+ public:
+ Handle(const Handle &);
+ virtual ~Handle();
+ ssize_t read(void *buf, size_t count) throw (IOException);
+ ssize_t write(const void *buf, size_t count) throw (IOException);
+ bool IsClosed(void);
+ virtual bool CanRead() = 0;
+ virtual bool CanWrite() = 0;
+ virtual String GetName() = 0;
+ protected:
+ Handle(int h);
+ int GetHandle();
+ private:
+ int h;
+ bool closed;
+};
+
+Handle & operator<<(Handle &, const String &);
+Handle & operator>>(Handle &, String &);
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/HttpServ.h b/include/HttpServ.h
new file mode 100644
index 0000000..71dc4eb
--- /dev/null
+++ b/include/HttpServ.h
@@ -0,0 +1,44 @@
+#ifndef __HTTPSERV_H__
+#define __HTTPSERV_H__
+#ifdef __cplusplus
+
+#include "Socket.h"
+#include "String.h"
+#include "Exceptions.h"
+#include "Variables.h"
+#include "Action.h"
+
+/*
+ * La classe HttpServ. Le constructueur (int, const String &) indique le port
+ * et le nom du serveur à indiquer dans les entetes HTTP.
+ *
+ * Une fois lance, il suffit de lancer MainLoop en indiquant le menu principal,
+ * qui est obligatoirement statique et doit posseder l'url /bin/start.
+ */
+
+class HttpServ : public Base {
+ public:
+ HttpServ(int = 1500, const String & = String("GruiK Server v0.1"));
+ ~HttpServ() {}
+ void MainLoop(Action *);
+ private:
+ String GetMime(const String &);
+ void ProcessRequest(Action *);
+ bool ParseUri(String &, String &, Socket &);
+ void ParseVars(Socket &, int);
+ void ShowError(Socket &);
+ void SendHeads(Socket &, const String &);
+ void SendRedirect(Socket &);
+ String name;
+ Socket Listener;
+ Variables * Vars;
+ int localport;
+ bool bad;
+};
+
+extern String endhl, endnl;
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Input.h b/include/Input.h
new file mode 100644
index 0000000..81a48d8
--- /dev/null
+++ b/include/Input.h
@@ -0,0 +1,26 @@
+#ifndef __INPUT_H__
+#define __INPUT_H__
+#ifdef __cplusplus
+
+#include "String.h"
+#include "Handle.h"
+
+/*
+ * Cette classe sert à créer un fichier ouvert en lecture.
+ */
+
+class Input : public Handle {
+ public:
+ Input(String = "") throw (IOGeneral);
+ virtual ~Input() {}
+ virtual bool CanWrite();
+ virtual bool CanRead();
+ virtual String GetName();
+ protected:
+ String n;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..f58566a
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,2 @@
+include_HEADERS = Exceptions.h Handle.h String.h Output.h Socket.h HttpServ.h Variables.h Menu.h Action.h Message.h Form.h Confirm.h Table.h
+
diff --git a/include/Menu.h b/include/Menu.h
new file mode 100644
index 0000000..67bc54e
--- /dev/null
+++ b/include/Menu.h
@@ -0,0 +1,35 @@
+#ifndef __MENU_H__
+#define __MENU_H__
+#ifdef __cplusplus
+
+#include "Exceptions.h"
+#include "Action.h"
+#include "String.h"
+
+/*
+ * Cette classe permet d'afficher un menu.
+ * Constructeur:
+ * - titre = titre de la page
+ * - url = url de la page
+ * - labels = labels de items du menu
+ * - listac = liste des pointeurs sur les actions
+ * - nb = nombre d'items
+ */
+
+class Menu : public Action {
+ public:
+ Menu(const String & titre, const String & url, String * labels, Action ** listac, int nb);
+ virtual ~Menu() {}
+ virtual String GetTitle();
+ virtual void Do(Variables *, Handle *);
+ private:
+ String tit;
+ String * lt;
+ Action ** la;
+ int nba;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Message.h b/include/Message.h
new file mode 100644
index 0000000..1cdb297
--- /dev/null
+++ b/include/Message.h
@@ -0,0 +1,32 @@
+#ifndef __MESSAGE_H__
+#define __MESSAGE_H__
+#ifdef __cplusplus
+
+#include "Exceptions.h"
+#include "Action.h"
+#include "String.h"
+
+/*
+ * Cette classe sert a afficher un message.
+ * Constructeur:
+ * - titre = titre de la page
+ * - msg = message de la boite de dialogue
+ * - url = url de la page
+ * - ok = action a effectuer lorsque l'on clique sur Ok.
+ */
+
+class Message : public Action {
+ public:
+ Message(const String & titre, const String & msg, const String & url, Action * ok = 0);
+ virtual ~Message() { }
+ virtual String GetTitle();
+ virtual void Do(Variables *, Handle *);
+ private:
+ String tit, msg;
+ Action * Next;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Output.h b/include/Output.h
new file mode 100644
index 0000000..6c944ab
--- /dev/null
+++ b/include/Output.h
@@ -0,0 +1,26 @@
+#ifndef __OUTPUT_H__
+#define __OUTPUT_H__
+#ifdef __cplusplus
+
+#include "String.h"
+#include "Handle.h"
+
+/*
+ * Ouvre un fichier en ecriture.
+ */
+
+class Output : public Handle {
+ public:
+ Output(String = "", int trunc = 1) throw (IOGeneral);
+ virtual ~Output() {}
+ virtual bool CanWrite();
+ virtual bool CanRead();
+ virtual String GetName();
+ protected:
+ String n;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Socket.h b/include/Socket.h
new file mode 100644
index 0000000..355d3b2
--- /dev/null
+++ b/include/Socket.h
@@ -0,0 +1,55 @@
+#ifndef __SOCKET_H__
+#define __SOCKET_H__
+#ifdef __cplusplus
+
+#include "String.h"
+#include "Handle.h"
+#include "Exceptions.h"
+#include "Output.h"
+#include "Input.h"
+
+/*
+ * Cree un socket.
+ *
+ * SetLocal(hostname, port) définit le hostname local et le port a écouter, si le
+ * socket est destine a etre un socket serveur, ou la vhost et le port source si
+ * le socket est destine a se etre un socket client. Renvoie faux si probleme quelconque.
+ *
+ * Connect(hostname, port) passe le socket en mode client et va se connecter sur
+ * l'adresse hostname:port specifiee.
+ *
+ * Listen passe le socket en mode serveur.
+ *
+ * Accept permet de récuperer un client qui se connecte sur un socket server, et
+ * renvoie le socket de lecture/ecriture correspondant.
+ *
+ * Les methodes IsConnected et IsListening permettent de verifier l'etat du socket.
+ *
+ * Les fonctions WriteFile et ReadFile permettent de transmettre un fichier sur le socket.
+ * Tres utile pour l'upload ou le download.
+ */
+
+class Socket : public Handle {
+ public:
+ Socket() throw (GeneralException);
+ virtual ~Socket() {}
+ bool SetLocal(String, int = 0);
+ bool Connect(String, int);
+ bool Listen();
+ Socket Accept();
+ bool IsConnected();
+ bool IsListening();
+ size_t WriteFile(Output &);
+ size_t ReadFile(Input &);
+ virtual bool CanRead();
+ virtual bool CanWrite();
+ virtual String GetName();
+ private:
+ Socket(int s);
+ bool connected, listening;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/String.h b/include/String.h
new file mode 100644
index 0000000..65bf0ac
--- /dev/null
+++ b/include/String.h
@@ -0,0 +1,89 @@
+#ifndef __STRING_H__
+#define __STRING_H__
+#ifdef __cplusplus
+
+#include <iostream.h>
+#include <string.h>
+#include "Exceptions.h"
+
+/*
+ * Cette classe permet de stocker des chaînes de caractères simplement.
+ * Elle est une base essentielle et permet d'effectuer énormément d'opérations:
+ * - set fonctionne comme sprintf, et réassigne la chaîne.
+ * - to_charp() transforme la chaîne en pointeur.
+ * - to_charp(from) extrait la chaîne depuis le caractère numéro from
+ * - to_charp(from, to) extrait la chaîne depuis le caractère numéro from
+ * jusqu'au caractère numéro to.
+ * ATTENTION: les fonctions to_charp renvoie un pointeur sur un tableau
+ * statique, et ce tableau sera modifié au prochain
+ * appel à to_charp ou a set.
+ * - to_int transforme la chaîne en int.
+ * - to_double transforme la chaîne en double
+ * - to_sqldate effectue la conversion suivante: DD/MM/YYYY ==> YYYYMMDD
+ * - to_sqltime effectue la conversion suivante: h:m ==> h * 60 + m
+ * - from_sqldate et from_sqltime effectue les conversions inverses.
+ * - datedif calcule la différence en jours entre deux dates. Si le résultat
+ * est négatif, alors une des deux dates étaient invalide.
+ * - is_date, is_number, is_float, is_time renvoient des booléens de test.
+ * - strlen renvoie la longueur de la chaine
+ * - strchr(c) renvoie la position du caractère c
+ * - strchr(c, p) recherche le caractère c à partir de la position p
+ * - strrchr(c) renvoie la position du caractère c, en recherchant depuis la droite.
+ * - strstr(s) renvoie la position de la chaine s
+ * NOTE: les fonctions de recherche renvoient un résultat négatif si pas trouvé.
+ * - strchrcnt(c) compte le nombre d'occurences du caractère c.
+ *
+ * Les opérateurs !=, ==, <=, >=, < et > permettent de comparer deux chaînes, en mode
+ * 'case sensitive'. L'operateur [] renvoie un caractère de la chaîne.
+ *
+ * Les opérateurs << et >> vers un ostream ou depuis un istream sont supportés.
+ */
+
+class String : public Base {
+ public:
+ String(const String &);
+ String(const char * = "");
+ String(char);
+ String(int);
+ String(double);
+ ~String();
+ char * set(char *, ...);
+ char * to_charp(size_t = 0, ssize_t = -1) const;
+ int to_int() const;
+ double to_double() const;
+ String to_sqldate() const;
+ String to_sqltime() const;
+ String from_sqldate() const;
+ String from_sqltime() const;
+ double datedif(const String &) const;
+ bool is_date() const;
+ bool is_number() const;
+ bool is_float() const;
+ bool is_time() const;
+ size_t strlen() const;
+ ssize_t strchr(char, size_t = 0) const;
+ ssize_t strrchr(char) const;
+ ssize_t strstr(const String &) const;
+ int strchrcnt(char) const;
+ String & operator=(const String &);
+ String operator+(const String &) const;
+ String & operator+=(const String &);
+ bool operator!=(const String &) const;
+ bool operator==(const String &) const;
+ bool operator<=(const String &) const;
+ bool operator>=(const String &) const;
+ bool operator<(const String &) const;
+ bool operator>(const String &) const;
+ char operator[](size_t i) const;
+ private:
+ static char t[BUFSIZ];
+ char * str;
+};
+
+ostream & operator<<(ostream &, const String &);
+istream & operator>>(istream &, String &);
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Table.h b/include/Table.h
new file mode 100644
index 0000000..bfcd652
--- /dev/null
+++ b/include/Table.h
@@ -0,0 +1,36 @@
+#ifndef __TABLE_H__
+#define __TABLE_H__
+#ifdef __cplusplus
+
+#include "Exceptions.h"
+#include "Action.h"
+#include "String.h"
+
+/*
+ * Affiche une table.
+ * Constructeurs:
+ * - titre = titre de la page
+ * - url = url de la page
+ * - heads = liste des titres des colonnes. Si = 0, la ligne de titre est désactivée.
+ * - cells = liste de toutes les cellules. Notez qu'il s'agit d'une liste linéaire.
+ * - nbcol = nombre de colonnes
+ * - nblig = nombre de lignes
+ * - ok = action à effectuer si on clique sur le bouton Ok. Page principale par défaut.
+ */
+
+class Table : public Action {
+ public:
+ Table(const String & titre, const String & url, String * heads, String * cells, int nbcol, int nblgn, Action * ok = 0);
+ virtual ~Table() { }
+ virtual String GetTitle();
+ virtual void Do(Variables *, Handle *);
+ private:
+ String tit, * hds, * cls;
+ int nc, nl;
+ Action * Next;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/Variables.h b/include/Variables.h
new file mode 100644
index 0000000..955cf62
--- /dev/null
+++ b/include/Variables.h
@@ -0,0 +1,46 @@
+#ifndef __VARIABLES_H__
+#define __VARIABLES_H__
+#ifdef __cplusplus
+
+#include "Exceptions.h"
+#include "String.h"
+#include "Handle.h"
+
+/*
+ * Cette classe nous sert a gérer les variables transportées par les formulaires.
+ * Elle sera initialisée dans la classe HttpServ et sera passée en paramètre aux
+ * actions. Le constructeur indique le nombre de variables qu'il faut allouer.
+ *
+ * SetTo sert à définir une variable suivant son numéro. On indique la string sous
+ * la forme "Nom=Valeur".
+ *
+ * L'opérateur [] est surchargé deux fois et permet:
+ * - si on indique un int, de récupérer la variable sous la forme "Nom=Valeur"
+ * - si on indique une string, de récupérer la valeur de la variable.
+ *
+ * La fonction Dump sert à sortir toutes les variables en un formulaire HTML, de
+ * sorte à faire transiter les variables d'un formulaire à l'autre. Toutes les actions
+ * implémentées ici possèdant des boutons font appel à cette méthode. En particulier,
+ * les formulaires en cascadent cumulent leurs variables.
+ *
+ * GetNb sert à lire le nombre de variables stockés dans l'instance.
+ */
+
+class Variables : public Base {
+ public:
+ Variables(int);
+ ~Variables();
+ void SetTo(int i, const String &);
+ String operator[](const String &);
+ String operator[](int i);
+ void Dump(Handle *);
+ int GetNb();
+ private:
+ String * Vars;
+ int nbvars;
+};
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif
diff --git a/include/template.h b/include/template.h
new file mode 100644
index 0000000..f18662f
--- /dev/null
+++ b/include/template.h
@@ -0,0 +1,8 @@
+#ifndef ___H__
+#define ___H__
+#ifdef __cplusplus
+
+#else
+#error This only works with a C++ compiler
+#endif
+#endif