%p 5000
%e 2000
%{
#undef NDEBUG
#include "GR_config.h"
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
  
#ifdef YY_START
#define MY_YY_START YY_START
#else
#ifdef YYSTATE
#define MY_YY_START YYSTATE
#else
#define MY_YY_START yy_start
#endif
#endif

#define TWO_D 22
#define SURFACE 23
#define THREE_D 33
 
#if (defined(dim2))
#define TYPE TWO_D
#define MeshOutput "                \"2d mesh output\");\n"
#elif (defined(surf))
#define TYPE SURFACE
#define MeshOutput "                \"surface mesh output\");\n"
#elif (defined(dim3))
#define TYPE THREE_D
#define MeshOutput "                \"3d mesh output\");\n"
#else
#error Must define either dim2, surf, or dim3
#endif
 
#define TOPO_DIM (TYPE / 10)
#define SPACE_DIM (TYPE % 10)
 
  static const char * const pstrTopOfSource[] = {
    "#include <stdio.h>",
    "#include \"GR_misc.h\"",
    "#include \"GR_events.h\"",
    "#include \"GR_Face.h\"",
    "#include \"GR_Cell.h\"",
    "#include \"GR_BFace.h\"",
    "#include \"GR_Vertex.h\"",
#if (TYPE == TWO_D)
    "#include \"GR_Mesh2D.h\"",
    "void vWriteFile_Mesh2D(Mesh2D& OutMesh,",
#elif (TYPE == SURFACE)
    "#include \"GR_SurfMesh.h\"",
    "#include \"GR_Bdry3D.h\"",
    "void vWriteFile_Surface(SurfMesh& OutMesh,",
#else
    "#include \"GR_VolMesh.h\"",
    "void vWriteFile_VolMesh(VolMesh& OutMesh,",
#endif
    "                        const char strBaseFileName[],",
    "                        const char strExtraFileSuffix[])",
    "{",
    "  SUMAA_LOG_EVENT_BEGIN(OUTPUT);",
    "  assert(OutMesh.qSimplicial());",
    "  int iVertOffset = 0, iFaceOffset = 0;",
    "  int iCellOffset = 0, iBFaceOffset = 1;",
    "  FILE *pFOutFile = fopen(\"/dev/zero\", \"r\");",
    "  char strFileName[1024];",
    "  OutMesh.vPurge();",
    ""
  };

  static void vAppendToString(char strIn[], int * const piLen, const int iMaxLen, const char strApp[])
    {
      int iAppLen = strlen(strApp);
      assert(strlen(strIn) == *piLen);
      if (iAppLen + *piLen > iMaxLen) exit(1);
      sprintf(&(strIn[*piLen]), "%s", strApp);
      *piLen = *piLen + iAppLen;
      assert(strlen(strIn) == *piLen);
    }

  static void vClearString(char strIn[], const int iSize)
    {
      int ii;
      for (ii = 0; ii < iSize; ii++)
	strIn[ii] = '\0';
    }

#define vUserIntOutput(strArgs, piArgsLen, strInput, piInputLen, strCallString)\
  { \
    vAppendToString(strArgs, piArgsLen, 1024, strCallString); \
    vAppendToString(strInput, piInputLen, 1024, yytext); \
    iPrevContext = MY_YY_START; \
    BEGIN(USER_INT_SIZE); \
  }

#define vDefaultIntOutput(strFormat, piFormatLen, strArgs, piArgsLen, strInput, piInputLen, strCallString)\
  {\
    vAppendToString(strFormat, piFormatLen, 1024, "%d");\
    vAppendToString(strArgs, piArgsLen, 1024, strCallString);\
    vAppendToString(strInput, piInputLen, 1024, yytext);\
  }

#define vUserCoordOutput(strArgs, piArgsLen, strInput, piInputLen, strCallString)\
  {\
    char strDummy[1024];\
    sprintf(strDummy, ", OutMesh.pVVert(iV)->%s()", strCallString);\
    vAppendToString(strArgs, piArgsLen, 1024, strDummy);\
    vAppendToString(strInput, piInputLen, 1024, yytext);\
    iPrevContext = MY_YY_START;\
    BEGIN(USER_FLOAT_SIZE);\
  }

#define vDefaultCoordOutput(strFormat, piFormatLen, strArgs, piArgsLen, strInput, piInputLen, strCallString)\
  {\
    char strDummy[1024];\
    sprintf(strDummy, ", OutMesh.pVVert(iV)->%s()", strCallString);\
    vAppendToString(strFormat, piFormatLen, 1024, "%.14g");\
    vAppendToString(strArgs, piArgsLen, 1024, strDummy);\
    vAppendToString(strInput, piInputLen, 1024, yytext);\
  }

%}

