Make a program work with input and a file - c++

I am making a shell interpreter which works only with keyboard input, but I have to make it work with a text files.
int main(int argc, char *argv[], char *envp[]) {
string comando;
mi_argv[0] = NULL;
int pid_aux;
el_prompt = "$> ";
if(argv[1] != NULL)
{
ifstream input(argv[1]);
if (!input)
{
cerr << "No se reconoce el archivo " << argv[1] << endl;
exit(EXIT_FAILURE);
}
}
while(!cin.eof())
{
cout << el_prompt;
getline(cin, comando);
...
}
}
The point is to make this work with a file like argument ./shell file.txt. I tried to redirect the file to cin, but I don't know how to do it.

Put the code reading from the input stream in a separate function, and pass a reference to the input stream to the function. Then you can pass any input stream to the function, a file you have opened or std::cin.
Like e.g.
void main_loop(std::istream& input)
{
// Use `input` here like any other input stream
}
Now you can call the function either with standard input
main_loop(std::cin);
or your file
main_loop(input);
Also, be careful with that loop condition, doing while (!stream.eof()) will in most cases not work as expected. The reason being that the eofbit flag is not set until after you try to read from beyond the end of the stream, and will lead to the loop being run one extra time.
Instead do e.g. while (std::getline(...)).

Something like this.
#include <string>
#include <iostream>
#include <fstream>
void usage() {
std::cout << "Usage: shell <filename>\n";
}
int main(int argc, char* argv[]) {
std::string comando;
std::string el_prompt = "$> ";
if (argc != 2) {
usage();
exit(1);
}
std::ifstream input(argv[1]);
while (std::getline(input, comando)) {
std::cout << el_prompt << comando;
}
}
You would need code of course to parse the command and execute it.

Related

Sending text file name from command line c++

I want to run my code and send my file in 2 ways
myprogram < input.txt or cat input.txt | myprogram
myprogram input.txt
I have figured out the secong way using argc and argv[] but I am not able to figure out how to write the code for the first option.
int main (int argc, char *argv[])
{
ifstream fin;
if(argc > 1){
fin.open (argv[1]);
}
else
}
As mentioned above in the comment, a portable way is passing either the open file or std::cin as an istream reference to a function and doing your input there. In that case either the file or std::cin may be passed. E.g.
#include <iostream>
#include <fstream>
#include <string>
void readinfo (std::istream& in)
{
std::string s;
while (in >> s)
std::cout << s << '\n';
}
int main (int argc, char **argv) {
if (argc > 1) { /* read from file if given as argument */
std::ifstream fin (argv[1]);
if (fin.is_open())
readinfo (fin);
else {
std::cerr << "error: file open failed.\n";
return 1;
}
}
else { /* read from stdin */
readinfo (std::cin);
}
return 0;
}
A non-portable Linux only option reading from /dev/stdin if no file is given simply requires a ternary operator, e.g.
std::ifstream fin (argc > 1 ? argv[1] : "/dev/stdin");
if (!fin.is_open()) {
std::cerr << "error: file open failed.\n";
return 1;
}
/* read from fin here */
Neither are completely elegant, but both support (subject to the OS constraint)
myprogram < input.txt
or
myprogram input.txt
You want to read from stdin, and for that there's 2 options:
std::cin
fread() and other C-style IO
std::cin >> https://en.cppreference.com/w/cpp/io/cin has the advantage of reading formatted text into some binary representation https://en.cppreference.com/w/cpp/io/basic_istream/operator_gtgt
C-style IO https://en.cppreference.com/w/cpp/io/c has the advantage of reading binary data well.
It depends on what you want to do with it your input

How to read from an input stream into a file stream?

