Initial commit

master
Joeyrp 4 years ago
commit 04a24a6ac3

59
.gitignore vendored

@ -0,0 +1,59 @@
######################## VSCODE IGNORES
.vscode/
######################## C++ IGNORES
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# other
*.log
*.zip
*.ini
test_data/test_save.xml
######################## CMAKE IGNORES
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
######################## BUILD IGNORES
build/

@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.16.3)
# Set the project name and version
project(cgen VERSION 0.1.0)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
configure_file(cgenConfig.h.in cgenConfig.h)
set( CGEN_SRC
src/main.cpp
src/utils/CmdArgParser.cpp
src/utils/StringManip.cpp
)
# add the executable
add_executable(${PROJECT_NAME} ${CGEN_SRC})
target_include_directories(${PROJECT_NAME}
PUBLIC "${PROJECT_BINARY_DIR}"
PUBLIC src
)

@ -0,0 +1,7 @@
Copyright 2021 Joseph R Pollack
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,4 @@
// the configured options and settings for Lunarium
#define cgen_VERSION_MAJOR @cgen_VERSION_MAJOR@
#define cgen_VERSION_MINOR @cgen_VERSION_MINOR@
#define cgen_VERSION_PATCH @cgen_VERSION_PATCH@

@ -0,0 +1,17 @@
@echo off
REM This script expects to be run from the parent directory
REM ex. scripts/build.bat
IF not exist build/ (
echo This script needs to be run from the directory above build/
goto END
)
IF "%~1" == "r" (
cmake --build build/ --target ALL_BUILD --config Release
) ELSE (
cmake --build build/ --target ALL_BUILD --config Debug
)
:END

@ -0,0 +1,13 @@
@echo off
IF not exist build/ (
echo This script needs to be run from the directory above build/
goto END
)
echo Removing the build directory
del /s /q build
rd /s /q build
:END

@ -0,0 +1,7 @@
@echo off
REM This script expects to be run from the parent directory
REM ex. scripts/cmconfig.bat
@echo off
cmake -Wno-dev -B build/ -S . -G "Visual Studio 16 2019" -A x64

@ -0,0 +1,23 @@
/******************************************************************************
* File - main.cpp
* Author - Joey Pollack
* Date - 2021/12/03 (y/m/d)
* Mod Date - 2021/12/03 (y/m/d)
* Description - Generates a new C++ project with CMake
******************************************************************************/
#include <utils/CmdArgParser.h>
#include <utils/StringManip.h>
#include <iostream>
typedef jpUtils::CmdArgParser::ArgDesc ArgDesc;
int main(int argc, char** argv)
{
jpUtils::CmdArgParser argParser(argc, argv, "Generates a new C++ project with CMake");
return 0;
}