%s USER_INT_SIZE USER_FLOAT_SIZE QUOTE
%s VERTEX_LINE FORTRAN_LINE
%s CELL_LINE TRI_CELL_LINE QUAD_CELL_LINE 
%s TET_CELL_LINE PYR_CELL_LINE PRISM_CELL_LINE HEX_CELL_LINE
%s FACE_LINE TRI_FACE_LINE QUAD_FACE_LINE
%s BFACE_LINE INT_BFACE_LINE TRI_BFACE_LINE QUAD_BFACE_LINE

%%
%{
  char strFormat[1024], strArgs[1024];
  char strInput[1024];
  int iFormatLen = 0, iArgsLen = 0, iInputLen = 0;
  int qWriteCellA = 0, qWriteCellB = 0;
  int iPrevContext;
  bool qFortranVerts = false, qFortranFaces = false, qFortranCells = false;

  vClearString(strInput, 1024);
  vClearString(strFormat, 1024);
  vClearString(strArgs, 1024);
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
%}

% {
  vAppendToString(strInput, &iInputLen, 1024, "%");
  vAppendToString(strFormat, &iFormatLen, 1024, "%%");
}

<INITIAL>^#.* {
  /* echo comments to the mesh file  unless the comment begins
     with ##; such comments are swallowed */
  if (yytext[1] != '#')
    printf("  fprintf(pFOutFile, \"%s\\n\");\n", yytext);
}

<INITIAL,FACE_LINE,VERTEX_LINE,CELL_LINE,BFACE_LINE,INT_BFACE_LINE>\" {
  vAppendToString(strInput, &iInputLen, 1024, "\"");
  iPrevContext = MY_YY_START; 
  BEGIN(QUOTE);
}

<QUOTE>\" {
  vAppendToString(strInput, &iInputLen, 1024, "\"");
  BEGIN(iPrevContext);
}

<QUOTE>\\\" {
  vAppendToString(strInput, &iInputLen, 1024, "\\\"");
  vAppendToString(strFormat, &iFormatLen, 1024, "\\\"");
}

<QUOTE>[^\\\"]* {
  vAppendToString(strInput, &iInputLen, 1024, yytext);
  vAppendToString(strFormat, &iFormatLen, 1024, yytext);
}

<INITIAL>^fortran[ \t]*\n {
  printf("    /* fortran */\n");
  printf("  iVertOffset = 1;\n");
  printf("  iFaceOffset = 1;\n");
#if (TYPE != SURFACE)
  printf("  iBFaceOffset = 1;\n");
#endif
  printf("  iCellOffset = 1;\n");
  vClearString(strInput, 1024);
  iInputLen = 0;
  vClearString(strFormat, 1024);
  iFormatLen = 0;
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
  vClearString(strArgs, 1024);
  iArgsLen = 0;
  qFortranVerts = true;
  qFortranCells = true;
  qFortranFaces = true;
}

<INITIAL>^fortran {
  vAppendToString(strInput, &iInputLen, 1024, yytext);
  BEGIN(FORTRAN_LINE);
}

<FORTRAN_LINE>verts {
  vAppendToString(strInput, &iInputLen, 1024, yytext);
  qFortranVerts = true;
}

<FORTRAN_LINE>cells {
  vAppendToString(strInput, &iInputLen, 1024, yytext);
  qFortranCells = true;
}

<FORTRAN_LINE>faces {
  vAppendToString(strInput, &iInputLen, 1024, yytext);
  qFortranFaces = true;
}

