Adding a -q switch to a list of arguments - c++

I am trying to figure a way to add an optional quiet switch to my command line arguments. The program I'm working on is a text to HTML converter, and at minimum requires a text sourcefile to be included in order for the program to run. What I am trying to get, is when a user enters -q anywhere in the argument list, the program will still run but suppress the output to the console. I have tried a few if statements and loops that will re assign argument values to my infile and outfile variables but those are not working either. The code can be found here: https://gist.github.com/anonymous/ab8ecfd09bddba0d4fcc. I am still relatively new to working with C++ so if you provide an explanation as to how to get closer to my goal in a simple way, I'd really appreciate it.

Something jumped out at me right away, you're testing if the argument equals -q by
if( strcmp( argv[1], "-q" ) != 0) //This is an example of what I am trying to do.
{
quiet = true;
infile.open( argv[2] );
}
which is incorrect. strcmp returns the lexical difference between the two strings compared :
http://www.cplusplus.com/reference/cstring/strcmp/
so I believe you want
if( strcmp( argv[1], "-q" ) == 0) //This is an example of what I am trying to do.
{
quiet = true;
infile.open( argv[2] );
}
Like I said, I haven't tested anything, it just jumped out at me.
edit
how I would parse in the sourcefile, destfile, and -q option
std::string sourceFile;
std::string destFile;
if ( argc == 3 )
{
sourceFile = std::string( argv[1] );
destFile = std::string( argv[2] );
}
else if ( argc == 4 )
{
// quiet mode is enabled
std::string arg1( argv[1] );
std::string arg2( argv[2] );
std::string arg3( argv[3] );
if ( arg1 != "-q" )
vec.push_back( std::string( arg1 );
if ( arg2 != "-q" )
vec.push_back( std::string( arg2 );
if ( arg3 != "-q" )
vec.push_back( std::string( arg3 );
if ( vec.size() != 2 )
{
// maybe error?
}
else
{
sourceFile = vec[0];
destFile = vec[1];
}
}
Certainly not as clean as possible, and I haven't tested it so there may be a small error.

Related

Need to save product twice to have auto tag updated correctly

Thanks to 7uc1f3r, I was able to programatically assign tags to products based on their stock status. Link here
However, I have run into an issue. There is no error. At times, I have to save the product twice for the correct tag to reflect. I have tried the code using else & elseif but the issue persists. If someone could guide me to use switch case, I can try that & see if the tags get assigned correctly on the first save. Alternatively, if there is information on why this would occur & possible remedies, please let me know. Looks like the product is in the process of saving in the backend & the tag gets assigned prior to that but I don't know for sure. Please advise.
add_action( 'woocommerce_admin_process_product_object', 'mycode_woocommerce_stockstatus_tag', 10, 1 );
function mycode_woocommerce_stockstatus_tag( $product ) {
if( !$product->is_in_stock() ) {
$product->set_tag_ids( array (113) );
}
elseif( $product->is_on_backorder(1) ) {
$product->set_tag_ids( array (111) );
}
elseif( $product->is_in_stock() && !$product->is_on_backorder(1) ) {
$product->set_tag_ids( array (112) );
}
}
I am also posting a variant of the code where I split out where stock is being managed or not. The if statements here are independent & appear to do a better job. However, I still request if someone could pitch in & help with switch case as I believe it will execute faster.
add_action( 'woocommerce_admin_process_product_object', 'mycode_woocommerce_stockstatus_tag', 10, 1 );
function mycode_woocommerce_stockstatus_tag( $product ) {
if( $product->managing_stock() && ( $product->get_stock_quantity() > 0 ) ) {
$product->set_tag_ids( array (112) );
}
if( $product->managing_stock() && ( $product->get_stock_quantity() <= 0 ) && ( $product->backorders_allowed() || $product->backorders_require_notification() ) ) {
$product->set_tag_ids( array (111) );
}
if( $product->managing_stock() && ( $product->get_stock_quantity() <= 0 ) && !$product->backorders_allowed() && !$product->backorders_require_notification() ) {
$product->set_tag_ids( array (113) );
}
if( !$product->managing_stock() && $product->is_in_stock() && !$product->is_on_backorder(1) ) {
$product->set_tag_ids( array (112) );
}
if( !$product->managing_stock() && $product->is_on_backorder(1) ) {
$product->set_tag_ids( array (111) );
}
if( !$product->managing_stock() && !$product->is_in_stock() ) {
$product->set_tag_ids( array (113) );
}
}

C++ Text file Reading and Parsing for text-based adventure game

I'm a bit of a noob when it comes to programming, but as a small project I decided I'd try to make a VERY simple text-based adventure game just for some fun and practice. I have no idea how these types of games are normally made, but I decided to make a text file containing all the actual text rather than typing it all in the code, so here's what my "gamelocationdata.txt" file currently looks like.
[castleStart]
{
=castleStart=
You find yourself in a dark room inside a castle.
The walls are made of mossy stone and the entire room has a very eerie atmosphere.
There is a green bottle on the floor.
There are 2 exits, east and south.
Both exits are large doorways with grand arches.
You can see a large room through the south exit, but the east exit looks very dark and
somewhat frightening.
What will you do?
#"look arch" castleStartLookArch
#"look wall" castleStartLookWall
#"look bottle" castleStartLookBottle itemcond: hasBottle "0"
#"take bottle" castleStartLookBottle itemcond: hasBottle "0"
#"pick bottle" castleStartLookBottle itemcond: hasBottle "0"
#"go south" castleHall
#"go east" castleDark loccond: hasBeenCastleDark "0"
#"wait" castleStartWait
}
[castleStartLookArch]
{
=castleStart=
The arches above the doors look very fancy.
You can't quite figure out why this tiny room deserves to be decorated as such.
#(castleStart)
}
[castleStartLookWall]
{
=castleStart=
The wall is made of stone masonry in an old-fashioned way.
Some stones are covered in moss and there are cobwebs in the corners.
#(castleStart)
}
[castleStartWait]
{
=castleStart=
You sit still and admire the wall for a while.
Nothing happens.
#(castleStart)
}
[castleStartLookBottle]
{
=castleStart=
You pick the bottle up. It is covered in cobwebs.
The bottle is green and the label reads "1337". It contains a purple liquid.
Do you want to put the bottle in your backpack?
#"yes" castleStartTakeBottle
#"no" castleStartNoTakeBottle
}
[castleStartTakeBottle]
{
=castleStart=
You take the bottle and put it in your backpack.
+item: Bottle1337
+itemcond: hasBottle "1"
#(castleStart)
}
[castleStartNoTakeBottle]
{
=castleStart=
You put the bottle back down again.
#(castleStart)
}
[useBottle1337]
{
=curLocation=
You open the bottle and drink its contents.
It tastes very sweet.
You suddenly feel slightly stronger and more powerful.
+strength: 5
+remove_item: Bottle1337
#(castleStart)
}
[castleHall]
{
=castleHall=
You walk though the southern doorway and enter the grand hall of the castle.
It seems like the entire castle is just as old and worn out as the walls in that room,
though still very nicely decorated.
There are only a few candles on the walls, and they are somehow lit despite
the castle seeming very empty. There is not not a person to be seen.
You can go back north or proceed south through the hall.
#(castleStart)
}
[castleDark]
{
=castleStart=
You slowly tread into the dark room to the east, looking
around you as your surroundings get darker and darker.
Suddenly, you hear a noise. It sounds like the growling of an angry dog!
Horrified, you hastily turn around and run back.
+loccond: hasBeenCastleDark "1"
#(castleStart)
}
I realize I may have bitten of more than I can chew, but this is how the formatting I made up is supposed to work:
Example: [castleStart] is the name of a "location", and the curly
braces that come after encapsulate everything that has to do with that
location.
Example: =castleStart= is the location to print for the player when
they ask where they currently are.
The stuff that comes after that is what will be printed on screen when the player
"enters" that location.
After the location text, there are a bunch of options that all start
with a "#".
Example: #"wait" castleStartWait If the player types "wait", they will
be taken to the "location" named [castleStartWait].
Example: #"look bottle" castleStartLookBottle itemcond: hasBottle "0"
If the player types "look bottle", they will be taken to the location
named [castleStartLookBottle] as long as they meet the "item
requirement" that they do not already have the bottle.
Example: #"go east" castleDark loccond: hasBeenCastleDark "0" If the
player types "go east", they will be taken to the location named
[castleDark] as long as they meet the "location requirement" that they
haven't already been there.
Example: #(castleStart) This will use the same options as the ones listed in [castleStart].
Example: +strength: 5 This should add 5 points to the player's "strength" stat when they enter the location and print some hardcoded message like "You have acquired 5 strength points!"
Now, here's the problem: How do I write the function that reads and parses the data of a specific location and stores them in specific std::strings?
For example, if I do
readAndParseLocationData( castleStart );
it should look for [castleStart] in the text file, then read what's between the equals signs (=castleStart=) and store that in "std::string printLoc", then read the text after and store in a "std::string locText" and so on.
This is all the code I have so far:
//main.cpp
#include <iostream>
#include <string>
#include "ClearScreen.h"
#include "LocationData.h"
int main()
{
ClearScreen();
std::cout << "I am a banana!\n\n"; // this is just a test
readAndParseLocationData( "castleHall" );
printLocationData( "castleStart" ); // this is supposed to be used for debugging the location data by printing it.
return 0;
}
--
//LocationData.cpp
#include "LocationData.h"
#include <fstream>
#include <iostream>
#include <string>
void readAndParseLocationData( std::string location )
{
location.insert( 0,"[" );
location.append( "]" );
std::ifstream locfile( "gamelocationdata.txt" );
if( locfile.is_open() )
{
std::string line;
bool foundFile = false;
for( unsigned int curLine = 0; getline( locfile,line ); curLine++ )
{
if( line.find( location ) != std::string::npos )
{
std::cout << "found: " << location << ", line: " << curLine << "\n";
foundFile = true;
}
}
if( !foundFile )
{
std::cout << "\nERROR: Location " << location << " not found in data file!\n";
}
locfile.close();
}
else
{
std::cout << "\nERROR: Unable to open location data file!\n";
}
}
void printLocationData( std::string location )
{
//TODO: Implement
}
All I've managed to make it do (through extensive googling) is look for the location name and print what line it's on to the console.
I'm using Visual Studio Express 2013 on Windows 7.
I'd also love to hear if there is any way to improve my code or formatting in general!
It seems that what you want to do is parse the file just-in-time as you come across the locations you wish to access. This is a good idea if you expect your game to become too large to feasibly parse once and store in memory, but for a small example like this, it's probably unnecessary.
However, if you wish to implement this for learning purposes, there are a few things to look into. First of all, your current idea would involve re-parsing the file every time you want to look at the some location. A better idea would be to devise some kind of representation for the location data and implement a cache of some kind. A possible way to do this (only taking the names and location text into account) would be:
class Location
{
private:
std::string name;
std::string displayName;
std::string locationText;
}
std::unordered_map<std::string, Location> cache;
Location& readAndParseLocationData( std::string location )
{
//if we have already parsed this location
if (cache.count(location))
{
return cache[location];
}
else
{
Location parsed_location{};
//do the parsing
cache[location] = parsed_location;
}
}
In order to actually do the parsing, I would write a simple recursive descent parser. For your case, it would look something like this (in pseudocode):
Until we have found the location:
Look for a location
If this location matches:
Read the location into a string
Look for a opening brace
Read the location display name into a string
Read the rest into a string up until a closing brace
For future readers who happen to stumble upon this 2 year old question, here's the final code I ended up using to parse the location data.
(It's old and not pretty by any means, but note that the solution to my main problem was learning about std::getline and the various manipulation methods of std::string - mainly find() and substr().)
struct Location final
{
std::string displayName;
std::string optionsName;
std::string locationText;
std::string defaultOption;
std::string shop;
std::vector<int> battleLevel;
std::vector<int> battleChanceLevel;
std::vector<int> battleChancePercentage;
std::vector<std::string> battleEnemy;
std::vector<std::string> battleChanceEnemy;
std::vector<std::string> addItems;
std::vector<std::string> addWeapons;
std::vector<std::string> addConds;
std::vector<std::string> addStats;
std::vector<std::string> removeItems;
std::vector<std::string> removeWeapons;
std::vector<std::string> removeConds;
std::vector<std::string> removeStats;
std::unordered_set<std::string> options;
std::unordered_map<std::string, std::string> resultLoc;
std::unordered_map<std::string, std::string> conds;
};
std::unordered_map<std::string, Location> locationCache;
std::unordered_map<std::string, std::string> locationNewFileCache;
Location& loadLocationData( const std::string& location, const std::string& filename, const bool overRideData, const bool dataFile )
{
if( ::locationCache.count( location ) && overRideData == false ) // If we already parsed this location...
return ::locationCache[ location ]; // Return cached data.
else
{
auto filePath = std::string( "game/data/" );
if( !dataFile )
filePath.append( "locations/" );
std::ifstream locFile( filePath + filename );
if( locFile.is_open() )
{
bool foundLoc = false;
for( std::string line; std::getline(locFile, line); )
{
Location parsedLocation;
if( line.find( "[" + location + "]" ) != std::string::npos )
{
foundLoc = true;
// Parse optionsname/next filename.
std::string optsName; std::getline( locFile, optsName );
if( optsName.find( ".txt" ) != std::string::npos )
::locationNewFileCache[ location ] = optsName;
else
parsedLocation.optionsName = optsName;
// Parse display name.
std::string dispName; std::getline( locFile, dispName );
parsedLocation.displayName = dispName;
// Parse location text.
std::string locText;
for( std::string scanLine; ( (scanLine.empty()) ? true : scanLine.back() != '}' ) && std::getline( locFile, scanLine ); )
{
if( !scanLine.empty() && scanLine.front() == '{' )
locText = scanLine;
else
locText.append( "\n" + scanLine );
}
if( locText.size() >= 2 )
{
locText.erase( locText.begin() ); // Remove { at beginning.
locText.pop_back(); // Remove } at end.
}
parsedLocation.locationText = locText;
// Parse rest.
bool endReached = false;
for( std::string scanLine; !endReached && std::getline( locFile, scanLine ); )
{
if( !scanLine.empty() )
{
switch( scanLine.front() )
{
case '*': endReached = true; break; // END
case '#': // OPTION / DEFAULT OPTION
if( scanLine.at( 1 ) == '"' ) // OPTION
{
scanLine.erase( 0, 2 );
auto optionName = scanLine.substr( 0, scanLine.find( '\"' ) );
parsedLocation.options.insert( optionName );
scanLine.erase( 0, scanLine.find( '\"' ) + 2 );
auto optionResultLoc = scanLine.substr( 0, scanLine.find( ';' ) );
parsedLocation.resultLoc[ optionName ] = optionResultLoc;
scanLine.erase( 0, scanLine.find( ';' ) + 1 );
if( !scanLine.empty() ) // if the option has conditions...
{
auto condType = scanLine.substr( 0, scanLine.find( ':' ) );
scanLine.erase( 0, scanLine.find( ':' ) + 2 );
if( condType == "loccond" || condType == "itemcond" || condType == "statcond" )
parsedLocation.conds[ optionName ] = scanLine;
else
logError( "Invalid location data syntax in " + filename + "!", "Invalid condition" );
}
}
else if( scanLine.at( 1 ) == '(' ) // DEFAULT OPTION
{
scanLine.erase( 0, 2 );
parsedLocation.defaultOption = scanLine.substr( 0, scanLine.find( ')' ) );
}
else
logError( "Invalid location data syntax in " + filename + "!", "Neither option nor default option specified" );
break;
case '+': // ACTION (ITEM / STAT / CONDITION)
scanLine.erase( scanLine.begin() );
auto action = scanLine.substr( 0, scanLine.find( ':' ) );
scanLine.erase( 0, scanLine.find( ':' ) + 2 );
auto value = scanLine;
if( action == "item" )
parsedLocation.addItems.push_back( value );
else if( action == "remove_item" )
parsedLocation.removeItems.push_back( value );
else if( action == "weapon" )
parsedLocation.addWeapons.push_back( value );
else if( action == "remove_weapon" )
parsedLocation.removeWeapons.push_back( value );
else if( action == "itemcond" || action == "loccond" )
parsedLocation.addConds.push_back( value );
else if( action == "battle" )
{
auto enemyName = value.substr( 0, value.find( ' ' ) );
value.erase( 0, value.find( ' ' ) + 1 );
auto nEnemies = std::stoi( value.substr( 0, value.find( ',' ) ) );
value.erase( 0, value.find( ',' ) + 1 );
auto level = std::stoi( value );
for( auto i = 0; i < nEnemies; ++i )
{
parsedLocation.battleEnemy.push_back( enemyName );
parsedLocation.battleLevel.push_back( level );
}
}
else if( action == "battlechance" )
{
auto enemyName = value.substr( 0, value.find( ' ' ) );
value.erase( 0, value.find( ' ' ) + 1 );
auto chance = std::stoi( value.substr( 0, value.find( ',' ) ) );
value.erase( 0, value.find( ',' ) + 1 );
auto level = std::stoi( value );
parsedLocation.battleChanceEnemy.push_back( enemyName );
parsedLocation.battleChancePercentage.push_back( chance );
parsedLocation.battleChanceLevel.push_back( level );
}
else if( action == "shop" )
parsedLocation.shop = value;
else
parsedLocation.addStats.push_back( action + " " + value ); // Assume it's a stat.
break;
}
}
}
::locationCache[ location ] = parsedLocation;
return ::locationCache[ location ];
}
}
}
else
logError( "Unable to open location data file " + filename + "!" );
}
static Location dummyLocation;
return dummyLocation;
}

creating file for shell output redirection

This is a school assignment.
So basically I have written a C code for a shell that handles terminating the command with &, and input / output redirection using > or <. using pipes and fork(), execvp().
The problem is my input/output redirection only handles that for files that already exist.
What i need to know is how would I go about redirecting output to a file that doesn't exist - I know I would have to create the file, but I'm not sure how that works.
For example: ls -a < test.txt
If test.txt is not in the directory, i need to create it and redirect output to that.
So how do I create this file?
here is some basic example code which does not create a new file:
else if( '>' == buff[i] ){
i++;
j=0;
if( ' ' == buff[i] )
i++;
while( ' ' != buff[i] && i < len )
out_file[j++]=buff[i++];
out_file[j]='\0';
if ( ( ofd = open(out_file,1) ) < 0 ){
perror("output redirected file");
exit( 1 );
}
close(1);
dup(ofd);
}
Any help with how I can output and create a new file would be much appreciated! Thanks!
You need to tell open to create the file, if necessary:
if ( ( ofd = open(out_file, O_WRONLY | O_CREAT) ) < 0 ) {
Note that your code will be more readable if you use the named constants for the flags to open. Compare with the functionally equivalent
if ( ( ofd = open(out_file, 513) ) < 0 ) {
or even
if ( ( ofd = open(out_file, 0x0201) ) < 0 ) {

Iterating files with boost::filesystem 3.0

I want to iterate over all files in a directory matching something "keyword.txt". I searched for some solutions in google and found this:
Can I use a mask to iterate files in a directory with Boost?
As i figured out later on, the "leaf()" function was replaced (source: http://www.boost.org/doc/libs/1_41_0/libs/filesystem/doc/index.htm -> goto section 'Deprecated names and features')
what i got so far is this, but it's not running. Sorry for this somehow stupid question, but im more or less a c++ beginner.
const std::string target_path( "F:\\data\\" );
const boost::regex my_filter( "keyword.txt" );
std::vector< std::string > all_matching_files;
boost::filesystem::directory_iterator end_itr; // Default ctor yields past-the-end
for( boost::filesystem::directory_iterator i( target_path ); i != end_itr; ++i )
{
// Skip if not a file
if( !boost::filesystem::is_regular_file( i->status() ) ) continue;
boost::smatch what;
// Skip if no match
if( !boost::regex_match( i->path().filename(), what, my_filter ) ) continue;
// File matches, store it
all_matching_files.push_back( i->path().filename() );
}
Try
i->path().filename().string()
this is the equivalent for i->leaf() in boost::filesystem 3.0
In your code:
// Skip if no match
if( !boost::regex_match( i->path().filename().string(), what, my_filter ) )
continue;
// File matches, store it
all_matching_files.push_back( i->path().filename().string() );

C++ Prepend DateTime to console output

Searched around and couldn't find any info on this besides redirecting to files so hopefully someone can help me out.
I have a console application that launches and hooks another process, by default the new process output displays in the first console application.
What I would like to do is prepend a datetime value to all the output, the problem is that I don't control the output from the child process (3rd party app) so the easy solution of adding a datetime to all printed values is unavailable. Is it possible to prepend a string to all stdout?
Since you confirmed C++ (which implies a solution for
std::cout is what is needed, and not for stdout): the
obvious solution is a filtering streambuf:
class TimeStampStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ostream* myOwner;
bool myIsAtStartOfLine;
protected:
int overflow( int ch )
{
// To allow truly empty lines, otherwise drop the
// first condition...
if ( ch != '\n' && myIsAtStartOfLine ) {
std::string tmp = now();
// function now() should return the timestamp as a string
myDest->sputn( tmp.data(), tmp.size() );
}
myIsAtStartOfLine = ch == '\n';
ch = myDest->sputc( ch );
return ch;
}
public:
TimeStampStreambuf( std::streambuf* dest )
: myDest( dest )
, myOwner( nullptr )
, myIsAtStartOfLine( false )
{
}
TimeStampStreambuf( std::ostream& owner )
: myDest( dest.rdbuf() )
, myOwner( &owner )
, myIsAtStartOfLine( false )
{
myOwner->rdbuf( this );
}
~TimeStampStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
};
And to install it:
// scoped:
TimeStampStreambuf anyName( std::cout );
// Time stamping will be turned off when variable goes out
// of scope.
// unscoped:
std::streambuf* savedStreambuf = std::cout.rdbuf();
TimeStampStreambuf name( savedStreambuf );
// In this case, you have to restore the original streambuf
// yourself before calling exit.
As far as I know, the articles explaining this (from C++
Reports, Sept. 1998) are not on line.
EDIT:
I've actually found them:
http://gabisoft.free.fr/articles-en.html. I can't believe that
the link still works; it's been years since I had an account
with Free.