diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index 3622e57623cc89f2883f0bdf2cd044af6979f3b7..5caff558e19b74c4755dfdb61d364e990bf48fba 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -27,10 +27,11 @@
 #define FORMAT_PNGTEX        23
 #define FORMAT_PDF           24
 #define FORMAT_PDFTEX        25
-#define FORMAT_LC            26
+#define FORMAT_POS           26
 #define FORMAT_STL           27
 #define FORMAT_P3D           28
 #define FORMAT_SVG           29
+#define FORMAT_MESH          30
 
 // Element types in .msh file format
 #define LGN1 1
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 71fe96964c4df986d00d99a212734cd425127411..34a1bc34c251e07cd15ff6f571f028cd1f9db3e0 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.424 2006-08-07 13:57:13 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.425 2006-08-07 21:04:05 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -593,8 +593,9 @@ static char *file_types =
   "*"
   "\tGmsh geometry (*.geo)"
   "\tGmsh mesh (*.msh)"
-  "\tGmsh post-processing view (*.pos)"
-  "\tSTL triangulation (*.stl)"
+  "\tGmsh post-processing (*.pos)"
+  "\tSTL mesh (*.stl)"
+  "\tINRIA mesh (*.mesh)"
   "\tJPEG (*.jpg)"
   "\tPNG (*.png)"
   "\tBMP (*.bmp)"
@@ -643,9 +644,9 @@ int _save_msh(char *name)
   return msh_dialog(name);
 }
 
-int _save_lc(char *name)
+int _save_pos(char *name)
 {
-  CreateOutputFile(name, FORMAT_LC);
+  CreateOutputFile(name, FORMAT_POS);
   return 1;
 }
 
@@ -655,6 +656,12 @@ int _save_unv(char *name)
   return 1;
 }
 
+int _save_mesh(char *name)
+{
+  CreateOutputFile(name, CTX.mesh.format = FORMAT_MESH);
+  return 1;
+}
+
 int _save_vrml(char *name)
 {
   CreateOutputFile(name, CTX.mesh.format = FORMAT_VRML);
@@ -773,35 +780,40 @@ void file_save_as_cb(CALLBACK_ARGS)
   static char *pat = NULL;
   static patXfunc formats[] = {
     {"Guess from extension (*.*)", _save_auto},
+    {" ", _save_auto},
+    {"Gmsh mesh (*.msh)", _save_msh},
+    {"Gmsh mesh statistics (*.pos)", _save_pos},
     {"Gmsh options (*.opt)", _save_options},
     {"Gmsh unrolled geometry (*.geo)", _save_geo},
-    {"Gmsh mesh (*.msh)", _save_msh},
-    {"Gmsh mesh statistics (*.pos)", _save_lc},
+    {"  ", _save_auto},
     {"I-DEAS universal mesh (*.unv)", _save_unv},
+    {"INRIA mesh (*.mesh)", _save_mesh},
+    {"STL mesh (*.stl)", _save_stl},
     {"VRML surface mesh (*.wrl)", _save_vrml},
-    {"STL surface mesh (*.stl)", _save_stl},
+    {"   ", _save_auto},
+    {"Encapsulated PostScript (*.eps)", _save_eps},
     {"GIF (*.gif)", _save_gif},
 #if defined(HAVE_LIBJPEG)
     {"JPEG (*.jpg)", _save_jpeg},
 #endif
-#if defined(HAVE_LIBPNG)
-    {"PNG (*.png)", _save_png},
-#endif
-    {"PostScript (*.ps)", _save_ps},
-    {"Encapsulated PostScript (*.eps)", _save_eps},
-    {"PDF (*.pdf)", _save_pdf},
-    {"SVG (*.svg)", _save_svg},
-    {"PPM (*.ppm)", _save_ppm},
+    {"LaTeX EPS part without text (*.eps)", _save_epstex},
 #if defined(HAVE_LIBJPEG)
     {"LaTeX JPEG part without text (*.jpg)", _save_jpegtex},
 #endif
+    {"LaTeX PDF part without text (*.pdf)", _save_pdftex},
 #if defined(HAVE_LIBPNG)
     {"LaTeX PNG part without text (*.png)", _save_pngtex},
 #endif
-    {"LaTeX EPS part without text (*.eps)", _save_epstex},
-    {"LaTeX PDF part without text (*.pdf)", _save_pdftex},
     {"LaTeX text part (*.tex)", _save_tex},
-    {"YUV (*.yuv)", _save_yuv}
+    {"PDF (*.pdf)", _save_pdf},
+#if defined(HAVE_LIBPNG)
+    {"PNG (*.png)", _save_png},
+#endif
+    {"PostScript (*.ps)", _save_ps},
+    {"PPM (*.ppm)", _save_ppm},
+    {"SVG (*.svg)", _save_svg},
+    {"YUV (*.yuv)", _save_yuv},
+    {"    ", _save_auto},
   };
 
   nbformats = sizeof(formats) / sizeof(formats[0]);
@@ -829,7 +841,7 @@ void file_save_as_cb(CALLBACK_ARGS)
       if(!formats[i].func(name))
 	goto test;
     }
