From ac219c3287498cbecda7bed710593e792ca39bda Mon Sep 17 00:00:00 2001
From: Jonathan Lambrechts <jonathan.lambrechts@uclouvain.be>
Date: Tue, 21 Nov 2017 09:17:27 +0100
Subject: [PATCH] first version of the c api

---
 api/GenApi.py | 386 ++++++++++++++++++++++++++++++++++++++++----------
 api/Makefile  |   4 +
 api/gen.py    | 312 ++++++++++++++++++++--------------------
 api/main.c    |  81 +++++++++++
 4 files changed, 558 insertions(+), 225 deletions(-)
 create mode 100644 api/Makefile
 create mode 100644 api/main.c

diff --git a/api/GenApi.py b/api/GenApi.py
index aa66ce55e1..6d002dbfc0 100644
--- a/api/GenApi.py
+++ b/api/GenApi.py
@@ -1,132 +1,247 @@
-class arg :
+class arg:
 
-    def __init__(self, name, value=None) :
+    def __init__(self, name, value=None):
         self.name = name
         self.value = value
 
     @property
-    def cpp_value(self) :
-        if self.value is None :
+    def cpp_value(self):
+        if self.value is None:
             return ""
         return " = "+self.value
 
     @property
-    def cpp(self) :
+    def cpp(self):
         n = self.type_cpp 
-        if n[-1] != "&" :
+        if n[-1] != "&":
             n += " "
         n += self.name
         n += self.cpp_value
         return n
 
     @property
-    def c(self):
-        return ""
-
-class simplearg(arg) :
-    def __init__(self,cpptype,ctype,out,name,value):
-        self.type_cpp = cpptype
-        self.type_c = ctype
-        arg.__init__(self,name,value)
+    def c_cpp_arg(self):
+        return self.name
 
     @property
+    def c_cpp_pre(self):
+        return ""
+    @property
+    def c_cpp_post(self):
+        return ""
+    @property
     def c(self):
         return self.type_c + " " + self.name 
 
-class vectorarg(arg) :
+class simplearg(arg):
     def __init__(self,cpptype,ctype,out,name,value):
         self.type_cpp = cpptype
         self.type_c = ctype
-        vectorarg.__init__(self,name,value)
+        arg.__init__(self,name,value)
 
 class iint(simplearg):
     def __init__(self,name,value=None):
         simplearg.__init__(self,"const int","const int",False,name,value)
 
 class oint(simplearg):
-    def __init__(self,name,value=None) :
-        simplearg.__init__(self,"int &","int *",True,name,value)
+    def __init__(self,name,value=None):
+        simplearg.__init__(self,"int &","int*",True,name,value)
+    rtype_cpp = "int"
+    rtype_c = "int"
+    @property
+    def c_cpp_arg(self):
+        return "*"+self.name
 
-class istring(simplearg) :
-    def __init__(self,name,value=None) :
+class istring(simplearg):
+    def __init__(self,name,value=None):
         simplearg.__init__(self,"const std::string &", "const char*",False,name,value)
     @property
-    def cpp_value(self) :
-        if self.value is None :
+    def cpp_value(self):
+        if self.value is None:
             return ""
         return " = \""+self.value+"\""
 
-class ostring(simplearg) :
-    def __init__(self,name,value=None) :
+class ostring(simplearg):
+    def __init__(self,name,value=None):
         simplearg.__init__(self,"std::string &","char**",True,name,value)
+    @property
+    def c_cpp_arg(self):
+        return "api_"+self.name+"_"
+    @property
+    def c_cpp_pre(self):
+        return "  std::string "+self.c_cpp_arg +";\n"
+    @property
+    def c_cpp_post(self):
+        return "  *"+self.name+" = strdup("+self.c_cpp_arg+".c_str());\n"
 
-class idouble(simplearg) :
-    def __init__(self,name,value=None) :
+class idouble(simplearg):
+    def __init__(self,name,value=None):
         simplearg.__init__(self,"const double","const double",False,name,value)
 
-class odouble(simplearg) :
-    def __init__(self,name,value=None) :
-        simplearg.__init__(self,"double &","double *",True,name,value)
+class odouble(simplearg):
+    def __init__(self,name,value=None):
+        simplearg.__init__(self,"double &","double*",True,name,value)
+    @property
+    def c_cpp_arg(self):
+        return "*"+self.name
 
