]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/libreadline/examples/fileman.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / libreadline / examples / fileman.c
1 /* Copyright (C) 1987-2002 Free Software Foundation, Inc.
2
3    This file is part of the GNU Readline Library, a library for
4    reading lines of text with interactive input and history editing.
5
6    The GNU Readline Library is free software; you can redistribute it
7    and/or modify it under the terms of the GNU General Public License
8    as published by the Free Software Foundation; either version 2, or
9    (at your option) any later version.
10
11    The GNU Readline Library is distributed in the hope that it will be
12    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    The GNU General Public License is often shipped with GNU software, and
17    is generally kept in a file called COPYING or LICENSE.  If you do not
18    have a copy of the license, write to the Free Software Foundation,
19    59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21 /* fileman.c -- A tiny application which demonstrates how to use the
22    GNU Readline library.  This application interactively allows users
23    to manipulate files and their modes. */
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_FILE_H
31 #  include <sys/file.h>
32 #endif
33 #include <sys/stat.h>
34
35 #ifdef HAVE_UNISTD_H
36 #  include <unistd.h>
37 #endif
38
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <errno.h>
42
43 #if defined (HAVE_STRING_H)
44 #  include <string.h>
45 #else /* !HAVE_STRING_H */
46 #  include <strings.h>
47 #endif /* !HAVE_STRING_H */
48
49 #ifdef HAVE_STDLIB_H
50 #  include <stdlib.h>
51 #endif
52
53 #ifdef READLINE_LIBRARY
54 #  include "readline.h"
55 #  include "history.h"
56 #else
57 #  include <readline/readline.h>
58 #  include <readline/history.h>
59 #endif
60
61 extern char *xmalloc ();
62
63 /* The names of functions that actually do the manipulation. */
64 int com_list PARAMS((char *));
65 int com_view PARAMS((char *));
66 int com_rename PARAMS((char *));
67 int com_stat PARAMS((char *));
68 int com_pwd PARAMS((char *));
69 int com_delete PARAMS((char *));
70 int com_help PARAMS((char *));
71 int com_cd PARAMS((char *));
72 int com_quit PARAMS((char *));
73
74 /* A structure which contains information on the commands this program
75    can understand. */
76
77 typedef struct {
78   char *name;                   /* User printable name of the function. */
79   rl_icpfunc_t *func;           /* Function to call to do the job. */
80   char *doc;                    /* Documentation for this function.  */
81 } COMMAND;
82
83 COMMAND commands[] = {
84   { "cd", com_cd, "Change to directory DIR" },
85   { "delete", com_delete, "Delete FILE" },
86   { "help", com_help, "Display this text" },
87   { "?", com_help, "Synonym for `help'" },
88   { "list", com_list, "List files in DIR" },
89   { "ls", com_list, "Synonym for `list'" },
90   { "pwd", com_pwd, "Print the current working directory" },
91   { "quit", com_quit, "Quit using Fileman" },
92   { "rename", com_rename, "Rename FILE to NEWNAME" },
93   { "stat", com_stat, "Print out statistics on FILE" },
94   { "view", com_view, "View the contents of FILE" },
95   { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL }
96 };
97
98 /* Forward declarations. */
99 char *stripwhite ();
100 COMMAND *find_command ();
101
102 /* The name of this program, as taken from argv[0]. */
103 char *progname;
104
105 /* When non-zero, this global means the user is done using this program. */
106 int done;
107
108 char *
109 dupstr (s)
110      char *s;
111 {
112   char *r;
113
114   r = xmalloc (strlen (s) + 1);
115   strcpy (r, s);
116   return (r);
117 }
118
119 main (argc, argv)
120      int argc;
121      char **argv;
122 {
123   char *line, *s;
124
125   progname = argv[0];
126
127   initialize_readline ();       /* Bind our completer. */
128
129   /* Loop reading and executing lines until the user quits. */
130   for ( ; done == 0; )
131     {
132       line = readline ("FileMan: ");
133
134       if (!line)
135         break;
136
137       /* Remove leading and trailing whitespace from the line.
138          Then, if there is anything left, add it to the history list
139          and execute it. */
140       s = stripwhite (line);
141
142       if (*s)
143         {
144           add_history (s);
145           execute_line (s);
146         }
147
148       free (line);
149     }
150   exit (0);
151 }
152
153 /* Execute a command line. */
154 int
155 execute_line (line)
156      char *line;
157 {
158   register int i;
159   COMMAND *command;
160   char *word;
161
162   /* Isolate the command word. */
163   i = 0;
164   while (line[i] && whitespace (line[i]))
165     i++;
166   word = line + i;
167
168   while (line[i] && !whitespace (line[i]))
169     i++;
170
171   if (line[i])
172     line[i++] = '\0';
173
174   command = find_command (word);
175
176   if (!command)
177     {
178       fprintf (stderr, "%s: No such command for FileMan.\n", word);
179       return (-1);
180     }
181
182   /* Get argument to command, if any. */
183   while (whitespace (line[i]))
184     i++;
185
186   word = line + i;
187
188   /* Call the function. */
189   return ((*(command->func)) (word));
190 }
191
192 /* Look up NAME as the name of a command, and return a pointer to that
193    command.  Return a NULL pointer if NAME isn't a command name. */
194 COMMAND *
195 find_command (name)
196      char *name;
197 {
198   register int i;
199
200   for (i = 0; commands[i].name; i++)
201     if (strcmp (name, commands[i].name) == 0)
202       return (&commands[i]);
203
204   return ((COMMAND *)NULL);
205 }
206
207 /* Strip whitespace from the start and end of STRING.  Return a pointer
208    into STRING. */
209 char *
210 stripwhite (string)
211      char *string;
212 {
213   register char *s, *t;
214
215   for (s = string; whitespace (*s); s++)
216     ;
217     
218   if (*s == 0)
219     return (s);
220
221   t = s + strlen (s) - 1;
222   while (t > s && whitespace (*t))
223     t--;
224   *++t = '\0';
225
226   return s;
227 }
228
229 /* **************************************************************** */
230 /*                                                                  */
231 /*                  Interface to Readline Completion                */
232 /*                                                                  */
233 /* **************************************************************** */
234
235 char *command_generator PARAMS((const char *, int));
236 char **fileman_completion PARAMS((const char *, int, int));
237
238 /* Tell the GNU Readline library how to complete.  We want to try to complete
239    on command names if this is the first word in the line, or on filenames
240    if not. */
241 initialize_readline ()
242 {
243   /* Allow conditional parsing of the ~/.inputrc file. */
244   rl_readline_name = "FileMan";
245
246   /* Tell the completer that we want a crack first. */
247   rl_attempted_completion_function = fileman_completion;
248 }
249
250 /* Attempt to complete on the contents of TEXT.  START and END bound the
251    region of rl_line_buffer that contains the word to complete.  TEXT is
252    the word to complete.  We can use the entire contents of rl_line_buffer
253    in case we want to do some simple parsing.  Return the array of matches,
254    or NULL if there aren't any. */
255 char **
256 fileman_completion (text, start, end)
257      const char *text;
258      int start, end;
259 {
260   char **matches;
261
262   matches = (char **)NULL;
263
264   /* If this word is at the start of the line, then it is a command
265      to complete.  Otherwise it is the name of a file in the current
266      directory. */
267   if (start == 0)
268     matches = rl_completion_matches (text, command_generator);
269
270   return (matches);
271 }
272
273 /* Generator function for command completion.  STATE lets us know whether
274    to start from scratch; without any state (i.e. STATE == 0), then we
275    start at the top of the list. */
276 char *
277 command_generator (text, state)
278      const char *text;
279      int state;
280 {
281   static int list_index, len;
282   char *name;
283
284   /* If this is a new word to complete, initialize now.  This includes
285      saving the length of TEXT for efficiency, and initializing the index
286      variable to 0. */
287   if (!state)
288     {
289       list_index = 0;
290       len = strlen (text);
291     }
292
293   /* Return the next name which partially matches from the command list. */
294   while (name = commands[list_index].name)
295     {
296       list_index++;
297
298       if (strncmp (name, text, len) == 0)
299         return (dupstr(name));
300     }
301
302   /* If no names matched, then return NULL. */
303   return ((char *)NULL);
304 }
305
306 /* **************************************************************** */
307 /*                                                                  */
308 /*                       FileMan Commands                           */
309 /*                                                                  */
310 /* **************************************************************** */
311
312 /* String to pass to system ().  This is for the LIST, VIEW and RENAME
313    commands. */
314 static char syscom[1024];
315
316 /* List the file(s) named in arg. */
317 com_list (arg)
318      char *arg;
319 {
320   if (!arg)
321     arg = "";
322
323   sprintf (syscom, "ls -FClg %s", arg);
324   return (system (syscom));
325 }
326
327 com_view (arg)
328      char *arg;
329 {
330   if (!valid_argument ("view", arg))
331     return 1;
332
333 #if defined (__MSDOS__)
334   /* more.com doesn't grok slashes in pathnames */
335   sprintf (syscom, "less %s", arg);
336 #else
337   sprintf (syscom, "more %s", arg);
338 #endif
339   return (system (syscom));
340 }
341
342 com_rename (arg)
343      char *arg;
344 {
345   too_dangerous ("rename");
346   return (1);
347 }
348
349 com_stat (arg)
350      char *arg;
351 {
352   struct stat finfo;
353
354   if (!valid_argument ("stat", arg))
355     return (1);
356
357   if (stat (arg, &finfo) == -1)
358     {
359       perror (arg);
360       return (1);
361     }
362
363   printf ("Statistics for `%s':\n", arg);
364
365   printf ("%s has %d link%s, and is %d byte%s in length.\n",
366           arg,
367           finfo.st_nlink,
368           (finfo.st_nlink == 1) ? "" : "s",
369           finfo.st_size,
370           (finfo.st_size == 1) ? "" : "s");
371   printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime));
372   printf ("      Last access at: %s", ctime (&finfo.st_atime));
373   printf ("    Last modified at: %s", ctime (&finfo.st_mtime));
374   return (0);
375 }
376
377 com_delete (arg)
378      char *arg;
379 {
380   too_dangerous ("delete");
381   return (1);
382 }
383
384 /* Print out help for ARG, or for all of the commands if ARG is
385    not present. */
386 com_help (arg)
387      char *arg;
388 {
389   register int i;
390   int printed = 0;
391
392   for (i = 0; commands[i].name; i++)
393     {
394       if (!*arg || (strcmp (arg, commands[i].name) == 0))
395         {
396           printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
397           printed++;
398         }
399     }
400
401   if (!printed)
402     {
403       printf ("No commands match `%s'.  Possibilties are:\n", arg);
404
405       for (i = 0; commands[i].name; i++)
406         {
407           /* Print in six columns. */
408           if (printed == 6)
409             {
410               printed = 0;
411               printf ("\n");
412             }
413
414           printf ("%s\t", commands[i].name);
415           printed++;
416         }
417
418       if (printed)
419         printf ("\n");
420     }
421   return (0);
422 }
423
424 /* Change to the directory ARG. */
425 com_cd (arg)
426      char *arg;
427 {
428   if (chdir (arg) == -1)
429     {
430       perror (arg);
431       return 1;
432     }
433
434   com_pwd ("");
435   return (0);
436 }
437
438 /* Print out the current working directory. */
439 com_pwd (ignore)
440      char *ignore;
441 {
442   char dir[1024], *s;
443
444   s = getcwd (dir, sizeof(dir) - 1);
445   if (s == 0)
446     {
447       printf ("Error getting pwd: %s\n", dir);
448       return 1;
449     }
450
451   printf ("Current directory is %s\n", dir);
452   return 0;
453 }
454
455 /* The user wishes to quit using this program.  Just set DONE non-zero. */
456 com_quit (arg)
457      char *arg;
458 {
459   done = 1;
460   return (0);
461 }
462
463 /* Function which tells you that you can't do this. */
464 too_dangerous (caller)
465      char *caller;
466 {
467   fprintf (stderr,
468            "%s: Too dangerous for me to distribute.  Write it yourself.\n",
469            caller);
470 }
471
472 /* Return non-zero if ARG is a valid argument for CALLER, else print
473    an error message and return zero. */
474 int
475 valid_argument (caller, arg)
476      char *caller, *arg;
477 {
478   if (!arg || !*arg)
479     {
480       fprintf (stderr, "%s: Argument required.\n", caller);
481       return (0);
482     }
483
484   return (1);
485 }