-    else        // handle any additional automatic fltk filter
+    else // handle any additional automatic fltk filter
       _save_auto(name);
   }
 }
diff --git a/Geo/GModel.h b/Geo/GModel.h
index 1793db774a185831c3fe02ddd16397534ea568e8..1864c660f578786de0ec2042c14d8cf4fd36d576 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -89,6 +89,8 @@ class GModel
   int writeSTL(const std::string &name, double scalingFactor=1.0);
   int writeVRML(const std::string &name, double scalingFactor=1.0);
   int writeUNV(const std::string &name, double scalingFactor=1.0);
+  int readMESH(const std::string &name);
+  int writeMESH(const std::string &name, double scalingFactor=1.0);
 };
 
 #endif
diff --git a/Geo/GModelIO.cpp b/Geo/GModelIO.cpp
index 96b66bc155dc42113f6d47ed0238fd0d1723cf0e..dadc841d6b51c6d47a6bd0f78ecd4c496662a2cd 100644
--- a/Geo/GModelIO.cpp
+++ b/Geo/GModelIO.cpp
@@ -31,14 +31,6 @@ static int getNumVerticesForElementTypeMSH(int type)
   }
 }
 
-template<class T>
-static void associateEntityWithVertices(GEntity *ge, std::vector<T*> &elements)
-{
-  for(unsigned int i = 0; i < elements.size(); i++)
-    for(int j = 0; j < elements[i]->getNumVertices(); j++)
-      elements[i]->getVertex(j)->setEntity(ge);
-}
-
 template<class T>
 void copyElements(std::vector<T*> &dst, const std::vector<MElement*> &src)
 {
@@ -91,6 +83,52 @@ static void storeElementsInEntities(GModel *m, int type,
   }
 }
 
+template<class T>
+static void associateEntityWithVertices(GEntity *ge, std::vector<T*> &elements)
+{
+  for(unsigned int i = 0; i < elements.size(); i++)
+    for(int j = 0; j < elements[i]->getNumVertices(); j++)
+      elements[i]->getVertex(j)->setEntity(ge);
+}
+
+static void associateEntityWithVertices(GModel *m)
+{
+  // loop on regions, then on faces, edges and vertices and store the
+  // entity pointer in the the elements' vertices (this way we
+  // associate the entity of lowest geometrical degree with each
+  // vertex)
+  for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){
+    associateEntityWithVertices(*it, (*it)->tetrahedra);
+    associateEntityWithVertices(*it, (*it)->hexahedra);
+    associateEntityWithVertices(*it, (*it)->prisms);
+    associateEntityWithVertices(*it, (*it)->pyramids);
+  }
+  for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){
+    associateEntityWithVertices(*it, (*it)->triangles);
+    associateEntityWithVertices(*it, (*it)->quadrangles);
+  }
+  for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it){
+    associateEntityWithVertices(*it, (*it)->lines);
+  }
+  for(GModel::viter it = m->firstVertex(); it != m->lastVertex(); ++it){
+    (*it)->mesh_vertices[0]->setEntity(*it);
+  }
+}
+
+static void storeVerticesInEntities(std::map<int, MVertex*> &vertices)
+{
+  std::map<int, MVertex*>::const_iterator it = vertices.begin();
+  std::map<int, MVertex*>::const_iterator ite = vertices.end();
+  for(; it != ite; ++it){
+    MVertex *v = it->second;
+    GEntity *ge = v->onWhat();
+    if(ge) 
+      ge->mesh_vertices.push_back(v);
+    else
+      delete v; // we delete all unused vertices
+  }
+}
+
 static void storePhysicalTagsInEntities(GModel *m, int dim,
 					std::map<int, std::map<int, std::string> > &map)
 {
@@ -297,44 +335,18 @@ int GModel::readMSH(const std::string &name)
       v->mesh_vertices.push_back(it->second[0]);
     }
   }
