0

I've built a simple Linux shell in c++. It can take in standard bash commands, redirect to a file, etc. But, what I want is for it to be able to take in input, for example, if I have a commands.txt file that contain

ls -l /
some_invalid_command
echo this displays stuff

and I pipe it into my a.out like so

$./a.out < commands.txt

I want it to run the commands inside as if I had typed them in. However, when I do that, I run into an infinite loop where the '$' prompt displays over and over until I hit ctrl+c. I'm pretty sure the cause is that I'm not checking for an end of file anywhere in my code.

So my question is, how would I go about checking for the end of file in this situation? I think the character is '^d' but I'm not sure how I'd check for that. Would something like this work?

if (inputString == "\^d") {
    exit = true;
}

I'm only concerned that perhaps I want to input more information into the shell after the file has ran. setting exit to true would tell the shell to turn off.

Edit: Requested code...

void Shell::getInput() {
        emptyQueue();
        cout << "$ ";
        getline(cin, inputString);
        fillQueue();
};

void Shell::fillQueue() {

        if (inputString.empty()) {
                return;
        };

        int i = inputString.find_first_not_of(" ");
        int j = inputString.find_last_not_of(" \r\n");
        int k;
        string stringToAdd;

        while (i != -1) {
                k = i;
                while (inputString.at(k) != ' ') {
                        if (k == j) {
                                break;
                        };
                        k++;
                };

                if (k != j) {
                        k--;
                };

                stringToAdd = inputString.substr(i, k - i + 1);
                i = inputString.find_first_not_of(" ", k + 1);

                commandQueue.push_back(stringToAdd);
        };

        i = 0;
        while (i < commandQueue.size()) {
                pointers[i] = commandQueue[i].c_str();
                i++;
        };
};
Zach Thompson
  • 39
  • 2
  • 14
  • Can you show how you are reading from the commands file? – Tony Ruth Feb 15 '16 at 00:17
  • 1
    I think your mistake is in assuming that `inputString` was actually read successfully (with `std::getline` I assume) where you actually need to check the stream for errors and terminate when that happens (stream closed). You do _not_ check for Ctrl-D. – paddy Feb 15 '16 at 00:19
  • I made an edit if that helps. – Zach Thompson Feb 15 '16 at 00:34
  • Maybe your string trimming function is failing somewhere because different line endings in the input file? You can try these: https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring/25385766#25385766 – Galik Feb 15 '16 at 01:06
  • That wasn't it, I found the answer I was looking for here: http://stackoverflow.com/questions/1428911/detecting-eof-in-c – Zach Thompson Feb 15 '16 at 01:22

3 Answers3

1

An end of file is not a character itself.

When you reach the end of the file, any attempt to read more characters returns with an indication that 0 characters were read.

You did not show your code in question, but you must be running a loop that reads the next line of text from standard input. Typically, you would have either an explicit check that the number of characters were read is 0, or if you were using a std::istream, the eof() method.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
1

If the file is opened in (default) text mode, the Ctrl+D is translated into end of file. So you just have to make sure that your looping until there's no input anymore, typically:

while ( getline(cin, inputString) ) {  // or while (cin>>inputString)
    ...
}
Christophe
  • 68,716
  • 7
  • 72
  • 138
1
void Shell::getInput() {
    emptyQueue();
    cout << "$ ";
    getline(cin, inputString);
    if(feof(stdin)) {
        exit = true;
        return;
    };
    fillQueue();
};
Alfred Huang
  • 17,654
  • 32
  • 118
  • 189
Zach Thompson
  • 39
  • 2
  • 14