Pakman
Command.cc
1 #include <string>
2 
3 #include <string.h>
4 #include <stdlib.h>
5 
6 #include <unistd.h>
7 
8 #include "utils.h"
9 
10 #include "Command.h"
11 
12 // Default constructor
13 Command::Command() : m_argv(nullptr)
14 {
15 }
16 
17 // Construct from string
18 Command::Command(const std::string& raw_command)
19  : m_raw_command(raw_command)
20 {
21  // Split raw command into tokens
22  m_cmd_tokens = parse_command_tokens(m_raw_command);
23 
24  // Allocate memory for argv
25  m_argv = new char*[m_cmd_tokens.size() + 1];
26 
27  // Copy command tokens to argv
28  copyCommandTokensToArgv();
29 }
30 
31 // Construct from c-style string
32 Command::Command(const char raw_command[]) :
33  Command(static_cast<std::string>(raw_command))
34 {
35 }
36 
37 // Copy constructor
38 Command::Command(const Command& command) :
39  m_raw_command(command.m_raw_command), m_cmd_tokens(command.m_cmd_tokens)
40 {
41  // Allocate memory for argv
42  m_argv = new char*[m_cmd_tokens.size() + 1];
43 
44  // Copy command tokens to argv
45  copyCommandTokensToArgv();
46 }
47 
48 // Move constructor
50  m_raw_command(std::move(command.m_raw_command)),
51  m_cmd_tokens(std::move(command.m_cmd_tokens))
52 {
53  // Move argv
54  m_argv = command.m_argv;
55  command.m_argv = nullptr;
56 }
57 
58 // Copy-assignment constructor
60 {
61  // Copy assign raw command
62  m_raw_command = command.m_raw_command;
63 
64  // Free argv if argv is not nullptr
65  if (m_argv != nullptr)
66  freeArgv();
67 
68  // Copy assign command tokens
69  m_cmd_tokens = command.m_cmd_tokens;
70 
71  // Allocate memory for argv
72  m_argv = new char*[m_cmd_tokens.size() + 1];
73 
74  // Copy command tokens to argv
75  copyCommandTokensToArgv();
76 
77  return *this;
78 }
79 
80 // Move-assignment constructor
82 {
83  if (this != &command)
84  {
85  // Move assign raw command
86  m_raw_command = std::move(command.m_raw_command);
87 
88  // Free argv if argv is not nullptr
89  if (m_argv != nullptr)
90  freeArgv();
91 
92  // Move assign command tokens
93  m_cmd_tokens = std::move(command.m_cmd_tokens);
94 
95  // Move argv
96  m_argv = command.m_argv;
97  command.m_argv = nullptr;
98  }
99  return *this;
100 }
101 
102 // Destructor
104 {
105  // Free argv if argv is not nullptr
106  if (m_argv != nullptr)
107  freeArgv();
108 }
109 
110 // Return command as string
111 const std::string& Command::str() const
112 {
113  return m_raw_command;
114 }
115 
116 // Return argv
117 char** Command::argv() const
118 {
119  return m_argv;
120 }
121 
122 // Copy command tokens to argv
123 void Command::copyCommandTokensToArgv()
124 {
125  // Loop over command tokens and copy to argv
126  for (int i = 0; i < m_cmd_tokens.size(); i++)
127  {
128  // Allocate memory for argv token
129  m_argv[i] = new char[m_cmd_tokens[i].size() + 1];
130 
131  // Copy to argv
132  strcpy(m_argv[i], m_cmd_tokens[i].c_str());
133  }
134 
135  // Last entry is null pointer
136  m_argv[m_cmd_tokens.size()] = nullptr;
137 }
138 
139 // Free argv
140 void Command::freeArgv()
141 {
142  // Loop over argv
143  for (int i = 0; i < m_cmd_tokens.size(); i++)
144  // Free argv token
145  delete[] m_argv[i];
146 
147  // Free argv and assign nullptr
148  delete[] m_argv;
149  m_argv = nullptr;
150 }
151 
152 
154 {
155  // Copy executable into file
156  std::string file = m_argv[0];
157 
158  // If file has forward slash, check if file exists and is executable with
159  // access
160  size_t found = file.find('/');
161  if (found != std::string::npos)
162  return (access(file.c_str(), F_OK | X_OK) == 0);
163 
164  // Else, we need to check PATH
165  char *path = getenv("PATH");
166  std::string path_str;
167 
168  // If PATH does not exist, assign confstr(_CS_PATH)
169  if (path == nullptr)
170  {
171  size_t pathlen = confstr(_CS_PATH, nullptr, 0);
172  path = (char *) malloc(pathlen * sizeof(char));
173  confstr(_CS_PATH, path, pathlen);
174  path_str.assign(":");
175  path_str += path;
176  free(path);
177  }
178  else
179  path_str.assign(path);
180 
181  // Iterate over element in PATH
182  size_t left = 0, right = 0;
183  do
184  {
185  left = right;
186 
187  // Find next occurrence of ':'
188  right = path_str.find(':', left);
189 
190  // From glibc/execvp.c: Two adjacent colons, or a colon at the
191  // beginning or the end of `PATH' means to search the current
192  // directory.
193  std::string cmd;
194  if (left == right)
195  cmd += file;
196  else
197  {
198  cmd += path_str.substr(left, right - left);
199  cmd += '/';
200  cmd += file;
201  }
202 
203  if (access(cmd.c_str(), F_OK | X_OK) == 0)
204  return true;
205 
206  } while (++right != 0);
207 
208  // Executable was not found
209  return false;
210 }
~Command()
Definition: Command.cc:103
bool isExecutable() const
Definition: Command.cc:153
const std::string & str() const
Definition: Command.cc:111
Command & operator=(const Command &command)
Definition: Command.cc:59
std::vector< std::string > parse_command_tokens(const std::string &raw_command)
Definition: utils.cc:18
Command()
Definition: Command.cc:13
char ** argv() const
Definition: Command.cc:117