-class ovectorpair(arg) :
-    def __init__(self,name,value=None) :
+class ovectorpair(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "vector_pair &"
+    type_c = "int**"
+    @property
+    def c_cpp_arg(self):
+        return "api_"+self.name+"_"
+    @property
+    def c_cpp_pre(self):
+        return "  vector_pair "+self.c_cpp_arg +";\n"
+    @property
+    def c_cpp_post(self):
+        return "  pairvector2intptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size);\n"
+    @property
+    def c (self):
+        return "int** "+self.name+", size_t* "+self.name+"Size"
 
-class ivectorpair(arg) :
-    def __init__(self,name,value=None) :
+class ivectorpair(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "const vector_pair &"
+    type_c = "const int*"
+    @property
+    def c_cpp_arg(self):
+        return "intptr2pairvector("+self.name+","+self.name+"Size)"
+    @property
+    def c (self):
+        return "int* "+self.name+", size_t "+self.name+"Size"
 
-class ibool(arg) :
-    def __init__(self,name,value=None) :
+
+class ibool(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "const bool"
+    type_c = "const int"
     
-class obool(arg) :
-    def __init__(self,name,value=None) :
+class obool(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "bool &"
+    type_c = "int*"
+    @property
+    def c_cpp_arg(self):
+        return "api_"+self.name+"_"
+    @property
+    def c_cpp_pre(self):
+        return "  bool "+self.c_cpp_arg +";\n"
+    @property
+    def c_cpp_post(self):
+        return "  *"+self.name+" = (int)"+self.c_cpp_arg+";\n"
 
-class ivectorint(arg) :
-    def __init__(self,name,value=None) :
+class ivectorint(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "const std::vector<int> &"
+    type_c = "const int*"
+    @property
+    def c_cpp_arg(self):
+        return "ptr2vector("+self.name+", "+self.name+"Size)"
+    @property
+    def c (self):
+        return "int* "+self.name+", size_t "+self.name+"Size"
 
-class ovectorint(arg) :
-    def __init__(self,name,value=None) :
+class ovectorint(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "std::vector<int> &"
+    type_c = "int**"
+    @property
+    def c_cpp_arg(self):
+        return "api_"+self.name+"_"
+    @property
+    def c_cpp_pre(self):
+        return "  std::vector<int> "+self.c_cpp_arg +";\n"
+    @property
+    def c_cpp_post(self):
+        return "  vector2ptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size);\n"
+    @property
+    def c (self):
+        return "int** "+self.name+", size_t* "+self.name+"Size"
+
 
-class ovectorvectorint(arg) :
-    def __init__(self,name,value=None) :
+class ovectorvectorint(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "std::vector<std::vector<int> > &"
+    type_c = "int**"
+    @property
+    def c_cpp_arg(self):
+        return "api_"+self.name+"_"
+    @property
+    def c_cpp_pre(self):
+        return "  std::vector<std::vector<int> >"+self.c_cpp_arg +";\n"
+    @property
+    def c_cpp_post(self):
+        return "  vectorvector2ptrptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size, "+self.name+"SizeSize);\n"
+    @property
+    def c (self):
+        return "int*** "+self.name+", size_t** "+self.name+"Size"+", size_t *"+self.name+"SizeSize"
 
-class ovectorvectorpair(arg) :
-    def __init__(self,name,value=None) :
+class ovectorvectorpair(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "std::vector<vector_pair> &"
+    type_c = "int**"
+    @property
+    def c_cpp_arg(self):
+        return "api_"+self.name+"_"
+    @property
+    def c_cpp_pre(self):
+        return "  std::vector<vector_pair >"+self.c_cpp_arg +";\n"
+    @property
+    def c_cpp_post(self):
+        return "  pairvectorvector2intptrptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size, "+self.name+"SizeSize);\n"
+    @property
+    def c (self):
+        return "int*** "+self.name+", size_t** "+self.name+"Size"+", size_t *"+self.name+"SizeSize"
 
-class ivectordouble(arg) :
-    def __init__(self,name,value=None) :
+class ivectordouble(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "const std::vector<double> &"
+    type_c = "double**"
+    @property
+    def c_cpp_arg(self):
+        return "ptr2vector("+self.name+", "+self.name+"Size)"
+    @property
+    def c (self):
+        return "double* "+self.name+", size_t "+self.name+"Size"
 
-class ovectordouble(arg) :
-    def __init__(self,name,value=None) :
+class ovectordouble(arg):
+    def __init__(self,name,value=None):
         arg.__init__(self,name,value)
     type_cpp = "std::vector<double> &"
+    type_c = "double*"
+    @property
+    def c_cpp_arg(self):
+        return "api_"+self.name+"_"
+    @property
+    def c_cpp_pre(self):
+        return "  std::vector<double> "+self.c_cpp_arg +";\n"
+    @property
+    def c_cpp_post(self):
+        return "  vector2ptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size);\n"
+    @property
+    def c (self):
+        return "double** "+self.name+", size_t* "+self.name+"Size"
 
+class Module:
 
-class Module :
-
-    def __init__(self, name) :
+    def __init__(self, name):
         self.name = name
         self.fs = []
 
-    def add(self,name, *args) :
-        self.fs.append((name,args))
+    def add(self,rtype, name, *args):
+        self.fs.append((rtype,name,args))
 
 cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
 //
@@ -138,7 +253,7 @@ cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
 
 // This is the embryo of what will become the Gmsh API.
 //
-// Don't use it yet, it's not ready :-) We plan to release a first version in
+// Don't use it yet, it's not ready:-) We plan to release a first version in
 // Gmsh 3.1, and something more complete in Gmsh 4.0.
 //
 // Your input is welcome: please contribute your ideas on
@@ -156,12 +271,14 @@ cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
 #include <string>
 
 #if defined(WIN32)
-#define GMSH_API __declspec(dllexport) std::vector<int>
+#define GMSH_API __declspec(dllexport)
 #else
-#define GMSH_API std::vector<int>
+#define GMSH_API
 #endif
 
 typedef std::vector<std::pair<int, int> > vector_pair;
+
+GMSH_API void gmshInitialize(int argc, char **argv);
 """
 
 cpp_footer=""" 
@@ -170,15 +287,113 @@ cpp_footer="""
 #endif
 """
 
-c_header="""
+c_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh@onelab.info>.
+
+#ifndef _GMSHC_H_
+#define _GMSHC_H_
+
+// This is the embryo of what will become the Gmsh API.
+//
+// Don't use it yet, it's not ready:-) We plan to release a first version in
+// Gmsh 3.1, and something more complete in Gmsh 4.0.
+//
+// Your input is welcome: please contribute your ideas on
+// https://gitlab.onelab.info/gmsh/gmsh/issues/188
+//
+// By design, the API is purely functional, and only uses elementary C++ types
+// from the standard library. This design should not and will not change.
+
+// All functions return 0 as the first entry of the returned vector on
+// successful completion. Additional integer results can be appends to this
+// returned value, depending on context.
+
+#if defined(WIN32)
+#define GMSH_API __declspec(dllexport)
+#else
+#define GMSH_API
+#endif
+
+#include <stdlib.h>
+
+GMSH_API void gmshcInitialize(char argc, char **argv);
 """
 
 c_footer="""
+#undef GMSH_API
+
+#endif
+"""
+
+c_cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh@onelab.info>.
+
+extern \"C\" {
+    #include "gmshc.h"
+}
+#include "gmsh.h"
+#include <cstring>
+
+template<typename t>
+std::vector<t> ptr2vector(const t *p, size_t size) {
+  return std::vector<t>(p,p+size);
+}
+
+template<typename t>
+void vector2ptr(const std::vector<t>&v, t **p, size_t *size) {
+  *p = (t*)malloc(sizeof(t)*(v.size()));
+  for (size_t i = 0; i < v.size(); ++i){
+    (*p)[i] = v[i];
+  }
+  *size = v.size();
+}
+
+void pairvector2intptr(const vector_pair &v, int **p, size_t *size) {
+  *p = (int*)malloc(sizeof(int)*(v.size()*2));
+  for (size_t i = 0; i < v.size(); ++i){
+    (*p)[i*2+0] = v[i].first;
+    (*p)[i*2+1] = v[i].second;
+  }
+  *size = v.size()*2;
+}
+
+vector_pair intptr2pairvector(const int *p, size_t size){
+  vector_pair v(size);
+  for (size_t i = 0; i < size; ++i) {
+    v[i].first = p[i*2+0];
+    v[i].second = p[i*2+1];
+  }
+  return v;
+}
+
+template<typename t>
+void vectorvector2ptrptr(const std::vector<std::vector<t> > &v, t ***p, size_t **size, size_t *sizeSize) {
+  *p = (t**)malloc(sizeof(t*)*v.size());
+  *size = (size_t*)malloc(sizeof(size_t)*v.size()); 
+  for (size_t i = 0; i < v.size(); ++i)
+    vector2ptr(v[i], &((*p)[i]), &((*size)[i]));
+  *sizeSize = v.size();
+}
+
+int** pairvectorvector2intptrptr(const std::vector<vector_pair > &v, int ***p, size_t **size, size_t *sizeSize) {
+  *p = (int**)malloc(sizeof(int*)*v.size());
+  for (size_t i = 0; i < v.size(); ++i)
+    pairvector2intptr(v[i],p[i],size[i]);
+  *sizeSize = v.size();
+}
+
+void gmshcInitialize(char argc, char **argv){
+  gmshInitialize(argc, argv);
+}
 """
 
-class API :
+class API:
 
-    def __init__(self) :
+    def __init__(self):
         self.modules = []
 
     def add_module(self, name):
@@ -187,23 +402,52 @@ class API :
         return module
 
     def write_cpp(self, filename):
-        with open(filename+".h","w") as f :
+        with open(filename+".h","w") as f:
             f.write(cpp_header)
-            for module in self.modules :
+            for module in self.modules:
                 f.write("\n")
                 f.write("// gmsh"+module.name+"\n")
-                for name, args in module.fs :
-                    f.write("GMSH_API gmsh" + module.name+name+"("+", ".join(
+                for rtype, name, args in module.fs:
+                    rt = rtype.rtype_cpp if rtype else "void"
+                    f.write("GMSH_API " + rt + " gmsh" + module.name+name+"("+", ".join(
                         list((a.cpp for a in args)))+");\n")
             f.write(cpp_footer)
 
-    def write_c(self,filename) :
-        with open(filename+".h","w") as f :
+    def write_c(self,filename):
+        with open(filename+".h","w") as f:
             f.write(c_header)
-            for module in self.modules :
+            for module in self.modules:
                 f.write("\n")
-                f.write("// gmsh"+module.name+"\n")
-                for name, args in module.fs :
-                    f.write("GMSH_API gmsh" + module.name+name+"("+", ".join(
-                        list((a.c for a in args)))+");\n")
+                f.write("/* gmsh"+module.name+" */\n")
+                for rtype, name, args in module.fs:
+                    f.write("GMSH_API int gmshc" + module.name+name+"("+", ".join(
+                        list((a.c for a in args))) +
+                        ((", "+rtype.rtype_c + " *result") if rtype else "") +
+                        ");\n")
             f.write(c_footer)
+
+        with open(filename+".cc","w") as f:
+            f.write(c_cpp_header)
+            for module in self.modules:
+                f.write("\n")
+                f.write("/* gmsh"+module.name+" */\n")
+                for rtype, name, args in module.fs:
+                    #rt = rtype.rtype_c if rtype else "void"
+                    f.write("int gmshc" + module.name+name+"("+", ".join(
+                        list((a.c for a in args)))+
+                        ((", "+rtype.rtype_c + " *result") if rtype else "") +
+                        "){\n"
+                        )
+                    f.write("  try {\n");
+                    f.write("".join((a.c_cpp_pre for a in args)))
+                    if rtype:
+                        f.write(rtype.rtype_c + " result_api_ = ")
+                    f.write("  gmsh" + module.name+name+"("+", ".join(
+                        list((a.c_cpp_arg for a in args)))+
+                        ");\n")
+                    if rtype:
+                        f.write("if(result) *result = result_api_;\n")
+                    f.write("".join((a.c_cpp_post for a in args)))
+                    f.write("  } catch(int api_ierr_) {return api_ierr_;}\n");
+                    f.write("  return 0;\n");
+                    f.write("}\n\n")
diff --git a/api/Makefile b/api/Makefile
new file mode 100644
index 0000000000..88b79cb95c
--- /dev/null
+++ b/api/Makefile
@@ -0,0 +1,4 @@
+all :
+	python gen.py
+	g++ -c gmshc.cc -shared -o libgmshc.so
+	gcc main.c -L. -L../build -Wl,-rpath=../build -lstdc++ -lgmsh  -lgmshc -lgmsh -o main
diff --git a/api/gen.py b/api/gen.py
index f22d280fd7..5374fd53bf 100644
--- a/api/gen.py
+++ b/api/gen.py
@@ -5,91 +5,89 @@ api = API()
 #add_function("","Initialize",[iintp("argc"),arg("char **","argv")])
 gmsh = api.add_module("")
 
-gmsh.add("Finalize")
-gmsh.add("Open",istring("fileName"))
-gmsh.add("Merge",istring("fileName"))
-gmsh.add("Export",istring("fileName"))
-gmsh.add("Clear")
+gmsh.add(None,"Finalize")
+gmsh.add(None,"Open",istring("fileName"))
+gmsh.add(None,"Merge",istring("fileName"))
+gmsh.add(None,"Export",istring("fileName"))
+gmsh.add(None,"Clear")
 
 options = api.add_module("Option")
-options.add("SetNumber",istring("name"),idouble("value"))
-options.add("GetNumber",istring("name"),odouble("value"))
-options.add("SetString",istring("name"),istring("value"))
-options.add("GetString",istring("name"),ostring("value"))
+options.add(None,"SetNumber",istring("name"),idouble("value"))
+options.add(None,"GetNumber",istring("name"),odouble("value"))
+options.add(None,"SetString",istring("name"),istring("value"))
+options.add(None,"GetString",istring("name"),ostring("value"))
 
 model = api.add_module("Model")
-model.add("Create",istring("name"))
-model.add("SetCurrent",istring("name"))
-model.add("Destroy")
+model.add(None,"Create",istring("name"))
+model.add(None,"SetCurrent",istring("name"))
+model.add(None,"Delete")
 
-model.add("GetEntities",ovectorpair("dimTags"),iint("dim","-1"))
-model.add("GetPhysicalGroups",ovectorpair("dimTags"),iint("dim","-1"))
-model.add("AddPhysicalGroup",iint("dim"),iint("tag"),ivectorint("tags"))
-model.add("GetEntitiesForPhysicalGroup",iint("dim"),iint("tag"),ovectorint("tags"))
-model.add("SetPhysicalName",iint("dim"),iint("tag"),istring("name"))
-model.add("GetPhysicalName",iint("dim"),iint("tag"),ostring("name"))
-model.add("GetVertexCoordinates",iint("tag"),odouble("x"),odouble("y"),odouble("z"))
-model.add("GetBoundary",ivectorpair("inDimTags"),ovectorpair("outDimTags"),
+model.add(None,"GetEntities",ovectorpair("dimTags"),iint("dim","-1"))
+model.add(None,"GetPhysicalGroups",ovectorpair("dimTags"),iint("dim","-1"))
+model.add(oint,"AddPhysicalGroup",iint("dim"),ivectorint("tags"),iint("tag","-1"))
+model.add(None,"GetEntitiesForPhysicalGroup",iint("dim"),iint("tag"),ovectorint("tags"))
+model.add(None,"SetPhysicalName",iint("dim"),iint("tag"),istring("name"))
+model.add(None,"GetPhysicalName",iint("dim"),iint("tag"),ostring("name"))
+model.add(None,"GetBoundary",ivectorpair("inDimTags"),ovectorpair("outDimTags"),
         ibool("combined","true"),ibool("oriented","true"),ibool("recursive","false"))
-model.add("GetEntitiesInBoundingBox",
+model.add(None,"GetEntitiesInBoundingBox",
         idouble("x1"),idouble("y1"),idouble("z1"),
         idouble("x2"),idouble("y2"),idouble("z2"),
         ovectorpair("tags"),iint("dim","-1"))
 
-model.add("GetBoundingBox",iint("dim"),iint("tag"),odouble("x1"),odouble("y1"),
+model.add(None,"GetBoundingBox",iint("dim"),iint("tag"),odouble("x1"),odouble("y1"),
         odouble("z1"),odouble("x2"),odouble("y2"),odouble("z2"))
-model.add("Remove",ivectorpair("dimTags"),ibool("recursive","false"))
-model.add("Mesh",iint("dim"))
-model.add("GetMeshVertices",iint("dim"),iint("tag"),
+model.add(None,"Remove",ivectorpair("dimTags"),ibool("recursive","false"))
+model.add(None,"Mesh",iint("dim"))
+model.add(None,"GetMeshVertices",iint("dim"),iint("tag"),
         ovectorint("vertexTags"),
-        ovectordouble("coords"))
-model.add("GetMeshElements",iint("dim"),iint("tag"),
+        ovectordouble("coords"),
+        ovectordouble("parametricCoord")
+        )
+model.add(None,"GetMeshElements",iint("dim"),iint("tag"),
         ovectorint("types"),
         ovectorvectorint("elementTags"),
         ovectorvectorint("vertexTags"))
-model.add("SetMeshSize",ivectorpair("dimTags"),idouble("size"))
-model.add("SetTransfiniteLine",iint("tag"),iint("nPoints"),
+model.add(None,"SetMeshSize",ivectorpair("dimTags"),idouble("size"))
+model.add(None,"SetTransfiniteLine",iint("tag"),iint("nPoints"),
         istring("type","Progression"),
         idouble("coef","1."))
-model.add("SetTransfiniteSurface",iint("tag"),
+model.add(None,"SetTransfiniteSurface",iint("tag"),
         istring("arrangement","Left"),
         ivectorint("cornerTags","std::vector<int>()"))
-model.add("SetTransfiniteVolume",iint("tag"),
+model.add(None,"SetTransfiniteVolume",iint("tag"),
         ivectorint("cornerTags","std::vector<int>()"))
-model.add("SetRecombine",iint("dim"),iint("tag"),idouble("angle","45."))
-model.add("SetSmoothing",iint("dim"),iint("tag"),iint("val"))
-model.add("SetReverseMesh",iint("dim"),iint("tag"),ibool("val","true"))
-model.add("Embed",iint("dim"),ivectorint("tags"),iint("inDim"),
+model.add(None,"SetSmoothing",iint("dim"),iint("tag"),iint("val"))
+model.add(None,"SetReverseMesh",iint("dim"),iint("tag"),ibool("val","true"))
+model.add(None,"Embed",iint("dim"),ivectorint("tags"),iint("inDim"),
         iint("inTag"))
 
 model_geo = api.add_module("ModelGeo")
-model_geo.add("AddPoint",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("meshSize","0."))
-model_geo.add("AddLine",iint("tag"),iint("startTag"),iint("endTag"))
-model_geo.add("AddCircleArc",iint("tag"),iint("startTag"),
-        iint("centerTag"),iint("endTag"),
-        idouble("nx","0."),idouble("ny","0."),
-        idouble("nz","0."))
-model_geo.add("AddEllipseArc",iint("tag"),iint("startTag"),iint("centerTag"),
-        iint("majorTag"),iint("endTag"),
-        idouble("nx","0."),idouble("ny","0."),
-        idouble("nz","0."))
-model_geo.add("AddSpline",iint("tag"),ivectorint("vertexTags"))
-model_geo.add("AddBSpline",iint("tag"),ivectorint("vertexTags"))
-model_geo.add("AddBezier",iint("tag"),ivectorint("vertexTags"))
-model_geo.add("AddLineLoop",iint("tag"),ivectorint("edgeTags"))
-model_geo.add("AddPlaneSurface",iint("tag"),ivectorint("wireTags"))
-model_geo.add("AddSurfaceFilling",iint("tag"),ivectorint("wireTags"),
-        iint("sphereCenterTag","-1"))
-model_geo.add("AddSurfaceLoop",iint("tag"),ivectorint("faceTags"))
-model_geo.add("AddVolume",iint("tag"),ivectorint("shellTags"))
-model_geo.add("Extrude",ivectorpair("inDimTags"),
+model_geo.add(oint,"AddPoint",idouble("x"),idouble("y"), idouble("z"),idouble("meshSize","0."),iint("tag","-1"))
+model_geo.add(oint,"AddLine",iint("startTag"),iint("endTag"),iint("tag","-1"))
+model_geo.add(oint,"AddCircleArc",
+        iint("startTag"), iint("centerTag"),iint("endTag"),
+        iint("tag","-1"),
+        idouble("nx","0."),idouble("ny","0."), idouble("nz","0."))
+model_geo.add(oint,"AddEllipseArc",
+        iint("startTag"),iint("centerTag"),iint("majorTag"),iint("endTag"),
+        iint("tag","-1"),
+        idouble("nx","0."),idouble("ny","0."), idouble("nz","0."))
+model_geo.add(oint,"AddSpline",ivectorint("vertexTags"),iint("tag","-1"))
+model_geo.add(oint,"AddBSpline",ivectorint("vertexTags"),iint("tag","-1"))
+model_geo.add(oint,"AddBezier",ivectorint("vertexTags"),iint("tag","-1"))
+model_geo.add(oint,"AddLineLoop",ivectorint("edgeTags"),iint("tag","-1"))
+model_geo.add(oint,"AddPlaneSurface",ivectorint("wireTags"),iint("tag","-1"))
+model_geo.add(oint,"AddSurfaceFilling",ivectorint("wireTags"), iint("sphereCenterTag","-1"),iint("tag","-1"))
+model_geo.add(oint,"AddSurfaceLoop",ivectorint("faceTags"),iint("tag","-1"))
+model_geo.add(oint,"AddVolume",ivectorint("shellTags"),iint("tag","-1"))
+model_geo.add(None,"Extrude",ivectorpair("inDimTags"),
         idouble("dx"),idouble("dy"),idouble("dz"),
         ovectorpair("outDimTags"),
         ivectorint("numElements","std::vector<int>()"),
         ivectordouble("heights","std::vector<double>()"),
         ibool("recombine","false"))
-model_geo.add("Revolve",ivectorpair("inDimTags"),
+model_geo.add(None,"Revolve",ivectorpair("inDimTags"),
         idouble("x"),idouble("y"),idouble("z"),
         idouble("ax"),idouble("ay"),
         idouble("az"),idouble("angle"),
@@ -97,7 +95,7 @@ model_geo.add("Revolve",ivectorpair("inDimTags"),
         ivectorint("numElements","std::vector<int>()"),
         ivectordouble("heights","std::vector<double>()"),
         ibool("recombine","false"))
-model_geo.add("Twist",ivectorpair("inDimTags"),
+model_geo.add(None,"Twist",ivectorpair("inDimTags"),
         idouble("x"),idouble("y"),idouble("z"),
         idouble("dx"),idouble("dy"),idouble("dz"),
         idouble("ax"),idouble("ay"),idouble("az"),
@@ -106,163 +104,169 @@ model_geo.add("Twist",ivectorpair("inDimTags"),
         ivectorint("numElements","std::vector<int>()"),
         ivectordouble("heights","std::vector<double>()"),
         ibool("recombine","false"))
-model_geo.add("Translate",ivectorpair("dimTags"),
+model_geo.add(None,"Translate",ivectorpair("dimTags"),
         idouble("dx"),idouble("dy"),idouble("dz"))
-model_geo.add("Rotate",ivectorpair("dimTags"),idouble("x"),idouble("y"),
+model_geo.add(None,"Rotate",ivectorpair("dimTags"),idouble("x"),idouble("y"),
         idouble("z"),idouble("ax"),idouble("ay"),
         idouble("az"),idouble("angle"))
-model_geo.add("Dilate",ivectorpair("dimTags"),idouble("x"),idouble("y"),
+model_geo.add(None,"Dilate",ivectorpair("dimTags"),idouble("x"),idouble("y"),
         idouble("z"),idouble("a"),idouble("b"),
         idouble("c"))
-model_geo.add("Symmetry",ivectorpair("dimTags"),idouble("a"),idouble("b"),
+model_geo.add(None,"Symmetry",ivectorpair("dimTags"),idouble("a"),idouble("b"),
         idouble("c"),idouble("d"))
-model_geo.add("Copy",ivectorpair("inDimTags"),ovectorpair("outDimTags"))
-model_geo.add("Remove",ivectorpair("dimTags"),ibool("recursive","false"))
-model_geo.add("RemoveAllDuplicates")
-model_geo.add("SetMeshSize",ivectorpair("dimTags"),idouble("size"))
-model_geo.add("SetTransfiniteLine",iint("tag"),iint("nPoints"),
+model_geo.add(None,"Copy",ivectorpair("inDimTags"),ovectorpair("outDimTags"))
+model_geo.add(None,"Remove",ivectorpair("dimTags"),ibool("recursive","false"))
+model_geo.add(None,"RemoveAllDuplicates")
+model_geo.add(None,"SetMeshSize",ivectorpair("dimTags"),idouble("size"))
+model_geo.add(None,"SetTransfiniteLine",iint("tag"),iint("nPoints"),
         istring("type","Progression"),
         idouble("coef","1."))
-model_geo.add("SetTransfiniteSurface",iint("tag"),
+model_geo.add(None,"SetTransfiniteSurface",iint("tag"),
         istring("arrangement","Left"),
-        ivectorint("cornerTags = std::vector<int>()"))
-model_geo.add("SetTransfiniteVolume",iint("tag"),
-        ivectorint("cornerTags = std::vector<int>()"))
-model_geo.add("SetRecombine",iint("dim"),iint("tag"),idouble("angle","45."))
-model_geo.add("SetSmoothing",iint("dim"),iint("tag"),iint("val"))
-model_geo.add("SetReverseMesh",iint("dim"),iint("tag"),ibool("val","true"))
-model_geo.add("Synchronize")
+        ivectorint("cornerTags","std::vector<int>()"))
+model_geo.add(None,"SetTransfiniteVolume",iint("tag"),
+        ivectorint("cornerTags","std::vector<int>()"))
+model_geo.add(None,"SetRecombine",iint("dim"),iint("tag"),idouble("angle","45."))
+model_geo.add(None,"SetSmoothing",iint("dim"),iint("tag"),iint("val"))
+model_geo.add(None,"SetReverseMesh",iint("dim"),iint("tag"),ibool("val","true"))
+model_geo.add(None,"Synchronize")
 
 model_occ = api.add_module("ModelOcc")
-model_occ.add("AddPoint",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("meshSize","0."))
-model_occ.add("AddLine",iint("tag"),iint("startTag"),iint("endTag"))
-model_occ.add("AddCircleArc",iint("tag"),iint("startTag"),iint("centerTag"),
-        iint("endTag"))
-model_occ.add("AddCircle",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("r"),
-        idouble("angle1","0."),idouble("angle2","2*M_PI"))
-model_occ.add("AddEllipseArc",iint("tag"),iint("startTag"),iint("centerTag"),
-        iint("endTag"))
-model_occ.add("AddEllipse",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("r1"),idouble("r2"),
-        idouble("angle1","0."),
-        idouble("angle2","2*M_PI"))
-model_occ.add("AddSpline",iint("tag"),ivectorint("vertexTags"))
-model_occ.add("AddBezier",iint("tag"),ivectorint("vertexTags"))
-model_occ.add("AddBSpline",iint("tag"),ivectorint("vertexTags"))
-model_occ.add("AddWire",iint("tag"),ivectorint("edgeTags"),
-        ibool("checkClosed","false"))
-model_occ.add("AddLineLoop",iint("tag"),ivectorint("edgeTags"))
-model_occ.add("AddRectangle",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("dx"),idouble("dy"),
-        idouble("roundedRadius","0."))
-model_occ.add("AddDisk",iint("tag"),idouble("xc"),idouble("yc"),
-        idouble("zc"),idouble("rx"),idouble("ry"))
-model_occ.add("AddPlaneSurface",iint("tag"),ivectorint("wireTags"))
-model_occ.add("AddSurfaceFilling",iint("tag"),iint("wireTag"))
-model_occ.add("AddSurfaceLoop",iint("tag"),ivectorint("faceTags"))
-model_occ.add("AddVolume",iint("tag"),ivectorint("shellTags"))
-model_occ.add("AddSphere",iint("tag"),idouble("xc"),idouble("yc"),
-        idouble("zc"),idouble("radius"),
-        idouble("angle1","-M_PI/2"),
-        idouble("angle2","M_PI/2"),
-        idouble("angle3","2*M_PI"))
-model_occ.add("AddBox",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("dx"),idouble("dy"),
-        idouble("dz"))
-model_occ.add("AddCylinder",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("dx"),idouble("dy"),
-        idouble("dz"),idouble("r"),
-        idouble("angle","2*M_PI"))
-model_occ.add("AddCone",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("dx"),idouble("dy"),
-        idouble("dz"),idouble("r1"),idouble("r2"),
-        idouble("angle","2*M_PI"))
-model_occ.add("AddWedge",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("dx"),idouble("dy"),
-        idouble("dz"),idouble("ltx","0."))
-model_occ.add("AddTorus",iint("tag"),idouble("x"),idouble("y"),
-        idouble("z"),idouble("r1"),idouble("r2"),
-        idouble("angle","2*M_PI"))
-model_occ.add("AddThruSections",iint("tag"),ivectorint("wireTags"),
-        ovectorpair("outDimTags"),ibool("makeSolid","true"),
-        ibool("makeRuled","false"))
+#model_occ.add(oint,"AddPoint",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("meshSize","0."))
+#model_occ.add(oint,"AddLine",iint("tag"),iint("startTag"),iint("endTag"))
+#model_occ.add(oint,"AddCircleArc",iint("tag"),iint("startTag"),iint("centerTag"),
+#        iint("endTag"))
+#model_occ.add(oint,"AddCircle",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("r"),
+#        idouble("angle1","0."),idouble("angle2","2*M_PI"))
+#model_occ.add(oint,"AddEllipseArc",iint("tag"),iint("startTag"),iint("centerTag"),
+#        iint("endTag"))
+#model_occ.add(oint,"AddEllipse",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("r1"),idouble("r2"),
+#        idouble("angle1","0."),
+#        idouble("angle2","2*M_PI"))
+#model_occ.add(oint,"AddSpline",iint("tag"),ivectorint("vertexTags"))
+#model_occ.add(oint,"AddBezier",iint("tag"),ivectorint("vertexTags"))
+#model_occ.add(oint,"AddBSpline",iint("tag"),ivectorint("vertexTags"))
+#model_occ.add(oint,"AddWire",iint("tag"),ivectorint("edgeTags"),
+#        ibool("checkClosed","false"))
+#model_occ.add(oint,"AddLineLoop",iint("tag"),ivectorint("edgeTags"))
+#model_occ.add(oint,"AddRectangle",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("dx"),idouble("dy"),
+#        idouble("roundedRadius","0."))
+#model_occ.add(oint,"AddDisk",iint("tag"),idouble("xc"),idouble("yc"),
+#        idouble("zc"),idouble("rx"),idouble("ry"))
+#model_occ.add(oint,"AddPlaneSurface",iint("tag"),ivectorint("wireTags"))
+#model_occ.add(oint,"AddSurfaceFilling",iint("tag"),iint("wireTag"))
+#model_occ.add(oint,"AddSurfaceLoop",iint("tag"),ivectorint("faceTags"))
+#model_occ.add(oint,"AddVolume",iint("tag"),ivectorint("shellTags"))
+#model_occ.add(oint,"AddSphere",iint("tag"),idouble("xc"),idouble("yc"),
+#        idouble("zc"),idouble("radius"),
+#        idouble("angle1","-M_PI/2"),
+#        idouble("angle2","M_PI/2"),
+#        idouble("angle3","2*M_PI"))
+#model_occ.add(oint,"AddBox",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("dx"),idouble("dy"),
+#        idouble("dz"))
+#model_occ.add(oint,"AddCylinder",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("dx"),idouble("dy"),
+#        idouble("dz"),idouble("r"),
+#        idouble("angle","2*M_PI"))
+#model_occ.add(oint,"AddCone",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("dx"),idouble("dy"),
+#        idouble("dz"),idouble("r1"),idouble("r2"),
+#        idouble("angle","2*M_PI"))
+#model_occ.add(oint,"AddWedge",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("dx"),idouble("dy"),
+#        idouble("dz"),idouble("ltx","0."))
+#model_occ.add(oint,"AddTorus",iint("tag"),idouble("x"),idouble("y"),
+#        idouble("z"),idouble("r1"),idouble("r2"),
+#        idouble("angle","2*M_PI"))
+#model_occ.add(oint,"AddThruSections",ivectorint("wireTags"),
+#        ovectorpair("outDimTags"),
+#        iint("tag"),
+#        ibool("makeSolid","true"),
+#        ibool("makeRuled","false"))
 #GMSH_API addThickSolid"",iint("tag"),iint("solidTag"),
 #                       ivectorint("excludeFaceTags"),
 #                       idouble("offset"),ovectorpair("outDimTags"))
-model_occ.add("Extrude",ivectorpair("inDimTags"),idouble("dx"),idouble("dy"),
+model_occ.add(None,"Extrude",ivectorpair("inDimTags"),idouble("dx"),idouble("dy"),
         idouble("dz"),ovectorpair("outDimTags"),
         ivectorint("numElements","std::vector<int>()"),
         ivectordouble("heights","std::vector<double>()"),
         ibool("recombine","false"))
-model_occ.add("Revolve",ivectorpair("inDimTags"),
+model_occ.add(None,"Revolve",ivectorpair("inDimTags"),
         idouble("x"),idouble("y"),idouble("z"),
         idouble("ax"),idouble("ay"),idouble("az"),
         idouble("angle"),ovectorpair("outDimTags"),
         ivectorint("numElements","std::vector<int>()"),
         ivectordouble("heights","std::vector<double>()"),
         ibool("recombine","false"))
-model_occ.add("AddPipe",ivectorpair("inDimTags"),iint("wireTag"),
+model_occ.add(None,"AddPipe",ivectorpair("inDimTags"),iint("wireTag"),
         ovectorpair("outDimTags"))
-model_occ.add("Fillet",ivectorint("regionTags"),
+model_occ.add(None,"Fillet",ivectorint("regionTags"),
         ivectorint("edgeTags"),
         idouble("radius"),ovectorpair("outDimTags"),
         ibool("removeRegion","true"))
-model_occ.add("BooleanUnion",iint("tag"),ivectorpair("objectDimTags"),
+model_occ.add(oint,"BooleanUnion",ivectorpair("objectDimTags"),
         ivectorpair("toolDimTags"),
         ovectorpair("outDimTags"),
         ovectorvectorpair("outDimTagsMap"),
+        iint("tag","-1"),
         ibool("removeObject","true"),
         ibool("removeTool","true"))
-model_occ.add("BooleanIntersection",iint("tag"),ivectorpair("objectDimTags"),
+model_occ.add(oint,"BooleanIntersection",ivectorpair("objectDimTags"),
         ivectorpair("toolDimTags"),
         ovectorpair("outDimTags"),
         ovectorvectorpair("outDimTagsMap"),
+        iint("tag"),
         ibool("removeObject","true"),
         ibool("removeTool","true"))
-model_occ.add("BooleanDifference",iint("tag"),ivectorpair("objectDimTags"),
+model_occ.add(oint,"BooleanDifference",ivectorpair("objectDimTags"),
         ivectorpair("toolDimTags"),
         ovectorpair("outDimTags"),
         ovectorvectorpair("outDimTagsMap"),
+        iint("tag","-1"),
         ibool("removeObject","true"),
         ibool("removeTool","true"))
-model_occ.add("BooleanFragments",iint("tag"),ivectorpair("objectDimTags"),
+model_occ.add(oint,"BooleanFragments",ivectorpair("objectDimTags"),
         ivectorpair("toolDimTags"),
         ovectorpair("outDimTags"),
         ovectorvectorpair("outDimTagsMap"),
+        iint("tag","-1"),
         ibool("removeObject","true"),
         ibool("removeTool","true"))
-model_occ.add("Translate",ivectorpair("dimTags"),idouble("dx"),
+model_occ.add(None,"Translate",ivectorpair("dimTags"),idouble("dx"),
         idouble("dy"),idouble("dz"))
-model_occ.add("Rotate",ivectorpair("dimTags"),idouble("x"),
+model_occ.add(None,"Rotate",ivectorpair("dimTags"),idouble("x"),
         idouble("y"),idouble("z"),idouble("ax"),
         idouble("ay"),idouble("az"),idouble("angle"))
-model_occ.add("Dilate",ivectorpair("dimTags"),idouble("x"),
+model_occ.add(None,"Dilate",ivectorpair("dimTags"),idouble("x"),
         idouble("y"),idouble("z"),idouble("a"),
         idouble("b"),idouble("c"))
-model_occ.add("Symmetry",ivectorpair("dimTags"),idouble("a"),
+model_occ.add(None,"Symmetry",ivectorpair("dimTags"),idouble("a"),
         idouble("b"),idouble("c"),idouble("d"))
-model_occ.add("Copy",ivectorpair("inDimTags"),ovectorpair("outDimTags"))
-model_occ.add("Remove",ivectorpair("dimTags"),ibool("recursive","false"))
-model_occ.add("RemoveAllDuplicates")
-model_occ.add("ImportShapes",istring("fileName"),ovectorpair("outDimTags"),
+model_occ.add(None,"Copy",ivectorpair("inDimTags"),ovectorpair("outDimTags"))
+model_occ.add(None,"Remove",ivectorpair("dimTags"),ibool("recursive","false"))
+model_occ.add(None,"RemoveAllDuplicates")
+model_occ.add(None,"ImportShapes",istring("fileName"),ovectorpair("outDimTags"),
         ibool("highestDimOnly","true"),
         istring("format",""))
-model_occ.add("SetMeshSize",ivectorpair("dimTags"),idouble("size"))
-model_occ.add("Synchronize")
+model_occ.add(None,"SetMeshSize",ivectorpair("dimTags"),idouble("size"))
+model_occ.add(None,"Synchronize")
 
 model_field = api.add_module("ModelField")
-model_field.add("Create",iint("tag"),istring("type"))
-model_field.add("SetNumber",iint("tag"),istring("option"),idouble("value"))
-model_field.add("SetString",iint("tag"),istring("option"),istring("value"))
-model_field.add("SetNumbers",iint("tag"),istring("option"),ivectordouble("value"))
-model_field.add("SetAsBackground",iint("tag"))
-model_field.add("Delete",iint("tag"))
+model_field.add(oint,"Create",istring("type"),iint("tag","-1"))
+model_field.add(None,"SetNumber",iint("tag"),istring("option"),idouble("value"))
+model_field.add(None,"SetString",iint("tag"),istring("option"),istring("value"))
+model_field.add(None,"SetNumbers",iint("tag"),istring("option"),ivectordouble("value"))
+model_field.add(None,"SetAsBackground",iint("tag"))
+model_field.add(None,"Delete",iint("tag"))
 
 api.add_module("View")
 api.add_module("Plugin")
 api.add_module("Graphics")
 
 api.write_cpp("gmsh")
-#api.write_c("gmshc")
+api.write_c("gmshc")
diff --git a/api/main.c b/api/main.c
new file mode 100644
index 0000000000..a43fba97bf
--- /dev/null
+++ b/api/main.c
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include "gmshc.h"
+
+#define chk(ierr) if (ierr != 0) {fprintf(stderr, "ERROR on line %i in function '%s': gmsh function return non-zero error code: %i\n",__LINE__, __FUNCTION__,ierr); gmshcFinalize(); exit(ierr);}
+
+void genGeometry() {
+  int ierr;
+  ierr = gmshcModelCreate("square");
+  ierr = gmshcModelGeoAddPoint(0,0,0,0.1,1,NULL);chk(ierr);
+  ierr = gmshcModelGeoAddPoint(1,0,0,0.1,2,NULL);chk(ierr);
+  ierr = gmshcModelGeoAddPoint(1,1,0,0.1,3,NULL);chk(ierr);
+  ierr = gmshcModelGeoAddPoint(0,1,0,0.1,4,NULL);chk(ierr);
+  ierr = gmshcModelGeoAddLine(1,2,1,NULL); chk(ierr);
+  ierr = gmshcModelGeoAddLine(2,3,2,NULL); chk(ierr);
+  ierr = gmshcModelGeoAddLine(3,4,3,NULL); chk(ierr);
+  // try automatic assignement of tag
+  int line4;
+  ierr = gmshcModelGeoAddLine(4,1,-1,&line4); chk(ierr);
+  printf("line4 received tag %i\n\n", line4);
+  int ll[] = {1,2,3,line4};
+  ierr = gmshcModelGeoAddLineLoop(ll,4,1,NULL); chk(ierr);
+  int s[] = {1};
+  ierr = gmshcModelGeoAddPlaneSurface(ll,1,6,NULL); chk(ierr);
+  ierr = gmshcModelGeoSynchronize(); chk(ierr);
+}
+
+void printMesh() {
+  int ierr;
+  int *dimTags;
+  size_t ndimTags;
+
+  ierr = gmshcModelGetEntities(&dimTags, &ndimTags, -1); chk(ierr);
+
+  for (size_t ie = 0; ie < ndimTags/2; ++ie) {
+    int *types, **elementTags, **vertexTags;
+    size_t ntypes, *nelementTags, nnelementTags, *nvertexTags, nnvertexTags;
+
+    ierr = gmshcModelGetMeshElements(dimTags[ie*2+0], dimTags[ie*2+1], &types, &ntypes, &elementTags, &nelementTags, &nnelementTags, &vertexTags, &nvertexTags, &nnvertexTags); chk(ierr);
+
+    printf("entity %i of dim %i\n", dimTags[ie*2+1], dimTags[ie*2+0]);
+    for (size_t i = 0; i < nnelementTags; ++i) {
+      printf("  %lu elements of type %i : ", nelementTags[i], types[i]);
+      size_t nnodesbyel = nvertexTags[i]/nelementTags[i];
+      for (size_t j = 0; j < nelementTags[i] && j < 3; ++j) {
+        printf("%i ( ", elementTags[i][j]);
+        for (size_t k = 0; k < nnodesbyel; ++k)
+          printf("%i ", vertexTags[i][j*nnodesbyel+k]);
+        printf(") ");
+      }
+      if (nelementTags[i] > 3)
+        printf("...");
+      printf("\n");
+    }
+
+    free(types);
+    for (size_t i = 0; i < nnelementTags; ++i)
+      free(elementTags[i]);
+    for (size_t i = 0; i < nnvertexTags; ++i)
+      free(vertexTags[i]);
+    free(nelementTags);
+    free(nvertexTags);
+  }
+  free(dimTags);
+}
+
+void genError() {
+  int ierr;
+  printf("\n** generate an error **\n");
+  ierr = gmshcModelGetMeshElements(999, 999, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); chk(ierr);
+}
+
+int main(int argc, char **argv) {
+  int ierr;
+  gmshcInitialize(argc, argv);
+  genGeometry();
+  ierr = gmshcModelMesh(2); chk(ierr);
+  ierr = gmshcExport("square.msh"); chk(ierr);
+  printMesh();
+  genError();
+  ierr = gmshcFinalize(); chk(ierr);
+}
-- 
GitLab