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