StdAir Logo  1.00.0
C++ Standard Airline IT Object Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
readline_autocomp.hpp
Go to the documentation of this file.
1 
6 #ifndef __AIRINV_READLINE_AUTOCOMP_HPP
7 #define __AIRINV_READLINE_AUTOCOMP_HPP
8 
9 // STL
10 #include <string>
11 #include <iosfwd>
12 #include <cstdio>
13 #include <sys/types.h>
14 #include <sys/file.h>
15 #include <sys/stat.h>
16 #include <sys/errno.h>
17 
18 #include <readline/readline.h>
19 #include <readline/history.h>
20 
21 extern char* getwd();
22 extern char* xmalloc (size_t);
23 
24 /* The names of functions that actually do the manipulation. */
25 int com_list (char*);
26 int com_view (char*);
27 int com_rename (char*);
28 int com_stat (char*);
29 int com_pwd (char*);
30 int com_delete (char*);
31 int com_help (char*);
32 int com_cd (char*);
33 int com_quit (char*);
34 
35 typedef int (*pt2Func) (char*);
36 
41 typedef struct {
45  char const* name;
46 
51 
55  char *doc;
56 } COMMAND;
57 
59  { "cd", (*com_cd)(), "Change to directory DIR" },
60  { "delete", com_delete, "Delete FILE" },
61  { "help", com_help, "Display this text" },
62  { "?", com_help, "Synonym for `help'" },
63  { "list", com_list, "List files in DIR" },
64  { "ls", com_list, "Synonym for `list'" },
65  { "pwd", com_pwd, "Print the current working directory" },
66  { "quit", com_quit, "Quit using airinv" },
67  { "rename", com_rename, "Rename FILE to NEWNAME" },
68  { "stat", com_stat, "Print out statistics on FILE" },
69  { "view", com_view, "View the contents of FILE" },
70  { (char*) NULL, (pt2Func) NULL, (char*) NULL }
71 };
72 
73 // Forward declarations
74 char* stripwhite (char* iString);
75 COMMAND* find_command (char* iString);
76 
80 int done;
81 
85 char* dupstr (char* iString) {
86  char* r = xmalloc (std::strlen (iString) + 1);
87  strcpy (r, iString);
88  return r;
89 }
90 
94 int execute_line (char* line) {
95  register int i;
96  COMMAND* command;
97  char* word;
98 
99  /* Isolate the command word. */
100  i = 0;
101  while (line[i] && whitespace (line[i])) {
102  i++;
103  }
104  word = line + i;
105 
106  while (line[i] && !whitespace (line[i])) {
107  i++;
108  }
109 
110  if (line[i]) {
111  line[i++] = '\0';
112  }
113 
114  command = find_command (word);
115 
116  if (!command) {
117  std::cerr << word << ": No such command for airinv." << std::endl;
118  return -1;
119  }
120 
121  /* Get argument to command, if any. */
122  while (whitespace (line[i])) {
123  i++;
124  }
125 
126  word = line + i;
127 
128  /* Call the function. */
129  return (*(command->func)) (word);
130 }
131 
136 COMMAND* find_command (char* name) {
137  register int i;
138 
139  for (i = 0; commands[i].name; i++) {
140  if (strcmp (name, commands[i].name) == 0) {
141  return (&commands[i]);
142  }
143  }
144 
145  return (COMMAND*) NULL;
146 }
147 
152 char* stripwhite (char* string) {
153  register char *s, *t;
154 
155  for (s = string; whitespace (*s); s++) {
156  }
157 
158  if (*s == 0) {
159  return s;
160  }
161 
162  t = s + strlen (s) - 1;
163  while (t > s && whitespace (*t)) {
164  t--;
165  }
166  *++t = '\0';
167 
168  return s;
169 }
170 
171 /* **************************************************************** */
172 /* */
173 /* Interface to Readline Completion */
174 /* */
175 /* **************************************************************** */
176 
177 char* command_generator (char* text, int state);
178 char** fileman_completion (char* text, int start, int end);
179 
186  /* Allow conditional parsing of the ~/.inputrc file. */
187  rl_readline_name = "airinv";
188 
189  /* Tell the completer that we want a crack first. */
190  rl_attempted_completion_function = (rl_completion_func_t*) fileman_completion;
191 }
192 
200 char** fileman_completion (char* text, int start, int end) {
201  char **matches;
202 
203  matches = (char**) NULL;
204 
210  if (start == 0) {
211  matches = completion_matches (text, command_generator);
212  }
213 
214  return matches;
215 }
216 
222 char* command_generator (char* text, int state) {
223  static int list_index, len;
224  char* name;
225 
231  if (!state) {
232  list_index = 0;
233  len = strlen (text);
234  }
235 
236  /* Return the next name which partially matches from the command list. */
237  while (name = commands[list_index].name) {
238  ++list_index;
239 
240  if (strncmp (name, text, len) == 0) {
241  return dupstr (name);
242  }
243  }
244 
245  /* If no names matched, then return NULL. */
246  return (char*) NULL;
247 }
248 
249 /* **************************************************************** */
250 /* */
251 /* airinv Commands */
252 /* */
253 /* **************************************************************** */
254 
259 static char syscom[1024];
260 
264 void com_list (char* arg) {
265  if (!arg) {
266  arg = "";
267  }
268 
269  std::ostringstream oStr;
270  oStr << "ls -FClg " << arg;
271  return system (oStr.c_str());
272 }
273 
274 int com_view (char* arg) {
275  if (!valid_argument ("view", arg)) {
276  return 1;
277  }
278 
279  std::ostringstream oStr;
280  oStr << "more " << arg;
281  return system (syscom);
282 }
283 
284 int com_rename (char* arg) {
285  too_dangerous ("rename");
286  return 1;
287 }
288 
289 int com_stat (char* arg) {
290  struct stat finfo;
291 
292  if (!valid_argument ("stat", arg)) {
293  return 1;
294  }
295 
296  if (stat (arg, &finfo) == -1) {
297  perror (arg);
298  return 1;
299  }
300 
301  std::cout << "Statistics for `" << arg << "':" << std::endl;
302 
303  const std::string lPluralEnd1 = (finfo.st_nlink == 1) ? "" : "s";
304  const std::string lPluralEnd2 = (finfo.st_size == 1) ? "" : "s";
305  std::cout << arg << " has "
306  << finfo.st_nlink << " link" << lPluralEnd1 << ", and is "
307  << finfo.st_size << " byte" << lPluralEnd2 << " in length."
308  << std::endl;
309  std::cout << " Inode Last Change at: " << ctime (&finfo.st_ctime) << std::endl;
310  std::cout << " Last access at: " << ctime (&finfo.st_atime) << std::endl;
311  std::cout << " Last modified at: " << ctime (&finfo.st_mtime) << std::endl;
312  return 0;
313 }
314 
315 int com_delete (char* arg) {
316  too_dangerous ("delete");
317  return 1;
318 }
319 
324 int com_help (char* arg) {
325  register int i;
326  int printed = 0;
327 
328  for (i = 0; commands[i].name; i++) {
329  if (!*arg || (strcmp (arg, commands[i].name) == 0)) {
330  printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
331  printed++;
332  }
333  }
334 
335  if (!printed) {
336  printf ("No commands match `%s'. Possibilties are:\n", arg);
337 
338  for (i = 0; commands[i].name; i++) {
339  /* Print in six columns. */
340  if (printed == 6) {
341  printed = 0;
342  printf ("\n");
343  }
344 
345  printf ("%s\t", commands[i].name);
346  printed++;
347  }
348 
349  if (printed)
350  printf ("\n");
351  }
352  return 0;
353 }
354 
355 /* Change to the directory ARG. */
356 int com_cd (char* arg) {
357  if (chdir (arg) == -1) {
358  perror (arg);
359  return 1;
360  }
361 
362  com_pwd ("");
363  return 0;
364 }
365 
366 /* Print out the current working directory. */
367 int com_pwd (char* ignore) {
368  char dir[1024], *s;
369 
370  s = getwd (dir);
371  if (s == 0) {
372  printf ("Error getting pwd: %s\n", dir);
373  return 1;
374  }
375 
376  printf ("Current directory is %s\n", dir);
377  return 0;
378 }
379 
380 /* The user wishes to quit using this program. Just set DONE non-zero. */
381 int com_quit (char* arg) {
382  done = 1;
383  return 0;
384 }
385 
386 /* Function which tells you that you can't do this. */
387 void too_dangerous (char* caller) {
388  fprintf (stderr,
389  "%s: Too dangerous for me to distribute. Write it yourself.\n",
390  caller);
391 }
392 
393 /* Return non-zero if ARG is a valid argument for CALLER, else print
394  * an error message and return zero. */
395 int valid_argument (char* caller, char* arg) {
396  if (!arg || !*arg) {
397  fprintf (stderr, "%s: Argument required.\n", caller);
398  return 0;
399  }
400 
401  return 1;
402 }
403 
404 #endif // _AIRINV_READLINE_AUTOCOMP_HPP