In this cryptography post it says
The chain can go as long as you want, until it hits the original input. When it hits that point, it will just repeat itself and it will be useless.
So my starting point is 12345 but I can't get the end point and having an endless loop because 12345 doesn't repeat. I'm using qt4.7 (lib version: 4.7.3) to achieve this. Here is my code
rainbowTable::rainbowTable(QWidget *parent) :
QWidget(parent),
ui(new Ui::rainbowTable)
{
ui->setupUi(this);
passwordLength = 5;
qDebug() << getLastReduction("12345",false);
}
QString rainbowTable::hashString(QString value)
{
QString dataToReturn = QString(QCryptographicHash::hash((value.toAscii()),QCryptographicHash::Md5).toHex());
return dataToReturn;
}
QString rainbowTable::reductionOfString(QString hash)
{
QString dataToReturn = "";
int iterator = 0;
while ( iterator < hash.count() )
{
if ( hash.at(iterator) == '0' ||
hash.at(iterator) == '1' ||
hash.at(iterator) == '2' ||
hash.at(iterator) == '3' ||
hash.at(iterator) == '4' ||
hash.at(iterator) == '5' ||
hash.at(iterator) == '6' ||
hash.at(iterator) == '7' ||
hash.at(iterator) == '8' ||
hash.at(iterator) == '9' )
{
dataToReturn += hash.at(iterator);
if( dataToReturn.count() == passwordLength )
break;
}
iterator++;
}
return dataToReturn;
}
QString rainbowTable::getLastReduction(QString value,bool isHash)
{
int flagToAvoidImmediateExit = 0;
if( isHash )
{
QString startPoint = value;
startPoint = reductionOfString(startPoint);
QString endPoint = "";
QString tempPoint = startPoint;
while( startPoint != tempPoint || flagToAvoidImmediateExit == 0 )
{
flagToAvoidImmediateExit = 1;
endPoint = tempPoint;
tempPoint = hashString(tempPoint);
tempPoint = reductionOfString(tempPoint);
qDebug() << tempPoint;
}
return endPoint;
}
else
{
QString startPoint = value;
QString endPoint = "";
QString tempPoint = startPoint;
while( startPoint != tempPoint || flagToAvoidImmediateExit == 0 )
{
flagToAvoidImmediateExit = 1;
endPoint = tempPoint;
tempPoint = hashString(tempPoint);
tempPoint = reductionOfString(tempPoint);
qDebug() << tempPoint;
}
return endPoint;
}
}
Here is the debug ouput for a few seconds:
"38064"
"37923"
"59636"
"14842"
"81105"
"83011"
"84978"
"72903"
"28301"
"59067"
"94222"
"35329"
"75907"
"52980"
"64297"
"36654"
"12207"
"83738"
"03523"
"79083"
"15597"
"32652"
"13934"
"88497"
"75435"
"79791"
"58265"
"09856"
"18041"
"43966"
"65978"
"64242"
"52739"
"55704"
"56811"
"58183"
"68597"
"84064"
"85717"
"46438"
"18042"
"71321"
"88067"
"70648"
"83580"
"11878"
"32297"
"52376"
"41289"
"07909"
"50439"
"03819"
"50325"
"82736"
"41621"
"05497"
"15546"
"64017"
"90503"
"13150"
"30287"
"01749"
"81308"
"12036"
"37241"
"35850"
"97225"
"80539"
"17472"
"63098"
"85818"
"18438"
"26139"
"09545"
"97042"
"63672"
"37406"
"41180"
"14910"
"28900"
"29729"
"56861"
"16208"
"83565"
"30912"
"95541"
"08468"
"29539"
"93679"
"42487"
"95833"
"42793"
"97064"
"18087"
"75623"
"13910"
"60404"
"52557"
"95932"
"65477"
"28304"
"08456"
"27849"
"11429"
"38896"
"08634"
"97107"
"96385"
"44159"
"32875"
"17063"
"86213"
"85052"
"46852"
"97541"
"81412"
"31199"
"96618"
"16178"
"56100"
"50394"
"42087"
"90552"
"51966"
"13598"
"28757"
"38715"
"71025"
"61334"
"43686"
"74633"
"50360"
"99883"
"01361"
"49662"
"62929"
"07280"
"59161"
"32509"
"93670"
"95649"
"15206"
"99927"
"93692"
"37748"
"23350"
"74680"
"68259"
"04819"
"26627"
"65968"
"06919"
"09194"
"50084"
"74452"
"23763"
"17953"
"35026"
"86691"
"67542"
"95634"
"00793"
"20270"
"24386"
"35606"
"76055"
"00010"
"00798"
"30867"
"20697"
"02143"
"12044"
"05098"
"52828"
"98446"
"54039"
"08778"
"98405"
"92267"
"71783"
"61953"
"87447"
"66505"
"66535"
"01776"
"90120"
"51497"
"56082"
"18253"
"15222"
"74769"
"19614"
"86376"
"65391"
"43365"
"90484"
"32717"
"75052"
"16186"
"89444"
"15439"
"65166"
"75785"
"72462"
"75920"
"91383"
"41678"
"94123"
"61751"
"47976"
"67798"
"59438"
"10180"
"65854"
"40218"
"77990"
"44843"
"84554"
"52350"
"73347"
"51901"
"61155"
"30316"
"83096"
"64946"
"05985"
"24208"
"28718"
"02241"
"22303"
"23331"
"18410"
"54868"
"51723"
"06401"
"49554"
"65577"
"28105"
"42319"
"34167"
"85036"
"98679"
"08594"
"31075"
"80514"
"11517"
"66780"
"33411"
"83180"
"61910"
"70423"
"16885"
"09107"
"83702"
"81842"
"88430"
"59146"
"29140"
"47236"
"29625"
"03078"
"26540"
"79321"
"41649"
"10210"
"75702"
"12020"
"36877"
"57307"
"03222"
"46603"
"58449"
"94709"
"01436"
"84975"
"39385"
"15952"
"67607"
"91666"
"34456"
"53385"
"21512"
"06712"
"42073"
"61343"
"66825"
"70199"
"73203"
"60216"
"39469"
"84324"
"47850"
"84825"
"52471"
"92397"
"86051"
"33676"
"04221"
"79740"
"11573"
"26304"
"52510"
"12679"
"05930"
"49607"
"10880"
"99174"
"53967"
"06397"
"25700"
"96721"
"94694"
"96566"
"31746"
"57359"
"84870"
"06236"
"10673"
"45914"
"19209"
"32478"
"38824"
"71178"
"22983"
"36320"
"46594"
"66538"
"80495"
"35645"
"38064"
"37923"
"59636"
"14842"
"81105"
"83011"
"84978"
"72903"
"28301"
"59067"
"94222"
"35329"
"75907"
"52980"
"64297"
"36654"
"12207"
"83738"
"03523"
"79083"
"15597"
"32652"
"13934"
"88497"
"75435"
"79791"
"58265"
"09856"
"18041"
"43966"
"65978"
"64242"
"52739"
"55704"
"56811"
"58183"
"68597"
"84064"
"85717"
"46438"
"18042"
"71321"
"88067"
"70648"
"83580"
"11878"
"32297"
"52376"
"41289"
"07909"
"50439"
"03819"
"50325"
"82736"
"41621"
"05497"
"15546"
"64017"
"90503"
"13150"
"30287"
"01749"
"81308"
"12036"
"37241"
"35850"
"97225"
"80539"
"17472"
"63098"
"85818"
"18438"
"26139"
"09545"
"97042"
"63672"
"37406"
"41180"
"14910"
"28900"
"29729"
"56861"
"16208"
"83565"
"30912"
"95541"
"08468"
"29539"
"93679"
"42487"
"95833"
"42793"
"97064"
"18087"
"75623"
"13910"
"60404"
"52557"
"95932"
"65477"
"28304"
"08456"
"27849"
"11429"
"38896"
"08634"
"97107"
"96385"
"44159"
"32875"
"17063"
"86213"
"85052"
"46852"
"97541"
"81412"
"31199"
"96618"
"16178"
"56100"
"50394"
"42087"
"90552"
"51966"
"13598"
"28757"
"38715"
"71025"
"61334"
"43686"
"74633"
"50360"
"99883"
"01361"
"49662"
"62929"
"07280"
"59161"
"32509"
"93670"
"95649"
"15206"
"99927"
"93692"
"37748"
"23350"
"74680"
"68259"
"04819"
"26627"
"65968"
"06919"
"09194"
"50084"
"74452"
"23763"
"17953"
"35026"
"86691"
"67542"
"95634"
"00793"
"20270"
"24386"
"35606"
"76055"
"00010"
"00798"
"30867"
"20697"
"02143"
"12044"
"05098"
"52828"
"98446"
"54039"
"08778"
"98405"
"92267"
"71783"
"61953"
"87447"
"66505"
"66535"
"01776"
"90120"
"51497"
"56082"
"18253"
"15222"
"74769"
"19614"
"86376"
"65391"
"43365"
"90484"
As you see 12345 doesn't repeat but other numbers are repeated and having endless loop. Is my starting point wrong?
The chain is not guaranteed to ever hit the initial value again. More often than not you'll probably find it entering a loop like this:
If the input is larger than the hash output, it is impossible by definition to ever hit the initial input value again. However, even if the input has an equal length to the output, it is not guaranteed that the hash will cover every single possible value in the output space before looping around. This actually depends on the characteristics and quality of the hash. A hash may have one big cycle, covering every single possible output value in its loop. Other hashes may enter a number of different possible loops, each covering a different subset of the output space. Other hashes may not ever cover every possible output value.
Related
so I get this error when i run my code
Error in module (TraCIDemoRSU11p) RSUExampleScenario.rsu[0].appl (id=8) at event #4000, t=45.40151998544: std::length_error: basic_string::_M_create.
TRAPPING on the exception above, due to a debug-on-errors=true configuration option. Is your debugger ready?
it shows that I have this issue at this line after looping multiple times
VehTD = *iteh2;
please be informed that I'm trying to remove from this vehicle list to another vehicle list and delete the moved items.
std::list<std::pair<std::string,std::string>>::const_iterator iteh2 = waitingList.begin();
for (std::list<std::pair<std::string,std::string>>::const_iterator iteh = waitingList.begin(); iteh != waitingList.end() && !waitingList.empty(); ){
iteh2 = iteh;
cout<<"Veh ID TF 1:";
cout<<VehTD.first<<endl;
cout<<VehTD.second<<endl;
VehTD = *iteh2;
cout<<"Veh ID TF 2:";
cout<<VehTD.first<<endl;
cout<<VehTD.second<<endl;
CompareResult3 = Locks(Locked,VehTD.second);
if(CompareResult3.second == 1 || CompareResult3.second == 2 ){
//remove from waiting and add to crossing
std::string ehk = "";
simtime_t VehicleT = simTime();
std::pair<std::pair<std::string, std::string>, simtime_t> VehicleWithTime;
crossingList.push_back(VehTD);
iteh2 = waitingList.erase(iteh2);
}
else{
++iteh;
}
}
}
I'm using Oment++ 5.0 and veins 4.4
I put a try and catch at this function, and it seems that the exception happens towards the end of the list.
Update:
I have this output:
WCounter 1
WCounter 2
Moving from waiting list Timer Function Exception
WCounter 1
WCounter 2
WCounter 3
Moving from waiting list Timer Function Exception
WCounter 1
WCounter 2
Moving from waiting list Timer Function Exception
The WCounter is a variable to show how many times it looped before having the exception at the point explained earlier.
based on request I added the locks function:
std::pair<std::list<std::string>,int> TraCIDemoRSU11p::Locks(std::list<std::string> alreadyLocked, std::string laneNo){
bool debugL;
//create variables for the lanes for easier use
try{
debugL = false;
zero = "171270266#0_0";
one = "171270266#0_1";
two = "-171270025#1_0";
three = "-171270025#1_1";
four = "-171270266#1_0";
five = "-171270266#1_1";
six = "171270025#0_0";
seven = "171270025#0_1";
//create lists of locks
Locks0 = Locks1 = Locks2 = Locks3 = Locks4 = Locks5 = Locks6 = Locks7 = RequestToLock = {};
CounterOfSimilarLanes = 0;
//set of 0 ,Locks0;
Locks0.push_back(zero);
Locks0.push_back(five);
Locks0.push_back(seven);
//set of 1 ,Locks1;
Locks1.push_back(one);
Locks1.push_back(three);
Locks1.push_back(six);
//set of 2 ,Locks2;
Locks2.push_back(one);
Locks2.push_back(two);
Locks2.push_back(seven);
//set of 3 ,Locks3;
Locks3.push_back(zero);
Locks3.push_back(three);
Locks3.push_back(five);
//set of 4 ,Locks4;
Locks4.push_back(one);
Locks4.push_back(three);
Locks4.push_back(four);
//set of 5 ,Locks5;
Locks5.push_back(two);
Locks5.push_back(five);
Locks5.push_back(seven);
//set of 6 ,Locks6;
Locks6.push_back(three);
Locks6.push_back(five);
Locks6.push_back(six);
//set of 7 ,Locks7;
Locks7.push_back(one);
Locks7.push_back(four);
Locks7.push_back(seven);
//This is the request to lock from the vehicle using its lane number
if (laneNo == zero ){
RequestToLock.insert(RequestToLock.end(),Locks0.begin(),Locks0.end());
}else if (laneNo == one){
RequestToLock.insert(RequestToLock.end(),Locks1.begin(),Locks1.end()) ;
}else if (laneNo == two){
RequestToLock.insert(RequestToLock.end(),Locks2.begin(),Locks2.end()) ;
}else if (laneNo == three){
RequestToLock.insert(RequestToLock.end(),Locks3.begin(),Locks3.end()) ;
}else if (laneNo == four){
RequestToLock.insert(RequestToLock.end(),Locks4.begin(),Locks4.end()) ;
}else if (laneNo == five){
RequestToLock.insert(RequestToLock.end(),Locks5.begin(),Locks5.end()) ;
}else if (laneNo == six){
RequestToLock.insert(RequestToLock.end(),Locks6.begin(),Locks6.end()) ;
}else if (laneNo == seven){
RequestToLock.insert(RequestToLock.end(),Locks7.begin(),Locks7.end()) ;
}
} //if the already locked from the controller is empty so we take the requested lock
catch(const std::exception &e){
cout<<"Preparing Locks Algorithm Exception"<<endl;
}
try{
if (alreadyLocked.empty()){
markOfLocks = 0;
alreadyLocked.insert(alreadyLocked.end(),RequestToLock.begin(),RequestToLock.end()) ;
Locked.insert(Locked.end(),RequestToLock.begin(),RequestToLock.end()) ;
if (debugL == true){
cout<<"First Lock in the locking algorithm"<<endl;
// dumplistLock(Locked);
}
ReturnOfLocks = make_pair(alreadyLocked,markOfLocks);
}else{ // if the already locked by the controller isnt empty, so we need to compare the request with it
//Search for similar items in the 2 lists
for(std::list<std::string>::/*const_*/iterator it_1 = alreadyLocked.begin();it_1 != alreadyLocked.end();)
{
for(std::list<std::string>::/*const_*/iterator it_2 = RequestToLock.begin(); it_2 != RequestToLock.end();)
{
if(*it_1 == *it_2)
{
++CounterOfSimilarLanes;
}
++it_2;
}
++it_1;
}
if (RequestToLock == alreadyLocked){
markOfLocks = 1;
Locked.clear();
Locked = {};
Locked.insert(Locked.end(),alreadyLocked.begin(),alreadyLocked.end()) ;
if (debugL == true){
cout<<"Same Lane"<<endl;
dumplistLock(Locked);
}
ReturnOfLocks = make_pair(alreadyLocked,markOfLocks);
}else if(CounterOfSimilarLanes == 0){ //if the request is concurrent meaning totally different locks
markOfLocks = 2;
//alreadyLocked.insert(alreadyLocked.end(),RequestToLock.begin(),RequestToLock.end()) ;
Locked.clear();
Locked = {};
Locked.insert(Locked.end(),alreadyLocked.begin(),alreadyLocked.end()) ;
if (debugL == true){
cout<<"Concurrent Lane"<<endl;
dumplistLock(Locked);
}
}else if(CounterOfSimilarLanes == 1 || CounterOfSimilarLanes == 2){ // if there's a similarity is 1 lock at least so it leads to conflict
markOfLocks = 3;
Locked.clear();
Locked = {};
Locked.insert(Locked.end(),alreadyLocked.begin(),alreadyLocked.end()) ;
if (debugL == true){
cout<< "opposite Lane"<<endl;
dumplistLock(Locked);
}
ReturnOfLocks = make_pair(alreadyLocked,markOfLocks);
}else{
markOfLocks = 1;
Locked.clear();
Locked.insert(Locked.end(),alreadyLocked.begin(),alreadyLocked.end()) ;
if (debugL == true){
cout<<"default case"<<endl;
dumplistLock(Locked);
}
ReturnOfLocks = make_pair(alreadyLocked,markOfLocks);
}
}
}catch(const std::exception &e){
cout<<"Lock Cases Exceptions"<<endl;
}
try{
return ReturnOfLocks;
}catch(const std::exception &e){
cout<<"No Return of Locks in Locks Alg Exception"<<endl;
}
}
so I changed the for loop to a while loop and it didn't show an exception, and not sure why.
therefore the loop looks like this now:
//while loop instead.
std::list<std::pair<std::string,std::string>>::iterator iterwil = waitingList.begin();
std::pair<std::string, std::string> Vehwil ;
while (iterwil != waitingList.end()){
Vehwil = *iterwil;
CompareResult3 = Locks(Locked,Vehwil.second);
if(CompareResult3.second == 1 || CompareResult3.second == 2 ){
crossingList.push_back(Vehwil);
waitingList.erase(iterwil++);
}else{
++iterwil;
}
}
if someone has a valid reason to enlighten me on why the while loop works with no exception unlike the for loop that would be great. ^^"
You should use iterator instead of const_iterator because you modify (i.e. delete) indicated element.
By the way, in the code iteh2 is unnecessary - iteh is sufficient as well as VehicleT and ehk variables are not used and may be removed.
I am working on a legacy code base which has the following snippet:
if ((results[0].Length == 0))
customerName = "";
else
customerName = results[0].Substring(18);
if ((results[1].Length == 0))
meterSerialNumber = "";
else
meterSerialNumber = results[1];
if ((results[2].Length == 0))
customerID = "";
else
customerID = results[2];
if ((results[3].Length == 0))
meterCreditAmount = "";
else
meterCreditAmount = results[3];
if ((results[4].Length == 0))
debtInstallmentDeduction = "";
else
debtInstallmentDeduction = results[4];
if ((results[5].Length == 0))
vatOnEnergyAmount = "";
else
vatOnEnergyAmount = results[5];
if ((results[6].Length == 0))
vatOnDebt = "";
else
vatOnDebt = results[6];
if ((results[7].Length == 0))
outstandingDebtAmount = "";
else
outstandingDebtAmount = results[7];
if ((results[8].Length == 0))
tariffCategory = "";
else
tariffCategory = results[8];
if ((results[9].Length == 0))
tariffId = "";
else
tariffId = results[9];
if ((results[10].Length == 0))
encryptedToken1 = "";
else
encryptedToken1 = results[10];
if ((results[11].Length == 0))
encryptedToken2 = "";
else
encryptedToken2 = results[11];
if ((results[12].Length == 0))
encryptedToken3 = "";
else
encryptedToken3 = results[12];
if ((results[13].Length == 0))
encryptedToken4 = "";
else
encryptedToken4 = results[13];
if ((results[14].Length == 0))
systemMessage = "";
else
systemMessage = results[14];
if ((results[15].Length == 0))
customerMessage = "";
else
customerMessage = results[15];
if ((results[16].Length == 0))
predefinedMessage = "";
else
predefinedMessage = results[16];
if ((results[17].Length == 0))
transactionAcknowledgeNumber = "";
else
transactionAcknowledgeNumber = results[17];
What would be the best way to refactor this for acceptable coding standards? Would it be acceptable to make this a case statement instead?
This is not a case-wise execution so it can't be refactored to a switch-case. However it can be converted to functional code and then it factored out into a separate method so that the "ugly" part is hidden behind a method call.
Step#1 - Making the code functional
Here, we rewrite the code by following functional code writing practices. The rewritten code will look like:
customerName = (results[0].Length == 0) ? "" : results[0].Substring(18);
meterSerialNumber = (results[1].Length == 0) ? "" : results[1];
customerID = (results[2].Length == 0) ? "" : results[2];
meterCreditAmount = (results[3].Length == 0) ? "" : results[3];
debtInstallmentDeduction = (results[4].Length == 0) ? "" : results[4];
vatOnEnergyAmount = (results[5].Length == 0) ? "" : results[5];
.
.
.
transactionAcknowledgeNumber = (results[17].Length == 0) ? "" : results[17];
There are numerous advantages of writing the code this way. Important ones include:
terseness of code;
values being initialized at one place (by means of ternary operator) instead of two (one in if and another in else clause).
Step#2 - Factoring out the method
Now that the values are being initialized functionally, you can create a class (or you may be already having this class) containing the properties customerName, meterSerialNumber, ..., transactionAcknowledgeNumber. Either the constructor of the class can be designed to read the results and populate the class members or you may write a method to read the results. So it will look like:
ResultValues resultVal = new ResultValues();
resultVal.Read(results);
.
.
.
//Accessing the values later in the code
Print(resultVal.customerName);
...
PS:
1. I admit that ResultValues may not be a good class to make. Alternatively, you may create multiple classes by clubbing the related data and then have the Read() method of those classes read the values from results.
2. The essential idea of Step#2 is to factor out the "ugly" part to another simple and readable method call(s).
Currently writing an IRC bot for fun and I have some trouble setting up the bot to listen to my commands. ( Works for !quit but not for !join or !leave )
void onPrivMsg(IRCMessage message, IRCClient* client)
{
// received text
std::string text = message.parameters.at(message.parameters.size() - 1);
if (text[0] == '!')
{
if (text == "!Join #channel" || text == "!join #channel")
client->SendIRC("JOIN #channel");
if (text == "!Leave #channel" || text == "!leave #channel")
client->SendIRC("PART #channel");
if (text == "!Quit" || text == "!quit")
client->SendIRC("QUIT");
} else{
client->SendIRC("PRIVMSG #channel :Wrong command.");
}
}
I'm calling it like so:
client.HookIRCCommand("PRIVMSG", &onPrivMsg);
How would I get the channel name (#ChannelISpecify) from the text message line?
Example: If I'd type "!join #funnyposts" in IRC it would join the channel #funnyposts.
Appriciate any kind of help.
Figured it out. Now filters for different commands and acts accordingly.
if (text[0] == '!')
{
std::string commandApi = text.substr(0, text.find(" "));
if (commandApi == "!Join" || commandApi == "!join"){
if (commandApi[0] = '!'){
commandApi[0] = '/';
}
std::string channel2 = text.substr(text.find("#"));
client->SendIRC("PRIVMSG " + channel2 + " :Joining channel");
client->SendIRC("JOIN " + channel2);
}
I have made a simple Script reading class in C++ which allows me to read and parse scripts.
Basically there's a FILE class, which then I proceed to open with "fopen".
In functions I proceed to call "fgetc" and "ftell" to parse the script file as needed, note this ain't an interpreter.
Every script file is supposed to follow a syntax, but this is why I'm asking here for a solution.
Here's how a script looks like:
# Script File Comment
USERNAME = "Joe"
PASSWORD = "pw0001"
ACCESSLEVEL = 3
DATABASE = ("localhost",3306,"db","user","password")
Basically I have a few functions:
// This function searches for "variables"
nextToken();
// After I have the variable, e.g: USERNAME, PASSWORD, ACCESSLEVEL or DATABASE
// I proceed to call this function
// This function reads the char array for (,-{}()[]=) these are symbols
readSymbol();
// In a condition I check what "token/variable" I got and proceed to read
// it accordingly
// e.g; for USERNAME I do:
readString(); // reads text inside "
// e.g; for ACCESSLEVEL I do:
readNumber(); // reads digits until the next char ain't a digit
// e.g; for DATABASE I do:
readSymbol(); // (
readString(); // 127.0.0.1
readSymbol(); // ,
readNumber(); // 3306
readSymbol(); // ,
readString(); // db
readSymbol(); // ,
readString(); // user
readSymbol(); // ,
readString(); // password
readSymbol(); // )
I would like to be able to read a variable declaration like this:
DATABASELIST = {"data1","data2","data3"}
or
DATABASELIST = {"data1"}
I could easily do readSymbol and readString to read for 3 different string definitions inside the variable, however this list is supposed to have custom user data, like 5 different strings, or 8 different strings - depends.
And I seriously have no idea how can I do this with the parser I wrote.
Please note that I am basing this in some Pseudo code I took from a scripter for this type of format, I have the pseudo code extracted from IDA, if you would like to see it for better understanding post here
Here's an example of my "readSymbol" function.
READSYMBOL
int TReadScriptFile::readSymbol()
{
int currentData = 0;
int stringStart = -1;
// Check if we can't read anymore
if (end)
return 0;
while (true)
{
// Basically get chars in the script
currentData = fgetc(File);
// Check for end of file
if (currentData == -1)
{
end = true;
break;
}
if (stringStart == -1)
{
if (isdigit(currentData) || isalpha(currentData))
{
printf("TReadScriptFile::readSymbol: Symbol expected\n");
close();
return 0;
}
else if
(
currentData == '=' || currentData == ',' ||
currentData == '(' || currentData == ')' ||
currentData == '{' || currentData == '}' ||
currentData == '>' || currentData == '<' ||
currentData == ':' || currentData == '-'
)
{
#ifdef __DEBUG__
printf("Symbol: %c\n", currentData);
#endif
stringStart = ftell(File);
break;
}
}
}
return 1;
}
NEXTTOKEN
int TReadScriptFile::nextToken()
{
int currentData = 0;
int stringStart = -1;
int stringEnd = -1;
RecursionDepth = -1;
memset(String, 0, 4000);
// Check if we can't read anymore
if (end)
return 0;
while (true)
{
// ** Syntax **
if (isdigit(getNext()) || getNext() == -1)
{
printf("No more tokens left.\n");
end = true;
close();
return 0;
}
// End
// Basically get chars in the script
currentData = fgetc(File);
// Check for end of file
if (currentData == -1)
{
end = true;
break;
}
// Syntax Checking Part, this really isn't needed but w/e
if (stringStart == -1)
{
if (currentData == '=' || isdigit(currentData))
{
printf("TReadScriptFile::nextToken: Syntax Error: string expected\n");
close();
return 0;
}
}
// End Syntax Checking
// It's a comment line, we should skip
if (currentData == '#')
{
seekNewLn();
continue;
}
// There are no variables, yet
if (stringStart == -1)
{
// We found a letter, we are near a token!
if (isalpha(currentData))
{
stringStart = ftell(File);
// We might as well add the letter to the string
RecursionDepth++;
String[RecursionDepth] = currentData;
continue;
}
}
else if (stringStart != -1)
{
// Let's wait until we get an identifier or space
// We found a digit, error
if (isdigit(currentData))
{
printf("TReadScriptFile::nextToken: string expected\n");
close();
return 0;
}
// We found a space, maybe we should stop looking for tokens?
else if (isspace(currentData))
{
#ifdef __DEBUG__
printf("Token: %s\n", String);
#endif
break;
}
RecursionDepth++;
String[RecursionDepth] = currentData;
}
}
return 1;
}
I found a good example of the approach I followed here:
http://llvm.org/docs/tutorial/LangImpl1.html
One mechanism to deal with DATABASE_LIST would be this:
After finding the variable DATABASE_LIST read a symbol using readSymbol() checking if it is a { then in a loop do readString() add it to a std::vector (or some other suitable container) then check for a , or } (using readSymbol()) . If it is a ,(comma) then you go back and read another string add to the vector etc. until you do finally reach } . When you are finished you'd have a vector (dynamic array) of strings that represent a DATABASE_LIST
How to use QLineEdit's built-in undo/redo functionality while implementing custom input logic?
I am implementing a custom editor for amounts of money for a cashier's efficient work. Basic features are:
The format is always ^\d+,\d{2}$;
When cursor is left to comma, it edits the integer part (e.g., when 0,00 is edited, the first digit input replaces the zero; i.e., 0,00 becomes 1,00 after '1' is entered);
Comma or period entered moves cursor to the fractional part;
Deletes and backspaces respect the format.
I can't use masks since they can't manage arbitrary length without unnecessary spaces. I can't use validators because of they are not enough flexible to handle logic of editing leading zero in place. That's why I sublassed QLineEdit and wrote the necessary logic myself.
The question is: is there a way to support undo functionality on QLineEdit's own logic? I use setText(), that resets undo/redo history. I could make two stacks of states and override undo() and redo() correspondingly, or make sequences of selections and insertions/deletions (what can cause unnecessary blinks), but I feel there may be even simpler way.
class MoneyLineEdit : public QLineEdit {
Q_OBJECT
public:
MoneyLineEdit(QWidget *parent = 0);
protected:
void keyPressEvent(QKeyEvent * event);
};
void MoneyLineEdit::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Comma || event->key() == Qt::Key_Period) {
setCursorPosition(text().length() - 2);
} else {
QString text = this->text();
int pos = cursorPosition();
if (event->key() == Qt::Key_Backspace) {
if (pos == text.length()) {
text.replace(text.length() - 1, 1, QChar('0'));
--pos;
} else if (pos == text.length() - 1) {
text.replace(text.length() - 2, 1, text.at(text.length() - 1));
text.replace(text.length() - 1, 1, QChar('0'));
--pos;
} else if (pos == text.length() - 2) {
--pos;
} else if (text.length() == 4 && pos == 1) {
text.replace(0, 1, QChar('0'));
}
setText(text);
setCursorPosition(pos);
} else if ((pos == text.length() - 3 || pos == text.length() - 2) && event->key() == Qt::Key_Delete && selectionStart() == -1){
text.replace(text.length() - 2, 1, text.at(text.length() - 1));
text.replace(text.length() - 1, 1, QChar('0'));
setText(text);
setCursorPosition(pos);
} else if (pos >= text.length() - 2 && pos <= text.length() - 1 && !event->text().isEmpty()){
text.replace(cursorPosition(), 1, event->text());
++pos;
setText(text);
setCursorPosition(pos);
} else if ((pos == 0 || pos == 1) && !text.isEmpty() && text.length() == 4 && text.at(0) == QChar('0') && !event->text().isEmpty()) {
text.replace(0, 1, event->text());
setText(text);
setCursorPosition(1);
} else {
QLineEdit::keyPressEvent(event);
}
}
}
Obviously, two stacks of Pair(text,cursorPosition) for undo()/redo() overloaded are sufficient.