<FORTRAN_LINE>\n {
  printf("  /*%s*/\n", strInput);
  if (qFortranVerts)
    printf("  iVertOffset = 1;\n");
  if (qFortranFaces)
    printf("  iFaceOffset = 1;\n");
  if (qFortranCells)
    printf("  iCellOffset = 1;\n");
  vClearString(strInput, 1024);
  iInputLen = 0;
  vClearString(strFormat, 1024);
  iFormatLen = 0;
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
  vClearString(strArgs, 1024);
  iArgsLen = 0;
  BEGIN(INITIAL);
}

<INITIAL>^newfile[ \t]+.* {
  vAppendToString(strInput, &iInputLen, 1024, yytext);
  {
    int iLow = 7, iHi;
    while (isspace(yytext[iLow])) iLow++;
    iHi = iLow;
    while (!isspace(yytext[iHi])) iHi++;
    printf("  sprintf(strFileName, \"%%s.%.*s%%s\", strBaseFileName, strExtraFileSuffix);\n",
	   iHi - iLow, &(yytext[iLow]));
  }
  printf("\n");
  printf("  /*%s*/\n", strInput);
  printf("  printf(\"Opening output file %%s\\n\", strFileName);\n");
  printf("  if (pFOutFile) fclose(pFOutFile);\n");
  printf("  pFOutFile = fopen(strFileName, \"w\");\n");
  printf("  if (NULL == pFOutFile)\n");
  printf("    vFatalError(\"Couldn't open output file for writing\",\n");
  printf(MeshOutput);
  printf("\n");
}

<USER_INT_SIZE>[0-9]+ {
  char strMiniFormat[16];
  sprintf(strMiniFormat, "%%%sd", yytext);
  vAppendToString(strFormat, &iFormatLen, 1024, strMiniFormat);
  vAppendToString(strInput, &iInputLen, 1024, yytext);
  BEGIN(iPrevContext);
}

<USER_FLOAT_SIZE>[0-9]+[.]?[0-9]* {
  char strMiniFormat[16];
  sprintf(strMiniFormat, "%%%sg", yytext);
  vAppendToString(strFormat, &iFormatLen, 1024, strMiniFormat);
  vAppendToString(strInput, &iInputLen, 1024, yytext);
  BEGIN(iPrevContext);
}

<INITIAL>nverts[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumVerts()"); 
}

<INITIAL>nverts	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumVerts()"); 
}

<INITIAL>nfaces[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumFaces()"); 
}

<INITIAL>nfaces	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumFaces()"); 
}

<INITIAL>ncells[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumCells()"); 
}

<INITIAL>ncells	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumCells()"); 
}

%{
#if (TOPO_DIM == 2) /* 2D or surface mesh */
%}
<INITIAL>ntricells[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumTriCells()"); 
}

<INITIAL>ntricells	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumTriCells()"); 
}

<INITIAL>nquadcells[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumQuadCells()"); 
}

<INITIAL>nquadcells	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumQuadCells()"); 
}
%{
#else
%}

<INITIAL>ntetcells[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumTetCells()"); 
}

<INITIAL>ntetcells	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumTetCells()"); 
}

<INITIAL>npyrcells[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumPyrCells()"); 
}

<INITIAL>npyrcells	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumPyrCells()"); 
}

<INITIAL>nprismcells[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumPrismCells()"); 
}

<INITIAL>nprismcells	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumPrismCells()"); 
}

<INITIAL>nhexcells[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumHexCells()"); 
}

<INITIAL>nhexcells	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", OutMesh.iNumHexCells()"); 
}
%{
#endif
%}

<INITIAL>nbfaces[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumBdryFaces()");
  
}

<INITIAL>nbfaces	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iNumBdryFaces()"); 
}

<INITIAL>nintbfaces[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iNumIntBdryFaces()");
  
}

<INITIAL>nintbfaces	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iNumIntBdryFaces()"); 
}

