trying to read a config file - c++

sorry in advance for the formatting. Couldn't figure it out...
I'm passing a config file to a program via arguments
I'm trying to read a value from a specific parameter
I've got a cofigReader class with the following method for returning a string from a config file given a specific parameter
My problem,
it never finds the parameter. found is either 0 or -1....
string configReader::value(string config_file, string parameter)
{
string value;
char config_delimiter = '=';
size_t found;
file.open(config_file);
std::string line;
bool param_found = false;
while(param_found == false){
while (!file.eof())
{
getline(file,line);
logger.writetolog("INFO","Looking for " + parameter +
" on line "+ line);
found = line.find(parameter);
logger.writetolog("INFO",int(found));
if(found!=string::npos){
param_found = true;
}
}
param_found = true;
}
if (found!=string::npos)
{
size_t a = line.find(config_delimiter)+1;
logger.writetolog("INFO","Found" + parameter +
"splitting string at delimter" + config_delimiter +
" and return right side value");
value = line.substr(a);
return value;
}
else
{
return value;
}
file.close();
}
more info. Config file reads like this.
toemail=someemailaddress#gmail.com
outputdir=C:\tmp
configReader class used like this
//attempt to parse out the required parameters for the program
string toemail = config.value(configFileArg,"toemail");
it ALWAYS return empty

Your while (!file.eof()) loop continues after you find a match, over-writing the value of found which you check later.
You could fix this by changing your loop to something like
bool param_found = false;
while (!param_found && !file.eof()) {
if (getline(file,line)) {
break;
}
logger.writetolog("INFO","Looking for " + parameter +" on line "+ line);
found = line.find(parameter);
logger.writetolog("INFO",int(found));
if(found!=string::npos){
param_found = true;
break;
}
}
instead. (Notice that this code removes your while(param_found == false) loop. As sftrabbit points out, that loop is unnecessary.)

The idiomatic way to write loop is this:
bool param_found = false;
while (std::getline(file,line)) //<-- this is idiomatic loop!
{ //successfully read OR exit from the loop
logger.writetolog("INFO","Looking for " + parameter +" on line "+ line);
found = line.find(parameter);
logger.writetolog("INFO",int(found));
if(found!=string::npos){
param_found = true;
break;
}
}
You should not use eof() when writing loops:
Why is iostream::eof inside a loop condition considered wrong?
What's preferred pattern for reading lines from a file in C++?
These two topics discuss this in detail.

Related

I have a text file with each line containing an integer. I want to open the text tile and count the number of integers in the file