I am trying to bind input stream with a file stream , I hope that input something from input stream and then automatic flush to the file stream
It does not work...I enter something from keyboard , outfile is still empty
#include <iostream>
#include <fstream>
#include <stdexcept>
using namespace std;
int main(int argc, char const *argv[])
{
ofstream outfile("outfile" , ofstream::app | ofstream::out);
if(!outfile)
throw runtime_error("Open the file error");
ostream * old_tie = cin.tie();//get old tie
cin.tie(0);//unbind from old tie
cin.tie(&outfile);//bind new ostream
string temp;
while(cin >> temp)
{
if(temp == ".")//stop input
break;
}
cin.tie(0);
cin.tie(old_tie);// recovery old tie
return 0;
}
Your program is too complicated and is misusing tie(). Try the following:
#include <iostream>
#include <fstream>
int main() {
using namespace std;
ofstream outfile("outfile" , ofstream::app | ofstream::out);
if(!outfile) {
cerr << "Open the file error";
return 1;
}
char data(0);
while(data != '.') {
cin.get(data);
cin.clear(); // Prevents EOF errors;
outfile << data;
}
return 0;
}
It reads char by char until it finds a .
Errors:
why make throw exception if you don't catch it...
close file please
do you put data from file to temp and go through it to find "." and
end program?
Why do you use pointer for old_tie use it for the first ofstream file
like this ofstream * file.
fix if statement and break
include string library -- //This might solve your problem
what is filename??
is tie(0) function to unbind?
//EDIT
Explanation:
once you find first period with find_first_of function you create a substr and copy it into outfile. The Solution is so efficent and works every time. The logic is as simple as it can get. Don't use unnecessary functions and initialize unnecessary variables because it is more complex and more prone to errors when you have too many variables.
Solution: - No need for cin.tie()
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char const *argv[])
{
ofstream outfile("outfile" , ofstream::app | ofstream::out);
string s;
getline(cin, s);
int i = s.find_first_of(".");
if(i!=std::string::npos)
{
s = s.substr(0, i);
outfile << s;
}
else
{
cout << "No periods found" << endl;
}
}
Compiled code - http://ideone.com/ooj1ej
If this needs explanation please ask questions in comments below.

Text file I/O with fstream and ifstream

#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main(int argc, char *argv[])
{
ifstream is;
is.open(argv[1]);
ofstream outfile;
outfile.open(argv[2]);
char ch;
while (1)
{
ch = is.get(); // this is where test.txt is supposed
outfile.put(ch); // to be copied to test2.txt
if (is.eof())
break;
cout << ch; //this shows
}
is.close();
outfile.close();
ifstream outfile2;
outfile2.open(argv[2]);
char ch2;
while (1)
{
ch2 = outfile2.get();
if (outfile2.eof())
break;
cout << ch2; //this doesnt
}
outfile2.close();
system("PAUSE");
return 0;
}
I run it through cmd giving it 2 arguments test.txt test2.txt and it outputs what i have written in test.txt in cmd but test2.txt remains empty for some reason?
Please check the streamstate not just for eof() but also for failure. Also, after reading the last character, it wouldn't be uncommon if the streamstate was EOF even though the character was successfully read. Therefore, always try to read an element and if it succeeded, and only then, use the element:
ifstream in(argv[1]);
ofstream out(argv[2]);
char c;
while(in.get(c))
out.put(c);
To make this really efficient, use this though:
out << in.rdbuf();
In any case, check the streamstate for success:
if(!in.eof())
throw std::runtime_error("failed to read input file");
if(!out.flush())
throw std::runtime_error("failed to write output file");
for me its not coming blank but with some extra appended characters. this is because you are writing the character which you got from the old file to the new one before checking eof().
the code for writing from one file to another should be changed as
while (1)
{
ch = is.get();
if (is.eof())
break;
outfile.put(ch);
cout << ch; //this shows
}

File Input in C++

