From ec90f6ab67a16e2dbad9a0da2743015e506c0344 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sun, 16 Jan 2005 20:41:42 +0000
Subject: [PATCH] - fixed the "unix socket name is one character short" problem
 on MacOS and AIX. Unfortunately, this required the client code to be slightly
 modified as well (and as a consequence, old versions of getdp will for
 example not work with new versions of Gmsh on MacOs and AIX). But it's better
 to do things "the right way" (TM) for people who want to connect using
 different languages (Perl, Python).

- moved the GmshServer stuff in its own class

- added missing rules in parser makefile (so that the parser gets
  rebuilt automatically when one changes Gmsh.y or Gmsh.l)
---
 Fltk/GmshServer.cpp                           | 212 --------
 Fltk/GmshServer.h                             | 239 +++++++--
 Fltk/Makefile                                 |   4 +-
 Fltk/Message.cpp                              |   4 +-
 Fltk/Solvers.cpp                              | 114 ++--
 Parser/Gmsh.l                                 |  10 +-
 Parser/Gmsh.tab.cpp                           | 496 +++++++++---------
 Parser/Gmsh.y                                 |   9 +-
 Parser/Gmsh.yy.cpp                            |  12 +-
 Parser/Makefile                               |  30 +-
 doc/gmsh.html                                 |   3 +
 utils/solvers/c++/GmshClient.h                | 156 +++---
 utils/solvers/c++/Makefile                    |   4 +-
 utils/solvers/c++/solver.cpp                  |  44 ++
 utils/solvers/c/GmshClient.c                  |  17 +-
 utils/solvers/c/GmshClient.h                  |   2 +-
 utils/solvers/c/Makefile                      |   6 +-
 utils/solvers/c/mysolver.opt                  |  30 --
 utils/solvers/c/{mysolver.c => solver.c}      |  16 +-
 utils/solvers/c/solver.opt                    |  15 +
 utils/solvers/perl/GMSH_CLIENT.pm             |   3 +-
 utils/solvers/perl/myperlsolver.opt           |  30 --
 utils/solvers/perl/solver.opt                 |  15 +
 .../perl/{myperlsolver.pl => solver.pl}       |  10 +-
 24 files changed, 729 insertions(+), 752 deletions(-)
 delete mode 100644 Fltk/GmshServer.cpp
 delete mode 100644 utils/solvers/c/mysolver.opt
 rename utils/solvers/c/{mysolver.c => solver.c} (94%)
 create mode 100644 utils/solvers/c/solver.opt
 delete mode 100755 utils/solvers/perl/myperlsolver.opt
 create mode 100755 utils/solvers/perl/solver.opt
 rename utils/solvers/perl/{myperlsolver.pl => solver.pl} (91%)

