-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCommandPreprocessor.cpp
143 lines (113 loc) · 3.43 KB
/
CommandPreprocessor.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
* CommandPreprocessor.cpp
*
* Created on: Nov 21, 2016
* Author: paul
*/
#include "CommandPreprocessor.h"
#include "iash.h"
#include "UserCommand.h"
#include "tools/Token.h"
#include "tools/Tokenizer.h"
#include <fstream>
#include <sstream>
using namespace std;
CommandPreprocessor::CommandPreprocessor(iash *parent) : m_parent(parent) {}
CommandPreprocessor::~CommandPreprocessor()
{
cleanup();
}
void CommandPreprocessor::cleanup ()
{
m_allCommands.clear();
for (ios* stream : m_dynamicStreams) delete stream;
m_dynamicStreams.clear();
}
const vector<UserCommand>& CommandPreprocessor::process(const string& raw)
{
istream *stdinCand;
ostream *stdoutCand;
stringstream *pipeStream = nullptr;
const Token *commandToken = nullptr;
//Clear the previous set of commands and dynamic streams
cleanup();
//Tokenize individual command calls
Tokenizer parse (raw, ";|");
vector<Token> cmds = parse.getTokens();
//Now tokenize for input/output from/to files
parse.setDelims("<>");
for (Token &cmdToken : cmds)
{
parse.setSource(cmdToken.getToken());
//Set default stdin and stdout for the command
stdinCand = pipeStream == nullptr ? &cin : pipeStream;
stdoutCand = &cout;
//If the pipe stream is stdout, clear the pipeStream pointer
if (stdinCand == pipeStream) pipeStream = nullptr;
//If the user is performing a pipe, create a pipe stream and make it
//stdin
if (cmdToken.getFollowingDelimiter() == '|')
{
pipeStream = new stringstream (ios::in | ios::out);
m_dynamicStreams.push_back(pipeStream);
stdoutCand = pipeStream;
}
for (const Token &ioToken : parse.getTokens())
{
//If the token is the command call
if (ioToken.getPrecedingDelimiter() == '\0') commandToken = &ioToken;
//If the token is an input stream pathspec
else if (ioToken.getPrecedingDelimiter() == '<')
{
if (ioToken.isToken(' ') && stdinCand == &cin)
{
string fname = (Token (ioToken)).finalize();
if (*(fname.begin()) != '/')
{
const Directory &cwd = *(m_parent->getCwd());
fname = cwd.resolvePath(fname);
}
if (Directory::isFile(fname.c_str()))
{
stdinCand = new ifstream(fname.c_str());
m_dynamicStreams.push_back(stdinCand);
}
else throw FileNotFoundException (fname);
}
else if (stdinCand != &cin)
throw SyntaxException("Input stream already specified");
else throw SyntaxException("Unexpected ' ' in pathspec");
}
//If the token is an output stream pathspec
else if (ioToken.getPrecedingDelimiter() == '>')
{
if (ioToken.isToken(' ') && stdoutCand == &cout)
{
string fname = (Token(ioToken)).finalize();
if (*(fname.begin()) != '/')
{
const Directory &cwd = *(m_parent->getCwd());
fname = cwd.resolvePath(fname);
}
if (Directory::isFile(fname.c_str()))
{
stdoutCand = new ofstream(fname.c_str());
m_dynamicStreams.push_back(stdoutCand);
}
else throw FileNotFoundException(fname);
}
else if (stdoutCand != &cout)
throw SyntaxException("Output stream already specified");
else throw SyntaxException("Unexpected ' ' in pathspec");
}
}
m_allCommands.push_back(UserCommand(*commandToken, *stdinCand, *stdoutCand));
}
return m_allCommands;
}
const vector<UserCommand>& CommandPreprocessor::getCommands () const
{
return m_allCommands;
}
SyntaxException::SyntaxException (const string &reason)
: runtime_error("syntax error: " + reason) {}