@ -0,0 +1,267 @@
/******************************************************************************
* File - CmdArgParser.cpp
* Author - Joey Pollack
* Date - 2018/09/27 (y/m/d)
* Mod Date - 2018/10/15 (y/m/d)
* Description - Parses the program's command line arguments and makes
* them easily available.
*
* Code should work on windows and *nix
******************************************************************************/
#include "CmdArgParser.h"
#include "StringManip.h"
namespace jpUtils
{
const CmdArgParser::Argument CmdArgParser::InvalidArg;
CmdArgParser::CmdArgParser(int argc, char ** argv, std::string programDesc, char prefixChar)
: mArgc(argc), mArgv(argv), mPrefixChar(prefixChar), mUsageText(""), mErrorMessage(""), mProgramDesc(programDesc)
{
// TODO: Add -h arg?
}
bool CmdArgParser::ContainsOption(const char * option) const
{
return mOptionalArgs.find(option) != mOptionalArgs.end();
}
const CmdArgParser::Argument& CmdArgParser::GetPositionalArg(int pos) const
{
if (pos < 0 || pos >= (signed)mPositionalArgs.size())
return CmdArgParser::InvalidArg;
return mPositionalArgs[pos];
}
const std::vector<CmdArgParser::Argument> CmdArgParser::GetAllPosArgs() const
{
return mPositionalArgs;
}
const CmdArgParser::Argument& CmdArgParser::GetOptionValue(const char * option) const
{
auto iter = mOptionalArgs.find(std::string(option));
if (iter == mOptionalArgs.end())
return CmdArgParser::InvalidArg;
return iter->second;
}
bool CmdArgParser::Parse()
{
mOptionalArgs.clear();
mPositionalArgs.clear();
std::vector<std::string> tempPosValues;
mErrorMessage = "";
for (int i = 1; i < mArgc; i++)
{
// If this is an optional arg
if (mArgv[i][0] == mPrefixChar)
{
// Optional args must occur before or after all positional args
if (mPositionalArgs.size() != 0 && mPositionalArgs.size() < mExpectedPosArgs.size())
{
mErrorMessage += "\nMissing Required Arguments";
return false;
}
auto iter = mExpectedOptArgs.find(std::string(mArgv[i]));
if (iter == mExpectedOptArgs.end())
{
mErrorMessage += "\nUknown Argument: " + std::string(mArgv[i]);
continue; // Non fatal error
}
const ArgDesc& arg = (ArgDesc)(*iter).second;
if (mOptionalArgs.find(arg.name) != mOptionalArgs.end())
{
mErrorMessage += "\nDuplicate Argument: " + std::string(mArgv[i]);
return false;
}
Argument theArg;
theArg.name = arg.name;
for (int j = 0; j < arg.numExpectedValues; j++)
{
i++;
if (i >= mArgc)
{
mErrorMessage += "\nNot enough values given for option argument: " + theArg.name;
return false;
}
if (mArgv[i][0] == mPrefixChar)
{
mErrorMessage += "\nNot enough values given for option argument: " + theArg.name;
return false;
}
theArg.values.push_back(std::string(mArgv[i]));
}
mOptionalArgs.insert(std::pair<std::string, Argument>(theArg.name, theArg));
}
// If this is a positional arg
else
{
tempPosValues.push_back(std::string(mArgv[i]));
}
}
//if (mPositionalArgs.size() > mExpectedPosArgs.size())
//{
// mErrorMessage += "\nToo many Arguments given";
// return true; // non fatal error
//}
// Split the positional args into lists based on how many values are expected for each
int numArgs = mExpectedPosArgs.size();
int numValues = tempPosValues.size();
int minNeededValues = 0;
int used = 0;
// find the min number of values needed to satisfy all arg requirements
for (int i = 0; i < (signed)mExpectedPosArgs.size(); i++)
{
if (mExpectedPosArgs[i].numExpectedValues > 0)
minNeededValues += mExpectedPosArgs[i].numExpectedValues;
if (mExpectedPosArgs[i].numExpectedValues == -1)
minNeededValues += 1;
}
if (numValues < minNeededValues)
{
// TODO: Could add logic to print the name of the missing args
mErrorMessage += "\nNot enough arguments";
return false;
}
for (int i = 0; i < (signed)mExpectedPosArgs.size(); i++)
{
Argument arg;
arg.name = mExpectedPosArgs[i].name;
// if -1 this arg will accept 1 or more values available
if (-1 == mExpectedPosArgs[i].numExpectedValues)
{
// How many values can be put in this arg list while still
// having enough left over to fill the rest of the args?
// numUsable should always be at least 1
int numUsable = (tempPosValues.size() - used) - (minNeededValues - 1);
#ifdef _DEBUG
if (numUsable < 1)
{
throw "numUsable is < 1!";
}
#endif // _DEBUG
// used is the index of the next available value in tempPosValues
// numUsable + used is the index past the last value in
// tempPosValues that will fit here
int endIdx = (numUsable + used);
for (int j = used; j < endIdx; j++)
{
arg.values.push_back(tempPosValues[j]);
used++;
}
}
else
{
int endIdx = (mExpectedPosArgs[i].numExpectedValues + used);
for (int j = used; j < endIdx; j++)
{
arg.values.push_back(tempPosValues[j]);
used++;
}
}
mPositionalArgs.push_back(arg);
}
return true;
}
std::string CmdArgParser::GetErrorMessage() const
{
return mErrorMessage;
}
bool CmdArgParser::AddArg(ArgDesc desc)
{
// With new args the usage text needs to be regenerated
// Making it empty will force it to be regenerated when GetUsageText() is called
mUsageText = "";
// argument names must not contain spaces
// so remove anything after the first space
if (desc.name.length() > 0)
desc.name = StringManip::Split(desc.name)[0];
if (desc.optional)
{
if (mExpectedOptArgs.find(desc.name) != mExpectedOptArgs.end())
return false;
mExpectedOptArgs.insert(std::pair<std::string, ArgDesc>(desc.name, desc));
}
else
{
mExpectedPosArgs.push_back(desc);
}
return true;
}
std::string CmdArgParser::GetUsageText()
{
if ("" == mUsageText)
GenerateUsageText();
return mUsageText;
}
void CmdArgParser::GenerateUsageText()
{
// TODO: GenerateUsageText()
mUsageText = "";
std::string programName = StringManip::GetFileNameFromPath(std::string(mArgv[0]), false);
mUsageText = programName;
mUsageText += ": " + mProgramDesc;
mUsageText += "\n\nUsage: ";
mUsageText += programName;
mUsageText += " [OPTIONS] ";
for (EPITER iter = mExpectedPosArgs.begin(); iter != mExpectedPosArgs.end(); iter++)
{
mUsageText += (*iter).name + " ";
}
mUsageText += "\n\nOPTIONS:";
for (EOITER iter = mExpectedOptArgs.begin(); iter != mExpectedOptArgs.end(); iter++)
{
mUsageText += "\n\t" + (*iter).first;
mUsageText += " " + (*iter).second.helpText;
}
mUsageText += "\n\nREQUIRED ARGS:";
for (EPITER iter = mExpectedPosArgs.begin(); iter != mExpectedPosArgs.end(); iter++)
{
mUsageText += "\n\t" + (*iter).name + ": " + (*iter).helpText;
}
// ...
}
}

