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. */
10 #ifdef HAVE_SYS_FILE_H
11 # include <sys/file.h>
23 #if defined (HAVE_STRING_H)
25 #else /* !HAVE_STRING_H */
27 #endif /* !HAVE_STRING_H */
33 #ifdef READLINE_LIBRARY
34 # include "readline.h"
37 # include <readline/readline.h>
38 # include <readline/history.h>
41 extern char *xmalloc ();
43 /* The names of functions that actually do the manipulation. */
44 int com_list
__P((char *));
45 int com_view
__P((char *));
46 int com_rename
__P((char *));
47 int com_stat
__P((char *));
48 int com_pwd
__P((char *));
49 int com_delete
__P((char *));
50 int com_help
__P((char *));
51 int com_cd
__P((char *));
52 int com_quit
__P((char *));
54 /* A structure which contains information on the commands this program
58 char *name
; /* User printable name of the function. */
59 rl_icpfunc_t
*func
; /* Function to call to do the job. */
60 char *doc
; /* Documentation for this function. */
63 COMMAND commands
[] = {
64 { "cd", com_cd
, "Change to directory DIR" },
65 { "delete", com_delete
, "Delete FILE" },
66 { "help", com_help
, "Display this text" },
67 { "?", com_help
, "Synonym for `help'" },
68 { "list", com_list
, "List files in DIR" },
69 { "ls", com_list
, "Synonym for `list'" },
70 { "pwd", com_pwd
, "Print the current working directory" },
71 { "quit", com_quit
, "Quit using Fileman" },
72 { "rename", com_rename
, "Rename FILE to NEWNAME" },
73 { "stat", com_stat
, "Print out statistics on FILE" },
74 { "view", com_view
, "View the contents of FILE" },
75 { (char *)NULL
, (rl_icpfunc_t
*)NULL
, (char *)NULL
}
78 /* Forward declarations. */
80 COMMAND
*find_command ();
82 /* The name of this program, as taken from argv[0]. */
85 /* When non-zero, this global means the user is done using this program. */
94 r
= xmalloc (strlen (s
) + 1);
107 initialize_readline (); /* Bind our completer. */
109 /* Loop reading and executing lines until the user quits. */
112 line
= readline ("FileMan: ");
117 /* Remove leading and trailing whitespace from the line.
118 Then, if there is anything left, add it to the history list
120 s
= stripwhite (line
);
133 /* Execute a command line. */
142 /* Isolate the command word. */
144 while (line
[i
] && whitespace (line
[i
]))
148 while (line
[i
] && !whitespace (line
[i
]))
154 command
= find_command (word
);
158 fprintf (stderr
, "%s: No such command for FileMan.\n", word
);
162 /* Get argument to command, if any. */
163 while (whitespace (line
[i
]))
168 /* Call the function. */
169 return ((*(command
->func
)) (word
));
172 /* Look up NAME as the name of a command, and return a pointer to that
173 command. Return a NULL pointer if NAME isn't a command name. */
180 for (i
= 0; commands
[i
].name
; i
++)
181 if (strcmp (name
, commands
[i
].name
) == 0)
182 return (&commands
[i
]);
184 return ((COMMAND
*)NULL
);
187 /* Strip whitespace from the start and end of STRING. Return a pointer
193 register char *s
, *t
;
195 for (s
= string
; whitespace (*s
); s
++)
201 t
= s
+ strlen (s
) - 1;
202 while (t
> s
&& whitespace (*t
))
209 /* **************************************************************** */
211 /* Interface to Readline Completion */
213 /* **************************************************************** */
215 char *command_generator
__P((const char *, int));
216 char **fileman_completion
__P((const char *, int, int));
218 /* Tell the GNU Readline library how to complete. We want to try to complete
219 on command names if this is the first word in the line, or on filenames
221 initialize_readline ()
223 /* Allow conditional parsing of the ~/.inputrc file. */
224 rl_readline_name
= "FileMan";
226 /* Tell the completer that we want a crack first. */
227 rl_attempted_completion_function
= fileman_completion
;
230 /* Attempt to complete on the contents of TEXT. START and END bound the
231 region of rl_line_buffer that contains the word to complete. TEXT is
232 the word to complete. We can use the entire contents of rl_line_buffer
233 in case we want to do some simple parsing. Return the array of matches,
234 or NULL if there aren't any. */
236 fileman_completion (text
, start
, end
)
242 matches
= (char **)NULL
;
244 /* If this word is at the start of the line, then it is a command
245 to complete. Otherwise it is the name of a file in the current
248 matches
= rl_completion_matches (text
, command_generator
);
253 /* Generator function for command completion. STATE lets us know whether
254 to start from scratch; without any state (i.e. STATE == 0), then we
255 start at the top of the list. */
257 command_generator (text
, state
)
261 static int list_index
, len
;
264 /* If this is a new word to complete, initialize now. This includes
265 saving the length of TEXT for efficiency, and initializing the index
273 /* Return the next name which partially matches from the command list. */
274 while (name
= commands
[list_index
].name
)
278 if (strncmp (name
, text
, len
) == 0)
279 return (dupstr(name
));
282 /* If no names matched, then return NULL. */
283 return ((char *)NULL
);
286 /* **************************************************************** */
288 /* FileMan Commands */
290 /* **************************************************************** */
292 /* String to pass to system (). This is for the LIST, VIEW and RENAME
294 static char syscom
[1024];
296 /* List the file(s) named in arg. */
303 sprintf (syscom
, "ls -FClg %s", arg
);
304 return (system (syscom
));
310 if (!valid_argument ("view", arg
))
313 #if defined (__MSDOS__)
314 /* more.com doesn't grok slashes in pathnames */
315 sprintf (syscom
, "less %s", arg
);
317 sprintf (syscom
, "more %s", arg
);
319 return (system (syscom
));
325 too_dangerous ("rename");
334 if (!valid_argument ("stat", arg
))
337 if (stat (arg
, &finfo
) == -1)
343 printf ("Statistics for `%s':\n", arg
);
345 printf ("%s has %d link%s, and is %d byte%s in length.\n",
348 (finfo
.st_nlink
== 1) ? "" : "s",
350 (finfo
.st_size
== 1) ? "" : "s");
351 printf ("Inode Last Change at: %s", ctime (&finfo
.st_ctime
));
352 printf (" Last access at: %s", ctime (&finfo
.st_atime
));
353 printf (" Last modified at: %s", ctime (&finfo
.st_mtime
));
360 too_dangerous ("delete");
364 /* Print out help for ARG, or for all of the commands if ARG is
372 for (i
= 0; commands
[i
].name
; i
++)
374 if (!*arg
|| (strcmp (arg
, commands
[i
].name
) == 0))
376 printf ("%s\t\t%s.\n", commands
[i
].name
, commands
[i
].doc
);
383 printf ("No commands match `%s'. Possibilties are:\n", arg
);
385 for (i
= 0; commands
[i
].name
; i
++)
387 /* Print in six columns. */
394 printf ("%s\t", commands
[i
].name
);
404 /* Change to the directory ARG. */
408 if (chdir (arg
) == -1)
418 /* Print out the current working directory. */
424 s
= getcwd (dir
, sizeof(dir
) - 1);
427 printf ("Error getting pwd: %s\n", dir
);
431 printf ("Current directory is %s\n", dir
);
435 /* The user wishes to quit using this program. Just set DONE non-zero. */
443 /* Function which tells you that you can't do this. */
444 too_dangerous (caller
)
448 "%s: Too dangerous for me to distribute. Write it yourself.\n",
452 /* Return non-zero if ARG is a valid argument for CALLER, else print
453 an error message and return zero. */
455 valid_argument (caller
, arg
)
460 fprintf (stderr
, "%s: Argument required.\n", caller
);