1 /* fileman.c -- A tiny application which demonstrates how to use the
2 GNU Readline library. This application interactively allows users
3 to manipulate files and their modes.
5 NOTE: this was taken from the GNU Readline documentation and ported
6 to libedit. A commad to output the history list was added.
11 #include <sys/types.h>
14 #include <sys/errno.h>
23 #include <readline/readline.h>
24 #include <readline/history.h>
26 #include <editline/readline.h>
28 void * xmalloc (size_t size);
29 void too_dangerous (char *caller);
30 void initialize_readline ();
31 int execute_line (char *line);
32 int valid_argument (char *caller, char *arg);
34 typedef int rl_icpfunc_t (char *);
36 /* The names of functions that actually do the manipulation. */
37 int com_list (char *);
38 int com_view (char *);
39 int com_history (char *);
40 int com_rename(char *);
43 int com_delete(char *);
48 /* A structure which contains information on the commands this program
52 char *name; /* User printable name of the function. */
53 rl_icpfunc_t *func; /* Function to call to do the job. */
54 char *doc; /* Documentation for this function. */
57 COMMAND commands[] = {
58 { "cd", com_cd, "Change to directory DIR" },
59 { "delete", com_delete, "Delete FILE" },
60 { "help", com_help, "Display this text" },
61 { "?", com_help, "Synonym for `help'" },
62 { "list", com_list, "List files in DIR" },
63 { "ls", com_list, "Synonym for `list'" },
64 { "pwd", com_pwd, "Print the current working directory" },
65 { "quit", com_quit, "Quit using Fileman" },
66 { "rename", com_rename, "Rename FILE to NEWNAME" },
67 { "stat", com_stat, "Print out statistics on FILE" },
68 { "view", com_view, "View the contents of FILE" },
69 { "history", com_history, "List editline history" },
70 { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL }
73 /* Forward declarations. */
75 COMMAND *find_command ();
77 /* The name of this program, as taken from argv[0]. */
80 /* When non-zero, this means the user is done using this program. */
88 r = xmalloc (strlen (s) + 1);
94 main (int argc, char **argv)
100 setlocale(LC_CTYPE, "");
102 initialize_readline(); /* Bind our completer. */
106 /* Loop reading and executing lines until the user quits. */
109 line = readline ("FileMan: ");
114 /* Remove leading and trailing whitespace from the line.
115 Then, if there is anything left, add it to the history list
117 s = stripwhite(line);
124 result = history_expand(s, &expansion);
126 if (result < 0 || result == 2) {
127 fprintf(stderr, "%s\n", expansion);
129 add_history(expansion);
130 execute_line(expansion);
142 /* Execute a command line. */
144 execute_line (char *line)
150 /* Isolate the command word. */
152 while (line[i] && isspace (line[i]))
156 while (line[i] && !isspace (line[i]))
162 command = find_command (word);
166 fprintf (stderr, "%s: No such command for FileMan.\n", word);
170 /* Get argument to command, if any. */
171 while (isspace (line[i]))
176 /* Call the function. */
177 return ((*(command->func)) (word));
180 /* Look up NAME as the name of a command, and return a pointer to that
181 command. Return a NULL pointer if NAME isn't a command name. */
183 find_command (char *name)
187 for (i = 0; commands[i].name; i++)
188 if (strcmp (name, commands[i].name) == 0)
189 return (&commands[i]);
191 return ((COMMAND *)NULL);
194 /* Strip whitespace from the start and end of STRING. Return a pointer
197 stripwhite (char *string)
199 register char *s, *t;
201 for (s = string; isspace (*s); s++)
207 t = s + strlen (s) - 1;
208 while (t > s && isspace (*t))
215 /* **************************************************************** */
217 /* Interface to Readline Completion */
219 /* **************************************************************** */
221 char *command_generator(const char *, int);
222 char **fileman_completion(const char *, int, int);
224 /* Tell the GNU Readline library how to complete. We want to try to
225 complete on command names if this is the first word in the line, or
226 on filenames if not. */
228 initialize_readline ()
230 /* Allow conditional parsing of the ~/.inputrc file. */
231 rl_readline_name = "FileMan";
233 /* Tell the completer that we want a crack first. */
234 rl_attempted_completion_function = fileman_completion;
237 /* Attempt to complete on the contents of TEXT. START and END
238 bound the region of rl_line_buffer that contains the word to
239 complete. TEXT is the word to complete. We can use the entire
240 contents of rl_line_buffer in case we want to do some simple
241 parsing. Returnthe array of matches, or NULL if there aren't any. */
243 fileman_completion (const char* text, int start, int end)
247 matches = (char **)NULL;
249 /* If this word is at the start of the line, then it is a command
250 to complete. Otherwise it is the name of a file in the current
254 matches = completion_matches (text, command_generator);
255 /* matches = rl_completion_matches (text, command_generator); */
260 /* Generator function for command completion. STATE lets us
261 know whether to start from scratch; without any state
262 (i.e. STATE == 0), then we start at the top of the list. */
264 command_generator (text, state)
268 static int list_index, len;
271 /* If this is a new word to complete, initialize now. This
272 includes saving the length of TEXT for efficiency, and
273 initializing the index variable to 0. */
280 /* Return the next name which partially matches from the
282 while (name = commands[list_index].name)
286 if (strncmp (name, text, len) == 0)
287 return (dupstr(name));
290 /* If no names matched, then return NULL. */
291 return ((char *)NULL);
294 /* **************************************************************** */
296 /* FileMan Commands */
298 /* **************************************************************** */
300 /* String to pass to system (). This is for the LIST, VIEW and RENAME
302 static char syscom[1024];
304 /* List the file(s) named in arg. */
311 sprintf (syscom, "ls -FClg %s", arg);
312 return (system (syscom));
318 if (!valid_argument ("view", arg))
321 sprintf (syscom, "more %s", arg);
322 return (system (syscom));
326 com_history(char* arg)
331 while (next_history())
334 for (he = current_history(); he != NULL; he = previous_history()) {
335 //printf("%5d %s\n", *((int*)he->data) - 1, he->line);
336 printf("%s\n", he->line);
343 com_rename (char *arg)
345 too_dangerous ("rename");
354 if (!valid_argument ("stat", arg))
357 if (stat (arg, &finfo) == -1)
363 printf ("Statistics for `%s':\n", arg);
365 printf ("%s has %ld link%s, and is %lld byte%s in length.\n", arg,
366 (long) finfo.st_nlink,
367 (finfo.st_nlink == 1) ? "" : "s",
368 (long long) finfo.st_size,
369 (finfo.st_size == 1) ? "" : "s");
370 printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime));
371 printf (" Last access at: %s", ctime (&finfo.st_atime));
372 printf (" Last modified at: %s", ctime (&finfo.st_mtime));
377 com_delete (char *arg)
379 too_dangerous ("delete");
383 /* Print out help for ARG, or for all of the commands if ARG is
391 for (i = 0; commands[i].name; i++)
393 if (!*arg || (strcmp (arg, commands[i].name) == 0))
395 printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
402 printf ("No commands match `%s'. Possibilties are:\n", arg);
404 for (i = 0; commands[i].name; i++)
406 /* Print in six columns. */
413 printf ("%s\t", commands[i].name);
423 /* Change to the directory ARG. */
427 if (chdir (arg) == -1)
437 /* Print out the current working directory. */
439 com_pwd (char* ignore)
443 s = (char*)getcwd(dir, sizeof(dir) - 1);
446 printf ("Error getting pwd: %s\n", dir);
450 printf ("Current directory is %s\n", dir);
454 /* The user wishes to quit using this program. Just set DONE
463 /* Function which tells you that you can't do this. */
465 too_dangerous (char *caller)
468 "%s: Too dangerous for me to distribute.\n",
470 fprintf (stderr, "Write it yourself.\n");
473 /* Return non-zero if ARG is a valid argument for CALLER,
474 else print an error message and return zero. */
476 valid_argument (char *caller, char *arg)
480 fprintf (stderr, "%s: Argument required.\n", caller);
488 xmalloc (size_t size)
490 register void *value = (void*)malloc(size);
492 fprintf(stderr, "virtual memory exhausted");