Reputation: 540
I am learning C++ [Java background fwiw] and trying to write a UNIX shell as a project. I am running into a funny little problem with tokenizing the input for execution. The tok function is getting called twice and I'm not sure why. My current test code is the following:
#include <iostream>
#include <vector>
#include <sstream>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
using namespace std;
void tok(string, char**);
int main(){
const char* EXIT = "exit";
string input;
cout << "shell>> ";
getline(cin, input);
pid_t pid = fork();
char* args[64]; //arbitrary size, 64 possible whitespace-delimited tokens in command
tok(input, args);
return 0;
}
//copied from http://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
void tok(string inStr, char** args){
int last = 0, next = 0, i = 0;
while( (next = inStr.find(' ', last)) != -1){
cout << i++ << ": " << inStr.substr(last, next-last) << endl;
*args++ = strdup(inStr.substr(last, next-last).c_str());
last = next + 1;
}
cout << i++ << ": " << inStr.substr(last) << endl;
*args++ = strdup(inStr.substr(last).c_str());
*args = '\0';
cout << "done tokenizing..." << endl;
}
My output when I actually run the program is:
$ ./a.out
shell>> ls -l
0: ls
1: -l
done tokenizing...
0: ls
1: -l
done tokenizing...
I'm not sure why it would do that. Can anyone guide me in the right direction please? Thank you
Upvotes: 1
Views: 2611
Reputation: 41120
When you call fork
, you create two processes. Each process has nearly the exact same state except for the respective pid_t
you receive. If that value is greater than 0, then you are in the parent process (main), and otherwise you are in the child (or fork failed).
Without performing a check on the returned pid_t
, both processes will call tok
, resulting in the double call behavior you witnessed.
Hide the call behind a check on pid
like so:
pid_t pid = fork();
if (pid > 0) // have parent process call tok
{
char* args[64]; //arbitrary size, 64 possible whitespace-delimited tokens in command
tok(input, args);
}
To see what else parent and child processes have in common (or not): check the docs
Upvotes: 1
Reputation: 379
following code may work fine
#include <iostream>
#include <vector>
#include <sstream>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
using namespace std;
void tok(string, char**);
int main(){
const char* EXIT = "exit";
string input;
cout << "shell>> ";
getline(cin, input);
// pid_t pid = fork();
char* args[64];
tok(input, args);
return 0;
}
void tok(string inStr, char** args){
int last = 0, next = 0, i = 0;
while( (next = inStr.find(' ', last)) != -1){
cout << i++ << ": " << inStr.substr(last, next-last) << endl;
*args++ = strdup(inStr.substr(last, next-last).c_str());
last = next + 1;
}
cout << i++ << ": " << inStr.substr(last) << endl;
*args++ = strdup(inStr.substr(last).c_str());
*args = '\0';
cout << "done tokenizing..." << endl;
}
Upvotes: 1
Reputation: 182819
The fork
function returns twice, once in the original process and once in the newly-created, forked process. Both of those processes then call tok
.
There doesn't seem to be any clear reason why you called fork
. So the fix may be as simple as eliminating the call to fork
.
Upvotes: 9