<INITIAL>\n {
  if (iFormatLen != 1) {
    vAppendToString(strFormat, &iFormatLen, 1024, "\\n\"");
    printf("  /*%s*/\n", strInput);
    printf("  fprintf(pFOutFile, %s%s);\n", strFormat, strArgs);
  }
  vClearString(strInput, 1024);
  iInputLen = 0;
  vClearString(strFormat, 1024);
  iFormatLen = 0;
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
  vClearString(strArgs, 1024);
  iArgsLen = 0;
}

[ \t]+	{
  strFormat[iFormatLen++] = ' ';
  vAppendToString(strInput, &iInputLen, 1024, yytext);
}

<INITIAL>^verts:[ \t]+ {
  printf("\n");
  BEGIN(VERTEX_LINE);
  printf("  for (int iV = 0; iV < OutMesh.iNumVerts(); iV++) \n");
  vAppendToString(strInput, &iInputLen, 1024, "verts: ");
}

<VERTEX_LINE>index[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", iV+iVertOffset"); 
}

<VERTEX_LINE>index	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", iV+iVertOffset"); 
}

<VERTEX_LINE>coords {
  vDefaultCoordOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		      strInput, &iInputLen, "dX");
  yytext[0] = '\0';
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  vDefaultCoordOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		      strInput, &iInputLen, "dY");
#if (SPACE_DIM == 3)
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  vDefaultCoordOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		      strInput, &iInputLen, "dZ");
#endif
}

<VERTEX_LINE>x[ \t]*/[0-9]+ {
  vUserCoordOutput(strArgs, &iArgsLen, strInput, &iInputLen, "dX");
}

<VERTEX_LINE>x {
  vDefaultCoordOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		      strInput, &iInputLen, "dX"); 
}

<VERTEX_LINE>y[ \t]*/[0-9]+ {
  vUserCoordOutput(strArgs, &iArgsLen, strInput, &iInputLen, "dY");
}

<VERTEX_LINE>y {
  vDefaultCoordOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		      strInput, &iInputLen, "dY"); 
}

%{
#if (SPACE_DIM == 3)
%}
<VERTEX_LINE>z[ \t]*/[0-9]+ {
  vUserCoordOutput(strArgs, &iArgsLen, strInput, &iInputLen, "dZ");
}

<VERTEX_LINE>z {
  vDefaultCoordOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		      strInput, &iInputLen, "dZ"); 
}
%{
#endif
%}

<VERTEX_LINE>\n {
  vAppendToString(strFormat, &iFormatLen, 1024, "\\n\"");
  printf("    /*%s*/\n", strInput);
  printf("    fprintf(pFOutFile, %s%s);\n", strFormat, strArgs);
  printf("\n");
  vClearString(strInput, 1024);
  iInputLen = 0;
  vClearString(strFormat, 1024);
  iFormatLen = 0;
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
  vClearString(strArgs, 1024);
  iArgsLen = 0;
  BEGIN(INITIAL);
}

<INITIAL>^faces:[ \t]+ {
  BEGIN(FACE_LINE);
  qWriteCellA = qWriteCellB = 0;
  printf("\n");
  printf("  for (int iF = 0; iF < OutMesh.iNumFaces(); iF++) {\n");
  printf("    Face* pF = OutMesh.pFFace(iF);\n");
  printf("    int iCA, iCB;\n");
  vAppendToString(strInput, &iInputLen, 1024, "faces: ");
}

<FACE_LINE>index[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", iF+iFaceOffset"); 
}

<FACE_LINE>index {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", iF+iFaceOffset"); 
}

<FACE_LINE>cells {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", iCA");
  yytext[0] = '\0';
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", iCB");
  qWriteCellA = qWriteCellB = 1;
}

<FACE_LINE>cella[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", iCA"); 
  qWriteCellA = 1;
}

<FACE_LINE>cella {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", iCA"); 
  qWriteCellA = 1;
}

<FACE_LINE>cellb[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", iCB"); 
  qWriteCellB = 1;
}

<FACE_LINE>cellb {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", iCB"); 
  qWriteCellB = 1;
}

<FACE_LINE>verts {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pF->pVVert(0))+iVertOffset"); 
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  yytext[0] = '\0';
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pF->pVVert(1))+iVertOffset"); 
#if (TOPO_DIM == 3)
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pF->pVVert(2))+iVertOffset");
#endif
}