void DataHousing::FileOpen() {
int count = 0;
// attempt to open the file with read permission
ifstream inputHandle("NumFile500.txt", ios::in);
if (inputHandle.is_open() == true) {
while (!inputHandle.eof()) {
count++;
}
inputHandle.close();
}
else {
cout << "error";
}
cout << count;
}
This is getting stuck in the while loop. But shouldn't the while loop end when it gets to the end of file? Also, I'm not even sure yet if it is counting correctly.
A fairly easy way to do this would be to use std::cin instead. Assuming that you want to count the number of integers in a file you can just use a while loop like so:
int readInt;
int count = 0;
while(std::cin >> readInt){
count++;
}
Then you just pass in the file as an argument parameter to your executable as so:
exec < filename
If you prefer to go through the route you're going then you can just replace your while loop condition with !inputHandle.eof() && std::getline(inputHandle, someStringHere) Then proceed to check if someStringHere is an int and increment your count if it is like so:
int count = 0;
std::string s;
ifstream inputHandle("NumFile500.txt", ios::in);
if (inputHandle.is_open() == true) {
while (!inputHandle.eof() && std::getline(inputHandle, s)) {
if(check to see if it's a number here)
count++;
}
inputHandle.close();
}

Matching word c++ program using getline() running infinitely?

I am learning c++ so bear with me and apologize for any idiocy beforehand.
I am trying to write some code that matches the first word on each line in a file called "command.txt" to either "num_lines", "num_words", or "num_chars".
If the first word of the first line does not match the previously mentioned words, it reads the next line.
Once it hits a matching word (first words only!) it prints out the matching word.
Here is all of my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
ifstream comm_in("commands.txt"); // opens file
string command_name = "hi"; // stores command from file
bool is_command() {
if (command_name == "num_words" || command_name == "num_chars" || command_name == "num_lines") {
return true;
} else {
return false;
}
}
// FIND a first word of a line in file THAT MATCHES "num_words", "num_chars" or "num_lines"
void get_command() {
string line;
char c;
while (!is_command()) { // if command_name does not match a command
// GET NEXT LINE OF FILE TO STRING
getline(comm_in, line);
// SUPPOSED TO GET THE FIRST WORD OF A STRING (CANT USE SSTREAM)
for (int i = 0; i < line.size(); i++) { // increment through line
c = line[i]; // assign c as index value of line
if (c == ' ' || c == '\t') { // if c is a space/tab
break; // end for loop
} else {
command_name += c; // concatenate c to command_name
} // if
} // for
} // while
return;
}
int main() {
get_command();
cout << command_name; // supposed to print "num_lines"
}
The contents of the command.txt file:
my bear is happy
and that it
great ha
num_lines sigh
It compiles properly, but when I run it in my terminal, nothing shows up; it doesn't seem to ever stop loading.
How can I fix this?
Unless you really want to hate yourself in the morning (so to speak) you want to get out of the habit of using global variables. You'll also almost certainly find life easier if you break get_command into (at least) two functions, one specifically to get the first word from the string containing the line.
I'd write the code more like this:
bool is_cmd(std::string const &s) {
return s == "num_words" || s == "num_chars" || s == "num_lines";
}
std::string first_word(std::istream &is) {
std::string line, ret;
if (std::getline(is, line)) {
auto start = line.find_first_not_of(" \t");
auto end = line.find_first_of(" \t", start);
ret = line.substr(start, end - start);
}
return ret;
}
void get_command(std::istream &is) {
std::string cmd;
while (!(cmd = first_word(is)).empty())
if (is_cmd(cmd)) {
std::cout << cmd;
break;
}
}
This still isn't perfect (e.g., badly formed input could still cause it to fail) but at least it's a move in what I'd say is a better direction.
If something goes wrong and you reach the end of file the loop will never stop. You should change getline(comm_in, line) to if(!getline(comm_in, line)) break;, or better yet, use that as the condition for the loop.
You also have to reset command_name for each pass:
while(getline(comm_in, line))
{
command_name = "";
for(int i = 0; i < line.size(); i++)
{
c = line[i];
if(c == ' ' || c == '\t')
break;
else
command_name += c;
}
if(is_command())
break;
}
// FIND a first word of a line in file THAT MATCHES "num_words", "num_chars" or "num_lines"
void get_command()
{
string line;
char c;
while (!is_command()) { // if command_name does not match a command
// GET NEXT LINE OF FILE TO STRING
if(getline(comm_in, line),comm_in.fail()){
// end reading
break;
}
//clear
command_name = "";
// SUPPOSED TO GET THE FIRST WORD OF A STRING (CANT USE SSTREAM)
for (int i = 0; i < line.size(); i++) { // increment through line
c = line[i]; // assign c as index value of line
if (c == ' ' || c == '\t') { // if c is a space/tab
break; // end for loop
} else {
command_name += c; // concatenate c to command_name
} // if
} // for
} // while
return;
}
The key of this problem is that you didn't clear the command_name.
What's more, you have to add a judge about whether reaching the end of the file.
ps: if(getline(comm_in, line),comm_in.fail()) is equal to if(getline(comm_in, line)),

Alternating between reading and writing repeatedly

My objective is to read a file line by line, check if that line contains some number, and if so rewrite that line. Then continue reading the file.
I've successfully been able to do this for one line, but I can't figure out how to continue reading the rest of the file.
Here's how I replace one line (every line is a known fixed size):
while(getline(fs, line)){
if(condition){
pos = fs.tellg(); //gets current read position (end of the line I want to change)
pos -= line.length()+1; //position of the beginning of the line
fs.clear(); //switch to write mode
fs.seekp(pos); //seek to beginning of line
fs << new_data; //overwrite old data with new data (also fixed size)
fs.close(); //Done.
continue;
}
}
How do I switch back to read and continue the getline loop?
I had the same problem, TB-scale files and I wanted to modify some header information in the beginning of the file.
Obviously one has to leave enough room when one initially creates the file for any new content, because there is no way to increase the file size (besides appending to it) and the new line has to have the exact same line length as the original one.
Here is a simplification of my code:
#include <iostream>
#include <fstream>
using namespace std;
bool CreateDummy()
{
ofstream out;
out.open("Dummy.txt");
// skip: test if open
out<<"Some Header"<<endl;
out<<"REPLACE1 12345678901234567890"<<endl;
out<<"REPLACE2 12345678901234567890"<<endl;
out<<"Now ~1 TB of data follows..."<<endl;
out.close();
return true;
}
int main()
{
CreateDummy(); // skip: test if successful
fstream inout;
inout.open("Dummy.txt", ios::in | ios::out);
// skip test if open
bool FoundFirst = false;
string FirstText = "REPLACE1";
string FirstReplacement = "Replaced first!!!";
bool FoundSecond = false;
string SecondText = "REPLACE2";
string SecondReplacement = "Replaced second!!!";
string Line;
size_t LastPos = inout.tellg();
while (getline(inout, Line)) {
if (FoundFirst == false && Line.compare(0, FirstText.size(), FirstText) == 0) {
// skip: check if Line.size() >= FirstReplacement.size()
while (FirstReplacement.size() < Line.size()) FirstReplacement += " ";
FirstReplacement += '\n';
inout.seekp(LastPos);
inout.write(FirstReplacement.c_str(), FirstReplacement.size());
FoundFirst = true;
} else if (FoundSecond == false && Line.compare(0, SecondText.size(), SecondText) == 0) {
// skip: check if Line.size() >= SecondReplacement.size()
while (SecondReplacement.size() < Line.size()) SecondReplacement += " ";
SecondReplacement += '\n';
inout.seekp(LastPos);
inout.write(SecondReplacement.c_str(), SecondReplacement.size());
FoundSecond = true;
}
if (FoundFirst == true && FoundSecond == true) break;
LastPos = inout.tellg();
}
inout.close();
return 0;
}
The input is
Some Header
REPLACE1 12345678901234567890
REPLACE2 12345678901234567890
Now ~1 TB of data follows...
The output is:
Some Header
Replaced first!!!
Replaced second!!!
Now ~1 TB of data follows...

Search string for a given word and return a boolean value

I am new in this site and I would like to ask if anyone knows how to solve my question.
I have searched the net for hours but didn't find anything that works for me.
Any help will appreciated.
1) I have to write a function that asks for a word.
2) Add this word into an array.
3) Search a string if a word is matching the word given.
4) Boolean return value if is true or false otherwise.
Here what i done with my function so far. So i believe i am close to it( i need only the for loop to search for the word).
bool checkValidTitle( string modules[MODULENO+1]){
string array[1][20];
cout<< "Put the module: ";
cin>> array[1][20];
}
This is the function that you are being asked to write
bool checkValidTitle(string modules[], string word_to_check)
{
for (int i = 1; i <= MODULENO; ++i)
if (modules[i] == word_to_check)
return true;
return false;
}
Use it like this
string modules[MODULENO+1] = {"", "Maths", "Sciences", "French", "English"};
if (checkValidTitle(modules, "Maths"))
cout << "Maths is valid\n";
else
cout << "Maths is not valid\n";
if (checkValidTitle(modules, "Russian"))
cout << "Russian is valid\n";
else
cout << "Russian is not valid\n";
I'll leave you to fill in the rest.
I wrote back in the day a function, what returns a boolean value, if the first string contains the second string:
bool contains(const std::string & str, const std::string substr)
{
if(str.size()<substr.size()) return false;
for(int i=0; i<str.size(); i++)
{
if(str.size()-i < substr.size()) return false;
bool match = true;
for(int j=0; j<substr.size(); j++)
{
if(str.at(i+j) != substr.at(j))
{
match = false;
break;
}
}
if(match) return true;
}
return false;
}
I have tested it for some time, it seems to work. It searches with brute force, but i tried to optimize as much as i can.
Using this method you can do this:
std::string main_str = "Hello world!";
std::string sub_str = "ello";
std::string sub_str2 = "foo";
bool first = contains(main_str, sub_str); //this will give you true
bool second = contains(main_str, sub_str2); //this will give you false
Now i don't really understand, what you want with the array of strings, but i think, with this, you can get the desired output.

