I have a piece of code that I need to adjust so that it removes all lines with // while copying. I tried to do:
f (prevkar == '/' &&kar!= '/' )
uitput.put ('/');
but it didn't seem to work.
output.open ("output.txt",ios::out);
kar = input.get ( );
while ( ! input.eof ( ) )
{
//this part needs to be adjusted
output.put (kar);
kar = input.get ( );
}
You may change it to the following: (supposed your input is null-terminated)
bool linebreak=false, putknel=false;
while (kar!='\0')
{
if(linebreak)
{
if(kar=='\n')linebreak=false;
}
if(kar!='/')
{
output.put (kar);
if(putknel)
{
putknel=false;
output.put('/');
}
}
else
{
if(!putknel)putknel=true;
else
{
putknel=false;
linebreak=true;
}
}
kar = input.get ( );
}
But this may be somewhat tedious.
If you use the regular expression it will be much easier.
Just replace all that match //[^\r\n]*\r\n to empty strings.
Related
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) );
}
}
I've been following Kamran Bigdely-Shamloo's article on how to get positional information from the HTC Vive and it has worked well so far. My next step was to "listen" to button presses. I've read the documentation and it says here that all I need to do is query IVRSystem::GetControllerStateand it'll return a
"struct with the current state of the controller"
This struct however always contains variables that have the 0 value. The following function is called in a while (true) loop from the main function.
bool CMainApplication::HandleInput()
{
SDL_Event sdlEvent;
bool bRet = false;
while ( SDL_PollEvent( &sdlEvent ) != 0 )
{
if ( sdlEvent.type == SDL_QUIT )
{
bRet = true;
}
else if ( sdlEvent.type == SDL_KEYDOWN )
{
if ( sdlEvent.key.keysym.sym == SDLK_ESCAPE
|| sdlEvent.key.keysym.sym == SDLK_q )
{
bRet = true;
}
if( sdlEvent.key.keysym.sym == SDLK_c )
{
m_bShowCubes = !m_bShowCubes;
}
}
}
// Process SteamVR events
// Periodically returns an event of type 404 ("VREvent_SceneApplicationChanged = 404, // data is process - The App actually drawing the scene changed (usually to or from the compositor)"
vr::VREvent_t event;
vr::VREvent_Controller_t controllerEvent;
std::chrono::milliseconds ms4;
while( m_pHMD->PollNextEvent( &event, sizeof( event ) ) )
{
ms4 = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
);
ProcessVREvent( &event);
printPositionalData(&event, ms4);
}
vr::VRControllerState_t state;
// Check every device attached, usually it's four devices
// Second if statement is never reached
for (int i = 0; i < 1000; i++) {
if (m_pHMD->GetControllerState(i, &state, sizeof(state))) {
dprintf("%d", i);
if (state.ulButtonPressed != 0 || state.unPacketNum != 0 || state.ulButtonTouched != 0) {
dprintf("Some action?");
}
}
}
dprintf("\n");
// Process SteamVR action state
// UpdateActionState is called each frame to update the state of the actions themselves. The application
// controls which action sets are active with the provided array of VRActiveActionSet_t structs.
vr::VRActiveActionSet_t actionSet = { 0 };
actionSet.ulActionSet = m_actionsetDemo;
vr::VRInput()->UpdateActionState( &actionSet, sizeof(actionSet), 1 );
m_bShowCubes = !GetDigitalActionState( m_actionHideCubes );
vr::VRInputValueHandle_t ulHapticDevice;
if ( GetDigitalActionRisingEdge( m_actionTriggerHaptic, &ulHapticDevice ) )
{
if ( ulHapticDevice == m_rHand[Left].m_source )
{
vr::VRInput()->TriggerHapticVibrationAction( m_rHand[Left].m_actionHaptic, 0, 1, 4.f, 1.0f, vr::k_ulInvalidInputValueHandle );
}
if ( ulHapticDevice == m_rHand[Right].m_source )
{
vr::VRInput()->TriggerHapticVibrationAction( m_rHand[Right].m_actionHaptic, 0, 1, 4.f, 1.0f, vr::k_ulInvalidInputValueHandle );
}
}
vr::InputAnalogActionData_t analogData;
if ( vr::VRInput()->GetAnalogActionData( m_actionAnalongInput, &analogData, sizeof( analogData ), vr::k_ulInvalidInputValueHandle ) == vr::VRInputError_None && analogData.bActive )
{
m_vAnalogValue[0] = analogData.x;
m_vAnalogValue[1] = analogData.y;
}
m_rHand[Left].m_bShowController = true;
m_rHand[Right].m_bShowController = true;
vr::VRInputValueHandle_t ulHideDevice;
if ( GetDigitalActionState( m_actionHideThisController, &ulHideDevice ) )
{
if ( ulHideDevice == m_rHand[Left].m_source )
{
m_rHand[Left].m_bShowController = false;
}
if ( ulHideDevice == m_rHand[Right].m_source )
{
m_rHand[Right].m_bShowController = false;
}
}
for ( EHand eHand = Left; eHand <= Right; ((int&)eHand)++ )
{
vr::InputPoseActionData_t poseData;
if ( vr::VRInput()->GetPoseActionData( m_rHand[eHand].m_actionPose, vr::TrackingUniverseStanding, 0, &poseData, sizeof( poseData ), vr::k_ulInvalidInputValueHandle ) != vr::VRInputError_None
|| !poseData.bActive || !poseData.pose.bPoseIsValid )
{
m_rHand[eHand].m_bShowController = false;
}
else
{
m_rHand[eHand].m_rmat4Pose = ConvertSteamVRMatrixToMatrix4( poseData.pose.mDeviceToAbsoluteTracking );
vr::InputOriginInfo_t originInfo;
if ( vr::VRInput()->GetOriginTrackedDeviceInfo( poseData.activeOrigin, &originInfo, sizeof( originInfo ) ) == vr::VRInputError_None
&& originInfo.trackedDeviceIndex != vr::k_unTrackedDeviceIndexInvalid )
{
std::string sRenderModelName = GetTrackedDeviceString( originInfo.trackedDeviceIndex, vr::Prop_RenderModelName_String );
if ( sRenderModelName != m_rHand[eHand].m_sRenderModelName )
{
m_rHand[eHand].m_pRenderModel = FindOrLoadRenderModel( sRenderModelName.c_str() );
m_rHand[eHand].m_sRenderModelName = sRenderModelName;
}
}
}
}
return bRet;
m_pHMD is initalized as follows:
vr::IVRSystem *m_pHMD;
....
m_pHMD = vr::VR_Init( &eError, vr::VRApplication_Background );
I must be doing something wrong because in the following snippet, the if statement is passed only for the first four iterations, which should be a controller, the vive tracker, the headset and the lighthouses. This tells me that I am able to access these states, but I am somehow not able to read the information.
for (int i = 0; i < 1000; i++) {
if (m_pHMD->GetControllerState(i, &state, sizeof(state))) {
dprintf("%d", i);
if (state.ulButtonPressed != 0 || state.unPacketNum != 0 || state.ulButtonTouched != 0) {
dprintf("Some action?");
}
}
I can't imagine its a bug, so my guess is that my configuration is faulty, or I'm doing the wrong query.
Any help is greatly appreciated!
Apparently I was making two mistakes.
Mistake #1 was that I was using the wrong sample file. I used hellovr_opengl from the OpenVr sample folder, but instead hellovr_dx12 was the working solution. It must have a different kind of configration as well, since I copied a function which was working into the hellovr_opengl project and there, it did not work! Then I copied the functions I added to the hellovr_dx12 project and was able to get the controller states of the Vive controller.
However, I wanted to get the states of the Vive Tracker, which didn't work. After some googling I found out about an issue with the current SteamVR driver, so I reverted it back to a beta hoftix, which solved the Vive Tracker issue for me.
You have to call;
vr::VRInput()->SetActionManifestPath
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;
}
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.
I'm using tinyxml to parse xml files, and I've found that error handling here lends itself to arrow code. Our error handling is simply reporting a message to a file.
Here is an example:
const TiXmlElement *objectType = dataRoot->FirstChildElement( "game_object" );
if ( objectType ) {
do {
const char *path = objectType->Attribute( "path" );
if ( path ) {
const TiXmlElement *instance = objectType->FirstChildElement( "instance" );
if ( instance ) {
do {
int x, y = 0;
instance->QueryIntAttribute( "x", &x );
instance->QueryIntAttribute( "y", &y );
if ( x >= 0 && y >= 0 ) {
AddGameObject( new GameObject( path, x, y ));
} else {
LogErr( "Tile location negative for GameObject in state file." );
return false;
}
} while ( instance = instance->NextSiblingElement( "instance" ));
} else {
LogErr( "No instances specified for GameObject in state file." );
return false;
}
} else {
LogErr( "No path specified for GameObject in state file." );
return false;
}
} while ( objectType = objectType->NextSiblingElement( "game_object" ));
} else {
LogErr( "No game_object specified in <game_objects>. Thus, not necessary." );
return false;
}
return true;
I'm not huffing and puffing over it, but if anyone can think of a cleaner way to accomplish this it would be appreciated.
P.S. Exceptions not an option.
Edit:
Would something like this be preferable?
if ( !path ) {
// Handle error, return false
}
// Continue
This eliminates the arrow code, but the arrow code kind of puts all of the error logging on one place.
Using return values as error codes just leads to such code, it can't be improved much. A slightly cleaner way would use goto to group all error handling into a single block and to decrease the nesting of blocks.
This does however not solve the actual problem, which is using return values as error codes. In C, there is no alternative, but in C++ exceptions are available and should be used. If they are not an option, you're are stuck with what you have.
You could create a macro for that, which encapsulates the if (!var) { .. return false; } and error reporting.
However, I do not see how this can be improved all that much; its just the way it is. C'est la vie. C'est le code...
I'm not huffing and puffing over it,
but if anyone can think of a cleaner
way to accomplish this it would be
appreciated.
I have replaced the nested ifs with return statements on error (this makes the code "flow down" instead of going "arrow shaped". I have also replaced your do loopps with for loops (so I could understand it better).
Is this what you wanted?
const TiXmlElement *objectType = dataRoot->FirstChildElement( "game_object" );
if ( !objectType ) {
LogErr( "No game_object specified in <game_objects>. Thus, not necessary." );
return false;
}
for(; objectType != 0; objectType = objectType->NextSiblingElement( "game_object" )) {
const char *path = objectType->Attribute( "path" );
if ( !path ) {
LogErr( "No path specified for GameObject in state file." );
return false;
}
const TiXmlElement *instance = objectType->FirstChildElement( "instance" );
if ( !instance ) {
LogErr( "No instances specified for GameObject in state file." );
return false;
}
for(; instance != 0; instance = instance->NextSiblingElement( "instance" )) {
int x, y = 0;
instance->QueryIntAttribute( "x", &x );
instance->QueryIntAttribute( "y", &y );
if ( x >= 0 && y >= 0 ) {
AddGameObject( new GameObject( path, x, y ));
} else {
LogErr( "Tile location negative for GameObject in state file." );
return false;
}
}
}
return true;
I know it is a little late, but I know that QueryIntAttribute returns a value which can be used for error handling in case you want this for your attributes too.
if (instance->QueryIntAttribute("x",&x)!=TIXML_SUCCESS)
cout << "No x value found";