<FACE_LINE>verta[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pF->pVVert(0))+iVertOffset"); 
}

<FACE_LINE>verta {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pF->pVVert(0))+iVertOffset"); 
}

<FACE_LINE>vertb[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pF->pVVert(1))+iVertOffset"); 
}

<FACE_LINE>vertb {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pF->pVVert(1))+iVertOffset"); 
}

%{
#if (TOPO_DIM == 3)
%}
<FACE_LINE>vertc[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pF->pVVert(2))+iVertOffset"); 
}

<FACE_LINE>vertc {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pF->pVVert(2))+iVertOffset"); 
}
%{
#endif
%}

<FACE_LINE>\n {
  vAppendToString(strFormat, &iFormatLen, 1024, "\\n\"");
  if (qWriteCellA || qWriteCellB) {
    assert(qWriteCellA && qWriteCellB);
    printf("    Cell *pC = pF->pCCellLeft();\n");
    printf("    switch (pC->eType()) {\n");
    printf("    case Cell::eBdryEdge:\n");
    printf("    case Cell::eTriBFace:\n");
    printf("    case Cell::eQuadBFace:\n");
    printf("    case Cell::eIntBdryEdge:\n");
    printf("    case Cell::eIntTriBFace:\n");
    printf("    case Cell::eIntQuadBFace:\n");
    printf("      iCA = - (dynamic_cast<BFace*>(pC))->iBdryCond();\n");
    printf("      break;\n");
    printf("//    case Cell::eIntBdryEdge:\n");
    printf("//    case Cell::eIntTriBFace:\n");
    printf("//    case Cell::eIntQuadBFace:\n");
    printf("//      {\n");
    printf("//        Face *pFOther = pC->pFFace(0);\n");
    printf("//        if (pF == pFOther) pFOther = pC->pFFace(1);\n");
    printf("//        Cell *pCOther = pFOther->pCCellOpposite(pC);\n");
    printf("//        iCA = OutMesh.iCellIndex(pCOther)+iCellOffset;\n");
    printf("//      }\n");
    printf("//      break;\n");
    printf("    default:\n");
    printf("      iCA = OutMesh.iCellIndex(pC)+iCellOffset;\n");
    printf("      break;\n");
    printf("    }\n\n");

    printf("    pC = pF->pCCellRight();\n");
    printf("    switch (pC->eType()) {\n");
    printf("    case Cell::eBdryEdge:\n");
    printf("    case Cell::eTriBFace:\n");
    printf("    case Cell::eQuadBFace:\n");
    printf("    case Cell::eIntBdryEdge:\n");
    printf("    case Cell::eIntTriBFace:\n");
    printf("    case Cell::eIntQuadBFace:\n");
    printf("      iCB = - (dynamic_cast<BFace*>(pC))->iBdryCond();\n");
    printf("      break;\n");
    printf("//    case Cell::eIntBdryEdge:\n");
    printf("//    case Cell::eIntTriBFace:\n");
    printf("//    case Cell::eIntQuadBFace:\n");
    printf("//      {\n");
    printf("//        Face *pFOther = pC->pFFace(0);\n");
    printf("//        if (pF == pFOther) pFOther = pC->pFFace(1);\n");
    printf("//        Cell *pCOther = pFOther->pCCellOpposite(pC);\n");
    printf("//        iCB = OutMesh.iCellIndex(pCOther)+iCellOffset;\n");
    printf("//      }\n");
    printf("//      break;\n");
    printf("    default:\n");
    printf("      iCB = OutMesh.iCellIndex(pC)+iCellOffset;\n");
    printf("      break;\n");
    printf("    }\n");
  }
  printf("    /*%s*/\n", strInput);
  printf("    fprintf(pFOutFile, %s%s);\n", strFormat, strArgs);
  printf("  }\n");
  printf("\n");
  vClearString(strInput, 1024);
  iInputLen = 0;
  vClearString(strFormat, 1024);
  iFormatLen = 0;
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
  vClearString(strArgs, 1024);
  iArgsLen = 0;
  BEGIN(INITIAL);
}

