Using the filename generated from mkstemp - c++

The mkstemp() function generates a unique temporary filename from template, creates and opens the file, and returns an open file descriptor for the file. The last six characters of template must be "XXXXXX" and these are replaced with a string that makes the filename unique. Since it will be modified, template must not be a string constant, but should be declared as a character array.
After template is replaced with a string that makes the filename unique, I save the string to later use. This is where I'm encountering a strange problem I can't seem to wrap my head around. I can print the correct filename to my terminal, see the file in my file explorer and open it to see the correct contents, but when I include the string as part of a command to execute with popen() I get a pointer to an empty file. When I hard code the names of the tempory files back into my code however and run again, I get the correct result I am expecting. Is there something I'm overlooking or missing? Here is a code snippet:
char tmpname[] = "tmp.XXXXXX";
FILE *fpt = fdopen(mkstemp(tmpname), "w");
string saved_tmpname(tmpname);
// blah
// write to file
// blah blah
const string command = "mycommand " + saved_tmpname;
cout << command << endl; // prints correctly
FILE *fpipe = popen(command.c_str(), "r");
if (fpipe == NULL) {
perror(command.c_str());
}
char buff[4096];
while (fgets(buff, 4096, fpipe)) {
// we don't get here!
}

From the manpage for mkstemp:
The file is opened with the open(2) O_EXCL flag, guaranteeing that the caller is the process that creates the file.
The O_EXCL flag prevents you from opening the file again. This is OK, since it is a temporary file - only one process (the creator) should have access to it. Temporary files contain sensitive data sometimes.

Related

C++ input redirection causing error while file arguments work

When I specify an input file as a file argument, like so:
./asm ex1_in
everything works as it should!
However, when I specify an input file using redirection, like so:
./asm < ex1_in
the program throws the error it is supposed to throw when the input file is corrupt or doesn't exist.
This is the part of the code that handles input and file arguments:
int main(int argc, char * argv []) {
ifstream InFile(argv[1], ios::in);
if (!(InFile.is_open())) { /* check file */
fprintf (stderr, "The input file cannot be open or cannot be read. \n");
return 2;
}
if (InFile.is_open()) {
//some stuff
InFile.close();
}
//other stuff
}
I would like to be able to keep using ifstream, as it is very helpful for the rest of the program.
Also, the program is supposed to accept input directly on stdin if no file argument is supplied. Currently, if no file arguments are supplied, it throws the same error, instead of looking for user input.
EDIT: I added a line in main to try to see what's going on, and it looks like when input redirection is used, the program doesn't see argv[1] or anything after it.
cout << argv[0] << " " << argv[1] << " " << argv[2];
prints out only ./asm.
When input redirection isn't used, it prints out:
./asm ex1_in my1_out
You are trying to open argv[1] as a file every time you run the program.
In the first case, argv has a lenght of two (the executable name and the filename) so it opens and does what it needs to do normally, but when you run it redirecting the file to the stdin, argv just contains the executable name, and since argv[1] is a C-style string, it will read everything until it finds a null byte, then pass whatever it read to the std::ifstream constructor, failing each time.
You should use argc to know the number of arguments passed, and use either the file or stdin depending on the number of arguments.

C++ remove empty lines from cin and save to same file

A part of my assignment is to make a program that reads a file that is passed from command line like this: inputfile.cpp | ./pg_rmv_empty_lines.
This (I guess) is for that reason that later on I can pipe(?) the same file to multiple programs.
I know I can read lines in that file with:
int main()
{
string line;
while(getline(cin, line))
{
cout << line << endl;
}
return 0;
}
What I need to do, is to remove all empty lines in the file that the program receives, remove those lines and then save the modified file.
I don't know the name of the file that needs modification, it's passed from the command line by "client"
Filename should stay the same after the modifications.
This is confusing me because every example I find, people suggests something that includes hardcoding filename into the source code like outfile.open("movieList.txt",ios_base::app);. In my case I don't know the name of the input file.
Bear in mind that I'm using C++ first time and it's already making me lose my faith in humanity.
To get the filename you need to parse command line arguments. Once you've done that, examples you referred to will work to read the lines from the file. Assuming file isn't big, you can read it into the memory, skipping the empty lines using if statement.
Once you've read the file into memory, you should either close it and re-open for writing or reset to the beginning and write the buffer out.
If the file is large and couldn't be read into the memory buffer, you only can pull this out by doing one line (or limited number of lines) at a time and save the results into a temporary file with a different name. After that you'd have to delete the old file and rename the new file. Of course, the other way (first rename original file and then save new one with the old name) works as well.
Getting the filename from the command line is easy.
#include <iostream>
#include <fstream>
#include <string> // Because why not.
int main(int argc, char** argv) {
if (argc != 2) {
return -1; // Indicates error
}
std::string filename = argv[1];
std::ifstream input(filename);
// Do your stuff...
return 0;
}
No more hints :-)
Are you sure that the requirement is to use the pipe command? I think what you want is to use command line arguments. Maybe this article here helps:
http://www.cplusplus.com/articles/DEN36Up4/
You can define your main function as:
int main(int argc, char* argv[])
{
...
}
and then argc is the amount of commandline arguments were given and argv is the arguments. The first argument is always the name of your program. So if you execute myprogram.exe ./pg_rmv_empty_lines, argv[0] would be myprogram.exe and argv[1] would be ./pg_rmv_empty_lines
You can then use this to dynamically read from that file in your code but you first need to open the file. For example something along the lines of:
std::ifstream myFile;
std::string lineAsString;
myFile.open(argv[1]);
std::getline(myFile, lineAsString);
... do things with the line
myFile.close();