diff --git a/Fltk/GmshServer.cpp b/Fltk/GmshServer.cpp
deleted file mode 100644
index ce82f2e134..0000000000
--- a/Fltk/GmshServer.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/* $Id: GmshServer.cpp,v 1.26 2005-01-14 04:50:48 geuzaine Exp $ */
-/*
- * Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, and/or sell copies of the
- * Software, and to permit persons to whom the Software is furnished
- * to do so, provided that the above copyright notice(s) and this
- * permission notice appear in all copies of the Software and that
- * both the above copyright notice(s) and this permission notice
- * appear in supporting documentation.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
- * ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
- * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- * 
- *  Please report all bugs and problems to <gmsh@geuz.org>.
- *
- * Contributor(s):
- *   Christopher Stott
- */
-
-void SystemCall(char *str);
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(_AIX)
-#include <strings.h>
-#endif
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <netinet/in.h>
-
-/* private functions */
-
-static int Socket_ReceiveData(int socket, void *buffer, int bytes)
-{
-  int sofar, remaining, len;
-  char *buf;
-
-  buf = (char *)buffer;
-  sofar = 0;
-  remaining = bytes;
-  do {
-    len = read(socket, buf + sofar, remaining);
-    if(len <= 0)
-      return 0;
-    sofar += len;
-    remaining -= len;
-  } while(remaining > 0);
-  return bytes;
-}
-
-static int Socket_UnlinkName(char *name)
-{
-#if defined(_AIX) || defined(__APPLE__)
-  char name2[1000];
-  strcpy(name2, name);
-  name2[strlen(name2) - 1] = '\0';
-  return unlink(name2);
-#else
-  return unlink(name);
-#endif
-}
-
-
-/* public interface */
-
-int Gmsh_StartClient(char *command, char *sockname, int maxdelay)
-{
-  static int init = 0;
-  static int s;
-  int sock;
-#if defined(linux) || defined(_AIX) || defined(__FreeBSD__) || defined(__sun__)
-  socklen_t len;
-#else
-  int len;
-#endif
-  struct sockaddr_un addr_un, from_un;
-  struct sockaddr_in addr_in, from_in;
-  fd_set rfds;
-  struct timeval tv;
-  int retval, portno;
-  char *port;
-
-  /* no socket? launch the command! */
-  if(!sockname) {
-    SystemCall(command); //system(command);
-    return 1;
-  }
-
-  if(strstr(sockname, "/") || strstr(sockname, "\\") || !strstr(sockname, ":")){
-    /* UNIX socket (testing ":" is not enough with Windows paths) */
-    portno = -1;
-  }
-  else{
-    /* INET socket */
-    port = strstr(sockname, ":");
-    portno = atoi(port+1);
-  }
-
-  if(portno < 0){
-    /* delete the file if it already exists */
-    Socket_UnlinkName(sockname);
-
-    /* make the socket */
-    s = socket(PF_UNIX, SOCK_STREAM, 0);
-    if(s < 0)
-      return -1;  /* Error: Couldn't create socket */
-
-    /* bind the socket to its name */
-    strcpy(addr_un.sun_path, sockname);
-    addr_un.sun_family = AF_UNIX;
-    if(bind(s, (struct sockaddr *)&addr_un,
-	    strlen(addr_un.sun_path) + sizeof(addr_un.sun_family)) < 0)
-      return -2;  /* Error: Couldn't bind socket to name */
-
-    /* change permissions on the socket name in case it has to be rm'd later */
-    chmod(sockname, 0666);
-  }
-  else{
-    if(init != portno){ /* FIXME: need a better solution to deal with
-			   addresses that have already been bound! */
-      init = portno;
-
-      /* make the socket */
-      s = socket(AF_INET, SOCK_STREAM, 0);
-      if(s < 0)
-	return -1;  /* Error: Couldn't create socket */
-      
-      /* bind the socket to its name */
-      memset((char *) &addr_in, 0, sizeof(addr_in));
-      addr_in.sin_family = AF_INET;
-      addr_in.sin_addr.s_addr = INADDR_ANY;
-      addr_in.sin_port = htons(portno);
-      
-      if(bind(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0)
-	return -2;  /* Error: Couldn't bind socket to name */
-    }
-  }
-
-  /* Start the external function via system() call */
-  SystemCall(command); //system(command);
-
-  /* wait for external function to connect */
-  if(listen(s, 20))
-    return -3;  /* Error: Socket listen failed */
-
-  /* Watch s to see when it has input; wait up to N seconds */
-  tv.tv_sec = maxdelay;
-  tv.tv_usec = 0;
-  FD_ZERO(&rfds);
-  FD_SET(s, &rfds);
-  retval = select(s + 1, &rfds, NULL, NULL, &tv);
-
-  if(!retval)
-    return -4;  /* Error: Socket listening timeout */
-
-  if(portno < 0){
-    len = sizeof(from_un);
-    if((sock = accept(s, (struct sockaddr *)&from_un, &len)) < 0)
-      return -5;  /* Error: Socket accept failed */
-  }
-  else{
-    len = sizeof(from_in);
-    if((sock = accept(s, (struct sockaddr *)&from_in, &len)) < 0)
-      return -5;  /* Error: Socket accept failed */
-  }
-
-  return sock;
-}
-
-int Gmsh_ReceiveString(int socket, int *type, char str[])
-{
-  int len;
-
-  Socket_ReceiveData(socket, type, sizeof(int));
-  if(Socket_ReceiveData(socket, &len, sizeof(int))) {
-    if(Socket_ReceiveData(socket, str, len) == len) {
-      str[len] = '\0';
-      return 1;
-    }
-  }
-  return 0;
-}
-
-int Gmsh_StopClient(char *sockname, int sock)
-{
-  if(strstr(sockname, "/") || strstr(sockname, "\\") || !strstr(sockname, ":")){
-    /* UNIX socket */
-    if(Socket_UnlinkName(sockname) == -1)
-      return -1;  /* Impossible to unlink the socket */
-  }
-
-  close(sock);
-  return 0;
-}
diff --git a/Fltk/GmshServer.h b/Fltk/GmshServer.h
index 69aca24cd5..bb12ab2077 100644
--- a/Fltk/GmshServer.h
+++ b/Fltk/GmshServer.h
@@ -1,36 +1,213 @@
 #ifndef _GMSH_SERVER_H_
 #define _GMSH_SERVER_H_
 
-/*
- * Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, and/or sell copies of the
- * Software, and to permit persons to whom the Software is furnished
- * to do so, provided that the above copyright notice(s) and this
- * permission notice appear in all copies of the Software and that
- * both the above copyright notice(s) and this permission notice
- * appear in supporting documentation.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
- * ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
- * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- * 
- *  Please report all bugs and problems to <gmsh@geuz.org>.
- */
-
-int Gmsh_StartClient(char *command, char *sockname, int maxdelay);
-int Gmsh_ReceiveString(int socket, int *type, char str[]);
-int Gmsh_StopClient(char *sockname, int socket);
+// Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, and/or sell copies of the
+// Software, and to permit persons to whom the Software is furnished
+// to do so, provided that the above copyright notice(s) and this
+// permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice
+// appear in supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
+// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
+// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+// OF THIS SOFTWARE.
+// 
+// Please report all bugs and problems to <gmsh@geuz.org>.
+//
+// Contributor(s):
+//   Christopher Stott
+
+void SystemCall(char *str); // use our own instead of 'system()'
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_AIX)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <netinet/in.h>
+
+class GmshServer {
+ public:
+  // This should match what's in GmshClient.h
+  typedef enum{ CLIENT_START    = 1,
+		CLIENT_STOP     = 2,
+		CLIENT_INFO     = 10,
+		CLIENT_WARNING  = 11,
+		CLIENT_ERROR    = 12,
+		CLIENT_PROGRESS = 13,
+		CLIENT_VIEW     = 20,
+		CLIENT_OPTION_1 = 100,
+		CLIENT_OPTION_2 = 101,
+		CLIENT_OPTION_3 = 102,
+		CLIENT_OPTION_4 = 103,
+		CLIENT_OPTION_5 = 104 } MessageType;
+ private:
+  int _maxdelay, _portno, _sock;
+  char *_sockname;
+  int _ReceiveData(void *buffer, int bytes)
+  {
+    char *buf = (char *)buffer;
+    int sofar = 0;
+    int remaining = bytes;
+    do {
+      int len = read(_sock, buf + sofar, remaining);
+      if(len <= 0)
+	return 0;
+      sofar += len;
+      remaining -= len;
+    } while(remaining > 0);
+    return bytes;
+  }
+ public:
+  GmshServer(int maxdelay = 4)
+    : _maxdelay(maxdelay), _portno(-1), _sock(0), _sockname(NULL) {}
+  ~GmshServer(){}
+  int StartClient(char *command, char *sockname = NULL)
+  {
+    static int init = 0;
+    static int s;
+
+    _sockname = sockname;
+
+    // no socket? launch the command directly
+    if(!_sockname) {
+      SystemCall(command);
+      //system(command);
+      return 1;
+    }
+
+    if(strstr(_sockname, "/") || strstr(_sockname, "\\") || !strstr(_sockname, ":")){
+      // UNIX socket (testing ":" is not enough with Windows paths)
+      _portno = -1;
+    }
+    else{
+      // INET socket
+      char *port = strstr(_sockname, ":");
+      _portno = atoi(port+1);
+    }
+    
+    if(_portno < 0){
+      // delete the file if it already exists
+      unlink(_sockname);
+      
+      // make the socket
+      s = socket(PF_UNIX, SOCK_STREAM, 0);
+      if(s < 0)
+	return -1;  // Error: Couldn't create socket
+      
+      // bind the socket to its name
+      struct sockaddr_un addr_un;
+      strcpy(addr_un.sun_path, _sockname);
+      addr_un.sun_family = AF_UNIX;
+      if(bind(s, (struct sockaddr *)&addr_un, sizeof(addr_un)) < 0)
+	return -2;  // Error: Couldn't bind socket to name
+      
+      // change permissions on the socket name in case it has to be rm'd later
+      chmod(_sockname, 0666);
+    }
+    else{
+      if(init != _portno){ 
+	// FIXME: need a better solution to deal with addresses that
+	// have already been bound!
+	init = _portno;
+	
+	// make the socket
+	s = socket(AF_INET, SOCK_STREAM, 0);
+	if(s < 0)
+	  return -1;  // Error: Couldn't create socket
+	
+	// bind the socket to its name
+	struct sockaddr_in addr_in;
+	memset((char *) &addr_in, 0, sizeof(addr_in));
+	addr_in.sin_family = AF_INET;
+	addr_in.sin_addr.s_addr = INADDR_ANY;
+	addr_in.sin_port = htons(_portno);
+	if(bind(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0)
+	  return -2;  // Error: Couldn't bind socket to name
+      }
+    }
+
+    // Start the solver via system() call
+    SystemCall(command);
+    //system(command);
+    
+    // wait for solver to connect
+    if(listen(s, 20))
+      return -3;  // Error: Socket listen failed
+    
+    // Watch socket s to see when it has input; wait up to N seconds
+    struct timeval tv;
+    tv.tv_sec = _maxdelay;
+    tv.tv_usec = 0;
+    fd_set rfds;
+    FD_ZERO(&rfds);
+    FD_SET(s, &rfds);
+    if(!select(s + 1, &rfds, NULL, NULL, &tv))
+      return -4;  // Error: Socket listening timeout
+    
+    // accept connection request
+#if defined(linux) || defined(_AIX) || defined(__FreeBSD__) || defined(__sun__)
+    socklen_t len;
+#else
+    int len;
+#endif
+    if(_portno < 0){
+      struct sockaddr_un from_un;
+      len = sizeof(from_un);
+      if((_sock = accept(s, (struct sockaddr *)&from_un, &len)) < 0)
+	return -5;  // Error: Socket accept failed
+    }
+    else{
+      struct sockaddr_in from_in;
+      len = sizeof(from_in);
+      if((_sock = accept(s, (struct sockaddr *)&from_in, &len)) < 0)
+	return -5;  // Error: Socket accept failed
+    }
+   
+    return _sock;
+  }
+  int ReceiveString(int *type, char str[])
+  {
+    _ReceiveData(type, sizeof(int));
+    int len;
+    if(_ReceiveData(&len, sizeof(int))) {
+      if(_ReceiveData(str, len) == len) {
+	str[len] = '\0';
+	return 1;
+      }
+    }
+    return 0;
+  }
+  int StopClient()
+  {
+    if(_portno < 0){
+      // UNIX socket
+      if(unlink(_sockname) == -1)
+	return -1;  // Impossible to unlink the socket
+    }
+    close(_sock);
+    return 0;
+  }
+};
 
 #endif
diff --git a/Fltk/Makefile b/Fltk/Makefile
index 6e7bf19d6f..2988115ce3 100644
--- a/Fltk/Makefile
+++ b/Fltk/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.68 2005-01-14 04:50:48 geuzaine Exp $
+# $Id: Makefile,v 1.69 2005-01-16 20:41:38 geuzaine Exp $
 #
 # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 #
@@ -33,7 +33,6 @@ SRC = Main.cpp \
       Opengl.cpp\
       Opengl_Window.cpp\
       Colorbar_Window.cpp\
-      GmshServer.cpp\
       Solvers.cpp
 
 
@@ -150,7 +149,6 @@ Colorbar_Window.o: Colorbar_Window.cpp ../Common/Gmsh.h \
   ../Common/VertexArray.h ../Common/SmoothNormals.h ../Mesh/Metric.h \
   ../Mesh/Matrix.h Colorbar_Window.h ../Common/ColorTable.h \
   ../Common/Context.h
-GmshServer.o: GmshServer.cpp
 Solvers.o: Solvers.cpp ../Common/Gmsh.h ../Common/Message.h \
   ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
   ../DataStr/avl.h ../DataStr/Tools.h GmshServer.h ../Parser/OpenFile.h \
diff --git a/Fltk/Message.cpp b/Fltk/Message.cpp
index c6139c9d70..2a1aa33040 100644
--- a/Fltk/Message.cpp
+++ b/Fltk/Message.cpp
@@ -1,4 +1,4 @@
-// $Id: Message.cpp,v 1.61 2005-01-01 19:35:28 geuzaine Exp $
+// $Id: Message.cpp,v 1.62 2005-01-16 20:41:38 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -288,7 +288,7 @@ double GetValue(char *text, double defaultval)
   if(WID && !CTX.batch){ // pop up GUI dialog
     char defaultstr[256];
     sprintf(defaultstr, "%.16g", defaultval);
-    const char *ret = fl_input("%s", defaultstr, text);
+    const char *ret = fl_input(text, defaultstr);
     if(!ret)
       return defaultval;
     else
diff --git a/Fltk/Solvers.cpp b/Fltk/Solvers.cpp
index 79840820a9..652b1421d9 100644
--- a/Fltk/Solvers.cpp
+++ b/Fltk/Solvers.cpp
@@ -1,4 +1,4 @@
-// $Id: Solvers.cpp,v 1.34 2005-01-14 04:50:48 geuzaine Exp $
+// $Id: Solvers.cpp,v 1.35 2005-01-16 20:41:38 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -22,21 +22,6 @@
 #include "Gmsh.h"
 #include "GmshServer.h"
 
-// This should match what's in GmshClient.h
-#define GMSH_CLIENT_START       1
-#define GMSH_CLIENT_STOP        2
-#define GMSH_CLIENT_INFO        10
-#define GMSH_CLIENT_WARNING     11
-#define GMSH_CLIENT_ERROR       12
-#define GMSH_CLIENT_PROGRESS    13
-#define GMSH_CLIENT_VIEW        20
-#define GMSH_CLIENT_OPTION      100
-#define GMSH_CLIENT_OPTION_1    (GMSH_CLIENT_OPTION+0)
-#define GMSH_CLIENT_OPTION_2    (GMSH_CLIENT_OPTION+1)
-#define GMSH_CLIENT_OPTION_3    (GMSH_CLIENT_OPTION+2)
-#define GMSH_CLIENT_OPTION_4    (GMSH_CLIENT_OPTION+3)
-#define GMSH_CLIENT_OPTION_5    (GMSH_CLIENT_OPTION+4)
-
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -59,9 +44,9 @@ SolverInfo SINFO[MAXSOLVERS];
 
 int Solver(int num, char *args)
 {
-  int sock, type, stop = 0, i, j, n;
-  char command[1024], socket_name[1024], str[1024], prog[1024];
-  char buffer[1024];
+  char command[1024], sockname[1024], str[1024], prog[1024], buf[1024];
+
+  GmshServer server(CTX.solver.max_delay);
 
   FixWindowsPath(SINFO[num].executable_name, prog);
 
@@ -70,59 +55,59 @@ int Solver(int num, char *args)
 #if !defined(WIN32)
     strcat(command, " &");
 #endif
-    Gmsh_StartClient(command, NULL, CTX.solver.max_delay);
+    server.StartClient(command);
     return 1;
   }
 
   if(!strstr(CTX.solver.socket_name, ":")){
     // file socket
     sprintf(str, "%s%s-%d", CTX.home_dir, CTX.solver.socket_name, num);
-    FixWindowsPath(str, socket_name);
+    FixWindowsPath(str, sockname);
   }
   else
-    strcpy(socket_name, CTX.solver.socket_name);
+    strcpy(sockname, CTX.solver.socket_name);
 
-  sprintf(str, "\"%s\"", socket_name);
-  sprintf(buffer, SINFO[num].socket_command, str);
+  sprintf(str, "\"%s\"", sockname);
+  sprintf(buf, SINFO[num].socket_command, str);
   
-  sprintf(command, "%s %s %s", prog, args, buffer);
+  sprintf(command, "%s %s %s", prog, args, buf);
 #if !defined(WIN32)
   strcat(command, " &");
 #endif
 
-  sock = Gmsh_StartClient(command, socket_name, CTX.solver.max_delay);
+  int sock = server.StartClient(command, sockname);
   if(sock < 0) {
     switch (sock) {
     case -1:
-      Msg(GERROR, "Couldn't create socket '%s'", socket_name);
+      Msg(GERROR, "Couldn't create socket '%s'", sockname);
       break;
     case -2:
-      Msg(GERROR, "Couldn't bind socket to name '%s'", socket_name);
+      Msg(GERROR, "Couldn't bind socket to name '%s'", sockname);
       break;
     case -3:
-      Msg(GERROR, "Socket listen failed on '%s'", socket_name);
+      Msg(GERROR, "Socket listen failed on '%s'", sockname);
       break;
     case -4:
-      Msg(GERROR, "Socket listen timeout on '%s'", socket_name);
+      Msg(GERROR, "Socket listen timeout on '%s'", sockname);
       Msg(GERROR, "Is '%s' correctly installed?", prog);
       break;
     case -5:
-      Msg(GERROR, "Socket accept failed on '%s'", socket_name);
+      Msg(GERROR, "Socket accept failed on '%s'", sockname);
       break;
     }
-    for(i = 0; i < SINFO[num].nboptions; i++)
+    for(int i = 0; i < SINFO[num].nboptions; i++)
       WID->solver[num].choice[i]->clear();
     return 0;
   }
 
-  for(i = 0; i < SINFO[num].nboptions; i++)
+  for(int i = 0; i < SINFO[num].nboptions; i++)
     SINFO[num].nbval[i] = 0;
   SINFO[num].pid = 0;
 
   struct pollfd pfd;
   pfd.fd = sock;
-  pfd.events = POLLIN|POLLPRI;
-  
+  pfd.events = POLLIN;
+
   while(1) {
     // poll the socket file descriptor every 10 milliseconds until
     // data is avalable; when nothing is available, just tend to
@@ -132,7 +117,6 @@ int Solver(int num, char *args)
     // way on all the platforms.)
     while(1){
       if(SINFO[num].pid < 0){ // process has been killed
-	stop = 1;
 	break;
       }
       int ret = poll(&pfd, 1, 10);
@@ -143,48 +127,55 @@ int Solver(int num, char *args)
         break;
       }
       else{ // error
-        stop = 1;
+        SINFO[num].pid = -1;
         break;
       }
     }
-  
-    if(stop)
+
+    if(SINFO[num].pid < 0)
       break;
 
-    if(Gmsh_ReceiveString(sock, &type, str)){
+    int type;
+    if(server.ReceiveString(&type, str)){
       switch (type) {
-      case GMSH_CLIENT_START:
+      case GmshServer::CLIENT_START:
 	SINFO[num].pid = atoi(str);
 	break;
-      case GMSH_CLIENT_STOP:
+      case GmshServer::CLIENT_STOP:
 	SINFO[num].pid = -1;
-	stop = 1;
 	break;
-      case GMSH_CLIENT_PROGRESS:
+      case GmshServer::CLIENT_PROGRESS:
 	Msg(STATUS3N, "%s %s", SINFO[num].name, str);
 	break;
-      case GMSH_CLIENT_OPTION_1:
-      case GMSH_CLIENT_OPTION_2:
-      case GMSH_CLIENT_OPTION_3:
-      case GMSH_CLIENT_OPTION_4:
-      case GMSH_CLIENT_OPTION_5:
-	i = type - GMSH_CLIENT_OPTION;
-	strcpy(SINFO[num].option[i][SINFO[num].nbval[i]++], str);
+      case GmshServer::CLIENT_OPTION_1:
+	strcpy(SINFO[num].option[0][SINFO[num].nbval[0]++], str);
 	break;
-      case GMSH_CLIENT_VIEW:
+      case GmshServer::CLIENT_OPTION_2:
+	strcpy(SINFO[num].option[1][SINFO[num].nbval[1]++], str);
+	break;
+      case GmshServer::CLIENT_OPTION_3:
+	strcpy(SINFO[num].option[2][SINFO[num].nbval[2]++], str);
+	break;
+      case GmshServer::CLIENT_OPTION_4:
+	strcpy(SINFO[num].option[3][SINFO[num].nbval[3]++], str);
+	break;
+      case GmshServer::CLIENT_OPTION_5:
+	strcpy(SINFO[num].option[4][SINFO[num].nbval[4]++], str);
+	break;
+      case GmshServer::CLIENT_VIEW:
 	if(SINFO[num].merge_views) {
-	  n = List_Nbr(CTX.post.list);
+	  int n = List_Nbr(CTX.post.list);
 	  MergeProblem(str);
 	  Draw();
 	  if(n != List_Nbr(CTX.post.list))
 	    WID->set_context(menu_post, 0);
 	}
 	break;
-      case GMSH_CLIENT_INFO:
+      case GmshServer::CLIENT_INFO:
 	Msg(SOLVER, "%-8.8s: %s", SINFO[num].name, str);
 	break;
-      case GMSH_CLIENT_WARNING:
-      case GMSH_CLIENT_ERROR:
+      case GmshServer::CLIENT_WARNING:
+      case GmshServer::CLIENT_ERROR:
 	Msg(SOLVERR, "%-8.8s: %s", SINFO[num].name, str);
 	break;
       default:
@@ -195,15 +186,12 @@ int Solver(int num, char *args)
       }
       WID->check();
     }
-
-    if(stop)
-      break;
   }
   
-  for(i = 0; i < SINFO[num].nboptions; i++) {
+  for(int i = 0; i < SINFO[num].nboptions; i++) {
     if(SINFO[num].nbval[i]) {
       WID->solver[num].choice[i]->clear();
-      for(j = 0; j < SINFO[num].nbval[i]; j++)
+      for(int j = 0; j < SINFO[num].nbval[i]; j++)
         WID->solver[num].choice[i]->add(SINFO[num].option[i][j]);
       WID->solver[num].choice[i]->value(0);
     }
@@ -211,8 +199,8 @@ int Solver(int num, char *args)
 
   Msg(STATUS3N, "Ready");
 
-  if(Gmsh_StopClient(socket_name, sock) < 0)
-    Msg(WARNING, "Impossible to unlink the socket '%s'", socket_name);
+  if(server.StopClient() < 0)
+    Msg(WARNING, "Impossible to unlink the socket '%s'", sockname);
 
   return 1;
 }
diff --git a/Parser/Gmsh.l b/Parser/Gmsh.l
index c9f13d7c8b..e9e10c56a0 100644
--- a/Parser/Gmsh.l
+++ b/Parser/Gmsh.l
@@ -1,5 +1,5 @@
 %{
-// $Id: Gmsh.l,v 1.67 2005-01-14 17:54:25 geuzaine Exp $
+// $Id: Gmsh.l,v 1.68 2005-01-16 20:41:38 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -347,10 +347,12 @@ void skipcomments(void){
 }
 
 void parsestring(char endchar){
-  int c, i;
+  int c;
   char tmp[1024];
-
-  i = 0;
+  
+  // Note that we keep special characters (end-of-line \n, tabs \t,
+  // etc.) "as is" in the output string: see yyinput() above
+  int i = 0;
   while ((c = yyinput()) != endchar) {
     if(c == EOF){
       Msg(GERROR, "End of file in string");
diff --git a/Parser/Gmsh.tab.cpp b/Parser/Gmsh.tab.cpp
index 8b71dc853d..4e334bf0c6 100644
--- a/Parser/Gmsh.tab.cpp
+++ b/Parser/Gmsh.tab.cpp
@@ -199,7 +199,7 @@
 
 #line 1 "Gmsh.y"
 
-// $Id: Gmsh.tab.cpp,v 1.228 2005-01-14 17:54:25 geuzaine Exp $
+// $Id: Gmsh.tab.cpp,v 1.229 2005-01-16 20:41:38 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -769,29 +769,29 @@ static const short yyrline[] = { 0,
   1553,  1567,  1584,  1604,  1627,  1637,  1652,  1672,  1688,  1707,
   1726,  1744,  1762,  1780,  1806,  1824,  1850,  1870,  1894,  1918,
   1944,  1961,  1979,  1998,  2017,  2056,  2081,  2101,  2120,  2137,
-  2156,  2175,  2191,  2210,  2227,  2244,  2264,  2270,  2275,  2280,
-  2287,  2289,  2290,  2293,  2298,  2302,  2318,  2334,  2350,  2370,
-  2385,  2391,  2397,  2408,  2418,  2428,  2438,  2456,  2470,  2479,
-  2485,  2496,  2509,  2554,  2569,  2585,  2595,  2606,  2610,  2614,
-  2618,  2629,  2646,  2662,  2688,  2715,  2747,  2754,  2759,  2765,
-  2769,  2777,  2796,  2812,  2828,  2833,  2849,  2854,  2870,  2875,
-  2893,  2916,  2939,  2962,  2967,  2990,  2995,  3018,  3023,  3049,
-  3072,  3095,  3118,  3123,  3146,  3152,  3175,  3181,  3206,  3210,
-  3215,  3242,  3266,  3274,  3293,  3311,  3329,  3356,  3382,  3408,
-  3422,  3440,  3445,  3454,  3456,  3457,  3458,  3459,  3462,  3464,
-  3465,  3466,  3467,  3468,  3469,  3470,  3471,  3478,  3479,  3480,
-  3481,  3482,  3483,  3484,  3485,  3486,  3487,  3488,  3489,  3490,
-  3491,  3492,  3493,  3494,  3495,  3496,  3497,  3498,  3499,  3500,
-  3501,  3502,  3503,  3504,  3505,  3506,  3507,  3508,  3509,  3511,
-  3512,  3513,  3514,  3515,  3516,  3517,  3518,  3519,  3520,  3521,
-  3522,  3523,  3524,  3525,  3526,  3527,  3528,  3529,  3530,  3531,
-  3536,  3541,  3542,  3543,  3547,  3560,  3580,  3594,  3607,  3630,
-  3648,  3666,  3684,  3702,  3709,  3714,  3718,  3722,  3726,  3732,
-  3737,  3741,  3745,  3751,  3755,  3760,  3764,  3769,  3773,  3777,
-  3783,  3789,  3796,  3802,  3806,  3810,  3821,  3828,  3839,  3859,
-  3869,  3879,  3891,  3908,  3927,  3951,  3979,  3985,  3989,  3993,
-  4005,  4010,  4022,  4029,  4050,  4055,  4069,  4075,  4081,  4086,
-  4094,  4102,  4116,  4120,  4139,  4155
+  2156,  2175,  2191,  2211,  2228,  2245,  2265,  2271,  2276,  2281,
+  2288,  2290,  2291,  2294,  2299,  2303,  2319,  2335,  2351,  2371,
+  2386,  2392,  2398,  2409,  2419,  2429,  2439,  2457,  2471,  2480,
+  2486,  2497,  2510,  2555,  2570,  2586,  2596,  2607,  2611,  2615,
+  2619,  2630,  2647,  2663,  2689,  2716,  2748,  2755,  2760,  2766,
+  2770,  2778,  2797,  2813,  2829,  2834,  2850,  2855,  2871,  2876,
+  2894,  2917,  2940,  2963,  2968,  2991,  2996,  3019,  3024,  3050,
+  3073,  3096,  3119,  3124,  3147,  3153,  3176,  3182,  3207,  3211,
+  3216,  3243,  3267,  3275,  3294,  3312,  3330,  3357,  3383,  3409,
+  3423,  3441,  3446,  3455,  3457,  3458,  3459,  3460,  3463,  3465,
+  3466,  3467,  3468,  3469,  3470,  3471,  3472,  3479,  3480,  3481,
+  3482,  3483,  3484,  3485,  3486,  3487,  3488,  3489,  3490,  3491,
+  3492,  3493,  3494,  3495,  3496,  3497,  3498,  3499,  3500,  3501,
+  3502,  3503,  3504,  3505,  3506,  3507,  3508,  3509,  3510,  3512,
+  3513,  3514,  3515,  3516,  3517,  3518,  3519,  3520,  3521,  3522,
+  3523,  3524,  3525,  3526,  3527,  3528,  3529,  3530,  3531,  3532,
+  3537,  3542,  3543,  3544,  3548,  3561,  3581,  3595,  3608,  3631,
+  3649,  3667,  3685,  3703,  3710,  3715,  3719,  3723,  3727,  3733,
+  3738,  3742,  3746,  3752,  3756,  3761,  3765,  3770,  3774,  3778,
+  3784,  3790,  3797,  3803,  3807,  3811,  3822,  3829,  3840,  3860,
+  3870,  3880,  3892,  3909,  3928,  3952,  3980,  3986,  3990,  3994,
+  4006,  4011,  4023,  4030,  4051,  4056,  4070,  4076,  4082,  4087,
+  4095,  4103,  4117,  4121,  4140,  4156
 };
 #endif
 
@@ -6872,7 +6872,7 @@ case 263:
     ;
     break;}
 case 264:
-#line 2211 "Gmsh.y"
+#line 2212 "Gmsh.y"
 {
       int num = (int)yyvsp[-4].d;
       if(FindVolume(num, THEM)){
@@ -6891,7 +6891,7 @@ case 264:
     ;
     break;}
 case 265:
-#line 2228 "Gmsh.y"
+#line 2229 "Gmsh.y"
 {
       int num = (int)yyvsp[-4].d;
       if(FindVolume(num, THEM)){
@@ -6910,7 +6910,7 @@ case 265:
     ;
     break;}
 case 266:
-#line 2245 "Gmsh.y"
+#line 2246 "Gmsh.y"
 {
       int num = (int)yyvsp[-4].d;
       if(FindPhysicalGroup(num, MSH_PHYSICAL_VOLUME, THEM)){
@@ -6928,59 +6928,59 @@ case 266:
     ;
     break;}
 case 267:
-#line 2266 "Gmsh.y"
+#line 2267 "Gmsh.y"
 {
       TranslateShapes(yyvsp[-3].v[0], yyvsp[-3].v[1], yyvsp[-3].v[2], yyvsp[-1].l, 1);
       yyval.l = yyvsp[-1].l;
     ;
     break;}
 case 268:
-#line 2271 "Gmsh.y"
+#line 2272 "Gmsh.y"
 {
       RotateShapes(yyvsp[-8].v[0], yyvsp[-8].v[1], yyvsp[-8].v[2], yyvsp[-6].v[0], yyvsp[-6].v[1], yyvsp[-6].v[2], yyvsp[-4].d, yyvsp[-1].l, 1);
       yyval.l = yyvsp[-1].l;
     ;
     break;}
 case 269:
-#line 2276 "Gmsh.y"
+#line 2277 "Gmsh.y"
 {
       SymmetryShapes(yyvsp[-3].v[0], yyvsp[-3].v[1], yyvsp[-3].v[2], yyvsp[-3].v[3], yyvsp[-1].l, 1);
       yyval.l = yyvsp[-1].l;
     ;
     break;}
 case 270:
-#line 2281 "Gmsh.y"
+#line 2282 "Gmsh.y"
 {
       DilatShapes(yyvsp[-6].v[0], yyvsp[-6].v[1], yyvsp[-6].v[2], yyvsp[-4].d, yyvsp[-1].l, 1);
       yyval.l = yyvsp[-1].l;
     ;
     break;}
 case 271:
-#line 2288 "Gmsh.y"
+#line 2289 "Gmsh.y"
 { yyval.l = yyvsp[0].l; ;
     break;}
 case 272:
-#line 2289 "Gmsh.y"
+#line 2290 "Gmsh.y"
 { yyval.l = yyvsp[0].l; ;
     break;}
 case 273:
-#line 2290 "Gmsh.y"
+#line 2291 "Gmsh.y"
 { yyval.l = yyvsp[0].l; ;
     break;}
 case 274:
-#line 2295 "Gmsh.y"
+#line 2296 "Gmsh.y"
 {
       yyval.l = List_Create(3, 3, sizeof(Shape));
     ;
     break;}
 case 275:
-#line 2299 "Gmsh.y"
+#line 2300 "Gmsh.y"
 {
       List_Add(yyval.l, &yyvsp[0].s);
     ;
     break;}
 case 276:
-#line 2303 "Gmsh.y"
+#line 2304 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-2].l); i++){
 	double d;
@@ -6998,7 +6998,7 @@ case 276:
     ;
     break;}
 case 277:
-#line 2319 "Gmsh.y"
+#line 2320 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-2].l); i++){
 	double d;
@@ -7016,7 +7016,7 @@ case 277:
     ;
     break;}
 case 278:
-#line 2335 "Gmsh.y"
+#line 2336 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-2].l); i++){
 	double d;
@@ -7034,7 +7034,7 @@ case 278:
     ;
     break;}
 case 279:
-#line 2351 "Gmsh.y"
+#line 2352 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-2].l); i++){
 	double d;
@@ -7052,7 +7052,7 @@ case 279:
     ;
     break;}
 case 280:
-#line 2372 "Gmsh.y"
+#line 2373 "Gmsh.y"
 {
       yyval.l = List_Create(3, 3, sizeof(Shape));
       for(int i = 0; i < List_Nbr(yyvsp[-1].l); i++){
@@ -7067,7 +7067,7 @@ case 280:
     ;
     break;}
 case 281:
-#line 2386 "Gmsh.y"
+#line 2387 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-4].c, "View")) AliasView((int)yyvsp[-2].d, 0);
       Free(yyvsp[-4].c);
@@ -7075,7 +7075,7 @@ case 281:
     ;
     break;}
 case 282:
-#line 2392 "Gmsh.y"
+#line 2393 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-4].c, "View")) AliasView((int)yyvsp[-2].d, 0);
       Free(yyvsp[-4].c);
@@ -7083,7 +7083,7 @@ case 282:
     ;
     break;}
 case 283:
-#line 2398 "Gmsh.y"
+#line 2399 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-4].c, "View")) AliasView((int)yyvsp[-2].d, 1);
       Free(yyvsp[-4].c);
@@ -7091,7 +7091,7 @@ case 283:
     ;
     break;}
 case 284:
-#line 2410 "Gmsh.y"
+#line 2411 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-1].l); i++){
 	Shape TheShape;
@@ -7102,7 +7102,7 @@ case 284:
     ;
     break;}
 case 285:
-#line 2419 "Gmsh.y"
+#line 2420 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-4].c, "View")){
 	RemoveViewByIndex((int)yyvsp[-2].d);
@@ -7114,7 +7114,7 @@ case 285:
     ;
     break;}
 case 286:
-#line 2429 "Gmsh.y"
+#line 2430 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-1].c, "Meshes") || !strcmp(yyvsp[-1].c, "All")){
 	Init_Mesh(THEM);
@@ -7126,7 +7126,7 @@ case 286:
     ;
     break;}
 case 287:
-#line 2439 "Gmsh.y"
+#line 2440 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-2].c, "Empty") && !strcmp(yyvsp[-1].c, "Views")){
 	for(int i = List_Nbr(CTX.post.list) - 1; i >= 0; i--){
@@ -7142,7 +7142,7 @@ case 287:
     ;
     break;}
 case 288:
-#line 2458 "Gmsh.y"
+#line 2459 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-1].l); i++){
 	Shape TheShape;
@@ -7153,7 +7153,7 @@ case 288:
     ;
     break;}
 case 289:
-#line 2472 "Gmsh.y"
+#line 2473 "Gmsh.y"
 {
       int m = (CTX.visibility_mode == 2) ? VIS_MESH : 
 	((CTX.visibility_mode == 1) ? VIS_GEOM : VIS_GEOM|VIS_MESH);
@@ -7163,7 +7163,7 @@ case 289:
     ;
     break;}
 case 290:
-#line 2480 "Gmsh.y"
+#line 2481 "Gmsh.y"
 {
       for(int i = 2; i < 6; i++)
 	SetVisibilityByNumber(yyvsp[-1].c, i, 0);
@@ -7171,7 +7171,7 @@ case 290:
     ;
     break;}
 case 291:
-#line 2486 "Gmsh.y"
+#line 2487 "Gmsh.y"
 {
       int m = (CTX.visibility_mode == 2) ? VIS_MESH :
 	((CTX.visibility_mode == 1) ? VIS_GEOM : VIS_GEOM|VIS_MESH);
@@ -7184,7 +7184,7 @@ case 291:
     ;
     break;}
 case 292:
-#line 2497 "Gmsh.y"
+#line 2498 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-1].l); i++){
 	Shape TheShape;
@@ -7195,7 +7195,7 @@ case 292:
     ;
     break;}
 case 293:
-#line 2511 "Gmsh.y"
+#line 2512 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-2].c, "Include")){
 	char tmpstring[1024];
@@ -7241,7 +7241,7 @@ case 293:
     ;
     break;}
 case 294:
-#line 2555 "Gmsh.y"
+#line 2556 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-6].c, "Save") && !strcmp(yyvsp[-5].c, "View")){
 	Post_View **vv = (Post_View **)List_Pointer_Test(CTX.post.list, (int)yyvsp[-3].d);
@@ -7258,7 +7258,7 @@ case 294:
     ;
     break;}
 case 295:
-#line 2570 "Gmsh.y"
+#line 2571 "Gmsh.y"
 {
       if(!strcmp(yyvsp[-2].c, "Sleep")){
 	long sleep_time = GetTime();
@@ -7276,7 +7276,7 @@ case 295:
     ;
     break;}
 case 296:
-#line 2586 "Gmsh.y"
+#line 2587 "Gmsh.y"
 {
        try {
 	 GMSH_PluginManager::instance()->action(yyvsp[-4].c, yyvsp[-1].c, 0);
@@ -7288,7 +7288,7 @@ case 296:
      ;
     break;}
 case 297:
-#line 2596 "Gmsh.y"
+#line 2597 "Gmsh.y"
 {
       // for backward compatibility
       if(!strcmp(yyvsp[-1].c, "Views"))
@@ -7301,25 +7301,25 @@ case 297:
     ;
     break;}
 case 298:
-#line 2607 "Gmsh.y"
+#line 2608 "Gmsh.y"
 {
       exit(0);
     ;
     break;}
 case 299:
-#line 2611 "Gmsh.y"
+#line 2612 "Gmsh.y"
 {
       SetBoundingBox();
     ;
     break;}
 case 300:
-#line 2615 "Gmsh.y"
+#line 2616 "Gmsh.y"
 {
       SetBoundingBox(yyvsp[-12].d, yyvsp[-10].d, yyvsp[-8].d, yyvsp[-6].d, yyvsp[-4].d, yyvsp[-2].d);
     ;
     break;}
 case 301:
-#line 2619 "Gmsh.y"
+#line 2620 "Gmsh.y"
 {
 #if defined(HAVE_FLTK)
       if(!CTX.batch) // we're in interactive mode
@@ -7328,7 +7328,7 @@ case 301:
     ;
     break;}
 case 302:
-#line 2632 "Gmsh.y"
+#line 2633 "Gmsh.y"
 {
       LoopControlVariablesTab[ImbricatedLoop][0] = yyvsp[-3].d;
       LoopControlVariablesTab[ImbricatedLoop][1] = yyvsp[-1].d;
@@ -7345,7 +7345,7 @@ case 302:
     ;
     break;}
 case 303:
-#line 2647 "Gmsh.y"
+#line 2648 "Gmsh.y"
 {
       LoopControlVariablesTab[ImbricatedLoop][0] = yyvsp[-5].d;
       LoopControlVariablesTab[ImbricatedLoop][1] = yyvsp[-3].d;
@@ -7363,7 +7363,7 @@ case 303:
     ;
     break;}
 case 304:
-#line 2663 "Gmsh.y"
+#line 2664 "Gmsh.y"
 {
       LoopControlVariablesTab[ImbricatedLoop][0] = yyvsp[-3].d;
       LoopControlVariablesTab[ImbricatedLoop][1] = yyvsp[-1].d;
@@ -7391,7 +7391,7 @@ case 304:
     ;
     break;}
 case 305:
-#line 2689 "Gmsh.y"
+#line 2690 "Gmsh.y"
 {
       LoopControlVariablesTab[ImbricatedLoop][0] = yyvsp[-5].d;
       LoopControlVariablesTab[ImbricatedLoop][1] = yyvsp[-3].d;
@@ -7420,7 +7420,7 @@ case 305:
     ;
     break;}
 case 306:
-#line 2716 "Gmsh.y"
+#line 2717 "Gmsh.y"
 {
       if(ImbricatedLoop <= 0){
 	yymsg(GERROR, "Invalid For/EndFor loop");
@@ -7454,7 +7454,7 @@ case 306:
     ;
     break;}
 case 307:
-#line 2748 "Gmsh.y"
+#line 2749 "Gmsh.y"
 {
       if(!FunctionManager::Instance()->createFunction(yyvsp[0].c, yyin, yyname, yylineno))
 	yymsg(GERROR, "Redefinition of function %s", yyvsp[0].c);
@@ -7463,14 +7463,14 @@ case 307:
     ;
     break;}
 case 308:
-#line 2755 "Gmsh.y"
+#line 2756 "Gmsh.y"
 {
       if(!FunctionManager::Instance()->leaveFunction(&yyin, yyname, yylineno))
 	yymsg(GERROR, "Error while exiting function");
     ;
     break;}
 case 309:
-#line 2760 "Gmsh.y"
+#line 2761 "Gmsh.y"
 {
       if(!FunctionManager::Instance()->enterFunction(yyvsp[-1].c, &yyin, yyname, yylineno))
 	yymsg(GERROR, "Unknown function %s", yyvsp[-1].c);
@@ -7478,18 +7478,18 @@ case 309:
     ;
     break;}
 case 310:
-#line 2766 "Gmsh.y"
+#line 2767 "Gmsh.y"
 {
       if(!yyvsp[-1].d) skip_until("If", "EndIf");
     ;
     break;}
 case 311:
-#line 2770 "Gmsh.y"
+#line 2771 "Gmsh.y"
 {
     ;
     break;}
 case 312:
-#line 2781 "Gmsh.y"
+#line 2782 "Gmsh.y"
 {
       Curve *pc, *prc;
       Shape TheShape;
@@ -7507,7 +7507,7 @@ case 312:
     ;
     break;}
 case 313:
-#line 2797 "Gmsh.y"
+#line 2798 "Gmsh.y"
 {
       Curve *pc, *prc;
       Shape TheShape;
@@ -7525,7 +7525,7 @@ case 313:
     ;
     break;}
 case 314:
-#line 2813 "Gmsh.y"
+#line 2814 "Gmsh.y"
 {
       Curve *pc, *prc;
       Shape TheShape;
@@ -7543,14 +7543,14 @@ case 314:
     ;
     break;}
 case 315:
-#line 2829 "Gmsh.y"
+#line 2830 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 316:
-#line 2834 "Gmsh.y"
+#line 2835 "Gmsh.y"
 {
       Curve *pc, *prc;
       Shape TheShape;
@@ -7568,14 +7568,14 @@ case 316:
     ;
     break;}
 case 317:
-#line 2850 "Gmsh.y"
+#line 2851 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 318:
-#line 2855 "Gmsh.y"
+#line 2856 "Gmsh.y"
 {
       Curve *pc, *prc;
       Shape TheShape;
@@ -7593,14 +7593,14 @@ case 318:
     ;
     break;}
 case 319:
-#line 2871 "Gmsh.y"
+#line 2872 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 320:
-#line 2876 "Gmsh.y"
+#line 2877 "Gmsh.y"
 {
       Curve *pc, *prc;
       Shape TheShape;
@@ -7618,7 +7618,7 @@ case 320:
     ;
     break;}
 case 321:
-#line 2894 "Gmsh.y"
+#line 2895 "Gmsh.y"
 {
       Surface *ps;
       Shape TheShape;
@@ -7643,7 +7643,7 @@ case 321:
     ;
     break;}
 case 322:
-#line 2917 "Gmsh.y"
+#line 2918 "Gmsh.y"
 {
       Surface *ps;
       Shape TheShape;
@@ -7668,7 +7668,7 @@ case 322:
     ;
     break;}
 case 323:
-#line 2940 "Gmsh.y"
+#line 2941 "Gmsh.y"
 {
       Surface *ps;
       Shape TheShape;
@@ -7693,14 +7693,14 @@ case 323:
     ;
     break;}
 case 324:
-#line 2963 "Gmsh.y"
+#line 2964 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 325:
-#line 2968 "Gmsh.y"
+#line 2969 "Gmsh.y"
 {
       Surface *ps;
       Shape TheShape;
@@ -7725,14 +7725,14 @@ case 325:
     ;
     break;}
 case 326:
-#line 2991 "Gmsh.y"
+#line 2992 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 327:
-#line 2996 "Gmsh.y"
+#line 2997 "Gmsh.y"
 {
       Surface *ps;
       Shape TheShape;
@@ -7757,14 +7757,14 @@ case 327:
     ;
     break;}
 case 328:
-#line 3019 "Gmsh.y"
+#line 3020 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 329:
-#line 3024 "Gmsh.y"
+#line 3025 "Gmsh.y"
 {
       Surface *ps;
       Shape TheShape;
@@ -7789,7 +7789,7 @@ case 329:
     ;
     break;}
 case 330:
-#line 3050 "Gmsh.y"
+#line 3051 "Gmsh.y"
 {
       Volume *pv;
       Shape TheShape;
@@ -7814,7 +7814,7 @@ case 330:
     ;
     break;}
 case 331:
-#line 3073 "Gmsh.y"
+#line 3074 "Gmsh.y"
 {
       Volume *pv;
       Shape TheShape;
@@ -7839,7 +7839,7 @@ case 331:
     ;
     break;}
 case 332:
-#line 3096 "Gmsh.y"
+#line 3097 "Gmsh.y"
 {
       Volume *pv;
       Shape TheShape;
@@ -7864,14 +7864,14 @@ case 332:
     ;
     break;}
 case 333:
-#line 3119 "Gmsh.y"
+#line 3120 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 334:
-#line 3124 "Gmsh.y"
+#line 3125 "Gmsh.y"
 {
       Volume *pv;
       Shape TheShape;
@@ -7896,14 +7896,14 @@ case 334:
     ;
     break;}
 case 335:
-#line 3147 "Gmsh.y"
+#line 3148 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 336:
-#line 3153 "Gmsh.y"
+#line 3154 "Gmsh.y"
 {
       Volume *pv;
       Shape TheShape;
@@ -7928,14 +7928,14 @@ case 336:
     ;
     break;}
 case 337:
-#line 3176 "Gmsh.y"
+#line 3177 "Gmsh.y"
 {
       extr.mesh.ExtrudeMesh = false;
       extr.mesh.Recombine = false;
     ;
     break;}
 case 338:
-#line 3182 "Gmsh.y"
+#line 3183 "Gmsh.y"
 {
       Volume *pv;
       Shape TheShape;
@@ -7960,17 +7960,17 @@ case 338:
     ;
     break;}
 case 339:
-#line 3208 "Gmsh.y"
+#line 3209 "Gmsh.y"
 {
     ;
     break;}
 case 340:
-#line 3211 "Gmsh.y"
+#line 3212 "Gmsh.y"
 {
     ;
     break;}
 case 341:
-#line 3217 "Gmsh.y"
+#line 3218 "Gmsh.y"
 {
       double d;
       extr.mesh.ExtrudeMesh = true;
@@ -7998,7 +7998,7 @@ case 341:
     ;
     break;}
 case 342:
-#line 3243 "Gmsh.y"
+#line 3244 "Gmsh.y"
 {
       double d;
       extr.mesh.ExtrudeMesh = true;
@@ -8024,13 +8024,13 @@ case 342:
     ;
     break;}
 case 343:
-#line 3267 "Gmsh.y"
+#line 3268 "Gmsh.y"
 {
       extr.mesh.Recombine = true;
     ;
     break;}
 case 344:
-#line 3276 "Gmsh.y"
+#line 3277 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-3].l); i++){
 	double d;
@@ -8050,7 +8050,7 @@ case 344:
     ;
     break;}
 case 345:
-#line 3294 "Gmsh.y"
+#line 3295 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-6].l); i++){
 	double d;
@@ -8070,7 +8070,7 @@ case 345:
     ;
     break;}
 case 346:
-#line 3312 "Gmsh.y"
+#line 3313 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-6].l); i++){
 	double d;
@@ -8090,7 +8090,7 @@ case 346:
     ;
     break;}
 case 347:
-#line 3330 "Gmsh.y"
+#line 3331 "Gmsh.y"
 {
       Surface *s = FindSurface((int)yyvsp[-4].d, THEM);
       if(!s)
@@ -8119,7 +8119,7 @@ case 347:
     ;
     break;}
 case 348:
-#line 3357 "Gmsh.y"
+#line 3358 "Gmsh.y"
 {
       Surface *s = FindSurface((int)yyvsp[-4].d, THEM);
       if(!s)
@@ -8147,7 +8147,7 @@ case 348:
     ;
     break;}
 case 349:
-#line 3383 "Gmsh.y"
+#line 3384 "Gmsh.y"
 {
       Volume *v = FindVolume((int)yyvsp[-4].d, THEM);
       if(!v)
@@ -8175,7 +8175,7 @@ case 349:
     ;
     break;}
 case 350:
-#line 3409 "Gmsh.y"
+#line 3410 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-3].l); i++){
 	double d;
@@ -8191,7 +8191,7 @@ case 350:
     ;
     break;}
 case 351:
-#line 3423 "Gmsh.y"
+#line 3424 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[-1].l); i++){
 	double d;
@@ -8206,71 +8206,71 @@ case 351:
     ;
     break;}
 case 352:
-#line 3442 "Gmsh.y"
+#line 3443 "Gmsh.y"
 { 
       ReplaceAllDuplicates(THEM);
     ;
     break;}
 case 353:
-#line 3446 "Gmsh.y"
+#line 3447 "Gmsh.y"
 { 
       IntersectAllSegmentsTogether();
     ;
     break;}
 case 354:
-#line 3455 "Gmsh.y"
+#line 3456 "Gmsh.y"
 {yyval.i = 1;;
     break;}
 case 355:
-#line 3456 "Gmsh.y"
+#line 3457 "Gmsh.y"
 {yyval.i = 0;;
     break;}
 case 356:
-#line 3457 "Gmsh.y"
+#line 3458 "Gmsh.y"
 {yyval.i = -1;;
     break;}
 case 357:
-#line 3458 "Gmsh.y"
+#line 3459 "Gmsh.y"
 {yyval.i = -1;;
     break;}
 case 358:
-#line 3459 "Gmsh.y"
+#line 3460 "Gmsh.y"
 {yyval.i = -1;;
     break;}
 case 359:
-#line 3463 "Gmsh.y"
+#line 3464 "Gmsh.y"
 { yyval.d = yyvsp[0].d;           ;
     break;}
 case 360:
-#line 3464 "Gmsh.y"
+#line 3465 "Gmsh.y"
 { yyval.d = yyvsp[-1].d;           ;
     break;}
 case 361:
-#line 3465 "Gmsh.y"
+#line 3466 "Gmsh.y"
 { yyval.d = -yyvsp[0].d;          ;
     break;}
 case 362:
-#line 3466 "Gmsh.y"
+#line 3467 "Gmsh.y"
 { yyval.d = yyvsp[0].d;           ;
     break;}
 case 363:
-#line 3467 "Gmsh.y"
+#line 3468 "Gmsh.y"
 { yyval.d = !yyvsp[0].d;          ;
     break;}
 case 364:
-#line 3468 "Gmsh.y"
+#line 3469 "Gmsh.y"
 { yyval.d = yyvsp[-2].d - yyvsp[0].d;      ;
     break;}
 case 365:
-#line 3469 "Gmsh.y"
+#line 3470 "Gmsh.y"
 { yyval.d = yyvsp[-2].d + yyvsp[0].d;      ;
     break;}
 case 366:
-#line 3470 "Gmsh.y"
+#line 3471 "Gmsh.y"
 { yyval.d = yyvsp[-2].d * yyvsp[0].d;      ;
     break;}
 case 367:
-#line 3472 "Gmsh.y"
+#line 3473 "Gmsh.y"
 { 
       if(!yyvsp[0].d)
 	yymsg(GERROR, "Division by zero in '%g / %g'", yyvsp[-2].d, yyvsp[0].d);
@@ -8279,235 +8279,235 @@ case 367:
     ;
     break;}
 case 368:
-#line 3478 "Gmsh.y"
+#line 3479 "Gmsh.y"
 { yyval.d = (int)yyvsp[-2].d % (int)yyvsp[0].d;  ;
     break;}
 case 369:
-#line 3479 "Gmsh.y"
+#line 3480 "Gmsh.y"
 { yyval.d = pow(yyvsp[-2].d, yyvsp[0].d);  ;
     break;}
 case 370:
-#line 3480 "Gmsh.y"
+#line 3481 "Gmsh.y"
 { yyval.d = yyvsp[-2].d < yyvsp[0].d;      ;
     break;}
 case 371:
-#line 3481 "Gmsh.y"
+#line 3482 "Gmsh.y"
 { yyval.d = yyvsp[-2].d > yyvsp[0].d;      ;
     break;}
 case 372:
-#line 3482 "Gmsh.y"
+#line 3483 "Gmsh.y"
 { yyval.d = yyvsp[-2].d <= yyvsp[0].d;     ;
     break;}
 case 373:
-#line 3483 "Gmsh.y"
+#line 3484 "Gmsh.y"
 { yyval.d = yyvsp[-2].d >= yyvsp[0].d;     ;
     break;}
 case 374:
-#line 3484 "Gmsh.y"
+#line 3485 "Gmsh.y"
 { yyval.d = yyvsp[-2].d == yyvsp[0].d;     ;
     break;}
 case 375:
-#line 3485 "Gmsh.y"
+#line 3486 "Gmsh.y"
 { yyval.d = yyvsp[-2].d != yyvsp[0].d;     ;
     break;}
 case 376:
-#line 3486 "Gmsh.y"
+#line 3487 "Gmsh.y"
 { yyval.d = yyvsp[-2].d && yyvsp[0].d;     ;
     break;}
 case 377:
-#line 3487 "Gmsh.y"
+#line 3488 "Gmsh.y"
 { yyval.d = yyvsp[-2].d || yyvsp[0].d;     ;
     break;}
 case 378:
-#line 3488 "Gmsh.y"
+#line 3489 "Gmsh.y"
 { yyval.d = yyvsp[-4].d? yyvsp[-2].d : yyvsp[0].d;  ;
     break;}
 case 379:
-#line 3489 "Gmsh.y"
+#line 3490 "Gmsh.y"
 { yyval.d = exp(yyvsp[-1].d);      ;
     break;}
 case 380:
-#line 3490 "Gmsh.y"
+#line 3491 "Gmsh.y"
 { yyval.d = log(yyvsp[-1].d);      ;
     break;}
 case 381:
-#line 3491 "Gmsh.y"
+#line 3492 "Gmsh.y"
 { yyval.d = log10(yyvsp[-1].d);    ;
     break;}
 case 382:
-#line 3492 "Gmsh.y"
+#line 3493 "Gmsh.y"
 { yyval.d = sqrt(yyvsp[-1].d);     ;
     break;}
 case 383:
-#line 3493 "Gmsh.y"
+#line 3494 "Gmsh.y"
 { yyval.d = sin(yyvsp[-1].d);      ;
     break;}
 case 384:
-#line 3494 "Gmsh.y"
+#line 3495 "Gmsh.y"
 { yyval.d = asin(yyvsp[-1].d);     ;
     break;}
 case 385:
-#line 3495 "Gmsh.y"
+#line 3496 "Gmsh.y"
 { yyval.d = cos(yyvsp[-1].d);      ;
     break;}
 case 386:
-#line 3496 "Gmsh.y"
+#line 3497 "Gmsh.y"
 { yyval.d = acos(yyvsp[-1].d);     ;
     break;}
 case 387:
-#line 3497 "Gmsh.y"
+#line 3498 "Gmsh.y"
 { yyval.d = tan(yyvsp[-1].d);      ;
     break;}
 case 388:
-#line 3498 "Gmsh.y"
+#line 3499 "Gmsh.y"
 { yyval.d = atan(yyvsp[-1].d);     ;
     break;}
 case 389:
-#line 3499 "Gmsh.y"
+#line 3500 "Gmsh.y"
 { yyval.d = atan2(yyvsp[-3].d, yyvsp[-1].d);;
     break;}
 case 390:
-#line 3500 "Gmsh.y"
+#line 3501 "Gmsh.y"
 { yyval.d = sinh(yyvsp[-1].d);     ;
     break;}
 case 391:
-#line 3501 "Gmsh.y"
+#line 3502 "Gmsh.y"
 { yyval.d = cosh(yyvsp[-1].d);     ;
     break;}
 case 392:
-#line 3502 "Gmsh.y"
+#line 3503 "Gmsh.y"
 { yyval.d = tanh(yyvsp[-1].d);     ;
     break;}
 case 393:
-#line 3503 "Gmsh.y"
+#line 3504 "Gmsh.y"
 { yyval.d = fabs(yyvsp[-1].d);     ;
     break;}
 case 394:
-#line 3504 "Gmsh.y"
+#line 3505 "Gmsh.y"
 { yyval.d = floor(yyvsp[-1].d);    ;
     break;}
 case 395:
-#line 3505 "Gmsh.y"
+#line 3506 "Gmsh.y"
 { yyval.d = ceil(yyvsp[-1].d);     ;
     break;}
 case 396:
-#line 3506 "Gmsh.y"
+#line 3507 "Gmsh.y"
 { yyval.d = fmod(yyvsp[-3].d, yyvsp[-1].d); ;
     break;}
 case 397:
-#line 3507 "Gmsh.y"
+#line 3508 "Gmsh.y"
 { yyval.d = fmod(yyvsp[-3].d, yyvsp[-1].d); ;
     break;}
 case 398:
-#line 3508 "Gmsh.y"
+#line 3509 "Gmsh.y"
 { yyval.d = sqrt(yyvsp[-3].d*yyvsp[-3].d+yyvsp[-1].d*yyvsp[-1].d); ;
     break;}
 case 399:
-#line 3509 "Gmsh.y"
+#line 3510 "Gmsh.y"
 { yyval.d = yyvsp[-1].d*(double)rand()/(double)RAND_MAX; ;
     break;}
 case 400:
-#line 3511 "Gmsh.y"
+#line 3512 "Gmsh.y"
 { yyval.d = exp(yyvsp[-1].d);      ;
     break;}
 case 401:
-#line 3512 "Gmsh.y"
+#line 3513 "Gmsh.y"
 { yyval.d = log(yyvsp[-1].d);      ;
     break;}
 case 402:
-#line 3513 "Gmsh.y"
+#line 3514 "Gmsh.y"
 { yyval.d = log10(yyvsp[-1].d);    ;
     break;}
 case 403:
-#line 3514 "Gmsh.y"
+#line 3515 "Gmsh.y"
 { yyval.d = sqrt(yyvsp[-1].d);     ;
     break;}
 case 404:
-#line 3515 "Gmsh.y"
+#line 3516 "Gmsh.y"
 { yyval.d = sin(yyvsp[-1].d);      ;
     break;}
 case 405:
-#line 3516 "Gmsh.y"
+#line 3517 "Gmsh.y"
 { yyval.d = asin(yyvsp[-1].d);     ;
     break;}
 case 406:
-#line 3517 "Gmsh.y"
+#line 3518 "Gmsh.y"
 { yyval.d = cos(yyvsp[-1].d);      ;
     break;}
 case 407:
-#line 3518 "Gmsh.y"
+#line 3519 "Gmsh.y"
 { yyval.d = acos(yyvsp[-1].d);     ;
     break;}
 case 408:
-#line 3519 "Gmsh.y"
+#line 3520 "Gmsh.y"
 { yyval.d = tan(yyvsp[-1].d);      ;
     break;}
 case 409:
-#line 3520 "Gmsh.y"
+#line 3521 "Gmsh.y"
 { yyval.d = atan(yyvsp[-1].d);     ;
     break;}
 case 410:
-#line 3521 "Gmsh.y"
+#line 3522 "Gmsh.y"
 { yyval.d = atan2(yyvsp[-3].d, yyvsp[-1].d);;
     break;}
 case 411:
-#line 3522 "Gmsh.y"
+#line 3523 "Gmsh.y"
 { yyval.d = sinh(yyvsp[-1].d);     ;
     break;}
 case 412:
-#line 3523 "Gmsh.y"
+#line 3524 "Gmsh.y"
 { yyval.d = cosh(yyvsp[-1].d);     ;
     break;}
 case 413:
-#line 3524 "Gmsh.y"
+#line 3525 "Gmsh.y"
 { yyval.d = tanh(yyvsp[-1].d);     ;
     break;}
 case 414:
-#line 3525 "Gmsh.y"
+#line 3526 "Gmsh.y"
 { yyval.d = fabs(yyvsp[-1].d);     ;
     break;}
 case 415:
-#line 3526 "Gmsh.y"
+#line 3527 "Gmsh.y"
 { yyval.d = floor(yyvsp[-1].d);    ;
     break;}
 case 416:
-#line 3527 "Gmsh.y"
+#line 3528 "Gmsh.y"
 { yyval.d = ceil(yyvsp[-1].d);     ;
     break;}
 case 417:
-#line 3528 "Gmsh.y"
+#line 3529 "Gmsh.y"
 { yyval.d = fmod(yyvsp[-3].d, yyvsp[-1].d); ;
     break;}
 case 418:
-#line 3529 "Gmsh.y"
+#line 3530 "Gmsh.y"
 { yyval.d = fmod(yyvsp[-3].d, yyvsp[-1].d); ;
     break;}
 case 419:
-#line 3530 "Gmsh.y"
+#line 3531 "Gmsh.y"
 { yyval.d = sqrt(yyvsp[-3].d*yyvsp[-3].d+yyvsp[-1].d*yyvsp[-1].d); ;
     break;}
 case 420:
-#line 3531 "Gmsh.y"
+#line 3532 "Gmsh.y"
 { yyval.d = yyvsp[-1].d*(double)rand()/(double)RAND_MAX; ;
     break;}
 case 421:
-#line 3540 "Gmsh.y"
+#line 3541 "Gmsh.y"
 { yyval.d = yyvsp[0].d; ;
     break;}
 case 422:
-#line 3541 "Gmsh.y"
+#line 3542 "Gmsh.y"
 { yyval.d = 3.141592653589793; ;
     break;}
 case 423:
-#line 3542 "Gmsh.y"
+#line 3543 "Gmsh.y"
 { yyval.d = ParUtil::Instance()->rank(); ;
     break;}
 case 424:
-#line 3543 "Gmsh.y"
+#line 3544 "Gmsh.y"
 { yyval.d = ParUtil::Instance()->size(); ;
     break;}
 case 425:
-#line 3548 "Gmsh.y"
+#line 3549 "Gmsh.y"
 {
       Symbol TheSymbol;
       TheSymbol.Name = yyvsp[0].c;
@@ -8522,7 +8522,7 @@ case 425:
     ;
     break;}
 case 426:
-#line 3561 "Gmsh.y"
+#line 3562 "Gmsh.y"
 {
       Symbol TheSymbol;
       TheSymbol.Name = yyvsp[-3].c;
@@ -8544,7 +8544,7 @@ case 426:
     ;
     break;}
 case 427:
-#line 3581 "Gmsh.y"
+#line 3582 "Gmsh.y"
 {
       Symbol TheSymbol;
       TheSymbol.Name = yyvsp[-2].c;
@@ -8560,7 +8560,7 @@ case 427:
     ;
     break;}
 case 428:
-#line 3595 "Gmsh.y"
+#line 3596 "Gmsh.y"
 {
       Symbol TheSymbol;
       TheSymbol.Name = yyvsp[-1].c;
@@ -8575,7 +8575,7 @@ case 428:
     ;
     break;}
 case 429:
-#line 3608 "Gmsh.y"
+#line 3609 "Gmsh.y"
 {
       Symbol TheSymbol;
       TheSymbol.Name = yyvsp[-4].c;
@@ -8597,7 +8597,7 @@ case 429:
     ;
     break;}
 case 430:
-#line 3631 "Gmsh.y"
+#line 3632 "Gmsh.y"
 {
       double (*pNumOpt)(int num, int action, double value);
       StringXNumber *pNumCat;
@@ -8617,7 +8617,7 @@ case 430:
     ;
     break;}
 case 431:
-#line 3649 "Gmsh.y"
+#line 3650 "Gmsh.y"
 {
       double (*pNumOpt)(int num, int action, double value);
       StringXNumber *pNumCat;
@@ -8637,7 +8637,7 @@ case 431:
     ;
     break;}
 case 432:
-#line 3667 "Gmsh.y"
+#line 3668 "Gmsh.y"
 {
       double (*pNumOpt)(int num, int action, double value);
       StringXNumber *pNumCat;
@@ -8657,7 +8657,7 @@ case 432:
     ;
     break;}
 case 433:
-#line 3685 "Gmsh.y"
+#line 3686 "Gmsh.y"
 {
       double (*pNumOpt)(int num, int action, double value);
       StringXNumber *pNumCat;
@@ -8677,137 +8677,137 @@ case 433:
     ;
     break;}
 case 434:
-#line 3703 "Gmsh.y"
+#line 3704 "Gmsh.y"
 { 
       yyval.d = GetValue(yyvsp[-3].c, yyvsp[-1].d);
       Free(yyvsp[-3].c);
     ;
     break;}
 case 435:
-#line 3711 "Gmsh.y"
+#line 3712 "Gmsh.y"
 {
       memcpy(yyval.v, yyvsp[0].v, 5*sizeof(double));
     ;
     break;}
 case 436:
-#line 3715 "Gmsh.y"
+#line 3716 "Gmsh.y"
 {
       for(int i = 0; i < 5; i++) yyval.v[i] = -yyvsp[0].v[i];
     ;
     break;}
 case 437:
-#line 3719 "Gmsh.y"
+#line 3720 "Gmsh.y"
 { 
       for(int i = 0; i < 5; i++) yyval.v[i] = yyvsp[0].v[i];
     ;
     break;}
 case 438:
-#line 3723 "Gmsh.y"
+#line 3724 "Gmsh.y"
 { 
       for(int i = 0; i < 5; i++) yyval.v[i] = yyvsp[-2].v[i] - yyvsp[0].v[i];
     ;
     break;}
 case 439:
-#line 3727 "Gmsh.y"
+#line 3728 "Gmsh.y"
 {
       for(int i = 0; i < 5; i++) yyval.v[i] = yyvsp[-2].v[i] + yyvsp[0].v[i];
     ;
     break;}
 case 440:
-#line 3734 "Gmsh.y"
+#line 3735 "Gmsh.y"
 { 
       yyval.v[0] = yyvsp[-9].d;  yyval.v[1] = yyvsp[-7].d;  yyval.v[2] = yyvsp[-5].d;  yyval.v[3] = yyvsp[-3].d; yyval.v[4] = yyvsp[-1].d;
     ;
     break;}
 case 441:
-#line 3738 "Gmsh.y"
+#line 3739 "Gmsh.y"
 { 
       yyval.v[0] = yyvsp[-7].d;  yyval.v[1] = yyvsp[-5].d;  yyval.v[2] = yyvsp[-3].d;  yyval.v[3] = yyvsp[-1].d; yyval.v[4] = 1.0;
     ;
     break;}
 case 442:
-#line 3742 "Gmsh.y"
+#line 3743 "Gmsh.y"
 {
       yyval.v[0] = yyvsp[-5].d;  yyval.v[1] = yyvsp[-3].d;  yyval.v[2] = yyvsp[-1].d;  yyval.v[3] = 0.0; yyval.v[4] = 1.0;
     ;
     break;}
 case 443:
-#line 3746 "Gmsh.y"
+#line 3747 "Gmsh.y"
 {
       yyval.v[0] = yyvsp[-5].d;  yyval.v[1] = yyvsp[-3].d;  yyval.v[2] = yyvsp[-1].d;  yyval.v[3] = 0.0; yyval.v[4] = 1.0;
     ;
     break;}
 case 444:
-#line 3753 "Gmsh.y"
+#line 3754 "Gmsh.y"
 {
     ;
     break;}
 case 445:
-#line 3756 "Gmsh.y"
+#line 3757 "Gmsh.y"
 {
     ;
     break;}
 case 446:
-#line 3762 "Gmsh.y"
+#line 3763 "Gmsh.y"
 {
     ;
     break;}
 case 447:
-#line 3765 "Gmsh.y"
+#line 3766 "Gmsh.y"
 {
     ;
     break;}
 case 448:
-#line 3771 "Gmsh.y"
+#line 3772 "Gmsh.y"
 {
     ;
     break;}
 case 449:
-#line 3774 "Gmsh.y"
+#line 3775 "Gmsh.y"
 {
        yyval.l = yyvsp[-1].l;
     ;
     break;}
 case 450:
-#line 3778 "Gmsh.y"
+#line 3779 "Gmsh.y"
 {
        yyval.l = yyvsp[-1].l;
     ;
     break;}
 case 451:
-#line 3785 "Gmsh.y"
+#line 3786 "Gmsh.y"
 {
       yyval.l = List_Create(2, 1, sizeof(List_T*));
       List_Add(yyval.l, &(yyvsp[0].l));
     ;
     break;}
 case 452:
-#line 3790 "Gmsh.y"
+#line 3791 "Gmsh.y"
 {
       List_Add(yyval.l, &(yyvsp[0].l));
     ;
     break;}
 case 453:
-#line 3798 "Gmsh.y"
+#line 3799 "Gmsh.y"
 {
       yyval.l = List_Create(2, 1, sizeof(double));
       List_Add(yyval.l, &(yyvsp[0].d));
     ;
     break;}
 case 454:
-#line 3803 "Gmsh.y"
+#line 3804 "Gmsh.y"
 {
       yyval.l = yyvsp[0].l;
     ;
     break;}
 case 455:
-#line 3807 "Gmsh.y"
+#line 3808 "Gmsh.y"
 {
       yyval.l = yyvsp[-1].l;
     ;
     break;}
 case 456:
-#line 3811 "Gmsh.y"
+#line 3812 "Gmsh.y"
 {
       yyval.l = yyvsp[-1].l;
       double *pd;
@@ -8818,7 +8818,7 @@ case 456:
     ;
     break;}
 case 457:
-#line 3823 "Gmsh.y"
+#line 3824 "Gmsh.y"
 { 
       yyval.l = List_Create(2, 1, sizeof(double)); 
       for(double d = yyvsp[-2].d; (yyvsp[-2].d < yyvsp[0].d) ? (d <= yyvsp[0].d) : (d >= yyvsp[0].d); (yyvsp[-2].d < yyvsp[0].d) ? (d += 1.) : (d -= 1.)) 
@@ -8826,7 +8826,7 @@ case 457:
     ;
     break;}
 case 458:
-#line 3829 "Gmsh.y"
+#line 3830 "Gmsh.y"
 {
       yyval.l = List_Create(2, 1, sizeof(double)); 
       if(!yyvsp[0].d || (yyvsp[-4].d < yyvsp[-2].d && yyvsp[0].d < 0) || (yyvsp[-4].d > yyvsp[-2].d && yyvsp[0].d > 0)){
@@ -8839,7 +8839,7 @@ case 458:
    ;
     break;}
 case 459:
-#line 3840 "Gmsh.y"
+#line 3841 "Gmsh.y"
 {
       // Returns the coordinates of a point and fills a list with it.
       // This allows to ensure e.g. that relative point positions are
@@ -8861,7 +8861,7 @@ case 459:
     ;
     break;}
 case 460:
-#line 3860 "Gmsh.y"
+#line 3861 "Gmsh.y"
 {
       yyval.l = List_Create(List_Nbr(yyvsp[0].l), 1, sizeof(double));
       for(int i = 0; i < List_Nbr(yyvsp[0].l); i++){
@@ -8873,7 +8873,7 @@ case 460:
     ;
     break;}
 case 461:
-#line 3870 "Gmsh.y"
+#line 3871 "Gmsh.y"
 {
       yyval.l = List_Create(List_Nbr(yyvsp[0].l), 1, sizeof(double));
       for(int i = 0; i < List_Nbr(yyvsp[0].l); i++){
@@ -8885,7 +8885,7 @@ case 461:
     ;
     break;}
 case 462:
-#line 3880 "Gmsh.y"
+#line 3881 "Gmsh.y"
 {
       // FIXME: The syntax for this is ugly: we get double semi-colons
       // at the end of the line
@@ -8899,7 +8899,7 @@ case 462:
     ;
     break;}
 case 463:
-#line 3892 "Gmsh.y"
+#line 3893 "Gmsh.y"
 {
       yyval.l = List_Create(2, 1, sizeof(double));
       Symbol TheSymbol;
@@ -8918,7 +8918,7 @@ case 463:
     ;
     break;}
 case 464:
-#line 3909 "Gmsh.y"
+#line 3910 "Gmsh.y"
 {
       yyval.l = List_Create(2, 1, sizeof(double));
       Symbol TheSymbol;
@@ -8939,7 +8939,7 @@ case 464:
     ;
     break;}
 case 465:
-#line 3928 "Gmsh.y"
+#line 3929 "Gmsh.y"
 {
       yyval.l = List_Create(2, 1, sizeof(double));
       Symbol TheSymbol;
@@ -8965,7 +8965,7 @@ case 465:
     ;
     break;}
 case 466:
-#line 3952 "Gmsh.y"
+#line 3953 "Gmsh.y"
 {
       yyval.l = List_Create(2, 1, sizeof(double));
       Symbol TheSymbol;
@@ -8993,26 +8993,26 @@ case 466:
     ;
     break;}
 case 467:
-#line 3981 "Gmsh.y"
+#line 3982 "Gmsh.y"
 {
       yyval.l = List_Create(2, 1, sizeof(double));
       List_Add(yyval.l, &(yyvsp[0].d));
     ;
     break;}
 case 468:
-#line 3986 "Gmsh.y"
+#line 3987 "Gmsh.y"
 {
       yyval.l = yyvsp[0].l;
     ;
     break;}
 case 469:
-#line 3990 "Gmsh.y"
+#line 3991 "Gmsh.y"
 {
       List_Add(yyval.l, &(yyvsp[0].d));
     ;
     break;}
 case 470:
-#line 3994 "Gmsh.y"
+#line 3995 "Gmsh.y"
 {
       for(int i = 0; i < List_Nbr(yyvsp[0].l); i++){
 	double d;
@@ -9023,19 +9023,19 @@ case 470:
     ;
     break;}
 case 471:
-#line 4007 "Gmsh.y"
+#line 4008 "Gmsh.y"
 {
       yyval.u = PACK_COLOR((int)yyvsp[-7].d, (int)yyvsp[-5].d, (int)yyvsp[-3].d, (int)yyvsp[-1].d);
     ;
     break;}
 case 472:
-#line 4011 "Gmsh.y"
+#line 4012 "Gmsh.y"
 {
       yyval.u = PACK_COLOR((int)yyvsp[-5].d, (int)yyvsp[-3].d, (int)yyvsp[-1].d, 255);
     ;
     break;}
 case 473:
-#line 4023 "Gmsh.y"
+#line 4024 "Gmsh.y"
 {
       int flag;
       yyval.u = Get_ColorForString(ColorString, -1, yyvsp[0].c, &flag);
@@ -9044,7 +9044,7 @@ case 473:
     ;
     break;}
 case 474:
-#line 4030 "Gmsh.y"
+#line 4031 "Gmsh.y"
 {
       unsigned int (*pColOpt)(int num, int action, unsigned int value);
       StringXColor *pColCat;
@@ -9065,13 +9065,13 @@ case 474:
     ;
     break;}
 case 475:
-#line 4052 "Gmsh.y"
+#line 4053 "Gmsh.y"
 {
       yyval.l = yyvsp[-1].l;
     ;
     break;}
 case 476:
-#line 4056 "Gmsh.y"
+#line 4057 "Gmsh.y"
 {
       yyval.l = List_Create(256, 10, sizeof(unsigned int));
       GmshColorTable *ct = Get_ColorTable((int)yyvsp[-3].d);
@@ -9085,26 +9085,26 @@ case 476:
     ;
     break;}
 case 477:
-#line 4071 "Gmsh.y"
+#line 4072 "Gmsh.y"
 {
       yyval.l = List_Create(256, 10, sizeof(unsigned int));
       List_Add(yyval.l, &(yyvsp[0].u));
     ;
     break;}
 case 478:
-#line 4076 "Gmsh.y"
+#line 4077 "Gmsh.y"
 {
       List_Add(yyval.l, &(yyvsp[0].u));
     ;
     break;}
 case 479:
-#line 4083 "Gmsh.y"
+#line 4084 "Gmsh.y"
 {
       yyval.c = yyvsp[0].c;
     ;
     break;}
 case 480:
-#line 4087 "Gmsh.y"
+#line 4088 "Gmsh.y"
 {
       yyval.c = (char *)Malloc(32*sizeof(char));
       time_t now;
@@ -9114,7 +9114,7 @@ case 480:
     ;
     break;}
 case 481:
-#line 4095 "Gmsh.y"
+#line 4096 "Gmsh.y"
 {
       yyval.c = (char *)Malloc((strlen(yyvsp[-3].c)+strlen(yyvsp[-1].c)+1)*sizeof(char));
       strcpy(yyval.c, yyvsp[-3].c);
@@ -9124,7 +9124,7 @@ case 481:
     ;
     break;}
 case 482:
-#line 4103 "Gmsh.y"
+#line 4104 "Gmsh.y"
 {
       yyval.c = (char *)Malloc((strlen(yyvsp[-1].c)+1)*sizeof(char));
       int i;
@@ -9140,13 +9140,13 @@ case 482:
     ;
     break;}
 case 483:
-#line 4117 "Gmsh.y"
+#line 4118 "Gmsh.y"
 {
       yyval.c = yyvsp[-1].c;
     ;
     break;}
 case 484:
-#line 4121 "Gmsh.y"
+#line 4122 "Gmsh.y"
 {
       char tmpstring[1024];
       int i = PrintListOfDouble(yyvsp[-3].c, yyvsp[-1].l, tmpstring);
@@ -9167,7 +9167,7 @@ case 484:
     ;
     break;}
 case 485:
-#line 4140 "Gmsh.y"
+#line 4141 "Gmsh.y"
 { 
       char* (*pStrOpt)(int num, int action, char *value);
       StringXString *pStrCat;
@@ -9185,7 +9185,7 @@ case 485:
     ;
     break;}
 case 486:
-#line 4156 "Gmsh.y"
+#line 4157 "Gmsh.y"
 { 
       char* (*pStrOpt)(int num, int action, char *value);
       StringXString *pStrCat;
@@ -9424,7 +9424,7 @@ yyerrhandle:
     }
   return 1;
 }
-#line 4173 "Gmsh.y"
+#line 4174 "Gmsh.y"
 
 
 void DeleteSymbol(void *a, void *b){
diff --git a/Parser/Gmsh.y b/Parser/Gmsh.y
index 44c01ec79b..c0ca20c875 100644
--- a/Parser/Gmsh.y
+++ b/Parser/Gmsh.y
@@ -1,5 +1,5 @@
 %{
-// $Id: Gmsh.y,v 1.199 2005-01-14 17:54:26 geuzaine Exp $
+// $Id: Gmsh.y,v 1.200 2005-01-16 20:41:40 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -2207,6 +2207,7 @@ Shape :
 
   // Volumes
 
+  // for backward compatibility:
   | tComplex tVolume '(' FExpr ')' tAFFECT ListOfDouble tEND
     {
       int num = (int)$4;
@@ -2415,7 +2416,7 @@ Delete :
       }
       List_Delete($3);
     }
-    | tDelete tSTRING '[' FExpr ']' tEND
+  | tDelete tSTRING '[' FExpr ']' tEND
     {
       if(!strcmp($2, "View")){
 	RemoveViewByIndex((int)$4);
@@ -2425,7 +2426,7 @@ Delete :
       }
       Free($2);
     }
-    | tDelete tSTRING tEND
+  | tDelete tSTRING tEND
     {
       if(!strcmp($2, "Meshes") || !strcmp($2, "All")){
 	Init_Mesh(THEM);
@@ -2435,7 +2436,7 @@ Delete :
       }
       Free($2);
     }
-    | tDelete tSTRING tSTRING tEND
+  | tDelete tSTRING tSTRING tEND
     {
       if(!strcmp($2, "Empty") && !strcmp($3, "Views")){
 	for(int i = List_Nbr(CTX.post.list) - 1; i >= 0; i--){
diff --git a/Parser/Gmsh.yy.cpp b/Parser/Gmsh.yy.cpp
index 67a3b5e7f9..cfcb8d683e 100644
--- a/Parser/Gmsh.yy.cpp
+++ b/Parser/Gmsh.yy.cpp
@@ -2,7 +2,7 @@
 /* A lexical scanner generated by flex */
 
 /* Scanner skeleton version:
- * $Header: /cvsroot/gmsh/Parser/Gmsh.yy.cpp,v 1.227 2005-01-14 17:54:26 geuzaine Exp $
+ * $Header: /cvsroot/gmsh/Parser/Gmsh.yy.cpp,v 1.228 2005-01-16 20:41:40 geuzaine Exp $
  */
 
 #define FLEX_SCANNER
@@ -1047,7 +1047,7 @@ char *yytext;
 #line 1 "Gmsh.l"
 #define INITIAL 0
 #line 2 "Gmsh.l"
-// $Id: Gmsh.yy.cpp,v 1.227 2005-01-14 17:54:26 geuzaine Exp $
+// $Id: Gmsh.yy.cpp,v 1.228 2005-01-16 20:41:40 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -3326,10 +3326,12 @@ void skipcomments(void){
 }
 
 void parsestring(char endchar){
-  int c, i;
+  int c;
   char tmp[1024];
-
-  i = 0;
+  
+  // Note that we keep special characters (end-of-line \n, tabs \t,
+  // etc.) "as is" in the output string: see yyinput() above
+  int i = 0;
   while ((c = yyinput()) != endchar) {
     if(c == EOF){
       Msg(GERROR, "End of file in string");
diff --git a/Parser/Makefile b/Parser/Makefile
index 05999552a9..391bcea8de 100644
--- a/Parser/Makefile
+++ b/Parser/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.68 2005-01-08 20:15:17 geuzaine Exp $
+# $Id: Makefile,v 1.69 2005-01-16 20:41:41 geuzaine Exp $
 #
 # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 #
@@ -26,8 +26,8 @@ INCLUDE = -I../Common -I../DataStr -I../Geo -I../Graphics\
           -I../Mesh -I../Numeric -I../Fltk -I../Plugin -I../Parallel
 CFLAGS  = ${OPTIM} ${FLAGS} ${INCLUDE}
 
-SRC = Gmsh.yy.cpp\
-      Gmsh.tab.cpp\
+SRC = Gmsh.tab.cpp\
+      Gmsh.yy.cpp\
       OpenFile.cpp\
       FunctionManager.cpp
 
@@ -47,11 +47,15 @@ ${LIB}: ${OBJ}
 Gmsh.tab.o:
 	${CXX} ${FLAGS} ${INCLUDE} -c $<
 
-parser:
+Gmsh.tab.cpp: Gmsh.y
 	bison --output Gmsh.tab.cpp -d Gmsh.y 
-	flex  -oGmsh.yy.cpp Gmsh.l
 	if [ -r Gmsh.tab.cpp.h ]; then mv Gmsh.tab.cpp.h Gmsh.tab.hpp ; fi
 
+Gmsh.yy.cpp: Gmsh.l
+	flex -oGmsh.yy.cpp Gmsh.l
+
+parser: Gmsh.yy.cpp Gmsh.tab.cpp
+
 clean:
 	rm -f *.o
 
@@ -64,14 +68,6 @@ depend:
 	rm -f Makefile.new
 
 # DO NOT DELETE THIS LINE
-Gmsh.yy.o: Gmsh.yy.cpp ../Common/Gmsh.h ../Common/Message.h \
-  ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
-  ../DataStr/avl.h ../DataStr/Tools.h ../Numeric/Numeric.h ../Geo/Geo.h \
-  ../Geo/CAD.h ../Mesh/Mesh.h ../Mesh/Vertex.h ../Mesh/Element.h \
-  ../Mesh/Simplex.h ../Mesh/Face.h ../Mesh/Edge.h ../Geo/ExtrudeParams.h \
-  ../Mesh/DiscreteSurface.h ../Common/VertexArray.h \
-  ../Common/SmoothNormals.h ../Mesh/Metric.h ../Mesh/Matrix.h \
-  Gmsh.tab.hpp
 Gmsh.tab.o: Gmsh.tab.cpp ../Plugin/PluginManager.h ../Plugin/Plugin.h \
   ../Common/Options.h ../Common/Message.h ../Common/Views.h \
   ../Common/ColorTable.h ../DataStr/List.h ../Common/VertexArray.h \
@@ -86,6 +82,14 @@ Gmsh.tab.o: Gmsh.tab.cpp ../Plugin/PluginManager.h ../Plugin/Plugin.h \
   ../Mesh/Create.h ../Geo/StepGeomDatabase.h ../Common/Colors.h Parser.h \
   OpenFile.h ../Common/CommandLine.h FunctionManager.h ../Common/Timer.h \
   ../Graphics/CreateFile.h ../Common/Visibility.h
+Gmsh.yy.o: Gmsh.yy.cpp ../Common/Gmsh.h ../Common/Message.h \
+  ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
+  ../DataStr/avl.h ../DataStr/Tools.h ../Numeric/Numeric.h ../Geo/Geo.h \
+  ../Geo/CAD.h ../Mesh/Mesh.h ../Mesh/Vertex.h ../Mesh/Element.h \
+  ../Mesh/Simplex.h ../Mesh/Face.h ../Mesh/Edge.h ../Geo/ExtrudeParams.h \
+  ../Mesh/DiscreteSurface.h ../Common/VertexArray.h \
+  ../Common/SmoothNormals.h ../Mesh/Metric.h ../Mesh/Matrix.h \
+  Gmsh.tab.hpp
 OpenFile.o: OpenFile.cpp ../Common/Gmsh.h ../Common/Message.h \
   ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
   ../DataStr/avl.h ../DataStr/Tools.h ../Numeric/Numeric.h \
diff --git a/doc/gmsh.html b/doc/gmsh.html
index 1eec7a1ebd..f5b36966e2 100644
--- a/doc/gmsh.html
+++ b/doc/gmsh.html
@@ -178,6 +178,9 @@ thumbnail"></a>
     (P. Geuzaine).
 <li>Lenna as background mesh:
     <a href="/gmsh/gallery/lenna.gif">pict1</a>.
+<li>Turbomachine:
+    <a href="/gmsh/gallery/pressure-ring.pbg">pict1</a>
+    (P. Geuzaine).
 <li>Parts of a magnetron: 
     <a href="/gmsh/gallery/magnetron1.gif">pict1</a>,
     <a href="/gmsh/gallery/magnetron2.gif">pict2</a>,
diff --git a/utils/solvers/c++/GmshClient.h b/utils/solvers/c++/GmshClient.h
index f5e5a5916b..847c659599 100644
--- a/utils/solvers/c++/GmshClient.h
+++ b/utils/solvers/c++/GmshClient.h
@@ -1,33 +1,31 @@
 #ifndef _GMSH_CLIENT_H_
 #define _GMSH_CLIENT_H_
 
-/*
- * Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, and/or sell copies of the
- * Software, and to permit persons to whom the Software is furnished
- * to do so, provided that the above copyright notice(s) and this
- * permission notice appear in all copies of the Software and that
- * both the above copyright notice(s) and this permission notice
- * appear in supporting documentation.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
- * ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
- * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
- * 
- * Please report all bugs and problems to <gmsh@geuz.org>.
- */
+// Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, and/or sell copies of the
+// Software, and to permit persons to whom the Software is furnished
+// to do so, provided that the above copyright notice(s) and this
+// permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice
+// appear in supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
+// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
+// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+// OF THIS SOFTWARE.
+// 
+// Please report all bugs and problems to <gmsh@geuz.org>.
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -46,16 +44,26 @@
 
 class GmshClient {
  private:
+  typedef enum{ CLIENT_START    = 1,
+		CLIENT_STOP     = 2,
+		CLIENT_INFO     = 10,
+		CLIENT_WARNING  = 11,
+		CLIENT_ERROR    = 12,
+		CLIENT_PROGRESS = 13,
+		CLIENT_VIEW     = 20,
+		CLIENT_OPTION_1 = 100,
+		CLIENT_OPTION_2 = 101,
+		CLIENT_OPTION_3 = 102,
+		CLIENT_OPTION_4 = 103,
+		CLIENT_OPTION_5 = 104 } MessageType;
   int _sock;
   void _SendData(void *buffer, int bytes)
   {
-    int sofar, remaining, len;
-    char *buf;
-    buf = (char *)buffer;
-    sofar = 0;
-    remaining = bytes;
+    char *buf = (char *)buffer;
+    int sofar = 0;
+    int remaining = bytes;
     do {
-      len = write(_sock, buf + sofar, remaining);
+      int len = write(_sock, buf + sofar, remaining);
       sofar += len;
       remaining -= len;
     } while(remaining > 0);
@@ -86,107 +94,99 @@ class GmshClient {
   ~GmshClient(){}
   int Connect(char *sockname)
   {
-    struct sockaddr_un addr_un;
-    struct sockaddr_in addr_in;
-    int len, sock;
-    int tries;
-    struct hostent *server;
-    int portno, remotelen;
-    char remote[256], *port;
-    
-    /* slight delay to be sure that the socket is bound by the
-       server before we attempt to connect to it... */
+    // slight delay to be sure that the socket is bound by the
+    // server before we attempt to connect to it...
     _Idle(0.1);
-    
+
+    int portno;
+    char remote[256];
     if(strstr(sockname, "/") || strstr(sockname, "\\") || !strstr(sockname, ":")){
-      /* UNIX socket (testing ":" is not enough with Windows paths) */
+      // UNIX socket (testing ":" is not enough with Windows paths)
       portno = -1;
     }
     else{
-      /* INET socket */
-      port = strstr(sockname, ":");
+      // INET socket
+      char *port = strstr(sockname, ":");
       portno = atoi(port+1);
-      remotelen = strlen(sockname) - strlen(port);
+      int remotelen = strlen(sockname) - strlen(port);
       if(remotelen > 0)
 	strncpy(remote, sockname, remotelen);
       remote[remotelen] = '\0';
     }
     
-    /* create socket */
+    // create socket
     
     if(portno < 0){
-      sock = socket(PF_UNIX, SOCK_STREAM, 0);
-      if(sock < 0)
-	return -1;  /* Error: Couldn't create socket */
-      /* try to connect socket to given name */
+      _sock = socket(PF_UNIX, SOCK_STREAM, 0);
+      if(_sock < 0)
+	return -1;  // Error: Couldn't create socket
+      // try to connect socket to given name
+      struct sockaddr_un addr_un;
       strcpy(addr_un.sun_path, sockname);
       addr_un.sun_family = AF_UNIX;
-      len = strlen(addr_un.sun_path) + sizeof(addr_un.sun_family);
-      for(tries = 0; tries < 5; tries++) {
-	if(connect(sock, (struct sockaddr *)&addr_un, len) >= 0){
-	  _sock = sock;
-	  return sock;
-	}
+      for(int tries = 0; tries < 5; tries++) {
+	if(connect(_sock, (struct sockaddr *)&addr_un, sizeof(addr_un)) >= 0)
+	  return _sock;
 	_Idle(0.1);
       }
     }
     else{
-      /* try to connect socket to given name */
-      sock = socket(AF_INET, SOCK_STREAM, 0);
-      if(sock < 0)
-	return -1;  /* Error: Couldn't create socket */
+      // try to connect socket to given name
+      _sock = socket(AF_INET, SOCK_STREAM, 0);
+      if(_sock < 0)
+	return -1; // Error: Couldn't create socket
+      struct hostent *server;
       if(!(server = gethostbyname(remote)))
-	return -3; /* Error: No such host */
+	return -3; // Error: No such host
+      struct sockaddr_in addr_in;
       memset((char *) &addr_in, 0, sizeof(addr_in));
       addr_in.sin_family = AF_INET;
       memcpy((char *)&addr_in.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
       addr_in.sin_port = htons(portno);
       addr_in.sin_addr.s_addr = INADDR_ANY;
-      for(tries = 0; tries < 5; tries++) {
-	if(connect(sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) >= 0){
-	  _sock = sock;
-	  return sock;
-	}
+      for(int tries = 0; tries < 5; tries++) {
+	if(connect(_sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) >= 0)
+	  return _sock;
 	_Idle(0.1);
       }
     }
-    return -2;    /* Error: Couldn't connect */
+    return -2; // Error: Couldn't connect
   }
   void Start(int pid)
   {
     char tmp[256];
     sprintf(tmp, "%d", getpid());
-    _SendString(1, tmp);
+    _SendString(CLIENT_START, tmp);
   }
   void Stop()
   {
-    _SendString(2, "Goodbye!");
+    _SendString(CLIENT_STOP, "Goodbye!");
   }
   void Info(char *str)
   {
-    _SendString(10, str);
+    _SendString(CLIENT_INFO, str);
   }
   void Warning(char *str)
   {
-    _SendString(11, str);
+    _SendString(CLIENT_WARNING, str);
   }
   void Error(char *str)
   {
-    _SendString(12, str);
+    _SendString(CLIENT_ERROR, str);
   }
   void Progress(char *str)
   {
-    _SendString(13, str);
+    _SendString(CLIENT_PROGRESS, str);
   }
   void View(char *str)
   {
-    _SendString(20, str);
+    _SendString(CLIENT_VIEW, str);
   }
   void Option(int num, char *str)
   {
     if(num < 1) num = 1;
     if(num > 5) num = 5;
-    _SendString(100 + num - 1, str);
+    _SendString(CLIENT_OPTION_1 + num - 1, str);
   }
   void Disconnect()
   {
diff --git a/utils/solvers/c++/Makefile b/utils/solvers/c++/Makefile
index 4d60902530..2baa56df25 100644
--- a/utils/solvers/c++/Makefile
+++ b/utils/solvers/c++/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.3 2005-01-14 17:54:01 geuzaine Exp $
+# $Id: Makefile,v 1.4 2005-01-16 20:41:42 geuzaine Exp $
 #
 # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 #
@@ -21,7 +21,7 @@
 
 include ../../../variables
 
-solver: solver.cpp
+solver.exe: solver.cpp
 	${CXX} ${FLAGS} ${OPTIM} -o solver.exe solver.cpp
 
 clean:
diff --git a/utils/solvers/c++/solver.cpp b/utils/solvers/c++/solver.cpp
index 5d61838f22..c9c22c6a08 100644
--- a/utils/solvers/c++/solver.cpp
+++ b/utils/solvers/c++/solver.cpp
@@ -1,3 +1,47 @@
+// $Id: solver.cpp,v 1.2 2005-01-16 20:41:42 geuzaine Exp $
+//
+// Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, and/or sell copies of the
+// Software, and to permit persons to whom the Software is furnished
+// to do so, provided that the above copyright notice(s) and this
+// permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice
+// appear in supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
+// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
+// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+// OF THIS SOFTWARE.
+// 
+// Please report all bugs and problems to <gmsh@geuz.org>.
+
+// This file contains a dummy client solver for Gmsh. It does not
+// solve anything, but shows how to program your own solver to interact
+// with the Gmsh solver module.
+//
+// To compile this solver, type something like:
+//
+// g++ solver.cpp -o solver.exe
+//
+// To run it, merge the contents of the file solver.opt into your
+// default Gmsh option file, or lauch Gmsh with the command:
+//
+// gmsh -option solver.opt 
+//
+// You will then see a new button labeled "My C++ solver" in Gmsh's
+// solver menu.
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
diff --git a/utils/solvers/c/GmshClient.c b/utils/solvers/c/GmshClient.c
index 129e0b0646..96759749fc 100644
--- a/utils/solvers/c/GmshClient.c
+++ b/utils/solvers/c/GmshClient.c
@@ -1,6 +1,6 @@
-/* $Id: GmshClient.c,v 1.1 2005-01-13 20:36:54 geuzaine Exp $ */
+/* $Id: GmshClient.c,v 1.2 2005-01-16 20:41:42 geuzaine Exp $ */
 /*
- * Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
+ * Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -24,7 +24,7 @@
  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  * OF THIS SOFTWARE.
  * 
- *  Please report all bugs and problems to <gmsh@geuz.org>.
+ * Please report all bugs and problems to <gmsh@geuz.org>.
  *
  * Contributor(s):
  *   Christopher Stott
@@ -83,7 +83,7 @@ int Gmsh_Connect(char *sockname)
 {
   struct sockaddr_un addr_un;
   struct sockaddr_in addr_in;
-  int len, sock;
+  int sock;
   int tries;
   struct hostent *server;
   int portno, remotelen;
@@ -112,13 +112,12 @@ int Gmsh_Connect(char *sockname)
   if(portno < 0){
     sock = socket(PF_UNIX, SOCK_STREAM, 0);
     if(sock < 0)
-      return -1;  /* Error: Couldn't create socket */
+      return -1; /* Error: Couldn't create socket */
     /* try to connect socket to given name */
     strcpy(addr_un.sun_path, sockname);
     addr_un.sun_family = AF_UNIX;
-    len = strlen(addr_un.sun_path) + sizeof(addr_un.sun_family);
     for(tries = 0; tries < 5; tries++) {
-      if(connect(sock, (struct sockaddr *)&addr_un, len) >= 0)
+      if(connect(sock, (struct sockaddr *)&addr_un, sizeof(addr_un)) >= 0)
 	return sock;
       Socket_Idle(0.1);
     }
@@ -127,7 +126,7 @@ int Gmsh_Connect(char *sockname)
     /* try to connect socket to given name */
     sock = socket(AF_INET, SOCK_STREAM, 0);
     if(sock < 0)
-      return -1;  /* Error: Couldn't create socket */
+      return -1; /* Error: Couldn't create socket */
     if(!(server = gethostbyname(remote)))
       return -3; /* Error: No such host */
     memset((char *) &addr_in, 0, sizeof(addr_in));
@@ -142,7 +141,7 @@ int Gmsh_Connect(char *sockname)
     }
   }
 
-  return -2;    /* Error: Couldn't connect */
+  return -2; /* Error: Couldn't connect */
 }
 
 void Gmsh_SendString(int socket, int type, char str[])
diff --git a/utils/solvers/c/GmshClient.h b/utils/solvers/c/GmshClient.h
index c0bb75d710..b0e2610841 100644
--- a/utils/solvers/c/GmshClient.h
+++ b/utils/solvers/c/GmshClient.h
@@ -2,7 +2,7 @@
 #define _GMSH_CLIENT_H_
 
 /*
- * Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
+ * Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
diff --git a/utils/solvers/c/Makefile b/utils/solvers/c/Makefile
index 74c06022eb..ce3adcc514 100644
--- a/utils/solvers/c/Makefile
+++ b/utils/solvers/c/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.2 2005-01-14 02:27:00 geuzaine Exp $
+# $Id: Makefile,v 1.3 2005-01-16 20:41:42 geuzaine Exp $
 #
 # Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 #
@@ -21,8 +21,8 @@
 
 include ../../../variables
 
-mysolver: mysolver.c GmshClient.c
-	${CXX} ${FLAGS} ${OPTIM} -o mysolver.exe mysolver.c GmshClient.c
+solver.exe: solver.c GmshClient.c
+	${CC} ${FLAGS} ${OPTIM} -o solver.exe solver.c GmshClient.c
 
 clean:
 	rm -f *.o *.exe *.pos
diff --git a/utils/solvers/c/mysolver.opt b/utils/solvers/c/mysolver.opt
deleted file mode 100644
index c03fca0237..0000000000
--- a/utils/solvers/c/mysolver.opt
+++ /dev/null
@@ -1,30 +0,0 @@
-// These options define 'mysolver.exe' as the second solver in Gmsh's
-// solver module, under the name 'My C Solver'.
-Solver.Name1 = "My C solver";
-Solver.Help1 = "A simple example of the client/server 
-solver implementation in Gmsh...";
-Solver.Executable1 = "./mysolver.exe";
-Solver.Extension1 = "";
-Solver.MeshName1 = "";
-Solver.MeshCommand1 = "";
-Solver.SocketCommand1 = "-socket %s";
-Solver.NameCommand1 = "%s";
-Solver.OptionCommand1 = "-options";
-Solver.FirstOption1 = "Option";
-Solver.SecondOption1 = "";
-Solver.ThirdOption1 = "";
-Solver.FourthOption1 = "";
-Solver.FifthOption1 = "";
-Solver.FirstButton1 = "Run";
-Solver.FirstButtonCommand1 = "-run %s";
-Solver.SecondButton1 = "";
-Solver.SecondButtonCommand1 = "";
-Solver.ThirdButton1 = "";
-Solver.ThirdButtonCommand1 = "";
-Solver.FourthButton1 = "";
-Solver.FourthButtonCommand1 = "";
-Solver.FifthButton1 = "";
-Solver.FifthButtonCommand1 = "";
-Solver.ClientServer1 = 1;
-Solver.MergeViews1 = 1;
-Solver.PopupMessages1 = 1;
diff --git a/utils/solvers/c/mysolver.c b/utils/solvers/c/solver.c
similarity index 94%
rename from utils/solvers/c/mysolver.c
rename to utils/solvers/c/solver.c
index f301cb10b0..a5a1da0526 100644
--- a/utils/solvers/c/mysolver.c
+++ b/utils/solvers/c/solver.c
@@ -1,6 +1,6 @@
-/* $Id: mysolver.c,v 1.1 2005-01-13 20:36:54 geuzaine Exp $ */
+/* $Id: solver.c,v 1.1 2005-01-16 20:41:42 geuzaine Exp $ */
 /*
- * Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle
+ * Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
@@ -33,12 +33,12 @@
    
    To compile this solver, type something like:
 
-   gcc -o mysolver.exe mysolver.c GmshClient.c
+   gcc -o solver.exe solver.c GmshClient.c
    
-   To run it, merge the contents of the file mysolver.opt into your
+   To run it, merge the contents of the file solver.opt into your
    default Gmsh option file, or lauch Gmsh with the command:
    
-   gmsh -option mysolver.opt 
+   gmsh -option solver.opt 
 
    You will then see a new button labeled "My C solver" in Gmsh's
    solver menu.
@@ -184,7 +184,7 @@ int main(int argc, char *argv[])
       }
       sprintf(tmp, "Done with %s!", name);
       Gmsh_SendString(s, GMSH_CLIENT_INFO, tmp);
-      file = fopen("mysolver.pos", "wb");
+      file = fopen("solver.pos", "wb");
       if(!file) {
         Gmsh_SendString(s, GMSH_CLIENT_ERROR, "Unable to open output file");
       }
@@ -193,7 +193,7 @@ int main(int argc, char *argv[])
 	fprintf(file, "ST(0,0,0,1,0,0,0,1,0){0,1,2};\n");
         fprintf(file, "};\n");
         fclose(file);
-        Gmsh_SendString(s, GMSH_CLIENT_VIEW, "mysolver.pos");
+        Gmsh_SendString(s, GMSH_CLIENT_VIEW, "solver.pos");
       }
       break;
     }
@@ -206,5 +206,5 @@ int main(int argc, char *argv[])
   }
 
   /* 4. That's it! */
-
+  return 0;
 }
diff --git a/utils/solvers/c/solver.opt b/utils/solvers/c/solver.opt
new file mode 100644
index 0000000000..bb035e8164
--- /dev/null
+++ b/utils/solvers/c/solver.opt
@@ -0,0 +1,15 @@
+// These options define 'solver.exe' as the second solver in Gmsh's
+// solver module, under the name 'My C Solver'.
+Solver.Name1 = "My C solver";
+Solver.Help1 = "A simple example of the client/server 
+solver implementation in Gmsh...";
+Solver.Executable1 = "./solver.exe";
+Solver.SocketCommand1 = "-socket %s";
+Solver.NameCommand1 = "%s";
+Solver.OptionCommand1 = "-options";
+Solver.FirstOption1 = "Option";
+Solver.FirstButton1 = "Run";
+Solver.FirstButtonCommand1 = "-run %s";
+Solver.ClientServer1 = 1;
+Solver.MergeViews1 = 1;
+Solver.PopupMessages1 = 1;
diff --git a/utils/solvers/perl/GMSH_CLIENT.pm b/utils/solvers/perl/GMSH_CLIENT.pm
index 0d8eae4498..ab98befc77 100755
--- a/utils/solvers/perl/GMSH_CLIENT.pm
+++ b/utils/solvers/perl/GMSH_CLIENT.pm
@@ -1,4 +1,4 @@
-# $Id: GMSH_CLIENT.pm,v 1.1 2005-01-13 20:36:54 geuzaine Exp $
+# $Id: GMSH_CLIENT.pm,v 1.2 2005-01-16 20:41:42 geuzaine Exp $
 #
 # Copyright (c) 2002 Laurent CHAMPANEY <laurent.champaney@meca.uvsq.fr>. 
 # All rights reserved.
@@ -50,6 +50,7 @@ sub SendString (*$;$$) {
 sub Disconnect (*) {
 	$socket = @_;
 	close $socket;
+	return;
 };
 
 sub Connect (*$;$$) {
diff --git a/utils/solvers/perl/myperlsolver.opt b/utils/solvers/perl/myperlsolver.opt
deleted file mode 100755
index 9a260c7f13..0000000000
--- a/utils/solvers/perl/myperlsolver.opt
+++ /dev/null
@@ -1,30 +0,0 @@
-// These options define 'myperlsolver.pl' as the second solver in
-// Gmsh's solver module, under the name'My Perl Solver'. 
-Solver.Name1 = "My Perl solver";
-Solver.Help1 = "A simple perl example of the client/server
-solver implementation in Gmsh...";
-Solver.Executable1 = "./myperlsolver.pl";
-Solver.Extension1 = "";
-Solver.MeshName1 = "";
-Solver.MeshCommand1 = "";
-Solver.SocketCommand1 = "-socket %s";
-Solver.NameCommand1 = "%s";
-Solver.OptionCommand1 = "-options";
-Solver.FirstOption1 = "Option";
-Solver.SecondOption1 = "";
-Solver.ThirdOption1 = "";
-Solver.FourthOption1 = "";
-Solver.FifthOption1 = "";
-Solver.FirstButton1 = "Run";
-Solver.FirstButtonCommand1 = "-run %s";
-Solver.SecondButton1 = "";
-Solver.SecondButtonCommand1 = "";
-Solver.ThirdButton1 = "";
-Solver.ThirdButtonCommand1 = "";
-Solver.FourthButton1 = "";
-Solver.FourthButtonCommand1 = "";
-Solver.FifthButton1 = "";
-Solver.FifthButtonCommand1 = "";
-Solver.ClientServer1 = 1;
-Solver.MergeViews1 = 1;
-Solver.PopupMessages1 = 1;
diff --git a/utils/solvers/perl/solver.opt b/utils/solvers/perl/solver.opt
new file mode 100755
index 0000000000..b9df3181e6
--- /dev/null
+++ b/utils/solvers/perl/solver.opt
@@ -0,0 +1,15 @@
+// These options define 'solver.pl' as the second solver in
+// Gmsh's solver module, under the name'My Perl Solver'. 
+Solver.Name1 = "My Perl solver";
+Solver.Help1 = "A simple perl example of the client/server
+solver implementation in Gmsh...";
+Solver.Executable1 = "./solver.pl";
+Solver.SocketCommand1 = "-socket %s";
+Solver.NameCommand1 = "%s";
+Solver.OptionCommand1 = "-options";
+Solver.FirstOption1 = "Option";
+Solver.FirstButton1 = "Run";
+Solver.FirstButtonCommand1 = "-run %s";
+Solver.ClientServer1 = 1;
+Solver.MergeViews1 = 1;
+Solver.PopupMessages1 = 1;
diff --git a/utils/solvers/perl/myperlsolver.pl b/utils/solvers/perl/solver.pl
similarity index 91%
rename from utils/solvers/perl/myperlsolver.pl
rename to utils/solvers/perl/solver.pl
index 0185fb27e4..0f55f2b40e 100755
--- a/utils/solvers/perl/myperlsolver.pl
+++ b/utils/solvers/perl/solver.pl
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# $Id: myperlsolver.pl,v 1.1 2005-01-13 20:36:54 geuzaine Exp $
+# $Id: solver.pl,v 1.1 2005-01-16 20:41:42 geuzaine Exp $
 #
 # Copyright (c) 2002 Laurent CHAMPANEY <laurent.champaney@meca.uvsq.fr>. 
 #
@@ -8,10 +8,10 @@
 # solve anything, but shows how to program your own perl solver 
 # to interact with the Gmsh solver module.
 #   
-# To test this solver, copy the myperlsolver.opt file into your default
+# To test this solver, copy the solver.opt file into your default
 # Gmsh option file, or lauch Gmsh with the command:
 #   
-# gmsh -option myperlsolver.opt 
+# gmsh -option solver.opt 
 #
 #
 use Getopt::Long;
@@ -86,13 +86,13 @@ if ($opt_run) {
 	$mess = "Done with $problem!"; 
 	GMSH_CLIENT::SendString(CLIENT, $GMSH_CLIENT::INFO, $mess);
 #
-	open (POSFIC, ">mysolver.pos")
+	open (POSFIC, ">solver.pos")
 		or die "Unable to open output file";
 	print POSFIC ("View \"$opt_run\"{\n");
 	print POSFIC "ST(0,0,0,1,0,0,0,1,0){0,1,2};\n";
 	print POSFIC "};\n";
 	close POSFIC;
-	GMSH_CLIENT::SendString(CLIENT, $GMSH_CLIENT::VIEW, "mysolver.pos");
+	GMSH_CLIENT::SendString(CLIENT, $GMSH_CLIENT::VIEW, "solver.pos");
 };
 #
 #   3.3. We can now disconnect the solver from Gmsh:
-- 
GitLab