<INITIAL>^cells:[ \t]+ {
  BEGIN(CELL_LINE);
  printf("\n");
  printf("  for (int iC = 0; iC < OutMesh.iNumCells(); iC++) {\n");
  printf("    Cell* pC = OutMesh.pCCell(iC);\n");
  vAppendToString(strInput, &iInputLen, 1024, "cells: ");
}

<CELL_LINE>index[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", iC+iCellOffset"); 
}

<CELL_LINE>index	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", iC+iCellOffset"); 
}

<CELL_LINE>region[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", pC->iRegion()"); 
}

<CELL_LINE>region {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", pC->iRegion()");
}

<CELL_LINE>faces {
  /* The tricky bit here is that the number of faces is not known, so
     we have to loop.  But before that, we have to flush the stuff
     that's already in the format and argument lists */
  if (iFormatLen > 1) {
    vAppendToString(strFormat, &iFormatLen, 1024, "\"");
    printf("    fprintf(pFOutFile, %s%s);\n", strFormat, strArgs);
    vClearString(strFormat, 1024);
    iFormatLen = 0;
    vAppendToString(strFormat, &iFormatLen, 1024, "\"");
    vClearString(strArgs, 1024);
    iArgsLen = 0;
  }
  vAppendToString(strInput, &iInputLen, 1024, "faces");
  printf("    for (int iF = 0; iF < pC->iNumFaces(); iF++) {\n");
  printf("      fprintf(pFOutFile, \"%%d \", OutMesh.iFaceIndex(pC->pFFace(iF))+iFaceOffset);\n"); 
  printf("    }\n");
}

<CELL_LINE>facea[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iFaceIndex(pC->pFFace(0))+iFaceOffset"); 
}

<CELL_LINE>facea {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pC->pFFace(0))+iFaceOffset"); 
}

<CELL_LINE>faceb[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iFaceIndex(pC->pFFace(1))+iFaceOffset"); 
}

<CELL_LINE>faceb {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pC->pFFace(1))+iFaceOffset"); 
}

<CELL_LINE>facec[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iFaceIndex(pC->pFFace(2))+iFaceOffset"); 
}

<CELL_LINE>facec {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pC->pFFace(2))+iFaceOffset"); 
}

%{
#if (TOPO_DIM == 3)
%}
<CELL_LINE>faced[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iFaceIndex(pC->pFFace(3))+iFaceOffset"); 
}

<CELL_LINE>faced {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pC->pFFace(3))+iFaceOffset"); 
}
%{
#endif
%}

<CELL_LINE>verts {
  /* The tricky bit here is that the number of verts is not known, so
     we have to loop.  But before that, we have to flush the stuff
     that's already in the format and argument lists */
  if (iFormatLen > 1) {
    vAppendToString(strFormat, &iFormatLen, 1024, "\"");
    printf("    fprintf(pFOutFile, %s%s);\n", strFormat, strArgs);
    vClearString(strFormat, 1024);
    iFormatLen = 0;
    vAppendToString(strFormat, &iFormatLen, 1024, "\"");
    vClearString(strArgs, 1024);
    iArgsLen = 0;
  }
  vAppendToString(strInput, &iInputLen, 1024, "verts");
  printf("    for (int iV = 0; iV < pC->iNumVerts(); iV++) {\n");
  printf("      fprintf(pFOutFile, \"%%d \", OutMesh.iVertIndex(pC->pVVert(iV))+iVertOffset);\n"); 
  printf("    }\n");
}

<CELL_LINE>verta[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pC->pVVert(0))+iVertOffset"); 
}

<CELL_LINE>verta {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pC->pVVert(0))+iVertOffset"); 
}

<CELL_LINE>vertb[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pC->pVVert(1))+iVertOffset"); 
}

<CELL_LINE>vertb {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pC->pVVert(1))+iVertOffset"); 
}

<CELL_LINE>vertc[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pC->pVVert(2))+iVertOffset"); 
}