Error in opening an output stream

In my code I'm opening an output stream and appending the data to the end of the file .. if there is no such file the stream should create one but the problem that it does not.
here is the code snippet:
char output_file[100];
strcpy(output_file, predicate.c_str());
ofstream output_file_ptr1;
output_file_ptr1.open(output_file,ios::out | ios::app | ios::binary );
if(output_file_ptr1.is_open()){
output_file_ptr1 << subject <<" " << object <<"\n";
output_file_ptr1.close();
}
else{
printf("Error opening out file \n");
return -1;
}
subject, object and predicate are variable strings that I created earlier.
Any idea it does not create the file?
+ it is very important for me that the data is appended to the end of the file.
Update:
predicate is the exact file name that I need , but it is not a usual naming i.e
< http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
is an example
A value such as <w3.org/1999/02/22-rdf-syntax-ns#type> is not a valid file name in most environments. Unix-style operating systems (e.g. Linux) do not support "/" inside the file name (unless the directory structure matches).

editing a file using cpp code without creating a new file

Is it possible to edit text in a file using cpp code. Already there is related question on it, but it doesn't solve my problem. Kindly help me out.
I have given a rough code line on this.
seek() through the file and try to replace the contents with new string from that point till the end of line.
I need the "hello" string be placed and must be the end of line.
like if we have new.txt as
ABCDEFGHIJKLMNOPQRST
If I want the file content to be changed as
ABCDEHELLO
I am getting the file content as
ABCDHELLOJKLMNOPQRST
fstream file("new.txt",fstream::in|fstream::out);
file.open();
while(getline(file,str))
{
if(value==strstr())
{
file.seekp(pos);
str.erase(pos,len);//len specifies the value till end of str
str.replace(pos,6,"hello");
char *d=new char[str.length()+1];
strcpy(d,str.c_str());
file.write(d,strlen(d));
delete [] d;
}
}
If I could copy the file contents to the string, manipulate it, then copy to the new file then it is possible.
Is it possible to change the contents in the same file. If so kindly help me out, I am struck in this. If the replacing string is longer than the one actually existing then this works, but if the replacing string is smaller than the one which is actually existing then I am unable to do.
if you case is only one line in the file you can easily separate the I/O process in two stages. Read the file and get the position of the text. then close the file and reopened as out then write the string you want. Note that this will work if you have one line in the file
check the following code
std::string value = "GFGHHFGHH";
std::string str;
std::fstream file("new.txt", std::ios::in);
std::size_t found;
while (file >> str)
{
found = str.find(value);
if (found != std::string::npos)
{
str.erase(value.length() );
str.replace(found, 6, "hello");
}
}
file.close();
file.open("new.txt", std::ios::out);
file << str;
file.close();
You can do it using system call for sed:
string s="sed -i s/hey/ho/g file0102.txt";
system(s.c_str());

Reading and writing to files isn't working in C++

I am basically trying to reverse the contents of a text file. When I run this code, nothing happens. Code:
getArguments();
stringstream ss;
ss << argument;
string fileName;
ss >> fileName;
fstream fileToReverse(fileName);
if (fileToReverse.is_open()) {
send(sock, "[*] Contents is being written to string ... ", strlen("\n[*] Contents is being written to string ... "), 0);
string line;
string contentsOfFile;
while (getline(fileToReverse, line)) {
contentsOfFile.append(line);
line = "\0";
}
send(sock, "done\n[*] File is being reversed ... ", strlen("done\n[*] File is being reversed ... "), 0);
string reversedText(contentsOfFile.length(), ' ');
int i;
int j;
for(i=0,j=contentsOfFile.length()-1;i<contentsOfFile.length();i++,j--) {
reversedText[i] = contentsOfFile[j];
}
contentsOfFile = "\0";
fileToReverse << reversedText;
fileToReverse.close();
send(sock, "done\n", strlen("done\n"), 0);
}
fileName is created from user input, and I know that the file exists. It just doesn't do anything to the file. If anyone has any ideas that they would like to share that would be great.
UPDATE:
I now can write reversedText to the file but how can I delete all of the files contents?
In this particular case, when you have read all the input content, your file is in an "error state" (eof and fail bits set in the status).
You need to clear that with fileToReverse.clear();. Your file position will also be at the end of the file, so you need to use fileToReverse.seekp(0, ios_base::beg) to set the position to the beginning.
But I, just as g-makulik, prefer to have two files, one for input and one for output. Saves a large amount of messing about.
When you need to debug something like this - saying "all the functions are being run and all the variables are being created, and it compiled without any warnings" isn't really debugging.
Debugging - this doesn't work. Remove bits until you find what doesn't work. Like you said - all variables are what you expect them. So... try and see if, for example, the way you read and write from a file works. Just write a small program that opens a file like you open it, reads from it like you do and then writes... whatever back into it in the same way you do. See if that works.
In other words, try and find the smallest program that reproduces what you see.