@ -0,0 +1,115 @@
/******************************************************************************
* File - CmdArgParser.h
* Author - Joey Pollack
* Date - 2018/09/27 (y/m/d)
* Mod Date - 2018/10/15 (y/m/d)
* Description - Parses the program's command line arguments and makes
* them easily available.
*
* Code should work on windows and *nix
******************************************************************************/
#ifndef CMD_ARG_PARSER_H_
#define CMD_ARG_PARSER_H_
#include <map>
#include <vector>
#include <string>
namespace jpUtils
{
class CmdArgParser
{
// TODO: Possibly add error codes
// TODO: Add support for --arguments
public:
struct Argument
{
std::string name = "INVALID";
std::vector<std::string> values;
bool operator==(const Argument& rhs)
{
return this->name == rhs.name;
}
};
static const Argument InvalidArg;
struct ArgDesc
{
std::string name;
bool optional;
// -1 for 1 or more args (if optional, 0 or more args)
int numExpectedValues;
std::string helpText;
ArgDesc(std::string _name, bool _optional, int _numExpectedValues, std::string _helpText)
: name(_name), optional(_optional), numExpectedValues(_numExpectedValues), helpText(_helpText)
{
}
};
private: // currently unused
enum ValueType { VTYPE_STRING, VTYPE_INT, VTYPE_DOUBLE, VTYPE_BOOL, VTYPE_INVALID };
public:
CmdArgParser(int argc, char** argv, std::string programDesc, char prefixChar = '-');
bool Parse();
// If the returned string is not empty errors occured when processing
// the arguments. The string contains the generated error messages.
std::string GetErrorMessage() const;
// Returns false if the arg cant be added - this would probably
// happen if a given arg already exists
bool AddArg(ArgDesc desc);
std::string GetUsageText();
bool ContainsOption(const char* option) const;
const CmdArgParser::Argument& GetPositionalArg(int pos) const;
const std::vector<Argument> GetAllPosArgs() const;
const Argument& GetOptionValue(const char* option) const;
private:
int mArgc;
char** mArgv;
std::string mUsageText;
std::string mErrorMessage;
std::string mProgramDesc;
// can be set to '-' or '/'
char mPrefixChar;
// Expected Positional Arguments
std::vector<ArgDesc> mExpectedPosArgs;
typedef std::vector<ArgDesc>::iterator EPITER;
// Positional args found
std::vector<Argument> mPositionalArgs;
typedef std::vector<std::string>::iterator PITER;
// Expected Optional args
std::map<std::string, ArgDesc> mExpectedOptArgs;
typedef std::map<std::string, ArgDesc>::iterator EOITER;
// Optional args found
std::map<std::string, Argument> mOptionalArgs;
typedef std::map<std::string, Argument>::iterator OITER;
private: // HELPER METHODS
void GenerateUsageText();
};
}
#endif // CMD_ARG_PARSER_H_

