]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/examples/fileman.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/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 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <sys/types.h>
10 #ifdef HAVE_SYS_FILE_H
11 # include <sys/file.h>
12 #endif
13 #include <sys/stat.h>
14
15 #ifdef HAVE_UNISTD_H
16 # include <unistd.h>
17 #endif
18
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <errno.h>
22
23 #if defined (HAVE_STRING_H)
24 # include <string.h>
25 #else /* !HAVE_STRING_H */
26 # include <strings.h>
27 #endif /* !HAVE_STRING_H */
28
29 #ifdef HAVE_STDLIB_H
30 # include <stdlib.h>
31 #endif
32
33 #ifdef READLINE_LIBRARY
34 # include "readline.h"
35 # include "history.h"
36 #else
37 # include <readline/readline.h>
38 # include <readline/history.h>
39 #endif
40
41 extern char *xmalloc ();
42
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 *));
53
54 /* A structure which contains information on the commands this program
55 can understand. */
56
57 typedef struct {
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. */
61 } COMMAND;
62
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 }
76 };
77
78 /* Forward declarations. */
79 char *stripwhite ();
80 COMMAND *find_command ();
81
82 /* The name of this program, as taken from argv[0]. */
83 char *progname;
84
85 /* When non-zero, this global means the user is done using this program. */
86 int done;
87
88 char *
89 dupstr (s)
90 char *s;
91 {
92 char *r;
93
94 r = xmalloc (strlen (s) + 1);
95 strcpy (r, s);
96 return (r);
97 }
98
99 main (argc, argv)
100 int argc;
101 char **argv;
102 {
103 char *line, *s;
104
105 progname = argv[0];
106
107 initialize_readline (); /* Bind our completer. */
108
109 /* Loop reading and executing lines until the user quits. */
110 for ( ; done == 0; )
111 {
112 line = readline ("FileMan: ");
113
114 if (!line)
115 break;
116
117 /* Remove leading and trailing whitespace from the line.
118 Then, if there is anything left, add it to the history list
119 and execute it. */
120 s = stripwhite (line);
121
122 if (*s)
123 {
124 add_history (s);
125 execute_line (s);
126 }
127
128 free (line);
129 }
130 exit (0);
131 }
132
133 /* Execute a command line. */
134 int
135 execute_line (line)
136 char *line;
137 {
138 register int i;
139 COMMAND *command;
140 char *word;
141
142 /* Isolate the command word. */
143 i = 0;
144 while (line[i] && whitespace (line[i]))
145 i++;
146 word = line + i;
147
148 while (line[i] && !whitespace (line[i]))
149 i++;
150
151 if (line[i])
152 line[i++] = '\0';
153
154 command = find_command (word);
155
156 if (!command)
157 {
158 fprintf (stderr, "%s: No such command for FileMan.\n", word);
159 return (-1);
160 }
161
162 /* Get argument to command, if any. */
163 while (whitespace (line[i]))
164 i++;
165
166 word = line + i;
167
168 /* Call the function. */
169 return ((*(command->func)) (word));
170 }
171
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. */
174 COMMAND *
175 find_command (name)
176 char *name;
177 {
178 register int i;
179
180 for (i = 0; commands[i].name; i++)
181 if (strcmp (name, commands[i].name) == 0)
182 return (&commands[i]);
183
184 return ((COMMAND *)NULL);
185 }
186
187 /* Strip whitespace from the start and end of STRING. Return a pointer
188 into STRING. */
189 char *
190 stripwhite (string)
191 char *string;
192 {
193 register char *s, *t;
194
195 for (s = string; whitespace (*s); s++)
196 ;
197
198 if (*s == 0)
199 return (s);
200
201 t = s + strlen (s) - 1;
202 while (t > s && whitespace (*t))
203 t--;
204 *++t = '\0';
205
206 return s;
207 }
208
209 /* **************************************************************** */
210 /* */
211 /* Interface to Readline Completion */
212 /* */
213 /* **************************************************************** */
214
215 char *command_generator __P((const char *, int));
216 char **fileman_completion __P((const char *, int, int));
217
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
220 if not. */
221 initialize_readline ()
222 {
223 /* Allow conditional parsing of the ~/.inputrc file. */
224 rl_readline_name = "FileMan";
225
226 /* Tell the completer that we want a crack first. */
227 rl_attempted_completion_function = fileman_completion;
228 }
229
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. */
235 char **
236 fileman_completion (text, start, end)
237 const char *text;
238 int start, end;
239 {
240 char **matches;
241
242 matches = (char **)NULL;
243
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
246 directory. */
247 if (start == 0)
248 matches = rl_completion_matches (text, command_generator);
249
250 return (matches);
251 }
252
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. */
256 char *
257 command_generator (text, state)
258 const char *text;
259 int state;
260 {
261 static int list_index, len;
262 char *name;
263
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
266 variable to 0. */
267 if (!state)
268 {
269 list_index = 0;
270 len = strlen (text);
271 }
272
273 /* Return the next name which partially matches from the command list. */
274 while (name = commands[list_index].name)
275 {
276 list_index++;
277
278 if (strncmp (name, text, len) == 0)
279 return (dupstr(name));
280 }
281
282 /* If no names matched, then return NULL. */
283 return ((char *)NULL);
284 }
285
286 /* **************************************************************** */
287 /* */
288 /* FileMan Commands */
289 /* */
290 /* **************************************************************** */
291
292 /* String to pass to system (). This is for the LIST, VIEW and RENAME
293 commands. */
294 static char syscom[1024];
295
296 /* List the file(s) named in arg. */
297 com_list (arg)
298 char *arg;
299 {
300 if (!arg)
301 arg = "";
302
303 sprintf (syscom, "ls -FClg %s", arg);
304 return (system (syscom));
305 }
306
307 com_view (arg)
308 char *arg;
309 {
310 if (!valid_argument ("view", arg))
311 return 1;
312
313 #if defined (__MSDOS__)
314 /* more.com doesn't grok slashes in pathnames */
315 sprintf (syscom, "less %s", arg);
316 #else
317 sprintf (syscom, "more %s", arg);
318 #endif
319 return (system (syscom));
320 }
321
322 com_rename (arg)
323 char *arg;
324 {
325 too_dangerous ("rename");
326 return (1);
327 }
328
329 com_stat (arg)
330 char *arg;
331 {
332 struct stat finfo;
333
334 if (!valid_argument ("stat", arg))
335 return (1);
336
337 if (stat (arg, &finfo) == -1)
338 {
339 perror (arg);
340 return (1);
341 }
342
343 printf ("Statistics for `%s':\n", arg);
344
345 printf ("%s has %d link%s, and is %d byte%s in length.\n",
346 arg,
347 finfo.st_nlink,
348 (finfo.st_nlink == 1) ? "" : "s",
349 finfo.st_size,
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));
354 return (0);
355 }
356
357 com_delete (arg)
358 char *arg;
359 {
360 too_dangerous ("delete");
361 return (1);
362 }
363
364 /* Print out help for ARG, or for all of the commands if ARG is
365 not present. */
366 com_help (arg)
367 char *arg;
368 {
369 register int i;
370 int printed = 0;
371
372 for (i = 0; commands[i].name; i++)
373 {
374 if (!*arg || (strcmp (arg, commands[i].name) == 0))
375 {
376 printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
377 printed++;
378 }
379 }
380
381 if (!printed)
382 {
383 printf ("No commands match `%s'. Possibilties are:\n", arg);
384
385 for (i = 0; commands[i].name; i++)
386 {
387 /* Print in six columns. */
388 if (printed == 6)
389 {
390 printed = 0;
391 printf ("\n");
392 }
393
394 printf ("%s\t", commands[i].name);
395 printed++;
396 }
397
398 if (printed)
399 printf ("\n");
400 }
401 return (0);
402 }
403
404 /* Change to the directory ARG. */
405 com_cd (arg)
406 char *arg;
407 {
408 if (chdir (arg) == -1)
409 {
410 perror (arg);
411 return 1;
412 }
413
414 com_pwd ("");
415 return (0);
416 }
417
418 /* Print out the current working directory. */
419 com_pwd (ignore)
420 char *ignore;
421 {
422 char dir[1024], *s;
423
424 s = getcwd (dir, sizeof(dir) - 1);
425 if (s == 0)
426 {
427 printf ("Error getting pwd: %s\n", dir);
428 return 1;
429 }
430
431 printf ("Current directory is %s\n", dir);
432 return 0;
433 }
434
435 /* The user wishes to quit using this program. Just set DONE non-zero. */
436 com_quit (arg)
437 char *arg;
438 {
439 done = 1;
440 return (0);
441 }
442
443 /* Function which tells you that you can't do this. */
444 too_dangerous (caller)
445 char *caller;
446 {
447 fprintf (stderr,
448 "%s: Too dangerous for me to distribute. Write it yourself.\n",
449 caller);
450 }
451
452 /* Return non-zero if ARG is a valid argument for CALLER, else print
453 an error message and return zero. */
454 int
455 valid_argument (caller, arg)
456 char *caller, *arg;
457 {
458 if (!arg || !*arg)
459 {
460 fprintf (stderr, "%s: Argument required.\n", caller);
461 return (0);
462 }
463
464 return (1);
465 }