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