<CELL_LINE>vertc {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pC->pVVert(2))+iVertOffset"); 
}

<CELL_LINE>vertd[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pC->pVVert(3))+iVertOffset"); 
}

<CELL_LINE>vertd {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pC->pVVert(3))+iVertOffset"); 
}

%{
#if (TYPE == SURFACE)
%}
<CELL_LINE>BC {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.pBdryPatch(pC)->iBdryCond()");
}

<CELL_LINE>patch {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", (int)(OutMesh.pBdryPatch(pC))");
}
%{
#endif
%}

<CELL_LINE>\n {
  vAppendToString(strFormat, &iFormatLen, 1024, "\\n\"");
  printf("    /*%s*/\n", strInput);
  printf("    fprintf(pFOutFile, %s%s);\n", strFormat, strArgs);
  printf("  }\n");
  printf("\n");
  vClearString(strInput, 1024);
  iInputLen = 0;
  vClearString(strFormat, 1024);
  iFormatLen = 0;
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
  vClearString(strArgs, 1024);
  iArgsLen = 0;
  BEGIN(INITIAL);
}

%{
#if (TYPE != SURFACE)
%}
<INITIAL>^bdryfaces:[ \t]+ {
  BEGIN(BFACE_LINE);
  printf("\n");
  printf("  for (int iBF = 0; iBF < OutMesh.iNumBdryFaces(); iBF++) {\n");
  printf("    BFace* pBF = OutMesh.pBFBFace(iBF);\n");
  vAppendToString(strInput, &iInputLen, 1024, "bdryfaces: ");
}

<BFACE_LINE>index[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", iBF+iBFaceOffset"); 
}

<BFACE_LINE>index	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", iBF+iBFaceOffset"); 
}

<BFACE_LINE>bc[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", pBF->iBdryCond()");
}

<BFACE_LINE>bc {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", pBF->iBdryCond()");
}

<BFACE_LINE>face[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iFaceIndex(pBF->pFFace(0))+iFaceOffset"); 
}

<BFACE_LINE>face {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pBF->pFFace(0))+iFaceOffset"); 
}

<BFACE_LINE>verts {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(0))+iVertOffset"); 
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  yytext[0] = '\0';
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(1))+iVertOffset"); 
#if (TYPE == THREE_D) 
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(2))+iVertOffset");
#endif
}

<BFACE_LINE>verta[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pBF->pVVert(0))+iVertOffset"); 
}

<BFACE_LINE>verta {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(0))+iVertOffset"); 
}

<BFACE_LINE>vertb[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pBF->pVVert(1))+iVertOffset"); 
}

<BFACE_LINE>vertb {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(1))+iVertOffset"); 
}

%{
#if (TYPE == THREE_D)
%}
<BFACE_LINE>vertc[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pBF->pVVert(2))+iVertOffset"); 
}

<BFACE_LINE>vertc {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(2))+iVertOffset"); 
}
%{
#endif
%}  

<BFACE_LINE>\n {
  vAppendToString(strFormat, &iFormatLen, 1024, "\\n\"");
  printf("    /*%s*/\n", strInput);
  printf("    fprintf(pFOutFile, %s%s);\n", strFormat, strArgs);
  printf("  }\n");
  printf("\n");
  vClearString(strInput, 1024);
  iInputLen = 0;
  vClearString(strFormat, 1024);
  iFormatLen = 0;
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
  vClearString(strArgs, 1024);
  iArgsLen = 0;
  BEGIN(INITIAL);
}
%{
#endif /* Done skipping over boundary stuff for surface meshes. */
%}

<INITIAL>^intbdryfaces:[ \t]+ {
  BEGIN(INT_BFACE_LINE);
  printf("\n");
  printf("  for (int iIBF = OutMesh.iNumBdryFaces(); \n");
  printf("       iIBF < OutMesh.iNumTotalBdryFaces(); iIBF++) {\n");
  printf("    BFace* pBF = OutMesh.pBFBFace(iIBF);\n");
  vAppendToString(strInput, &iInputLen, 1024, "intbdryfaces: ");
}

<INT_BFACE_LINE>index[ \t]+/[0-9]+	{
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", iIBF+iBFaceOffset"); 
}

