StdAir Logo  0.45.0
C++ Standard Airline IT Object Library
readline_autocomp.hpp
Go to the documentation of this file.
00001 
00006 #ifndef __AIRINV_READLINE_AUTOCOMP_HPP
00007 #define __AIRINV_READLINE_AUTOCOMP_HPP
00008 
00009 // STL
00010 #include <string>
00011 #include <iosfwd>
00012 #include <cstdio>
00013 #include <sys/types.h>
00014 #include <sys/file.h>
00015 #include <sys/stat.h>
00016 #include <sys/errno.h>
00017 
00018 #include <readline/readline.h>
00019 #include <readline/history.h>
00020 
00021 extern char* getwd();
00022 extern char* xmalloc (size_t);
00023 
00024 /* The names of functions that actually do the manipulation. */
00025 int com_list (char*);
00026 int com_view (char*);
00027 int com_rename (char*);
00028 int com_stat (char*);
00029 int com_pwd (char*);
00030 int com_delete (char*);
00031 int com_help (char*);
00032 int com_cd (char*);
00033 int com_quit (char*);
00034 
00035 typedef int (*pt2Func) (char*);
00036 
00041 typedef struct {
00045   char const* name;
00046 
00050   pt2Func *func;
00051 
00055   char *doc;
00056 } COMMAND;
00057 
00058 COMMAND commands[] = {
00059   { "cd", (*com_cd)(), "Change to directory DIR" },
00060   { "delete", com_delete, "Delete FILE" },
00061   { "help", com_help, "Display this text" },
00062   { "?", com_help, "Synonym for `help'" },
00063   { "list", com_list, "List files in DIR" },
00064   { "ls", com_list, "Synonym for `list'" },
00065   { "pwd", com_pwd, "Print the current working directory" },
00066   { "quit", com_quit, "Quit using airinv" },
00067   { "rename", com_rename, "Rename FILE to NEWNAME" },
00068   { "stat", com_stat, "Print out statistics on FILE" },
00069   { "view", com_view, "View the contents of FILE" },
00070   { (char*) NULL, (pt2Func) NULL, (char*) NULL }
00071 };
00072 
00073 // Forward declarations
00074 char* stripwhite (char* iString);
00075 COMMAND* find_command (char* iString);
00076 
00080 int done;
00081 
00085 char* dupstr (char* iString) {
00086   char* r = xmalloc (std::strlen (iString) + 1);
00087   strcpy (r, iString);
00088   return r;
00089 }
00090 
00094 int execute_line (char* line) {
00095   register int i;
00096   COMMAND* command;
00097   char* word;
00098 
00099   /* Isolate the command word. */
00100   i = 0;
00101   while (line[i] && whitespace (line[i])) {
00102     i++;
00103   }
00104   word = line + i;
00105 
00106   while (line[i] && !whitespace (line[i])) {
00107     i++;
00108   }
00109   
00110   if (line[i]) {
00111     line[i++] = '\0';
00112   }
00113 
00114   command = find_command (word);
00115 
00116   if (!command) {
00117     std::cerr << word << ": No such command for airinv." << std::endl;
00118     return -1;
00119   }
00120 
00121   /* Get argument to command, if any. */
00122   while (whitespace (line[i])) {
00123     i++;
00124   }
00125 
00126   word = line + i;
00127 
00128   /* Call the function. */
00129   return (*(command->func)) (word);
00130 }
00131 
00136 COMMAND* find_command (char* name) {
00137   register int i;
00138 
00139   for (i = 0; commands[i].name; i++) {
00140     if (strcmp (name, commands[i].name) == 0) {
00141       return (&commands[i]);
00142     }
00143   }
00144 
00145   return (COMMAND*) NULL;
00146 }
00147 
00152 char* stripwhite (char* string) {
00153   register char *s, *t;
00154 
00155   for (s = string; whitespace (*s); s++) {
00156   }
00157     
00158   if (*s == 0) {
00159     return s;
00160   }
00161 
00162   t = s + strlen (s) - 1;
00163   while (t > s && whitespace (*t)) {
00164     t--;
00165   }
00166   *++t = '\0';
00167 
00168   return s;
00169 }
00170 
00171 /* **************************************************************** */
00172 /*                                                                  */
00173 /*                  Interface to Readline Completion                */
00174 /*                                                                  */
00175 /* **************************************************************** */
00176 
00177 char* command_generator (char* text, int state);
00178 char** fileman_completion (char* text, int start, int end);
00179 
00185 void initialize_readline() {
00186   /* Allow conditional parsing of the ~/.inputrc file. */
00187   rl_readline_name = "airinv";
00188 
00189   /* Tell the completer that we want a crack first. */
00190   rl_attempted_completion_function = (rl_completion_func_t*) fileman_completion;
00191 }
00192 
00200 char** fileman_completion (char* text, int start, int end) {
00201   char **matches;
00202 
00203   matches = (char**) NULL;
00204 
00210   if (start == 0) {
00211     matches = completion_matches (text, command_generator);
00212   }
00213 
00214   return matches;
00215 }
00216 
00222 char* command_generator (char* text, int state) {
00223   static int list_index, len;
00224   char* name;
00225 
00231   if (!state) {
00232     list_index = 0;
00233     len = strlen (text);
00234   }
00235 
00236   /* Return the next name which partially matches from the command list. */
00237   while (name = commands[list_index].name) {
00238     ++list_index;
00239 
00240     if (strncmp (name, text, len) == 0) {
00241       return dupstr (name);
00242     }
00243   }
00244 
00245   /* If no names matched, then return NULL. */
00246   return (char*) NULL;
00247 }
00248 
00249 /* **************************************************************** */
00250 /*                                                                  */
00251 /*                       airinv Commands                            */
00252 /*                                                                  */
00253 /* **************************************************************** */
00254 
00259 static char syscom[1024];
00260 
00264 void com_list (char* arg) {
00265   if (!arg) {
00266     arg = "";
00267   }
00268 
00269   std::ostringstream oStr;
00270   oStr << "ls -FClg " << arg;
00271   return system (oStr.c_str());
00272 }
00273 
00274 int com_view (char* arg) {
00275   if (!valid_argument ("view", arg)) {
00276     return 1;
00277   }
00278 
00279   std::ostringstream oStr;
00280   oStr << "more " << arg;
00281   return system (syscom);
00282 }
00283 
00284 int com_rename (char* arg) {
00285   too_dangerous ("rename");
00286   return 1;
00287 }
00288 
00289 int com_stat (char* arg) {
00290   struct stat finfo;
00291 
00292   if (!valid_argument ("stat", arg)) {
00293     return 1;
00294   }
00295 
00296   if (stat (arg, &finfo) == -1) {
00297     perror (arg);
00298     return 1;
00299   }
00300 
00301   std::cout << "Statistics for `" << arg << "':" << std::endl;
00302 
00303   const std::string lPluralEnd1 = (finfo.st_nlink == 1) ? "" : "s";
00304   const std::string lPluralEnd2 = (finfo.st_size == 1) ? "" : "s";
00305   std::cout << arg << " has "
00306             << finfo.st_nlink << " link" << lPluralEnd1 << ", and is "
00307             << finfo.st_size << " byte" << lPluralEnd2 << " in length."
00308             << std::endl;
00309   std::cout << " Inode Last Change at: " << ctime (&finfo.st_ctime) << std::endl;
00310   std::cout << " Last access at: " << ctime (&finfo.st_atime) << std::endl;
00311   std::cout << " Last modified at: " << ctime (&finfo.st_mtime) << std::endl;
00312   return 0;
00313 }
00314 
00315 int com_delete (char* arg) {
00316   too_dangerous ("delete");
00317   return 1;
00318 }
00319 
00324 int com_help (char* arg) {
00325   register int i;
00326   int printed = 0;
00327 
00328   for (i = 0; commands[i].name; i++) {
00329     if (!*arg || (strcmp (arg, commands[i].name) == 0)) {
00330       printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
00331       printed++;
00332     }
00333   }
00334 
00335   if (!printed) {
00336     printf ("No commands match `%s'.  Possibilties are:\n", arg);
00337 
00338     for (i = 0; commands[i].name; i++) {
00339       /* Print in six columns. */
00340       if (printed == 6) {
00341         printed = 0;
00342         printf ("\n");
00343       }
00344 
00345       printf ("%s\t", commands[i].name);
00346       printed++;
00347     }
00348 
00349     if (printed)
00350       printf ("\n");
00351   }
00352   return 0;
00353 }
00354 
00355 /* Change to the directory ARG. */
00356 int com_cd (char* arg) {
00357   if (chdir (arg) == -1) {
00358     perror (arg);
00359     return 1;
00360   }
00361 
00362   com_pwd ("");
00363   return 0;
00364 }
00365 
00366 /* Print out the current working directory. */
00367 int com_pwd (char* ignore) {
00368   char dir[1024], *s;
00369 
00370   s = getwd (dir);
00371   if (s == 0) {
00372     printf ("Error getting pwd: %s\n", dir);
00373     return 1;
00374   }
00375 
00376   printf ("Current directory is %s\n", dir);
00377   return 0;
00378 }
00379 
00380 /* The user wishes to quit using this program.  Just set DONE non-zero. */
00381 int com_quit (char* arg) {
00382   done = 1;
00383   return 0;
00384 }
00385 
00386 /* Function which tells you that you can't do this. */
00387 void too_dangerous (char* caller) {
00388   fprintf (stderr,
00389            "%s: Too dangerous for me to distribute.  Write it yourself.\n",
00390            caller);
00391 }
00392 
00393 /* Return non-zero if ARG is a valid argument for CALLER, else print
00394  *    an error message and return zero. */
00395 int valid_argument (char* caller, char* arg) {
00396   if (!arg || !*arg) {
00397     fprintf (stderr, "%s: Argument required.\n", caller);
00398     return 0;
00399   }
00400 
00401   return 1;
00402 }
00403 
00404 #endif // _AIRINV_READLINE_AUTOCOMP_HPP