-  
-  // loop on regions, then on faces, edges and vertices and store the
-  // entity pointer in the the elements' vertices (this way we
-  // associate the entity of lowest geometrical degree with each
-  // vertex)
-  for(riter it = firstRegion(); it != lastRegion(); ++it){
-    associateEntityWithVertices(*it, (*it)->tetrahedra);
-    associateEntityWithVertices(*it, (*it)->hexahedra);
-    associateEntityWithVertices(*it, (*it)->prisms);
-    associateEntityWithVertices(*it, (*it)->pyramids);
-  }
-  for(fiter it = firstFace(); it != lastFace(); ++it){
-    associateEntityWithVertices(*it, (*it)->triangles);
-    associateEntityWithVertices(*it, (*it)->quadrangles);
-  }
-  for(eiter it = firstEdge(); it != lastEdge(); ++it){
-    associateEntityWithVertices(*it, (*it)->lines);
-  }
-  for(viter it = firstVertex(); it != lastVertex(); ++it){
-    // special case for points: the mesh vertex has been copied here
-    // so that we can assign the entity:
-    (*it)->mesh_vertices[0]->setEntity(*it);
-    // now that this is done, we reset mesh_vertices so that it can be
-    // filled again below
+
+  // associate the correct geometrical entity with each mesh vertex
+  associateEntityWithVertices(this);
+
+  // special case for geometry vertices: now that the correct
+  // geometrical entity has been associated with the vertices, we
+  // reset mesh_vertices so that it can be filled again below
+  for(viter it = firstVertex(); it != lastVertex(); ++it)
     (*it)->mesh_vertices.clear();
-  }
 
   // store the vertices in their associated geometrical entity
-  std::map<int, MVertex*>::const_iterator it = vertices.begin();
-  std::map<int, MVertex*>::const_iterator ite = vertices.end();
-  for(; it != ite; ++it){
-    MVertex *v = it->second;
-    GEntity *ge = v->onWhat();
-    if(ge) 
-      ge->mesh_vertices.push_back(v);
-    else
-      delete v; // we delete all unused vertices
-  }
+  storeVerticesInEntities(vertices);
 
   // store the physical tags
   for(int i = 0; i < 4; i++)  
@@ -836,3 +848,149 @@ int GModel::writeUNV(const std::string &name, double scalingFactor)
   fclose(fp);
   return 1;
 }
