int runSpecificGraphTests(void)
{
	char origDir[2049];
	int retVal = 0;

	if (!getcwd(origDir, 2048))
		return -1;

	if (chdir("samples") != 0)
	{
		if (chdir("..") != 0 || chdir("samples") != 0)
		{
			// Warn but give success result
			printf("WARNING: Unable to change to samples directory to run tests on samples.\n");
			return 0;
		}
	}

	if (runSpecificGraphTest("-p", "maxPlanar5.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-d", "maxPlanar5.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-d", "drawExample.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-p", "Petersen.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-o", "Petersen.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-2", "Petersen.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-3", "Petersen.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-4", "Petersen.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-c", "maxPlanar5.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-c", "Petersen.txt") < 0)
		retVal = -1;

	if (runSpecificGraphTest("-c", "drawExample.txt") < 0)
		retVal = -1;

	chdir(origDir);
    FlushConsole(stdout);
	return retVal;
}
示例#2
0
int Console::Flush()
{
	bool done_output = false;
	int num_running = 0;
	for(int i = 0; i < processes.GetCount(); i++)
		if(!!processes[i].process)
			num_running++;
	if(num_running) {
		int time = msecs();
		for(int i = 0; i < processes.GetCount(); i++) {
			Slot& slot = processes[i];
			if(!!slot.process) {
				Group& group = groups.GetAdd(slot.group);
				group.msecs += (time - slot.last_msecs) / num_running;
				group.raw_msecs += time - slot.last_msecs;
				slot.last_msecs = time;
			}
		}
	}
	bool running = false;
	for(int i = 0; i < processes.GetCount(); i++) {
		Slot& slot = processes[i];
		if(!slot.process)
			continue;
		String s;
		slot.process->Read(s);
		if(!IsNull(s)) {
			done_output = true;
			if(slot.outfile)
				slot.outfile->Put(s);
			if(!slot.quiet) {
				if(console_lock < 0 || console_lock == i) {
					console_lock = i;
					AppendOutput(s);
				}
				else
					slot.output.Cat(s);
			}
		}
		if(!slot.process->IsRunning()) {
			Kill(i);
			if(slot.exitcode != 0 && verbosebuild)
				spooled_output.Cat("Error executing " + slot.cmdline + "\n");
			if(console_lock == i)
				console_lock = -1;
			FlushConsole();
			CheckEndGroup();
			continue;
		}
		running = true;
	}
	return !running ? -1 : done_output ? 1 : 0;
}
示例#3
0
int  RandomGraphs(char command, int NumGraphs, int SizeOfGraphs)
{
char theFileName[256];
int  K, countUpdateFreq;
int Result=OK, MainStatistic=0;
int  ObstructionMinorFreqs[NUM_MINORS];
graphP theGraph=NULL, origGraph=NULL;
platform_time start, end;
int embedFlags = GetEmbedFlags(command);
int ReuseGraphs = TRUE;

     GetNumberIfZero(&NumGraphs, "Enter number of graphs to generate:", 1, 1000000000);
     GetNumberIfZero(&SizeOfGraphs, "Enter size of graphs:", 1, 10000);

   	 theGraph = MakeGraph(SizeOfGraphs, command);
   	 origGraph = MakeGraph(SizeOfGraphs, command);
   	 if (theGraph == NULL || origGraph == NULL)
   	 {
   		 gp_Free(&theGraph);
   		 return NOTOK;
   	 }

     // Initialize a secondary statistics array
     for (K=0; K < NUM_MINORS; K++)
          ObstructionMinorFreqs[K] = 0;

   	 // Seed the random number generator with "now". Do it after any prompting
   	 // to tie randomness to human process of answering the prompt.
   	 srand(time(NULL));

   	 // Select a counter update frequency that updates more frequently with larger graphs
   	 // and which is relatively prime with 10 so that all digits of the count will change
   	 // even though we aren't showing the count value on every iteration
   	 countUpdateFreq = 3579 / SizeOfGraphs;
   	 countUpdateFreq = countUpdateFreq < 1 ? 1 : countUpdateFreq;
   	 countUpdateFreq = countUpdateFreq % 2 == 0 ? countUpdateFreq+1 : countUpdateFreq;
   	 countUpdateFreq = countUpdateFreq % 5 == 0 ? countUpdateFreq+2 : countUpdateFreq;

   	 // Start the count
     fprintf(stdout, "0\r");
     fflush(stdout);

     // Start the timer
     platform_GetTime(start);

     // Generate and process the number of graphs requested
     for (K=0; K < NumGraphs; K++)
     {
          if ((Result = gp_CreateRandomGraph(theGraph)) == OK)
          {
              if (tolower(OrigOut)=='y')
              {
                  sprintf(theFileName, "random\\%d.txt", K%10);
                  gp_Write(theGraph, theFileName, WRITE_ADJLIST);
              }

              gp_CopyGraph(origGraph, theGraph);

              if (strchr("pdo234", command))
              {
                  Result = gp_Embed(theGraph, embedFlags);

                  if (gp_TestEmbedResultIntegrity(theGraph, origGraph, Result) != Result)
                      Result = NOTOK;

                  if (Result == OK)
                  {
                       MainStatistic++;

                       if (tolower(EmbeddableOut) == 'y')
                       {
                           sprintf(theFileName, "embedded\\%d.txt", K%10);
                           gp_Write(theGraph, theFileName, WRITE_ADJMATRIX);
                       }

                       if (tolower(AdjListsForEmbeddingsOut) == 'y')
                       {
                           sprintf(theFileName, "adjlist\\%d.txt", K%10);
                           gp_Write(theGraph, theFileName, WRITE_ADJLIST);
                       }
                  }
                  else if (Result == NONEMBEDDABLE)
                  {
                       if (embedFlags == EMBEDFLAGS_PLANAR || embedFlags == EMBEDFLAGS_OUTERPLANAR)
                       {
                           if (theGraph->IC.minorType & MINORTYPE_A)
                                ObstructionMinorFreqs[0] ++;
                           else if (theGraph->IC.minorType & MINORTYPE_B)
                                ObstructionMinorFreqs[1] ++;
                           else if (theGraph->IC.minorType & MINORTYPE_C)
                                ObstructionMinorFreqs[2] ++;
                           else if (theGraph->IC.minorType & MINORTYPE_D)
                                ObstructionMinorFreqs[3] ++;
                           else if (theGraph->IC.minorType & MINORTYPE_E)
                                ObstructionMinorFreqs[4] ++;

                           if (theGraph->IC.minorType & MINORTYPE_E1)
                                ObstructionMinorFreqs[5] ++;
                           else if (theGraph->IC.minorType & MINORTYPE_E2)
                                ObstructionMinorFreqs[6] ++;
                           else if (theGraph->IC.minorType & MINORTYPE_E3)
                                ObstructionMinorFreqs[7] ++;
                           else if (theGraph->IC.minorType & MINORTYPE_E4)
                                ObstructionMinorFreqs[8] ++;

                           if (tolower(ObstructedOut) == 'y')
                           {
                               sprintf(theFileName, "obstructed\\%d.txt", K%10);
                               gp_Write(theGraph, theFileName, WRITE_ADJMATRIX);
                           }
                       }
                  }
              }
              else if (command == 'c')
              {
      			if ((Result = gp_ColorVertices(theGraph)) == OK)
      				 Result = gp_ColorVerticesIntegrityCheck(theGraph, origGraph);
				if (Result == OK && gp_GetNumColorsUsed(theGraph) <= 5)
					MainStatistic++;
              }

              // If there is an error in processing, then write the file for debugging
              if (Result != OK && Result != NONEMBEDDABLE)
              {
                   sprintf(theFileName, "error\\%d.txt", K%10);
                   gp_Write(origGraph, theFileName, WRITE_ADJLIST);
              }
          }

          // Reinitialize or recreate graphs for next iteration
          ReinitializeGraph(&theGraph, ReuseGraphs, command);
          ReinitializeGraph(&origGraph, ReuseGraphs, command);

          // Show progress, but not so often that it bogs down progress
          if (quietMode == 'n' && (K+1) % countUpdateFreq == 0)
          {
              fprintf(stdout, "%d\r", K+1);
              fflush(stdout);
          }

          // Terminate loop on error
          if (Result != OK && Result != NONEMBEDDABLE)
          {
        	  ErrorMessage("\nError found\n");
              Result = NOTOK;
              break;
          }
     }

     // Stop the timer
     platform_GetTime(end);

     // Finish the count
     fprintf(stdout, "%d\n", NumGraphs);
     fflush(stdout);

     // Free the graph structures created before the loop
     gp_Free(&theGraph);
     gp_Free(&origGraph);

     // Print some demographic results
     if (Result == OK || Result == NONEMBEDDABLE)
         Message("\nNo Errors Found.");
     sprintf(Line, "\nDone (%.3lf seconds).\n", platform_GetDuration(start,end));
     Message(Line);

     // Report statistics for planar or outerplanar embedding
     if (embedFlags == EMBEDFLAGS_PLANAR || embedFlags == EMBEDFLAGS_OUTERPLANAR)
     {
         sprintf(Line, "Num Embedded=%d.\n", MainStatistic);
         Message(Line);

         for (K=0; K<5; K++)
         {
        	  // Outerplanarity does not produces minors C and D
        	  if (embedFlags == EMBEDFLAGS_OUTERPLANAR && (K==2 || K==3))
        		  continue;

              sprintf(Line, "Minor %c = %d\n", K+'A', ObstructionMinorFreqs[K]);
              Message(Line);
         }

         if (!(embedFlags & ~EMBEDFLAGS_PLANAR))
         {
             sprintf(Line, "\nNote: E1 are added to C, E2 are added to A, and E=E3+E4+K5 homeomorphs.\n");
             Message(Line);

             for (K=5; K<NUM_MINORS; K++)
             {
                  sprintf(Line, "Minor E%d = %d\n", K-4, ObstructionMinorFreqs[K]);
                  Message(Line);
             }
         }
     }

     // Report statistics for graph drawing
     else if (embedFlags == EMBEDFLAGS_DRAWPLANAR)
     {
         sprintf(Line, "Num Graphs Embedded and Drawn=%d.\n", MainStatistic);
         Message(Line);
     }

     // Report statistics for subgraph homeomorphism algorithms
     else if (embedFlags == EMBEDFLAGS_SEARCHFORK23)
     {
         sprintf(Line, "Of the generated graphs, %d did not contain a K_{2,3} homeomorph as a subgraph.\n", MainStatistic);
         Message(Line);
     }
     else if (embedFlags == EMBEDFLAGS_SEARCHFORK33)
     {
         sprintf(Line, "Of the generated graphs, %d did not contain a K_{3,3} homeomorph as a subgraph.\n", MainStatistic);
         Message(Line);
     }
     else if (embedFlags == EMBEDFLAGS_SEARCHFORK4)
     {
         sprintf(Line, "Of the generated graphs, %d did not contain a K_4 homeomorph as a subgraph.\n", MainStatistic);
         Message(Line);
     }

     // Report statistics for vertex coloring
     else if (command == 'c')
     {
         sprintf(Line, "Num Graphs colored with 5 or fewer colors=%d.\n", MainStatistic);
         Message(Line);
     }

     FlushConsole(stdout);

     return Result==OK || Result==NONEMBEDDABLE ? OK : NOTOK;
}
示例#4
0
int RandomGraph(char command, int extraEdges, int numVertices, char *outfileName, char *outfile2Name)
{
int  Result;
platform_time start, end;
graphP theGraph=NULL, origGraph;
int embedFlags = GetEmbedFlags(command);
char saveEdgeListFormat;

     GetNumberIfZero(&numVertices, "Enter number of vertices:", 1, 1000000);
     if ((theGraph = MakeGraph(numVertices, command)) == NULL)
    	 return NOTOK;

     srand(time(NULL));

     Message("Creating the random graph...\n");
     platform_GetTime(start);
     if (gp_CreateRandomGraphEx(theGraph, 3*numVertices-6+extraEdges) != OK)
     {
         ErrorMessage("gp_CreateRandomGraphEx() failed\n");
         return NOTOK;
     }
     platform_GetTime(end);

     sprintf(Line, "Created random graph with %d edges in %.3lf seconds. ", theGraph->M, platform_GetDuration(start,end));
     Message(Line);
     FlushConsole(stdout);

     // The user may have requested a copy of the random graph before processing
     if (outfile2Name != NULL)
     {
         gp_Write(theGraph, outfile2Name, WRITE_ADJLIST);
     }

     origGraph = gp_DupGraph(theGraph);

     // Do the requested algorithm on the randomly generated graph
     Message("Now processing\n");
     FlushConsole(stdout);

     if (strchr("pdo234", command))
     {
         platform_GetTime(start);
         Result = gp_Embed(theGraph, embedFlags);
         platform_GetTime(end);

    	 gp_SortVertices(theGraph);

         if (gp_TestEmbedResultIntegrity(theGraph, origGraph, Result) != Result)
             Result = NOTOK;
     }
     else if (command == 'c')
     {
         platform_GetTime(start);
    	 Result = gp_ColorVertices(theGraph);
         platform_GetTime(end);
     }
     else
    	 Result = NOTOK;

     // Write what the algorithm determined and how long it took
     WriteAlgorithmResults(theGraph, Result, command, start, end, NULL);

     // On successful algorithm result, write the output file and see if the
     // user wants the edge list formatted file.
     if (Result == OK || Result == NONEMBEDDABLE)
     {
    	 if (outfileName != NULL)
    		 gp_Write(theGraph, outfileName, WRITE_ADJLIST);

         Prompt("Do you want to save the generated graph in edge list format (y/n)? ");
         fflush(stdin);
         scanf(" %c", &saveEdgeListFormat);
         if (tolower(saveEdgeListFormat) == 'y')
         {
        	 char *fileName = "maxPlanarEdgeList.txt";
             if (extraEdges > 0)
            	 fileName = "nonPlanarEdgeList.txt";

             SaveAsciiGraph(theGraph, fileName);
             sprintf(Line, "Edge list format saved to '%s'\n", fileName);
        	 Message(Line);
         }
     }
     else ErrorMessage("Failure occurred");

     gp_Free(&theGraph);
     gp_Free(&origGraph);

     FlushConsole(stdout);
     return Result;
}
int SpecificGraph(char command, char *infileName, char *outfileName, char *outfile2Name)
{
graphP theGraph, origGraph;
platform_time start, end;
int Result;

    // Get the filename of the graph to test
    if ((infileName = ConstructInputFilename(infileName)) == NULL)
	    return NOTOK;

    // Create the graph and, if needed, attach the correct algorithm to it
    theGraph = gp_New();

	switch (command)
	{
		case 'd' : gp_AttachDrawPlanar(theGraph); break;
		case '2' : gp_AttachK23Search(theGraph); break;
		case '3' : gp_AttachK33Search(theGraph); break;
		case '4' : gp_AttachK4Search(theGraph); break;
		case 'c' : gp_AttachColorVertices(theGraph); break;
	}

    // Read the graph into memory
	Result = gp_Read(theGraph, infileName);
	if (Result == NONEMBEDDABLE)
	{
		Message("The graph contains too many edges.\n");
		// Some of the algorithms will still run correctly with some edges removed.
		if (strchr("pdo234", command))
		{
			Message("Some edges were removed, but the algorithm will still run correctly.\n");
			Result = OK;
		}
	}

	// If there was an unrecoverable error, report it
	if (Result != OK)
		ErrorMessage("Failed to read graph\n");

	// Otherwise, call the correct algorithm on it
	else
	{
		// Copy the graph for integrity checking
        origGraph = gp_DupGraph(theGraph);

        // Run the algorithm
        if (strchr("pdo234", command))
        {
    		int embedFlags = GetEmbedFlags(command);
	        platform_GetTime(start);

//	        gp_CreateDFSTree(theGraph);
//	        gp_SortVertices(theGraph);
//			gp_Write(theGraph, "debug.before.txt", WRITE_DEBUGINFO);
//	        gp_SortVertices(theGraph);

			Result = gp_Embed(theGraph, embedFlags);
	        platform_GetTime(end);
	        Result = gp_TestEmbedResultIntegrity(theGraph, origGraph, Result);
        }
        else
        {
	        platform_GetTime(start);
        	if (command == 'c')
        	{
    			if ((Result = gp_ColorVertices(theGraph)) == OK)
    				 Result = gp_ColorVerticesIntegrityCheck(theGraph, origGraph);
        	}
        	else
    			Result = NOTOK;
   	        platform_GetTime(end);
        }

        // Write what the algorithm determined and how long it took
        WriteAlgorithmResults(theGraph, Result, command, start, end, infileName);

        // Free the graph obtained for integrity checking.
        gp_Free(&origGraph);
	}

	// Report an error, if there was one, free the graph, and return
	if (Result != OK && Result != NONEMBEDDABLE)
	{
		ErrorMessage("AN ERROR HAS BEEN DETECTED\n");
		Result = NOTOK;
//		gp_Write(theGraph, "debug.after.txt", WRITE_DEBUGINFO);
	}

	// Provide the output file(s)
	else
	{
        // Restore the vertex ordering of the original graph (undo DFS numbering)
        if (strchr("pdo234", command))
            gp_SortVertices(theGraph);

        // Determine the name of the primary output file
        outfileName = ConstructPrimaryOutputFilename(infileName, outfileName, command);

        // For some algorithms, the primary output file is not always written
        if ((strchr("pdo", command) && Result == NONEMBEDDABLE) ||
        	(strchr("234", command) && Result == OK))
        {
        	// Do not write the file
        }

        // Write the primary output file, if appropriate to do so
        else
        {
			gp_Write(theGraph, outfileName, WRITE_ADJLIST);
        }

        // NOW WE WANT TO WRITE THE SECONDARY OUTPUT FILE

		// When called from the menu system, we want to write the planar or outerplanar
		// obstruction, if one exists. For planar graph drawing, we want the character
        // art rendition.  An empty but non-NULL string is passed to indicate the necessity
        // of selecting a default name for the second output file.
		if (outfile2Name != NULL)
		{
			if ((command == 'p' || command == 'o') && Result == NONEMBEDDABLE)
			{
				// By default, use the same name as the primary output filename
				if (strlen(outfile2Name) == 0)
				    outfile2Name = outfileName;
				gp_Write(theGraph, outfile2Name, WRITE_ADJLIST);
			}
			else if (command == 'd' && Result == OK)
			{
				// By default, add ".render.txt" to the primary output filename
				if (strlen(outfile2Name) == 0)
   				    strcat((outfile2Name = outfileName), ".render.txt");
				gp_DrawPlanar_RenderToFile(theGraph, outfile2Name);
			}
		}
	}

	// Free the graph
	gp_Free(&theGraph);

	// Flush any remaining message content to the user, and return the result
    FlushConsole(stdout);
	return Result;
}
void Prompt(char *message)
{
    Message(message);
    FlushConsole(stdout);
}
示例#7
0
int helpMessage(char *param)
{
	char *commandStr =
    	"C = command from menu\n"
    	"    -p = Planar embedding and Kuratowski subgraph isolation\n"
        "    -o = Outerplanar embedding and obstruction isolation\n"
        "    -d = Planar graph drawing\n"
        "    -2 = Search for subgraph homeomorphic to K_{2,3}\n"
        "    -3 = Search for subgraph homeomorphic to K_{3,3}\n"
        "    -4 = Search for subgraph homeomorphic to K_4\n"
		"    -c = Color the vertices of the graph\n"
    	"\n";

	ProjectTitle();

	if (param == NULL)
	{
	    Message(
            "'planarity': menu-driven\n"
            "'planarity (-h|-help)': this message\n"
            "'planarity (-h|-help) -menu': more help with menu-based command line\n"
    	    "'planarity -test [-q] [C]': runs tests (optional quiet mode, single test)\n"
	    	"\n"
	    );

	    Message(
	    	"Common usages\n"
	    	"-------------\n"
            "planarity -s -q -p infile.txt embedding.out [obstruction.out]\n"
	    	"Process infile.txt in quiet mode (-q), putting planar embedding in \n"
	    	"embedding.out or (optionally) a Kuratowski subgraph in Obstruction.out\n"
	    	"Process returns 0=planar, 1=nonplanar, -1=error\n"
	    	"\n"
            "planarity -s -q -d infile.txt embedding.out [drawing.out]\n"
            "If graph in infile.txt is planar, then put embedding in embedding.out \n"
            "and (optionally) an ASCII art drawing in drawing.out\n"
            "Process returns 0=planar, 1=nonplanar, -1=error\n"
	    	"\n"
	    );
	}

	else if (strcmp(param, "-menu") == 0)
	{
	    Message(
	    	"'planarity -r [-q] C K N': Random graphs\n"
	    	"'planarity -s [-q] C I O [O2]': Specific graph\n"
	        "'planarity -rm [-q] N O [O2]': Maximal planar random graph\n"
	        "'planarity -rn [-q] N O [O2]': Nonplanar random graph (maximal planar + edge)\n"
	        "'planarity I O [-n O2]': Legacy command-line (default -s -p)\n"
	    	"\n"
	    );

	    Message("-q is for quiet mode (no messages to stdout and stderr)\n\n");

	    Message(commandStr);

	    Message(
	    	"K = # of graphs to randomly generate\n"
	    	"N = # of vertices in each randomly generated graph\n"
	        "I = Input file (for work on a specific graph)\n"
	        "O = Primary output file\n"
	        "    For example, if C=-p then O receives the planar embedding\n"
	    	"    If C=-3, then O receives a subgraph containing a K_{3,3}\n"
	        "O2= Secondary output file\n"
	    	"    For -s, if C=-p or -o, then O2 receives the embedding obstruction\n"
	       	"    For -s, if C=-d, then O2 receives a drawing of the planar graph\n"
	    	"    For -m and -n, O2 contains the original randomly generated graph\n"
	    	"\n"
	    );

	    Message(
	        "planarity process results: 0=OK, -1=NOTOK, 1=NONEMBEDDABLE\n"
	    	"    1 result only produced by specific graph mode (-s)\n"
	        "      with command -2,-3,-4: found K_{2,3}, K_{3,3} or K_4\n"
	    	"      with command -p,-d: found planarity obstruction\n"
	    	"      with command -o: found outerplanarity obstruction\n"
	    );
	}

    FlushConsole(stdout);
    return 0;
}
示例#8
0
int menu(void)
{
char Choice;

     do {
    	ProjectTitle();

        Message("\n"
                "P. Planar embedding and Kuratowski subgraph isolation\n"
                "D. Planar graph drawing\n"
                "O. Outerplanar embedding and obstruction isolation\n"
                "2. Search for subgraph homeomorphic to K_{2,3}\n"
                "3. Search for subgraph homeomorphic to K_{3,3}\n"
                "4. Search for subgraph homeomorphic to K_4\n"
        		"C. Color the vertices of the graph\n"
        		"H. Help message for command line version\n"
                "R. Reconfigure options\n"
                "X. Exit\n"
        		"\n"
        );

        Prompt("Enter Choice: ");
        fflush(stdin);
        scanf(" %c", &Choice);
        Choice = tolower(Choice);

        if (Choice == 'h')
        	helpMessage(NULL);

        else if (Choice == 'r')
        	Reconfigure();

        else if (Choice != 'x')
        {
        	char *secondOutfile = NULL;
        	if (Choice == 'p'  || Choice == 'o' || Choice == 'd')
        		secondOutfile ="";

            switch (tolower(Mode))
            {
                case 's' : SpecificGraph(Choice, NULL, NULL, secondOutfile); break;
                case 'r' : RandomGraphs(Choice, 0, 0); break;
                case 'm' : RandomGraph(Choice, 0, 0, NULL, NULL); break;
                case 'n' : RandomGraph(Choice, 1, 0, NULL, NULL); break;
            }
        }

        if (Choice != 'r' && Choice != 'x')
        {
            Prompt("\nPress a key then hit ENTER to continue...");
            fflush(stdin);
            scanf(" %*c");
            fflush(stdin);
            Message("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
            FlushConsole(stdout);
        }

     }  while (Choice != 'x');

     // Certain debuggers don't terminate correctly with pending output content
     FlushConsole(stdout);
     FlushConsole(stderr);

     return 0;
}
示例#9
0
int helpMessage(char *param)
{
	char *commandStr =
    	"C = command (algorithm implementation to run)\n"
    	"    -p = Planar embedding and Kuratowski subgraph isolation\n"
        "    -d = Planar graph drawing by visibility representation\n"
        "    -o = Outerplanar embedding and obstruction isolation\n"
        "    -2 = Search for subgraph homeomorphic to K_{2,3}\n"
        "    -3 = Search for subgraph homeomorphic to K_{3,3}\n"
        "    -4 = Search for subgraph homeomorphic to K_4\n"
		"    -a = All of the above\n"
    	"\n";

	ProjectTitle();

	if (param == NULL)
	{
	    Message(
            "'planarity': if no command-line, then menu-driven\n"
            "'planarity (-h|-help)': this message\n"
            "'planarity (-h|-help) -gen': more help with graph generator command line\n"
            "'planarity (-h|-help) -menu': more help with menu-based command line\n"
	        "'planarity (-i|-info): copyright and license information\n"
    	    "'planarity -test [-q] [C]': runs tests (optional quiet mode, single test)\n"
	    	"\n"
	    );

	    Message(
	    	"Common usages\n"
	    	"-------------\n"
            "planarity -s -q -p infile.txt embedding.out [obstruction.out]\n"
	    	"Process infile.txt in quiet mode (-q), putting planar embedding in \n"
	    	"embedding.out or (optionally) a Kuratowski subgraph in Obstruction.out\n"
	    	"Process returns 0=planar, 1=nonplanar, -1=error\n"
	    	"\n"
            "planarity -s -q -d infile.txt embedding.out [drawing.out]\n"
            "If graph in infile.txt is planar, then put embedding in embedding.out \n"
            "and (optionally) an ASCII art drawing in drawing.out\n"
            "Process returns 0=planar, 1=nonplanar, -1=error\n"
	    );
	}

	else if (strcmp(param, "-i") == 0 || strcmp(param, "-info") == 0)
	{
	    Message(
		    "The Edge Addition Planarity Suite\n"
	    	"Copyright (c) 1997-2015, John M. Boyer\n"
		    "All rights reserved. \n"
	    	"See the LICENSE.TXT file for licensing information. \n"
            "\n"
	    	"Includes a reference implementation of the following:\n"
            "\n"
	    	"* John M. Boyer. \"Subgraph Homeomorphism via the Edge Addition Planarity \n"
	    	"  Algorithm\".  Journal of Graph Algorithms and Applications, Vol. 16, \n"
	    	"  no. 2, pp. 381-410, 2012. http://www.jgaa.info/16/268.html\n"
            "\n"
		    "* John M. Boyer. \"A New Method for Efficiently Generating Planar Graph\n"
		    "  Visibility Representations\". In P. Eades and P. Healy, editors,\n"
		    "  Proceedings of the 13th International Conference on Graph Drawing 2005,\n"
		    "  Lecture Notes Comput. Sci., Volume 3843, pp. 508-511, Springer-Verlag, 2006.\n"
            "\n"
		    "* John M. Boyer and Wendy J. Myrvold. \"On the Cutting Edge: Simplified O(n)\n"
		    "  Planarity by Edge Addition\". Journal of Graph Algorithms and Applications,\n"
		    "  Vol. 8, No. 3, pp. 241-273, 2004.\n"
		    "  http://www.jgaa.info/08/91.html\n"
            "\n"
		    "* John M. Boyer. \"Simplified O(n) Algorithms for Planar Graph Embedding,\n"
		    "  Kuratowski Subgraph Isolation, and Related Problems\". Ph.D. Dissertation,\n"
		    "  University of Victoria, 2001.\n"
            "\n"
	    );
	}

	else if (strcmp(param, "-menu") == 0)
	{
	    Message(
	    	"'planarity -r [-q] C K N': Random graphs\n"
	    	"'planarity -s [-q] C I O [O2]': Specific graph\n"
	        "'planarity -rm [-q] N O [O2]': Maximal planar random graph\n"
	        "'planarity -rn [-q] N O [O2]': Nonplanar random graph (maximal planar + edge)\n"
	        "'planarity I O [-n O2]': Legacy command-line (default -s -p)\n"
	    	"\n"
	    );

	    Message("-q is for quiet mode (no messages to stdout and stderr)\n\n");

	    Message(commandStr);

	    Message(
	    	"K = # of graphs to randomly generate\n"
	    	"N = # of vertices in each randomly generated graph\n"
	        "I = Input file (for work on a specific graph)\n"
	        "O = Primary output file\n"
	        "    For example, if C=-p then O receives the planar embedding\n"
	    	"    If C=-3, then O receives a subgraph containing a K_{3,3}\n"
	        "O2= Secondary output file\n"
	    	"    For -s, if C=-p or -o, then O2 receives the embedding obstruction\n"
	       	"    For -s, if C=-d, then O2 receives a drawing of the planar graph\n"
	    	"    For -m and -n, O2 contains the original randomly generated graph\n"
	    	"\n"
	    );

	    Message(
	        "planarity process results: 0=OK, -1=NOTOK, 1=NONEMBEDDABLE\n"
	    	"    1 result only produced by specific graph mode (-s)\n"
	        "      with command -2,-3,-4: found K_{2,3}, K_{3,3} or K_4\n"
	    	"      with command -p,-d: found planarity obstruction\n"
	    	"      with command -o: found outerplanarity obstruction\n"
	    );
	}

    FlushConsole(stdout);
    return 0;
}