I've been searching the internet for a while, but all I can find for file input in C++ is when you know the filename.
I'm trying to write a program to perform an addition of 2 numbers that are greater than 0 from a file, but without using scanf or cin. I want to load the file into memory, but all of the code I can find in regards to this situation requires knowledge of the filename. The file is formatted with 2 integers on a single line, separated by a space, and there are multiple lines of integers. The program will output the sum of the two numbers. I can easily do this with scanf, but if I were given a massive file, I would want to load it into memory (save mapping for later).
Loading the file into memory is giving me trouble, because I do not know the filename, nor how to find out, unless the user inputs the name of the file (not going to happen). I want the program to be executed like so, but using the most raw, and basic forms of C++ IO:
./myprog < boatloadofnumbers
How would I start my program to take the whole "boatloadofnumbers" as a file, so I can use more basic functions like read()? (also, what is the above method called? passing input?)
int main(){
int a,b;
while (scanf("%i,%i",&a,&b)>-1){
printf("%i\n",(a+b));
} //endwhile
return 0;
} //endmain
When the program is called as you state, then the content of boatloadofnumbers can be read from std::cin.
This method is called input redirection and is done by the shell, not your program.
Wiht input redirection the shell usually buffers the content of the file. That's a quite fast way to stream a file a single time through a computation.
It's not entirely clear how you're going to read a file when you don't know the filename. Presumably you don't know the filename at compile-time. That's okay, you can get this from the command-line at runtime, like this:
./myprog boatloadofnumbers
Then your filename is in argv[1] and you can access it using a std::ifstream.
If you're being given the input directly on stdin via redirection (such as ./myprog < boatloadofnumbers) you don't need a filename at all, you can just use std::cin.
The following main() will deal with both of these situations:
int main(int argc, char* argv[])
{
if (argc == 2)
{
std::cerr << "Reading from file" << argv[1] << std::endl;
std::ifstream ifs(argv[1]);
if (ifs)
{
sum_lines(ifs);
}
else
{
std::cerr << "Could not read from " << argv[1] << std::endl;
}
}
else
{
std::cerr << "Reading from stdin" << std::endl;
sum_lines(std::cin);
}
}
A sample sum_lines() may look a bit like this:
void sum_lines(std::istream& is)
{
int first = 0, second = 0;
std::string line = "";
while (std::getline(is, line))
{
std::istringstream iss(line);
if (is >> first >> second)
{
std::cout << first << " + " << second << " = " << first + second << std::endl;
}
else
{
std::cerr << "Could not parse [" << line << "]" << std::endl;
}
}
}
This doesn't care from where the input comes, so you can easily inject a std::istringstream for unit-testing. Also, this doesn't read the whole file into memory, just one line at a time, so it should deal with averybigboatloadofnumbers.
With shell redirection, your program can read from the standard input, which may be desirable. However, it may also be desirable to read from a file. It's easy to support both:
cat data > ./prog
./prog < data
./prog -f data
The first two are similar, and the contents of the file data are available from the program's standard input; the third line simply passes a command-line argument. Here's how we support this:
#include <cstdio>
#include <cstring>
void process_input(std::FILE * fp)
{
char buf[4];
std::fread(buf, 4, 1, fp);
// ...
}
int main(int argc, char * argv[])
{
std::FILE * fp = stdin; // already open!
if (argc >= 3 && 0 == std::strcmp(argv[1]. "-f"))
{
fp = std::fopen(argv[2], "rb");
if (!fp)
{
std::fprintf(stderr, "Could not open file %s.\n", argv[2]);
return 1;
}
}
process_input(fp);
if (fp != stdin) { std::fclose(fp); }
}
Equivalently, you can achieve something similar with iostreams, though it's a bit more roundabout to have a nice, universal reference:
#include <fstream>
int main()
{
std::ifstream ifp;
if ( /* as before */ )
{
ifp.open(argv[2], std::ios::binary);
if (!ifp) { /* error and die */ }
}
std::ifstream & infile = ifp ? ifp : std::cin;
process_input(infile);
}

ifstream does not work in loop

I just started programming using C++. I face some problem during execution of ifstream in loop.
do
{
system("cls");
inFile.open ("Account_Details.txt");
while (!inFile.eof())
{
getline (inFile, line);
cout << line << endl;
}
inFile.close();
cin.ignore(100, '\n');
cin >> choice;
}
while (choice != '1' && choice != '2');
This is part of my code. When the loop run, it doesnt show data in the txt file.
Thanks for any help. ^^
add infile.clear() after the infile.close() - the eof bits are not cleared by the close
There is a chance that the file doesn't exist. If that's the case, it will create an empty file. Check the path of the file.
I have been writing C++ code for close to 10 years. During that time I have learnt how to use C++ in a way that minimizes the number of errors (bugs) I create. Probably some will disagree with me, but I would recommend you to only use for and while to do looping. Never do-while. Learn these two well and you will be able to loop successfully any time you want.
To illustrate my technique, I have taken the liberty to rewrite your code using my style. It has complete error checking, uses a while loop with read-ahead, some C++0x, and simplified stream handling:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
int main(int argc, char** argv)
{
// check program arguments
if (argc<2) {
std::cerr << "Usage: " << argv[0] << " file" << std::endl;
return EXIT_FAILURE;
}
// check file can be opened
std::ifstream infile(argv[1]);
if (!infile) {
std::cerr << "Failed to read " << argv[1] << std::endl;
return EXIT_FAILURE;
}
std::string input;
// read-ahead
std::getline(std::cin, input);
while (input!="q" && input!="quit" && input!="exit") {
//system("cls");
// print contents of file by streaming its read buffer
std::cout << infile.rdbuf();
// read file again
infile = std::ifstream(argv[1]);
// finally, read again to match read-ahead
std::getline(std::cin, input);
}
}
Save to main.cpp, compile to print.exe and run with print.exe main.cpp.
Good luck with learning C++!