+
+int GModel::readMESH(const std::string &name)
+{
+  FILE *fp = fopen(name.c_str(), "r");
+  if(!fp){
+    Msg(GERROR, "Unable to open file '%s'", name.c_str());
+    return 0;
+  }
+
+  char buffer[256];
+  fgets(buffer, sizeof(buffer), fp);
+
+  char str[256];
+  int format;
+  sscanf(buffer, "%s %d", str, &format);
+
+  if(format != 1){
+    Msg(GERROR, "Non-ASCII INRIA mesh import is not yet available");
+    return 0;
+  }
+
+  std::map<int, MVertex*> vertices;
+  int elementTypes[2] = {TRI1, QUA1};
+  std::map<int, std::vector<MElement*> > elements[2];
+  SBoundingBox3d bbox;
+
+  while(!feof(fp)) {
+    fgets(buffer, sizeof(buffer), fp);
+    if(buffer[0] != '#'){ // skip comments
+      sscanf(buffer, "%s", str);
+      if(!strcmp(str, "Dimension")){
+	fgets(buffer, sizeof(buffer), fp);
+      }
+      else if(!strcmp(str, "Vertices")){
+	fgets(buffer, sizeof(buffer), fp);
+	int nbv;
+	sscanf(buffer, "%d", &nbv);
+	Msg(INFO, "%d vertices", nbv);
+	for(int i = 0; i < nbv; i++) {
+	  fgets(buffer, sizeof(buffer), fp);
+	  int cl;
+	  double x, y, z;
+	  sscanf(buffer, "%lf %lf %lf %d", &x, &y, &z, &cl);
+	  bbox += SPoint3(x, y, z);
+	  vertices[i + 1] = new MVertex(x, y, z);
+	}
+      }
+      else if(!strcmp(str, "Triangles")){
+	fgets(buffer, sizeof(buffer), fp);
+	int nbt;
+	sscanf(buffer, "%d", &nbt);
+	Msg(INFO, "%d triangles", nbt);
+	for(int i = 0; i < nbt; i++) {
+	  fgets(buffer, sizeof(buffer), fp);
+	  int n1, n2, n3, cl;
+	  sscanf(buffer, "%d %d %d %d", &n1, &n2, &n3, &cl);
+	  elements[0][cl].push_back
+	    (new MTriangle(vertices[n1], vertices[n2], vertices[n3]));
+	}
+      }
+      else if(!strcmp(str, "Quadrilaterals")) {
+	fgets(buffer, sizeof(buffer), fp);
+	int nbq;
+	sscanf(buffer, "%d", &nbq);
+	Msg(INFO, "%d quadrangles", nbq);
+	for(int i = 0; i < nbq; i++) {
+	  fgets(buffer, sizeof(buffer), fp);
+	  int n1, n2, n3, n4, cl;
+	  sscanf(buffer, "%d %d %d %d %d", &n1, &n2, &n3, &n4, &cl);
+	  elements[1][cl].push_back
+	    (new MQuadrangle(vertices[n1], vertices[n2], vertices[n3], vertices[n4]));
+	}
+      }
+    }
+  }
+
+  // store the elements in their associated elementary entity. If the
+  // entity does not exist, create a new one.
+  for(int i = 0; i < 2; i++)
+    storeElementsInEntities(this, elementTypes[i], elements[i]);
+
+  // associate the correct geometrical entity with each mesh vertex
+  associateEntityWithVertices(this);
+
+  // store the vertices in their associated geometrical entity
+  storeVerticesInEntities(vertices);
+
+  boundingBox += bbox;
+
+  fclose(fp);
+  return 1;
+}
+
+int GModel::writeMESH(const std::string &name, double scalingFactor)
+{
+  FILE *fp = fopen(name.c_str(), "w");
+  if(!fp){
+    Msg(GERROR, "Unable to open file '%s'", name.c_str());
+    return 0;
+  }
+
+  fprintf(fp, " MeshVersionFormatted 1\n");
+  fprintf(fp, " Dimension\n");
+  fprintf(fp, " 3\n");
+
+  int numVertices = renumberMeshVertices();
+  fprintf(fp, " Vertices\n");
+  fprintf(fp, " %d\n", numVertices);
+  for(viter it = firstVertex(); it != lastVertex(); ++it)
+    for(unsigned int i = 0; i < (*it)->mesh_vertices.size(); i++) 
+      (*it)->mesh_vertices[i]->writeMESH(fp, scalingFactor);
+  for(eiter it = firstEdge(); it != lastEdge(); ++it)
+    for(unsigned int i = 0; i < (*it)->mesh_vertices.size(); i++)
+      (*it)->mesh_vertices[i]->writeMESH(fp, scalingFactor);
+  for(fiter it = firstFace(); it != lastFace(); ++it)
+    for(unsigned int i = 0; i < (*it)->mesh_vertices.size(); i++) 
+      (*it)->mesh_vertices[i]->writeMESH(fp, scalingFactor);
+  for(riter it = firstRegion(); it != lastRegion(); ++it)
+    for(unsigned int i = 0; i < (*it)->mesh_vertices.size(); i++) 
+      (*it)->mesh_vertices[i]->writeMESH(fp, scalingFactor);
+  
+  int numTriangles = 0, numQuadrangles = 0;
+  for(fiter it = firstFace(); it != lastFace(); ++it){
+    numTriangles += (*it)->triangles.size();
+    numQuadrangles += (*it)->quadrangles.size();
+  }
+  if(numTriangles){
+    fprintf(fp, " Triangles\n");
+    fprintf(fp, " %d\n", numTriangles);
+    for(fiter it = firstFace(); it != lastFace(); ++it)
+      for(unsigned int i = 0; i < (*it)->triangles.size(); i++)
+	(*it)->triangles[i]->writeMESH(fp, (*it)->tag());
+  }
+  if(numQuadrangles){
+    fprintf(fp, " Quadrilaterals\n");
+    fprintf(fp, " %d\n", numQuadrangles);
+    for(fiter it = firstFace(); it != lastFace(); ++it)
+      for(unsigned int i = 0; i < (*it)->triangles.size(); i++)
+	(*it)->quadrangles[i]->writeMESH(fp, (*it)->tag());
+  }
+
+  fprintf(fp, " End\n");
+  
+  fclose(fp);
+  return 1;
+}
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 2e2625d02275166838fa127a0968e10ea6b6cb87..497f0e76d41951c25f5329616c928cd553c44701 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -192,3 +192,10 @@ void MElement::writeUNV(FILE *fp, int type, int elementary)
   if(n - 1 % 8 != 7)
     fprintf(fp, "\n");
 }