C++/CLI - URL Download to File

I'm not entirely familiar with how CLI works, but I have a general idea. I have a function that takes 2 System::String variables, and uses those to download a file from a webpage. As far as the download goes, it works fine, and the file shows up in my directory with the necessary content. However, it gives me the error
An unhandled exception of type 'System.AccessViolationException'
occurred in ParseLinks.exe
void downloadFile(System::String ^_URL, System::String ^_saveAs)
{
try
{
System::Net::WebClient ^webClient = gcnew System::Net::WebClient();
// Downloads the resource with the specified URI to a local file.
webClient->DownloadFile(_URL, _saveAs);
webClient->Dispose();
}
catch (System::Exception ^_e)
{
// Error
System::Console::WriteLine("Exception caught in process: {0}", _e);
}
}
I did some digging and output testing, and found out that the exe is hitting a break point somewhere in the text file, as the entire webpage did not save to the txt file.
Relevant code for that:
if (myFile.is_open()) //if file open
{
while (!myFile.eof()) //before end of file
{
getline(myFile, ln);
lines[count] = ln;
count++; //count total lines to set loop length for later parsing
//Error occurs somewhere in here
}
myFile.close();
}
else
cout<<"Error: Could not access file\n";
Brand New Error! :(
An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in ParseLinks.exe
The code after the file -> line array loop
myFile.close(); //Close txt file
//Loop through lines
for (int i = 0; i < count; i++)
{
string temp = parseLinks(lines[i]); //parse links from each line
The function for that:
string parseLinks(string str)
{
const int len = str.length();
string link;
bool quotes = false, islink = false;
string compare[5] = {".htm",".html",".php",".asp",".pdf"};
//Parse all quoted text
for (int i = 0; i != len; i++)
{
//Change bool if quote found
if (str[i] == '"')
{
if (quotes == false)
quotes = true;
else
quotes = false;
}
//If bool true, and char is not a quote, add to link string
if (quotes == true && str[i] != '"')
link += str[i];
}
//Discard non-link text
for (int i = 0; i < 5; i++)
{
//Link check for links given array of path filetypes
if (link.compare((link.length() - compare[i].length()),compare[i].length(),compare[i]) == 0)
islink = true;
}
//Link check for links with no path filetype (.html, .php, etc.)
if (link.compare(0,7,"http://") == 0)
islink = true;
//If not a link, return empty string
if (islink == false)
link = "";
return link;
}
The error points to my large compare statement in this function. (Also, I'm clearly terrible at compressing my code)
You're using getline wrong, and possibly that's causing your error. The correct idiom is this:
std::string line;
while (std::getline(myFile, line))
{
// process `line`
}
There's no need to check myFile for openness separately.