In C++, I need to start a secondary program from a primary program, sending the second some arguments. I need to return the data produced by the secondary program to the primary program. In this case, the data happens to be a two-dimensional std::string array; we'll call it stringArray. This is easy enough to do:
// snippet from Primary
std::string executionString ("./secondaryProgram arg1 arg2 arg3");
system(executionString);
What I don't know how to do is get the data that Secondary Program produces back to the Primary program (short of writing to a temporary file from Secondary and then reading the file from Primary).
In other words, it would be great if I could do something like:
// snippet from Primary
std::string stringArray[2][3];
stringArray = system(executionString);
I'm not hoping for a solution as simple as this or working code from anyone, any nudge in the right direction is appreciated.
I cannot use sockets for this purpose. I have not been able to figure out how to build a pipe between std::cout and std::cin that works for this case. My only real constraint is that my solution involve system() somehow.
system() does not create pipes to the child process. The child process inherits the parent's standard in, standard out, and standard error descriptors.
On Linux, you can use popen() if you want access to the child's stdin or stdout.
Since you have to use system(), you could
have the secondary program store its results in a file. Your main program would then open the file after the system completes. Sort of like this:
std::string executionString ("./secondaryProgram arg1 arg2 arg3 > output_file.txt");
system(executionString);
std::ifstream result("output_file.txt");
while( result >> str) {
result_vector.push_back(str);
}
Take a look at boost.interprocess. It contains many utilities that can be used for IPC in a portable way.
If you don't want to rely on boost, you can do something like this. Compile with C++11 mode and -pthread GCC option.
Why don't you write the relevant information in the second process to a file, and then read that file in the first process. Seems weird to do it this way, but I think it meets your professor's criteria, at least the parts you've shared with us.
Boost Interprocess should work for you. It supports message queues between threads on different processes.
You can use pipes to communicate. The link provided has examples for linux, but it's very similar to what you would write for windows.
If you need to send arbitrary data that might change at run time you might consider serializing the data sent over the pipes and deserializing it at the receiver. You might use XML, JSON, or something like Protobuf. If you make it human readable that adds the opportunity to reuse components or debug what's happening using the eyeball mark 1
Alright here's what I ended up doing.
"translate"
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <algorithm>
#include <cstdlib>
#include <unistd.h>
std::vector<std::string> sortTerms(int n, char* argv[]) {
std::vector<std::string> sortedTerms (n);
for (int i = 0; i < n; i++) {
sortedTerms[i] = argv[i+1]; // first term argv is program name
}
std::sort(sortedTerms.begin(),sortedTerms.end());
return sortedTerms;
}
std::vector<std::string> splitString(int n,std::string str) {
std::vector<std::string> stringVector (n);
std::istringstream iss(str);
for (int i = 0; i < n; i++)
std::getline(iss, stringVector[i], ' ');
return stringVector;
}
int main(int argc, char** argv) {
const int NUM_TERMS = (argc - 1); // number of words to translate
std::string output[NUM_TERMS][2]; // used to store a translated word alongside the English equivalent
std::string stringBuffer; // used to start dictionary with arguments
std::vector<std::string> stringVector (NUM_TERMS); // used as a buffer
std::ofstream outputFile("translated.txt"); // file to write translations to
const bool VERBOSE = true;
stringBuffer.clear();
stringBuffer.append("./dictionary ");
// Sort English words and load them into output
stringVector = sortTerms(NUM_TERMS, argv);
for (int i = 0; i < NUM_TERMS; i++) {
output[i][0] = stringVector[i];
stringBuffer = stringBuffer.append(stringVector[i]);
stringBuffer = stringBuffer.append(" ");
}
int pipeStatus;
int pipeOutput[2]; // file descriptor
pipeStatus = pipe(pipeOutput); // create output read/write pipe ends
if (pipeStatus < 0) {
std::cerr << "ERROR CREATING PIPE" << std::endl;
exit(1);
}
int pid = 0;
pid = fork();
if (pid == 0) { // dictionary
// Connect the pipes
dup2 (pipeOutput[1],1);
// Execute the program
system(stringBuffer.c_str());
// Close pipes
close(pipeOutput[0]);
close(pipeOutput[1]);
exit(0);
}
else if (pid > 0) { // Original process
char* buffer = new char[1024]; // input buffer
// Receive string from dictionary
read(pipeOutput[0],buffer,1024); // read in from output of dictionary
stringBuffer = buffer; // I'd rather work with a std::string
stringVector = splitString(NUM_TERMS, stringBuffer);
for (int i = 0; i < NUM_TERMS; i++)
output[i][1] = stringVector[i];
// Close pipes
close(pipeOutput[0]);
close(pipeOutput[1]);
if (VERBOSE) {
for (int i = 0; i < NUM_TERMS; i++)
std::cout << output[i][0] << " -> " << output[i][1] << std::endl;
}
// write translationString to file
for (int i = 0; i < NUM_TERMS; i++) {
outputFile.write(output[i][0].c_str(),output[i][0].length());
outputFile.write(" -> ",4);
outputFile.write(output[i][1].c_str(),output[i][1].length());
outputFile.write("\n",1);
}
outputFile.close();
exit(0);
}
else if (pid == -1) {
std::cerr << "ERROR FORKING PROCESS" << std::endl;
exit(1);
}
return 0;
}
"dictionary"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
std::vector<std::string> splitString(std::string str)
{
std::vector<std::string> stringVector (2);
std::istringstream iss(str);
std::getline(iss, stringVector[0], ' ');
std::getline(iss, stringVector[1], ' ');
return stringVector;
}
int main(int argc, char* argv[]) {
const int NUM_TERMS = (argc - 1);
std::string stringBuffer;
std::string returnString[NUM_TERMS];
std::vector<std::string> stringVector;
std::ifstream dictionaryFile ("./dictionary.txt");
// There must be at least one arguement
if (argc <= 1)
std::cout << "Nothing to translate..." << std::endl;
for (int i = 0; i < NUM_TERMS; i++) {
while (dictionaryFile) {
getline(dictionaryFile,stringBuffer);
stringVector = splitString(stringBuffer);
if (stringVector[0] == argv[i+1]) { // wut
returnString[i] = stringVector[1];
break;
}
}
}
// clear string buffer
stringBuffer.clear();
// Form translated words string
for (int i = 0; i < NUM_TERMS; i++) {
stringBuffer.append(returnString[i]);
if (i < (NUM_TERMS - 1))
stringBuffer.append(" "); // append a space after each but the last term
}
// print translated words
std::cout << stringBuffer << std::endl;
dictionaryFile.close();
return 0;
}
"dictionary.txt"
Apple Apfel
Banana Banane
Blackberry Brombeere
Blueberry Heidelbeere
Cherry Kirsche
Fruit Obst
Grape Traube
Lemon Zitrone
Lime Limone
Orange Orange
Peach Pfirsich
Pear Birne
Plum Zwetschge
Raspberry Himbeere
Strawberry Erdbeere
meant to be run like $ ./dictionary Apple Orange Strawberry
produces "translated.txt"
Apple -> Apfel
Orange -> Orange
Strawberry -> Erdbeere
I've still got a bit of polishing to do before I turn it in, but that's the gist of it. Thanks guys!
Related
This code was for implementing cat in Lin, and when I compiled it, it returned me "tp undefined". When I asked my professor, he said the way I used getline is in C language. I'm confused.
int main(int argc, char*argv[]) {
FILE* file;
for (int i = 1; i < argc; i++) {
file = fopen(argv[i],"w");//
if (file < 0) {
perror("Error, Can't open file!");
return -1;
}
if (file.is_open()) {
string tp;
while (getline(file, tp)) { // c type
printf("%d\n", tp);
}
}
}
fclose(file);
return 0;
}
Problem:
printf is incorrectly formatted. %d is for signed integers. %s is for strings of characters (More info here). Additionally, if you want to work with printf() you will need a C string or to call the std::string::c_str() function.
You're doing things in C style (using FILE*, fopen(), etc).
Solution:
If you still want or need to use a C style, replace with printf("%d\n", tp); with printf("%s\n", tp.c_str());.
Use a C++ style instead:
FILE* -> std::ifstream.
fopen() -> std::ifstream::is_open().
file < 0 -> std::ifstream::fail().
perr -> std::cerr.
printf() -> std::cout.
fclose() -> std::ifstream::close().
Additional information:
using namespace std; is considered a bad practice (More info here).
Full code:
#include <iostream>
#include <fstream>
int main(int argc, char*argv[])
{
for(int i = 1; i < argc; i++)
{
std::ifstream file(argv[i]);
if(file.fail())
{
std::cerr << "Error opening file.\n";
return 1;
}
std::string tp;
while(std::getline(file,tp))
std::cout << tp;
}
return 0;
}
I have the following c++ code which writes "Line from #" to a file while managing a file lock. I am running this code on two different computers, which share at least some of their memory. That is I can access my files by logging onto either of these computers.
On the first computer I run the program as ./test 1 (e.g. so it will print Line from 1 20,000 times) and on the second computer I run the program as ./test 17. I am starting these programs close enough in time so that the writes to file.txt should be interleaved and controlled by the file locks.
The problem is that I am losing output as the file has 22,770 newlines, but it should have exactly 40,000 newlines.
wc file.txt
22770 68310 276008 file.txt
Also,
cat -n file.txt | grep 18667
18667 ne from 17
My question is why are my file locks not preventing file overwriting, and how can I fix my code so that multiple processes can write to the same file without file loss.
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;
void inline Set_Lck(struct flock &flck, const int fd)
{
flck.l_type = F_WRLCK;
if (fcntl(fd, F_SETLKW, &flck) == -1) {
perror("fcntl");
exit(1);
}
}
void inline Release_Lck(struct flock &flck, const int fd)
{
flck.l_type = F_UNLCK;
if (fcntl(fd,F_SETLK,&flck) == -1) {
perror("fcntl");
exit(1);
}
}
void Print_Spec(fstream &fout, ostringstream &oss,struct flock &flck, const int fd)
{
Set_Lck(flck,fd);
fout.seekp(0,ios_base::end);
fout << oss.str() << endl;
flush(fout);
Release_Lck(flck,fd);
}
int main(int argc, char **argv)
{
int fd_cd;
struct flock flock_cd;
ostringstream oss;
fstream comp_data;
const string s_cd_lck = "file_lock.txt";
const string s_cd = "file.txt";
int my_id;
if (argc == 1) {
my_id = 0;
} else if (argc == 2) {
my_id = atoi(argv[1]);
} else {
fprintf(stderr,"error -- usage ./test [my_id]\n");
exit(1);
}
/* Open file computed_data.txt for writing; create it if non-existent.*/
comp_data.open(s_cd.c_str(),ios::app|ios::out);
if (comp_data.fail()) {
perror("comp_data.open");
exit(1);
}
/* Open file that we will be locking. */
fd_cd = open(s_cd_lck.c_str(),O_CREAT|O_WRONLY,0777);
if (fd_cd == -1) {
perror("fd_cd = open");
exit(1);
}
/* Set up the lock. */
flock_cd.l_type = F_WRLCK;
flock_cd.l_whence = SEEK_SET;
flock_cd.l_start = 0;
flock_cd.l_len = 0;
flock_cd.l_pid = getpid();
for (int i = 0; i < 20000; ++i) {
oss.str(""); /* Yes, this can be moved outside the loop. */
oss << "Line from " << my_id << endl;
Print_Spec(comp_data,oss,flock_cd,fd_cd);
}
return 0;
}
I am using c++ and this program is running on Red Hat Enterprise Linux Server release 7.2 (Maipo).
My Research
I am not sure if part of the answer comes from the following Stackoverflow post (https://stackoverflow.com/a/2059059/6417898) where they state that "locks are bound to processes."
At this website (http://perl.plover.com/yak/flock/samples/slide005.html), the author dissuades against using LOCK_UN with flock and suggests closing the file each time and reopening it as needed, so as to flush the file buffer. I don't know if this carries over with fcntl or if this is even necessary if flush the file buffer manually.
I have following piece of code that is supposed to calculate the SHA256 of a file. I am reading the file chunk by chunk and using EVP_DigestUpdate for the chunk. When I test the code with the file that has content
Test Message
Hello World
in Windows, it gives me SHA256 value of 97b2bc0cd1c3849436c6532d9c8de85456e1ce926d1e872a1e9b76a33183655f but the value is supposed to be 318b20b83a6730b928c46163a2a1cefee4466132731c95c39613acb547ccb715, which can be verified here too.
Here is the code:
#include <openssl\evp.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>
const int MAX_BUFFER_SIZE = 1024;
std::string FileChecksum(std::string, std::string);
int main()
{
std::string checksum = FileChecksum("C:\\Users\\Dell\\Downloads\\somefile.txt","sha256");
std::cout << checksum << std::endl;
return 0;
}
std::string FileChecksum(std::string file_path, std::string algorithm)
{
EVP_MD_CTX *mdctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
int i;
unsigned int md_len;
OpenSSL_add_all_digests();
md = EVP_get_digestbyname(algorithm.c_str());
if(!md) {
printf("Unknown message digest %s\n",algorithm);
exit(1);
}
mdctx = EVP_MD_CTX_create();
std::ifstream readfile(file_path,std::ifstream::in|std::ifstream::binary);
if(!readfile.is_open())
{
std::cout << "COuldnot open file\n";
return 0;
}
readfile.seekg(0, std::ios::end);
long filelen = readfile.tellg();
std::cout << "LEN IS " << filelen << std::endl;
readfile.seekg(0, std::ios::beg);
if(filelen == -1)
{
std::cout << "Return Null \n";
return 0;
}
EVP_DigestInit_ex(mdctx, md, NULL);
long temp_fil = filelen;
while(!readfile.eof() && readfile.is_open() && temp_fil>0)
{
int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
char *buffer = new char[bufferS+1];
buffer[bufferS] = 0;
readfile.read(buffer, bufferS);
std::cout << strlen(buffer) << std::endl;
EVP_DigestUpdate(mdctx, buffer, strlen(buffer));
temp_fil -= bufferS;
delete[] buffer;
}
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
printf("Digest is: ");
//char *checksum_msg = new char[md_len];
//int cx(0);
for(i = 0; i < md_len; i++)
{
//_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
printf("%02x", md_value[i]);
}
//std::string res(checksum_msg);
//delete[] checksum_msg;
printf("\n");
/* Call this once before exit. */
EVP_cleanup();
return "";
}
I tried to write the hash generated by program as string using _snprintf but it didn't worked. How can I generate the correct hash and return the value as string from FileChecksum Function? Platform is Windows.
EDIT: It seems the problem was because of CRLF issue. As Windows in saving file using \r\n, the Checksum calculated was different. How to handle this?
MS-DOS used the CR-LF convention,So basically while saving the file in windows, \r\n comes in effect for carriage return and newline. And while testing on online (given by you), only \n character comes in effect.
Thus either you have to check the checksum of Test Message\r\nHello World\r\n in string which is equivalent to creating and reading file in windows(as given above), which is the case here.
However, the checksum of files,wherever created, will be same.
Note: your code works fine :)
It seems the problem was associated with the value of length I passed in EVP_DigestUpdate. I had passed value from strlen, but replacing it with bufferS did fixed the issue.
The code was modified as:
while(!readfile.eof() && readfile.is_open() && temp_fil>0)
{
int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
char *buffer = new char[bufferS+1];
buffer[bufferS] = 0;
readfile.read(buffer, bufferS);
EVP_DigestUpdate(mdctx, buffer, bufferS);
temp_fil -= bufferS;
delete[] buffer;
}
and to send the checksum string, I modified the code as:
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_destroy(mdctx);
char str[128] = { 0 };
char *ptr = str;
std::string ret;
for(i = 0; i < md_len; i++)
{
//_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
sprintf(ptr,"%02x", md_value[i]);
ptr += 2;
}
ret = str;
/* Call this once before exit. */
EVP_cleanup();
return ret;
As for the wrong checksum earlier, the problem was associated in how windows keeps the line feed. As suggested by Zangetsu, Windows was making text file as CRLF, but linux and the site I mentioned earlier was using LF. Thus there was difference in the checksum value. For files other than text, eg dll the code now computes correct checksum as string
I m trying to implement a program using pipes where parent process accepts a string and passes it to child process. Need to be done with only single pipe. How does the pipe read & write accepts string.
Here is my sample code! all!
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
using namespace std;
int main()
{
int pid[2];
ssize_t fbytes;
pid_t childpid;
char str[20], rev[20];
char buf[20], red[20];
pipe(pid);
if ((childpid = fork()) == -1) {
perror("Fork");
return(1);
}
if (childpid == 0) {
// child process close the input side of the pipe
close(pid[0]);
int i = -1, j = 0;
while (str[++i] != '\0') {
while(i >= 0) {
rev[j++] = str[--i];
}
rev[j] = '\0';
}
// Send reversed string through the output side of pipe
write(pid[1], rev, sizeof(rev));
close(pid[0]);
return(0);
} else {
cout << "Enter a String: ";
cin.getline(str, 20);
// Parent process closing the output side of pipe.
close(pid[1]);
// reading the string from the pipe
fbytes = read(pid[0], buf, sizeof(buf));
cout << "Reversed string: " << buf;
close(pid[0]);
}
return 0;
}
You never pass the string to be reversed to the child, so it reverses some random garbage and sends it to the parent.
Minor issues:
write(pid[1], rev, sizeof(rev));
close(pid[0]); // Should be pid[1]
return(0); // Should be _exit(0)
The reason you don't want to return from main in the child is that you don't know what consequences that will have. You may call exit handlers that manipulate real world objects that the parent expects to remain intact.
I'm calling a LINUX command from within a C++ programme which creates the following output. I need to copy the first column of the output to a C++ variable (say a long int). How can I do it?? If that is not possible how can I copy this result into a .txt file with which I can work with?
Edit
0 +0
2361294848 +2361294848
2411626496 +50331648
2545844224 +134217728
2713616384 +167772160
I have this stored as a file, file.txt and I'm using the following code to
extract the left column with out the 0 to store it at integers
string stringy="";
int can_can=0;
for(i=begin;i<length;i++)
{
if (buffer[i]==' ' && can_can ==1) //**buffer** is the whole text file read in char*
{
num=atoi(stringy.c_str());
array[univ]=num; // This where I store the values.
univ+=1;
can_can=1;
}
else if (buffer[i]==' ' && can_can ==0)
{
stringy="";
}
else if (buffer[i]=='+')
{can_can=0;}
else{stringy.append(buffer[i]);}
}
I'm getting a segmentation error for this. What can be done ?
Thanks in advance.
Just create a simple streambuf wrapper around popen()
#include <iostream>
#include <stdio.h>
struct SimpleBuffer: public std::streambuf
{
typedef std::streambuf::traits_type traits;
typedef traits::int_type int_type;
SimpleBuffer(std::string const& command)
: stream(popen(command.c_str(), "r"))
{
this->setg(&c[0], &c[0], &c[0]);
this->setp(0, 0);
}
~SimpleBuffer()
{
if (stream != NULL)
{
fclose(stream);
}
}
virtual int_type underflow()
{
std::size_t size = fread(c, 1, 100, stream);
this->setg(&c[0], &c[0], &c[size]);
return size == 0 ? EOF : *c;
}
private:
FILE* stream;
char c[100];
};
Usage:
int main()
{
SimpleBuffer buffer("echo 55 hi there Loki");
std::istream command(&buffer);
int value;
command >> value;
std::string line;
std::getline(command, line);
std::cout << "Got int(" << value << ") String (" << line << ")\n";
}
Result:
> ./a.out
Got int(55) String ( hi there Loki)
It is popen you're probably looking for. Try
man popen
.
Or see this little example:
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
FILE *in;
char buff[512];
if(!(in = popen("my_script_from_command_line", "r"))){
return 1;
}
while(fgets(buff, sizeof(buff), in)!=NULL){
cout << buff; // here you have each line
// of the output of your script in buff
}
pclose(in);
return 0;
}
Unfortunately, it’s not easy since the platform API is written for C. The following is a simple working example:
#include <cstdio>
#include <iostream>
int main() {
char const* command = "ls -l";
FILE* fpipe = popen(command, "r");
if (not fpipe) {
std::cerr << "Unable to execute commmand\n";
return EXIT_FAILURE;
}
char buffer[256];
while (std::fgets(buffer, sizeof buffer, fpipe)) {
std::cout << buffer;
}
pclose(fpipe);
}
However, I’d suggest wrapping the FILE* handle in a RAII class to take care of resource management.
You probably want to use popen to execute the command. This will give you a FILE * that you can read its output from. From there, you can parse out the first number with (for example) something like:
fscanf(inpipe, "%d %*d", &first_num);
which, just like when reading from a file, you'll normally repeat until you receive an end of file indication, such as:
long total = 0;
while (1 == fscanf(inpipe, "%l %*d", &first_num))
total = first_num;
printf("%l\n", total);