+
+void MElement::writeMESH(FILE *fp, int elementary)
+{
+  for(int i = 0; i < getNumVertices(); i++)
+    fprintf(fp, " %d", getVertex(i)->getNum());
+  fprintf(fp, " %d\n", elementary);
+}
diff --git a/Geo/MElement.h b/Geo/MElement.h
index e464bb81859a2109e34bfa566a47b79d0b920968..4007a09b6d2f6a3bc37237214a3ab2cde38ae4a5 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -104,6 +104,7 @@ class MElement
   virtual void writeSTL(FILE *fp, double scalingFactor=1.0);
   virtual void writeVRML(FILE *fp);
   virtual void writeUNV(FILE *fp, int type, int elementary);
+  virtual void writeMESH(FILE *fp, int elementary);
   virtual char *getStringForPOS() = 0;
   virtual int getTypeForMSH() = 0;
 };
diff --git a/Geo/MVertex.cpp b/Geo/MVertex.cpp
index d900baf5879d57edd7a77dfa65bb9bf8ab41cf98..ce6599de431410356e38d2ac55f5540027fcabdb 100644
--- a/Geo/MVertex.cpp
+++ b/Geo/MVertex.cpp
@@ -39,3 +39,9 @@ void MVertex::writeUNV(FILE *fp, double scalingFactor)
   tmp[71] = 'D';
   fprintf(fp, tmp);
 }