<INT_BFACE_LINE>index	{
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", iIBF+iBFaceOffset"); 
}

<INT_BFACE_LINE>bc[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", pBF->iBdryCond()");
}

<INT_BFACE_LINE>bc {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen, ", pBF->iBdryCond()");
}

<INT_BFACE_LINE>facea[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iFaceIndex(pBF->pFFace(0))+iFaceOffset"); 
}

<INT_BFACE_LINE>facea {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pBF->pFFace(0))+iFaceOffset"); 
}

<INT_BFACE_LINE>faceb[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iFaceIndex(pBF->pFFace(1))+iFaceOffset"); 
}

<INT_BFACE_LINE>faceb {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pBF->pFFace(1))+iFaceOffset"); 
}

<INT_BFACE_LINE>faces {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pBF->pFFace(0))+iFaceOffset"); 
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  yytext[0] = '\0';
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iFaceIndex(pBF->pFFace(1))+iFaceOffset"); 
}

<INT_BFACE_LINE>verts {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(0))+iVertOffset"); 
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  yytext[0] = '\0';
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(1))+iVertOffset"); 
#if (TYPE == THREE_D) 
  vAppendToString(strFormat, &iFormatLen, 1024, " ");
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(2))+iVertOffset");
#endif
}

<INT_BFACE_LINE>verta[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pBF->pVVert(0))+iVertOffset"); 
}

<INT_BFACE_LINE>verta {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(0))+iVertOffset"); 
}

<INT_BFACE_LINE>vertb[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pBF->pVVert(1))+iVertOffset"); 
}

<INT_BFACE_LINE>vertb {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(1))+iVertOffset"); 
}

%{
#if (TYPE == THREE_D)
%}
<INT_BFACE_LINE>vertc[ \t]+/[0-9]+ {
  vUserIntOutput(strArgs, &iArgsLen, strInput, &iInputLen,
		 ", OutMesh.iVertIndex(pBF->pVVert(2))+iVertOffset"); 
}

<INT_BFACE_LINE>vertc {
  vDefaultIntOutput(strFormat, &iFormatLen, strArgs, &iArgsLen,
		    strInput, &iInputLen,
		    ", OutMesh.iVertIndex(pBF->pVVert(2))+iVertOffset"); 
}
%{
#endif
%}  

<INT_BFACE_LINE>\n {
  vAppendToString(strFormat, &iFormatLen, 1024, "\\n\"");
  printf("    /*%s*/\n", strInput);
  printf("    fprintf(pFOutFile, %s%s);\n", strFormat, strArgs);
  printf("  }\n");
  printf("\n");
  vClearString(strInput, 1024);
  iInputLen = 0;
  vClearString(strFormat, 1024);
  iFormatLen = 0;
  vAppendToString(strFormat, &iFormatLen, 1024, "\"");
  vClearString(strArgs, 1024);
  iArgsLen = 0;
  BEGIN(INITIAL);
}

<INITIAL,FACE_LINE,VERTEX_LINE,CELL_LINE,BFACE_LINE,INT_BFACE_LINE>.	{
  strFormat[iFormatLen++] = yytext[0];
  vAppendToString(strInput, &iInputLen, 1024, yytext);
}  /* LAST RULE */

%%

int main() {
  /* Write the header for the file that reads/writes the mesh */
  int ii = 0;
  while (strlen(pstrTopOfSource[ii]) != 0)
    printf("%s\n", pstrTopOfSource[ii++]);

  /* Parse the template and generate code. */
  yylex();

  printf("  /* Make sure compilers won't complain that these variables */\n");
  printf("  /* aren't used. */\n");
  printf("  iVertOffset++;\n");
  printf("  iFaceOffset++;\n");
  printf("  iBFaceOffset++;\n");
  printf("  iCellOffset++;\n");
  /* Write the footer for the file that reads/writes the mesh */
  printf("  fclose(pFOutFile);\n");
  printf("  SUMAA_LOG_EVENT_END(OUTPUT);\n");
  printf("}\n");
  exit(0);
}
