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