@ -0,0 +1,138 @@
/******************************************************************************
* File - StringManip.cpp
* Author - Joey Pollack
* Date - 2018/10/12 (y/m/d)
* Mod Date - 2018/10/12 (y/m/d)
* Description - Functions for working with std::string objects
*
******************************************************************************/
#include "StringManip.h"
#include <algorithm>
#include <cctype>
namespace jpUtils
{
std::vector<std::string> StringManip::Split(std::string str, char delim, int maxSplits)
{
std::vector<std::string> splits;
int startPos = 0;
for (int i = 0; i < (signed)str.length(); i++)
{
if (str[i] == delim)
{
if (startPos == i)
continue;
std::string s = str.substr(startPos, i - startPos);
splits.push_back(s);
startPos = i + 1;
if (maxSplits > 0 && (signed)splits.size() >= (maxSplits - 1))
{
break;
}
}
}
std::string s = str.substr(startPos);
splits.push_back(s);
return splits;
}
std::string StringManip::Trim(std::string str, std::string delims)
{
str = TrimStart(str, delims);
str = TrimEnd(str, delims);
return str;
}
std::string StringManip::TrimStart(std::string str, std::string delims)
{
bool isDelim = true;
while (isDelim && str.length() > 0)
{
isDelim = false;
for (int i = 0; i < (signed)delims.length(); i++)
{
if (str[0] == delims[i])
{
isDelim = true;
break;
}
}
if (isDelim)
str.erase(str.begin());
}
return str;
}
std::string StringManip::TrimEnd(std::string str, std::string delims)
{
bool isDelim = true;
while (isDelim && str.length() > 0)
{
isDelim = false;
for (int i = 0; i < (signed)delims.length(); i++)
{
if (*(str.rbegin()) == delims[i])
{
isDelim = true;
break;
}
}
if (isDelim)
str.erase((str.rbegin() + 1).base());
}
return str;
}
std::string StringManip::GetFileNameFromPath(std::string path, bool includeExt)
{
path.erase(path.begin(), std::find_if(path.rbegin(), path.rend(), [](int ch) { return ch == '\\' || ch == '/'; }).base());
if (!includeExt)
{
path.erase(std::find_if(path.rbegin(), path.rend(), [](int ch) { return ch == '.'; }).base(), path.end());
path.erase(path.begin() + path.size() - 1);
}
return path;
}
std::string StringManip::TrimFileNameFromPath(std::string path)
{
path.erase(std::find_if(path.rbegin(), path.rend(), [](int ch) { return ch == '\\' || ch == '/'; }).base(), path.end());
return path;
}
std::string StringManip::GetFileExtension(std::string filename)
{
filename.erase(filename.begin(), std::find_if(filename.begin(), filename.end(), [](int ch) { return ch == '.'; }));
filename.erase(filename.begin());
return filename;
}
int StringManip::AsInt(std::string value)
{
return atoi(value.c_str());
}
double StringManip::AsDouble(std::string value)
{
return atof(value.c_str());
}
bool StringManip::AsBool(std::string value)
{
return value == std::string("true");
}
}

@ -0,0 +1,56 @@
/******************************************************************************
* File - StringManip.h
* Author - Joey Pollack
* Date - 2018/10/12 (y/m/d)
* Mod Date - 2018/10/12 (y/m/d)
* Description - Functions for working with std::string objects
*
******************************************************************************/
#ifndef STRING_MANIP_H_
#define STRING_MANIP_H_
#include <string>
#include <vector>
namespace jpUtils
{
class StringManip
{
public:
// Generic string helpers
// ===========================================================
// Splits the string based on the given delimiter,
// maxSplit = -1 for unlimited number of splits
static std::vector<std::string> Split(std::string str, char delim = ' ', int maxSplits = -1);
// Trim given delimiters from start and end of string
static std::string Trim(std::string str, std::string delims = " \r\n\t");
// Trim given delimiters from start of string
static std::string TrimStart(std::string str, std::string delims = " \r\n\t");
// Trim given delimiters from end of string
static std::string TrimEnd(std::string str, std::string delims);
// File path helpers
// ===========================================================
static std::string GetFileNameFromPath(std::string path, bool includeExt = true);
static std::string TrimFileNameFromPath(std::string path);
static std::string GetFileExtension(std::string filename);
// Type Conversion
// ===========================================================
static int AsInt(std::string value);
static double AsDouble(std::string value);
static bool AsBool(std::string value);
};
}
#endif // STRING_MANIP_H_
Loading…
Cancel
Save