void _K33Search_FreeContext(void *pContext)
{
     K33SearchContext *context = (K33SearchContext *) pContext;

     _K33Search_ClearStructures(context);
     free(pContext);
}
void *_K33Search_DupContext(void *pContext, void *theGraph)
{
     K33SearchContext *context = (K33SearchContext *) pContext;
     K33SearchContext *newContext = (K33SearchContext *) malloc(sizeof(K33SearchContext));

     if (newContext != NULL)
     {
         int VIsize = gp_PrimaryVertexIndexBound((graphP) theGraph);
         int Esize = gp_EdgeIndexBound((graphP) theGraph);

         *newContext = *context;

         newContext->theGraph = (graphP) theGraph;

         newContext->initialized = 0;
         _K33Search_ClearStructures(newContext);
         if (((graphP) theGraph)->N > 0)
         {
             if (_K33Search_CreateStructures(newContext) != OK)
             {
                 _K33Search_FreeContext(newContext);
                 return NULL;
             }

             memcpy(newContext->E, context->E, Esize*sizeof(K33Search_EdgeRec));
             memcpy(newContext->VI, context->VI, VIsize*sizeof(K33Search_VertexInfo));
             LCCopy(newContext->separatedDFSChildLists, context->separatedDFSChildLists);
         }
     }

     return newContext;
}
void *_K33Search_DupContext(void *pContext, void *theGraph)
{
     K33SearchContext *context = (K33SearchContext *) pContext;
     K33SearchContext *newContext = (K33SearchContext *) malloc(sizeof(K33SearchContext));

     if (newContext != NULL)
     {
         int N = ((graphP) theGraph)->N;
         int Gsize = ((graphP) theGraph)->edgeOffset + ((graphP) theGraph)->arcCapacity;

         *newContext = *context;

         newContext->theGraph = (graphP) theGraph;

         newContext->initialized = 0;
         _K33Search_ClearStructures(newContext);
         if (N > 0)
         {
             if (_K33Search_CreateStructures(newContext) != OK)
             {
                 _K33Search_FreeContext(newContext);
                 return NULL;
             }

             LCCopy(newContext->sortedDFSChildLists, context->sortedDFSChildLists);
             memcpy(newContext->G, context->G, Gsize*sizeof(K33Search_GraphNode));
             memcpy(newContext->V, context->V, N*sizeof(K33Search_VertexRec));
         }
     }

     return newContext;
}
int  gp_AttachK33Search(graphP theGraph)
{
     K33SearchContext *context = NULL;

     // If the K3,3 search feature has already been attached to the graph,
     // then there is no need to attach it again
     gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);
     if (context != NULL)
     {
         return OK;
     }

     // Allocate a new extension context
     context = (K33SearchContext *) malloc(sizeof(K33SearchContext));
     if (context == NULL)
     {
         return NOTOK;
     }

     // First, tell the context that it is not initialized
     context->initialized = 0;

     // Save a pointer to theGraph in the context
     context->theGraph = theGraph;

     // Put the overload functions into the context function table.
     // gp_AddExtension will overload the graph's functions with these, and
     // return the base function pointers in the context function table
     memset(&context->functions, 0, sizeof(graphFunctionTable));

     context->functions.fpEmbeddingInitialize = _K33Search_EmbeddingInitialize;
     context->functions.fpEmbedBackEdgeToDescendant = _K33Search_EmbedBackEdgeToDescendant;
     context->functions.fpMergeBicomps = _K33Search_MergeBicomps;
     context->functions.fpMergeVertex = _K33Search_MergeVertex;
     context->functions.fpHandleBlockedBicomp = _K33Search_HandleBlockedBicomp;
     context->functions.fpEmbedPostprocess = _K33Search_EmbedPostprocess;
     context->functions.fpCheckEmbeddingIntegrity = _K33Search_CheckEmbeddingIntegrity;
     context->functions.fpCheckObstructionIntegrity = _K33Search_CheckObstructionIntegrity;

     context->functions.fpInitGraph = _K33Search_InitGraph;
     context->functions.fpReinitializeGraph = _K33Search_ReinitializeGraph;
     context->functions.fpEnsureArcCapacity = _K33Search_EnsureArcCapacity;

     _K33Search_ClearStructures(context);

     // Store the K33 search context, including the data structure and the
     // function pointers, as an extension of the graph
     if (gp_AddExtension(theGraph, &K33SEARCH_ID, (void *) context,
                         _K33Search_DupContext, _K33Search_FreeContext,
                         &context->functions) != OK)
     {
         _K33Search_FreeContext(context);
         return NOTOK;
     }

     // Create the K33-specific structures if the size of the graph is known
     // Attach functions are always invoked after gp_New(), but if a graph
     // extension must be attached before gp_Read(), then the attachment
     // also happens before gp_InitGraph(), which means N==0.
     // However, sometimes a feature is attached after gp_InitGraph(), in
     // which case N > 0
     if (theGraph->N > 0)
     {
         if (_K33Search_CreateStructures(context) != OK ||
             _K33Search_InitStructures(context) != OK)
         {
             _K33Search_FreeContext(context);
             return NOTOK;
         }
     }

     return OK;
}