/*=========================================================================== * * File: ConApp.CPP * Author: Dave Humphrey (uesp@m0use.net) * Created On: Wednesday, December 06, 2000 * * Contains the implementation for the CConsoleApp class providing a * base class for simple console applications. * * Steps to using CConsoleApp for your program: * 1. Derive a class from CConsoleApp such as * class CMyApp : public CConsoleApp { * 2. Add a global object of your class to your source code and * the standard macro to create the main() routine. * CMyApp theApp; * STANDARD_CONSOLEAPP_MAIN(theApp); * 3. Create an array of strings that you wish to display for the * program's help and set the ppHelpText class member to the * first string in the array. Don't forget to NULL terminate * the array. * char* pMyHelp[] = { * "This is my simple console application", * "", * "\tUsage: MyApp /?", * NULL }; * 4. Override the virtual methods ParseCommand() and ParseParameter() * if you wish to handle any command line arguments passed to the * program. Remember to call the base class method if you wish to * retain some of its capabilities. * 5. Override StartApp() to contain whatever it is your program does. * Consider this just a different main() function. * *=========================================================================*/ /* Include Files */ #include "conapp.h" #include #include /*=========================================================================== * * Begin Global/Local Variables * *=========================================================================*/ DEFINE_FILE(); /* A pointer to the one and only console application object */ CConsoleApp* pTheConsoleApp = NULL; /*=========================================================================== * End of Global/Local Variables *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Constructor * *=========================================================================*/ CConsoleApp::CConsoleApp() { //DEFINE_FUNCTION("CConsoleApp::CConsoleApp()"); /* Add the custom class errors only once */ static boolean InitErrors = AddClassErrors(); /* Initialize the program command line arguments */ NumArguments = 0; pArguments = NULL; pOutputStream = stdout; /* Initialize the program information */ pProgramName = NULL; pAppName = CreateString(DL_BASE_NAME); pAppDate = CreateString(DL_BASE_DATE); pAppAuthor = CreateString(DL_BASE_AUTHOR); ppHelpText = NULL; /* Create the compiled-on date */ pCompiledDate = CreateString(__DL_TIMESTAMP__); /* Set the initial version information */ MajorVersion = 0; MinorVersion = 0; ReleaseType = RELEASE_UNKNOWN; BuildNumber = -1; /* Set the command parsing options */ DoParseCommands = TRUE; DoParseParameters = TRUE; DoFlagParsing = TRUE; /* Set the various display options */ DisplayTitle = TRUE; DoOpenLog = TRUE; /* Set the initial paging options */ OutputLineCount = 0; DoPaging = TRUE; LinesPerPage = 23; } /*=========================================================================== * End of Class CConsoleApp Constructor *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - void Destroy (void) * * Destroys or resets any class members. * *=========================================================================*/ void CConsoleApp::Destroy (void) { //DEFINE_FUNCTION("CConsoleApp::Destroy()"); int LoopCounter; /* Delete the arguments array */ for (LoopCounter = 0; LoopCounter < NumArguments; LoopCounter++) { DestroyArrayPointer(pArguments[LoopCounter]); } DestroyArrayPointer(pArguments); /* Delete any allocated strings */ DestroyArrayPointer(pProgramName); DestroyArrayPointer(pAppName); DestroyArrayPointer(pAppDate); DestroyArrayPointer(pAppAuthor); DestroyArrayPointer(pCompiledDate); NumArguments = 0; OutputLineCount = 0; } /*=========================================================================== * End of Class Method CConsoleApp::Destroy() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - boolean AddClassErrors (void) * * Static function which registers the custom errors for the class. * *=========================================================================*/ boolean CConsoleApp::AddClassErrors (void) { //DEFINE_FUNCTION("CConsoleApp::AddClassErrors()"); ErrorDatabase.Add (ERRCONAPP_NOHELP, "No help text was defined!", ERRLEVEL_WARNING); ErrorDatabase.Add(ERRCONAPP_BADLINESPERPAGE, "Bad lines per page value specified!"); return (TRUE); } /*=========================================================================== * End of Class Method CConsoleApp::AddClassErrors() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - void AbortProgram (void) * * Aborts the program and outputs the error message in the ErrorHandler * object. Method does not return. * *=========================================================================*/ void CConsoleApp::AbortProgram (void) { //DEFINE_FUNCTION("CConsoleApp::AbortProgram()"); fprintf (pOutputStream, " Program Error...Aborting!\n"); fprintf (pOutputStream, "\t%s\n\n", ErrorHandler.GetLastErrorMsg()); /* Exit program with failure code */ exit(EXIT_FAILURE); } /*=========================================================================== * End of Class Method CConsoleApp::AbortProgram() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - boolean OpenLog (void) * * Opens a log file with the same name as the program with a LOG extension * for any debug builds. * *=========================================================================*/ boolean CConsoleApp::OpenLog (void) { //DEFINE_FUNCTION("CConsoleApp::OpenLog()"); #if defined(_DEBUG) char LogFilename[_MAX_FNAME + 5] = "temp.log"; /* Create a file with the new extension and attempt to open log */ ChangeExtension(LogFilename, pProgramName, ".log", _MAX_FNAME+4); return (SystemLog.Open(LogFilename)); #else return (TRUE); #endif } /*=========================================================================== * End of Class Method CConsoleApp::OpenLog() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - boolean OutputHelp (void) * * Output the application's help text. * *=========================================================================*/ boolean CConsoleApp::OutputHelp (void) { //DEFINE_FUNCTION( "CConsoleApp::OutputHelp()"); boolean Result = TRUE; int LoopCounter = 0; /* Output title if not already output */ if (!DisplayTitle) Result = OutputTitle(); /* Ignore if no help text array defined */ if (ppHelpText == NULL) { if (Result) Result = PrintLine("\tNo help defined!"); ErrorHandler.AddError(ERRCONAPP_NOHELP); return (Result); } /* Output the help text */ while (ppHelpText[LoopCounter] != NULL) { Result = PrintLine(ppHelpText[LoopCounter]); if (!Result) return (FALSE); LoopCounter++; } return (TRUE); } /*=========================================================================== * End of Class Method CConsoleApp::OutputHelp() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - boolean OutputTitle (void) * * Outputs the standard application title to the current output stream. * Returns FALSE on any output error. * *=========================================================================*/ boolean CConsoleApp::OutputTitle (void) { DEFINE_FUNCTION("CConsoleApp::OutputTitle()"); int Result = 0; /* Ensure valid input */ ASSERT(pOutputStream != NULL); /* Output the program name if present */ if (pAppName) Result = fprintf (pOutputStream, "%s ", pAppName); /* Output the application version */ if (Result >= 0) { Result = (OutputVersion() == TRUE) ? 0 : - 1; if (Result >= 0) Result = fprintf (pOutputStream, ", "); } /* Output application date, author name, and line feed */ if (pAppDate && Result >= 0) Result = fprintf (pOutputStream, "%s, ", pAppDate); if (pAppAuthor && Result >= 0) Result = fprintf (pOutputStream, "by %s", pAppAuthor); if (Result >= 0) Result = fprintf (pOutputStream, "\n"); /* Check for an error condition */ if (Result < 0 || ferror(pOutputStream)) { ErrorHandler.AddError(ERR_SYSTEM, errno, "Error writing to the output file stream!"); return (FALSE); } /* Increase the number of lines output and return success */ OutputLineCount++; return (TRUE); } /*=========================================================================== * End of Class Method CConsoleApp::OutputTitle() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - boolean OutputVersion (void) * * Outputs the version information to the current output stream. * *=========================================================================*/ boolean CConsoleApp::OutputVersion (void) { DEFINE_FUNCTION("CConsoleApp::OutputVersion()"); int Result; /* Ensure a valid output stream handle */ ASSERT(pOutputStream != NULL); Result = fprintf (pOutputStream, "v%0d.%0d%c", MajorVersion, MinorVersion, ReleaseTypeToChar(ReleaseType)); if (Result >= 0 && ReleaseType != RELEASE_FINAL && BuildNumber >= 0) Result = fprintf (pOutputStream, "(build %d)", BuildNumber); /* Check for an error condition */ if (Result < 0) { ErrorHandler.AddError(ERR_SYSTEM, errno, "Error writing to the output file stream!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CConsoleApp::OutputVersion() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - boolean ParseAllParameters (void) * * Parses each of the command line parameters. Returns FALSE on any error. * Protected class method. * *=========================================================================*/ boolean CConsoleApp::ParseAllParameters (void) { //DEFINE_FUNCTION("CConsoleApp::ParseAllParameters()"); cmdparse_t Result; int LoopCounter; for (LoopCounter = 0; LoopCounter < NumArguments; LoopCounter++) { Result = ParseOneParameter(pArguments[LoopCounter]); if (Result == CMDPARSE_FAILED) return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CConsoleApp::ParseAllParameters() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - cmdparse_t ParseCommand (char* pCommand, const boolean Flag) * * Parses the given command parameter string with the given flag. Returns * CMDPARSE_FAILED on error, CMDPARSE_SUCCESS on success, and CMDPARSE_NOTPARSED * if the command was not parsed. * *=========================================================================*/ cmdparse_t CConsoleApp::ParseCommand (char* pCommand, const boolean Flag) { //DEFINE_FUNCTION("CConsoleApp::ParseCommand()"); switch (tolower(*pCommand)) { /* Standard help display, do not return but exit program */ case '?': case 'h': OutputHelp(); exit(EXIT_SUCCESS); /* Paging options */ case 'p': return ParsePagingCommand(pCommand + 1, Flag); /* Unknown command option */ default: return (CMDPARSE_NOTPARSED); } } /*=========================================================================== * End of Class Method CConsoleApp::ParseCommand() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - cmdparse_t ParseOneParameter (char* pString) * * Parses the given parameter string depending on the parsing options. Checks * to see if it is a command string and calls the ParseCommand() method if * required. Returns CMDPARSE_FAILED on any error, CMDPARSE_NOTPARSED if the * parameter could not be parsed for any reason and CMDPARSE_SUCCESS on * success. Protected class method. * *=========================================================================*/ cmdparse_t CConsoleApp::ParseOneParameter (char* pString) { DEFINE_FUNCTION("CConsoleApp::ParseOneParameter()"); boolean CommandFlag = TRUE; int StringSize; /* Ensure valid input */ ASSERT(pString != NULL); pString = trim(pString); /* See if it can be parsed as a command first */ if (DoParseCommands && (*pString == '/' || *pString == '-')) { pString++; /* Check for an initial -/+ flag */ if (*pString == '-') { CommandFlag = FALSE; pString++; } else if (*pString == '+') { CommandFlag = TRUE; pString++; } StringSize = strlen(pString); /* Check for a terminating -/+ flag */ if (pString[StringSize - 1] == '-') CommandFlag = FALSE; else if (pString[StringSize - 1] == '+') CommandFlag = TRUE; /* Parse the command parameter */ return (ParseCommand(pString, CommandFlag)); } /* Default to parsing it as a regular parameter */ return (ParseParameter(pString)); } /*=========================================================================== * End of Class Method CConsoleApp::ParseOneParameter() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - cmdparse_t ParsePagingCommand (pString, Flag); * * Parses a paging option command string and returns CMDPARSE_SUCCESS or * CMDPARSE_FAILED on any error. * *=========================================================================*/ cmdparse_t CConsoleApp::ParsePagingCommand (char* pString, const boolean Flag) { //DEFINE_FUNCTION("CConsoleApp::ParsePagingCommand()"); /* Do we want to turn off paging? */ if (!Flag) { DoPaging = FALSE; return (CMDPARSE_SUCCESS); } /* Parse the number of lines per page from the string */ LinesPerPage = atoi(pString); /* Ensure a valid number */ if (LinesPerPage < 1) { DoPaging = FALSE; ErrorHandler.AddError(ERRCONAPP_BADLINESPERPAGE, "\tInvalid lines per page value specified (%d)!", LinesPerPage); return (CMDPARSE_FAILED); } DoPaging = TRUE; return (CMDPARSE_SUCCESS); } /*=========================================================================== * End of Class Method CConsoleApp::ParsePagingCommand() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - cmdparse_t ParseParameter (pString) * * Parses the given parameter string. Returns CMDPARSE_FAILED on any error, * CMDPARSE_NOTPARSED if the parameter could not be parsed for any reason * and CMDPARSE_SUCCESS on success. Protected class method. * *=========================================================================*/ cmdparse_t CConsoleApp::ParseParameter (char* /* pString*/ ) { //DEFINE_FUNCTION("CConsoleApp::ParseParameter()"); /* Default to not parsing the parameter */ return (CMDPARSE_NOTPARSED); } /*=========================================================================== * End of Class Method CConsoleApp::ParseParameter() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - boolean PrintLine (const char* pString, ...) * * Outputs one line to the current output file stream. Supports paging * as per the values of the current LinesPerPage and DoPaging members. * Returns FALSE on any error. * *=========================================================================*/ boolean CConsoleApp::PrintLine (const char* pString, ...) { //DEFINE_FUNCTION("CConsoleApp::PrintLine()"); int Result = 0; va_list Args; /* Output the variable list of arguments */ if (pString != NULL) { va_start(Args, pString); Result = vfprintf(pOutputStream, pString, Args); va_end(Args); } /* Output the line feed character */ if (Result >= 0) Result = fputs("\n", pOutputStream); OutputLineCount++; /* Check for a paging condition */ if (DoPaging && (OutputLineCount % LinesPerPage) == 0) { Result = fprintf (pOutputStream, "Press any key to continue...\n"); int InputChar = getch(); //getch(); if (Result >= 0) Result = fprintf (pOutputStream, "\n"); if (InputChar == ESC_CHAR) { ErrorHandler.AddError(ERR_BADINPUT, "Action aborted by used!"); AbortProgram(); } } /* Check for an error */ if (Result < 0 || ferror(pOutputStream)) { ErrorHandler.AddError(ERR_SYSTEM, errno, "Error writing to the output file stream!"); return (FALSE); } return (TRUE); } /*=========================================================================== * End of Class Method CConsoleApp::PrintLine() *=========================================================================*/ /*=========================================================================== * * Class CConsoleApp Method - int StartConsoleApp (ArgCount, pArgs[]) * * Entry point for the console app class. * *=========================================================================*/ int CConsoleApp::StartConsoleApp (const int ArgCount, char* pArgs[]) { DEFINE_FUNCTION("CConsoleApp::StartConsoleApp()"); int LoopCounter; boolean Result = TRUE; /* Set the global pointer to the console application */ pTheConsoleApp = this; /* Allocate the program name */ pProgramName = CreateString(pArgs[0]); NumArguments = ArgCount - 1; /* Allocate the arguments array */ if (NumArguments > 0) CreateArrayPointer(pArguments, char*, NumArguments); /* Create the argument strings */ for (LoopCounter = 0; LoopCounter < NumArguments; LoopCounter++) { pArguments[LoopCounter] = CreateString(pArgs[LoopCounter + 1]); } /* Create the standard log file */ if (DoOpenLog) Result = OpenLog(); /* Output the program title if required */ if (Result && DisplayTitle) Result = OutputTitle(); /* Parse any command line parameters if required */ if (Result && DoParseParameters) Result = ParseAllParameters(); if (!Result) return (EXIT_FAILURE); /* Call the user's overridden method */ return (StartApp()); } /*=========================================================================== * End of Class Method CConsoleApp::StartConsoleApp() *=========================================================================*/ /*=========================================================================== * * Function - CConsoleApp* GetConsoleApp (void) * * Returns the global console application object. * *=========================================================================*/ CConsoleApp* GetConsoleApp (void) { DEFINE_FUNCTION("GetConsoleApp()"); ASSERT(pTheConsoleApp != NULL); return (pTheConsoleApp); } /*=========================================================================== * End of Function GetConsoleApp() *=========================================================================*/ /*=========================================================================== * * Function - char ReleaseTypeToChar (ReleaseType); * * Converts a release type to a character for output. * *=========================================================================*/ char ReleaseTypeToChar (const release_t ReleaseType) { //DEFINE_FUNCTION("ReleaseTypeToChar()"); switch (ReleaseType) { case RELEASE_UNKNOWN: return ('?'); case RELEASE_DEBUG: return ('d'); case RELEASE_ALPHA: return ('a'); case RELEASE_BETA: return ('b'); case RELEASE_FINAL: return (' '); default: return ('?'); } } /*=========================================================================== * End of Function ReleaseTypeToChar() *=========================================================================*/