+
+void MVertex::writeMESH(FILE *fp, double scalingFactor)
+{
+  fprintf(fp, " %20.14E      %20.14E      %20.14E      %d\n", 
+	  x() * scalingFactor, y() * scalingFactor, z() * scalingFactor, 0);
+}
diff --git a/Geo/MVertex.h b/Geo/MVertex.h
index b732f779a1ebaa4904185b518afd132d2a50f3a7..24ed0d86fabccab8723ad027d183404592ee634b 100644
--- a/Geo/MVertex.h
+++ b/Geo/MVertex.h
@@ -41,6 +41,7 @@ class MVertex{
   void writeMSH(FILE *fp, double version, int num, int elementary, int physical);
   void writeVRML(FILE *fp, double scalingFactor=1.0);
   void writeUNV(FILE *fp, double scalingFactor=1.0);
+  void writeMESH(FILE *fp, double scalingFactor=1.0);
 };
 
 class MEdgeVertex : public MVertex{
diff --git a/Graphics/CreateFile.cpp b/Graphics/CreateFile.cpp
index f60bdc49c3e6b3ad4e4c66ad3aebc2c742af5016..f36beddce0c50426004536e39e0010278dc94eb4 100644
--- a/Graphics/CreateFile.cpp
+++ b/Graphics/CreateFile.cpp
@@ -1,4 +1,4 @@
-// $Id: CreateFile.cpp,v 1.88 2006-08-07 13:57:14 geuzaine Exp $
+// $Id: CreateFile.cpp,v 1.89 2006-08-07 21:04:05 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -56,7 +56,8 @@ int GuessFileFormatFromFileName(char *name)
   else if(!strcmp(ext, ".msh"))     return FORMAT_MSH;
   else if(!strcmp(ext, ".unv"))     return FORMAT_UNV;
   else if(!strcmp(ext, ".stl"))     return FORMAT_STL;
-  else if(!strcmp(ext, ".pos"))     return FORMAT_LC;
+  else if(!strcmp(ext, ".mesh"))    return FORMAT_MESH;
+  else if(!strcmp(ext, ".pos"))     return FORMAT_POS;
   else if(!strcmp(ext, ".gif"))     return FORMAT_GIF;
   else if(!strcmp(ext, ".jpg"))     return FORMAT_JPEG;
   else if(!strcmp(ext, ".jpeg"))    return FORMAT_JPEG;
@@ -72,6 +73,7 @@ int GuessFileFormatFromFileName(char *name)
   else if(!strcmp(ext, ".ppm"))     return FORMAT_PPM;
   else if(!strcmp(ext, ".yuv"))     return FORMAT_YUV;
   else if(!strcmp(ext, ".wrl"))     return FORMAT_VRML;
+  else if(!strcmp(ext, ".vrml"))    return FORMAT_VRML;
   else                              return -1;
 }
 
@@ -84,6 +86,7 @@ void GetDefaultFileName(int format, char *name)
   case FORMAT_VRML: strcpy(ext, ".wrl"); break;
   case FORMAT_UNV:  strcpy(ext, ".unv"); break;
   case FORMAT_STL:  strcpy(ext, ".stl"); break;
+  case FORMAT_MESH: strcpy(ext, ".mesh"); break;
   default: break;
   }
   strcat(name, ext);
@@ -141,7 +144,11 @@ void CreateOutputFile(char *filename, int format)
     GMODEL->writeUNV(name, CTX.mesh.scaling_factor);
     break;
 
-  case FORMAT_LC:
+  case FORMAT_MESH:
+    GMODEL->writeMESH(name, CTX.mesh.scaling_factor);
+    break;
+
+  case FORMAT_POS:
     GMODEL->writePOS(name);
     break;
 
diff --git a/Parser/OpenFile.cpp b/Parser/OpenFile.cpp
index c012e09b0382f7b4c2c75c486aa1eb0974440626..52f0a33088f16e2684ccd4660c07492610a7e373 100644
--- a/Parser/OpenFile.cpp
+++ b/Parser/OpenFile.cpp
@@ -1,4 +1,4 @@
-// $Id: OpenFile.cpp,v 1.102 2006-08-07 19:08:13 geuzaine Exp $
+// $Id: OpenFile.cpp,v 1.103 2006-08-07 21:04:05 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -293,6 +293,10 @@ int MergeProblem(char *name, int warn_if_missing)
     if(!GMODEL) GMODEL = new gmshModel;
     status = GMODEL->readSTL(name, CTX.mesh.stl_distance_tol);
   }
+  else if(!strcmp(ext, ".mesh")){
+    if(!GMODEL) GMODEL = new gmshModel;
+    status = GMODEL->readMESH(name);
+  }
 #if defined(HAVE_FLTK)
   else if(!strcmp(ext, ".pnm") || !strcmp(ext, ".PNM") ||
 	  !strcmp(ext, ".pbm") || !strcmp(ext, ".PBM") ||