I have 2 projects, both on the same solution.
Project#1: does a single action based on debug inputs.
for simplicity let say that the main prints the debug inputs.
Project#2: I want to run Project#1 with for loop that run over different debug
inputs.
How can I do this right and efficient?
from what I understand, calling Project#1 exe file from Project#2 is not recommended. any other way to run Project#1 ::main, without changing Project#1? with only changes in Project#2 ..
Thanks,
New to advanced c++.
You don't have to do it in separate projects, you can do all from a single one, with different command line options.
for option one you can run the command line as: pro.exe debug-print1
the project just print the arguments and exit.
for the second option you can create a file,
You can put all your debug prints in file, and iterate on each line from the file, you just need to mark it as a file for example with a -f filename.
Next step is to process multiple files or debug-prints, or combination of files and prints in the same run.
So consider the following code for example:
#include <string>
#include <iostream>
#include <fstream>
//process a line function:
void proccess_debug_line(const std::string& debug_line)
{
std::cout<<debug_line<<std::endl;
}
//process file by processing each line:
void process_debug_file(const std::string& debug_file_name)
{
std::string debug_line;
std::ifstream inputfile(debug_file_name);
if(!inputfile)
{
std::cerr<<"error openning file: "<< debug_file_name <<std::endl;
}
while(std::getline(inputfile, debug_line))
{
//use the process line
proccess_debug_line(debug_line);
}
}
//argument can be a line, or a file if there is -f before it.
int main(int argc, char **argv)
{
for(int i=1; i<argc; i++)
{
std::string param = argv[i];
if(param[0] == '-')
{
if(param == "-f") // arguments in form -f filename
{
if(i == argc-1 ) // -f is last arg
{
std::cerr<<"Missing argument for " << param << " option."<<std::endl;
}
else //-f filename
{
std::string filename = argv[++i];
process_debug_file(filename);
}
}
else if(param.substr(0,2)== "-f")// argument in form -ffilename can be legal too
{
std::string filename = &(argv[i][2]);
process_debug_file(filename);
}
else
{
std::cerr<<"Unknown option '" << param << "'"<<std::endl;
++i;
}
}
else //a 'regular' parameter (without -f before it) is a debug print
{
proccess_debug_line(param);
}
}
}
Related
I am trying to get the output of the curl command to work inside of an if statement
I am new to C++ and don't know how I could do this.
int curlreq;
curlreq = system("curl localhost/file.txt");
string curlreqstring = to_string(curlreq);
if ((krxcrlstr.find("hello") != string::npos) ) {
cout << "hello\n";
}
else if (curlreqstring.find("hello2") != string::npos) {
cout << "hello2\n";
}
I am doing this on Windows. The project is a console app C++ 20
All the above code is doing, is printing what the curl response is, but I need that as a variable to then determine what the program should do.
As you see I am getting the contents of a file from localhost, the file itself has a singular line.
std::system returns an int with an implementation-defined value. On many platforms, 0 means success and anything else means some sort of failure. I'm making this assumption in the below example.
My advice is to use libcurl which is what the curl command is using internally. With a little setup you can make your program perform curl actions and receive what you get back into your program. If you do not have access to libcurl or find it a bit hard to get started with, you could wrap your system command in a function which performs the curl command but directs the output to a temporary file which you read after curl is done.
Example:
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
// a simple class to remove the temporary file after use
struct file_to_remove {
// remove "filename" when the object is destroyed
~file_to_remove() { std::remove(filename.c_str()); }
const std::string& str() const { return filename; }
const std::string filename;
};
// A function to "curl":
std::string Curl(std::string options_plus_url) {
// An instance to remove the temporary file after use.
// Place it where you have permission to create files:
file_to_remove tempfile{"tmpfile"};
// build the command line
// -s to make curl silent
// -o to save to a file
options_plus_url = "curl -so " + tempfile.str() + " " + options_plus_url;
// perfom the system() command:
int rv = std::system(options_plus_url.c_str());
// not 0 is a common return value to indicate problems:
if(rv != 0) throw std::runtime_error("bad curl");
// open the file for reading
std::ifstream ifs(tempfile.str());
// throw if it didn't open ok:
if(!ifs) throw std::runtime_error(std::strerror(errno));
// put the whole file in the returned string:
return {std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>{}};
} // tmpfile is removed when file_to_remove goes out of scope
With the above Curl function you can perform curl commands and get the response as a std::string which you can then use in your if statements etc.
Example:
int main(int argc, char* argv[]) {
if(argc < 2) return 1; // must get an URL as argument
try {
std::string response = Curl(argv[1]);
std::cout << response << '\n';
} catch(const std::exception& ex) {
std::cout << "Exception: " << ex.what() << '\n';
}
}
I'm begginer in C++, so may be parts of my code doesn't have sense, sorry.
What I have to do is (C++, Linux, by fstream):
· Receive 3 or more files passed by terminal by:
./executable file1.txt file2.txt file3.txt
· programm a function that read the files file2.txt and file3.txt and copy it to file1.txt (concatenate, don't overwrite)
I don't know how to do it, I don't know anything about fstream, I'm just learning now by myself, so I really need help. Maybe there are similar questions solved in SO, but I don't know how to solve my problem by them.
I attach the code I have. I don't know how to code the function, so it's empty.
Thank you so much.
I try doing:
void concat(char *argv[], int numberoffilesreceived){
char c;
towritethefiles.open(argv[0], ios::app);
for(int i=1; i<numberoffilesreceived; i++){
toreadthefiles.open(argv[i], ios::in);
while(!toreadthefiles.eof()){
toreadthefiles >> c;
towritethefiles<< c;
}
}
}
It compiles but doesn't work, the program freezes when you run it.
and I also try using std::copy by I don't understand how it works.
ifstream toreadthefiles;
ofstream towritethefiles;
void concat(char *argv[], int numberoffilesreceived);
int main(int argc, char *argv[]){
/* 1/2 The code from below to 2/2 it's only to prevent path errors when receiving the files (it works fine) */
const char directory[SIZE]="./";
int count_files=0;
char files[SIZE][SIZE];
for(int i=1; i<argc; i++){
strcpy(files[i], directory);
strcat(files[i], argv[i]);
count_files++;
}
/*2/2 to add ./ to the name files when passed by terminal: ./executable ./file1.txt ./file2.txt ./file3.txt */
/*check if received almost 3 files like required */
if(argc<3){
cout<< "Error, to few files entered" << endl;
getchar();
exit(1);
}
/*pass the files to the concat function*/
for(int i=1; i<argc; i++){
concat(&argv[i], count_files);
}
toreadthefiles.close();
towritethefiles.close();
return 0;
}
void concat(char *argv[], int count_files){
}
I think I see an issue with your concat() function. You are calling concat() for each of the files passed in. Then in the function, you are using count_files to run that loop again for the number of files passed in.
I would consider rewriting concat() function so that it looks like this:
void concat(std::ofstream& outputStream, char* fileToAppend)
{
std::ifstream in(fileToAppend);
if (!in) {
cout << "Error, cannot open file: " << fileToAppend;
return;
}
// Use std::getline to read each line in the input stream,
// then write it to the output stream!
string line;
while (std::getline(in, line)) {
outputStream << line;
}
}
The benefit being that you can reuse the function for appending a single input file to an existing output stream, and you wrap up the check to ensure the file exists (you may want something more sophisticated like returning true/false on the file being appended, or throwing an error, etc.).
In main(), you would replace the code after the check for at least three files with something like:
// Create an output stream with the first file
// ios::out- output flag
// ios::app- append flag
std::ofstream out(argv[1], ios::out | ios::app);
// Make sure the file exists!
if (!out) {
cout << "Error, cannot open file: " << argv[1];
exit(1);
}
// For all other arguments, concat with the first.
for (int i = 2; i < argc; i++) {
concat(out, argv[i]);
}
You can use std::copy with stream iterators, and I've revised my previous suspicion that it would be slow, so here's one way using doing just that with comments in the code.
#include <iostream>
#include <fstream>
#include <vector>
#include <ios>
#include <stdexcept>
void concat(const std::string& destination, const std::vector<std::string>& sources) {
// open the destination file and keep it open until all is done
std::ofstream dest_fs(destination, std::ios_base::binary);
if(!dest_fs)
throw std::runtime_error("Could not write to \"" + destination + "\".");
// loop over the source files
for(const auto& source_file : sources) {
// open the current source file
std::ifstream source_fs(source_file, std::ios_base::binary);
if(!source_fs)
throw std::runtime_error("Could not read from \"" + source_file + "\".");
// copy from source to destination
std::copy(std::istreambuf_iterator<char>(source_fs),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(dest_fs));
}
}
int cppmain(std::string program, std::vector<std::string> args) {
if(args.size() < 2) {
std::cout << "USAGE: " << program << " destination_file input_file(s)\n";
return 1;
}
// extract the first argument which is the destination file
std::string destination_file = std::move(args.front());
args.erase(args.begin()); // erase first argument from the vector
try {
// do the concatenation
concat(destination_file, args);
return 0;
} catch(const std::exception& ex) {
std::cerr << program << ": ERROR: " << ex.what() << "\n";
return 1;
}
}
int main(int argc, char* argv[]) {
return cppmain(argv[0], {argv + 1, argv + argc});
}
Using C++, need to pass the contents of a file to the program as an argument à la $ ./main <filename.txt or $ echo the contents of the file | ./main
I want to be able to access the contents of the file as a variable or something so I can manipulate further.
I have this basic listing including some of the stuff I've been trying. The data doesn't seem to be in argv (my runs always tell me I have one argument). What is the way to access a command line argument passed in this way?
#include <fstream>
#include <iostream>
int main(int argc, char **argv)
{
std::cout << "Have " << argc << " arguments:" << std::endl;
for (int i = 0; i < argc; ++i) {
std::cout << argv[i] << std::endl;
}
std::istream* input = &std::cin;
if(argc > 1) {
std::cout << input;
std::cout << "more than argument found\n";
}
std::string inputs;
std::cout<< "1:\n";
std::cout<< argv[0];
std::cout<< "\n2:\n";
std::cout<< argv[1];
std::cout<< "\n3:\n";
std::cout<< input;
std::cout<< "\nEnd\n";
return 0;
}
EDIT
I perhaps wasn't entirely clear, given it was a fairly fundamental question I was asking but didn't realize. Essentially, passing using $ ./main <filename.txt is non-negotiable. User RPGillespie's comment pointed me in the right direction. The pipe sends it to stdin (which I didn't realize). Thus I wanted to handle the data using cin. A minimal working example would be
int main() {
// read input
for (std::string line; std::getline(std::cin, line);) {
std::cout << line << std::endl;
}
return 0;
}
cat file | ./main will pipe the file content to the input of the ./main, not the argument.
If you want to pipe arguments in this way, use xargs:
cat file | xargs ./main
While #liliscent has a great solution, the following also works (I am mentioning it for the sake of completeness and since I feel it is more readable):
./main $(cat file)
This takes the contents of the file called file (since it interprets the command inside the $( and )), and passes them as arguments to ./main.
So, quick question:
I am tasked with making a program that reads in a file, does some fancy things, and writes out to an html file with the re-purposed text, all simple stuff.
Furthermore the program must be able to accept up to four command line arguments (but a minumum of two). The executable of course, the file it is reading in, the file name it will be reading out to, and finally a "-r" argument for more information on the file (the amount of paragraphs, etc).
So the question I have is as follows:
the "-r" argument can be anywhere in the arguments (as long as it comes after argv[0] of course), or it can be completely non-existent (as can the output file name).
This is still simple to do, a little tedious writing a bunch of if's or even a switch or two, but I can't help but think that there may be an easier way to accomplish this, rather than having a plethora of if statements.
Any help would be greatly appreciated. (I also suppose you don't need any code considering I don't exactly have a problem.)
Here is roughly how one might do it without a library:
GCC 4.8.2: g++ -Wall -Wextra -std=c++0x main.cpp
#include <iostream>
#include <string>
int main(int argc, char* argv[]) {
char* input = nullptr;
char* output = nullptr;
char* r_arg = nullptr;
--argc; ++argv; // Skip the program name.
const char* def_in = "default in";
const char* def_out = "default out";
const char* def_r = "default r";
while (0 < argc) {
if (std::string(argv[0]) == "-r") {
// This code requires a space after the "-r", which is unusual.
++argv;
--argc;
r_arg = argv[0]; }
else if (input == nullptr) {
input = argv[0]; }
else if (output == nullptr) {
output = argv[0]; }
else {
std::cerr << "error: unexpected arg '" << argv[0] << "'\n"; }
++argv;
--argc; }
if (input == nullptr) {
input = const_cast<char*>(def_in); }
if (output == nullptr) {
output = const_cast<char*>(def_out); }
if (r_arg == nullptr) {
r_arg = const_cast<char*>(def_r); }
std::cout << "input: " << input << "\n"
<< "output: " << output << "\n"
<< "r arg: " << r_arg << "\n";
return 0; }
I have the following main method:
int main(string argf)
{
ifstream exprFile(argf);
string inExpr;
if (exprFile.is_open())
{
while ( getline(exprFile,inExpr) )
{
//do stuff
}
exprFile.close();
}
else cout << "Unable to open file";
system("pause"); // to wait for user input; allows the user to see what was printed before the window closes
return 0;
}
I have run this program from the command line using the following:
"C:\Complete Filepath\Project2.exe" "C:\Differnt Filepath\args.txt"
C:\Complete Filepath\Project2.exe C:\Differnt Filepath\args.txt
"C:\Complete Filepath\Project2.exe" "args.txt"
C:\Complete Filepath\Project2.exe args.txt
The last two with args.txt being in the same directory as the executable. All four gave the "Unable to open file" result. Attemping to print the argf value before doing anything with it yielded nothing at all. A completely blank print statement.
I then went into the Visual Studio 2010 options and added all variations of the args.txt file under the arguments section there with the file in different locations as well and nothing works.
What am I doing wrong?
How are you supposed to open a file passed as an argument on the command line?
int main ( int argc, char *argv[] )
This is correct way to get argument from main.
argc is number of arguments. argv is argument list.
Actual argument will start with index = 1. Value at index 0 will be always program name.
In your example,
"C:\Complete Filepath\Project2.exe" "C:\Differnt Filepath\args.txt"
argc = 2
argv[0] = "Project2.exe"
argv[1] = "C:\Differnt Filepath\args.txt"
Yay, code!
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char* argv[])
{
ifstream exprFile;
string inExpr;
for( int i = 1; i < argc; i++) { // 0 is the program name
exprFile.open(argv[i]);
if (exprFile.is_open()) {
while ( getline(exprFile,inExpr) ) {
cout << "Doing stuff on line: " << inExpr << "\n";
}
exprFile.close();
}
else cout << "Unable to open file " << argv[i];
}
}