]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/examples/fileman.c
Imported from ../bash-2.0.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 #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 bound the
198 region of rl_line_buffer that contains the word to complete. TEXT is
199 the word to complete. We can use the entire contents of rl_line_buffer
200 in case we want to do some simple parsing. Return the array of matches,
201 or NULL if there aren't any. */
202 char **
203 fileman_completion (text, start, end)
204 char *text;
205 int start, end;
206 {
207 char **matches;
208
209 matches = (char **)NULL;
210
211 /* If this word is at the start of the line, then it is a command
212 to complete. Otherwise it is the name of a file in the current
213 directory. */
214 if (start == 0)
215 matches = completion_matches (text, command_generator);
216
217 return (matches);
218 }
219
220 /* Generator function for command completion. STATE lets us know whether
221 to start from scratch; without any state (i.e. STATE == 0), then we
222 start at the top of the list. */
223 char *
224 command_generator (text, state)
225 char *text;
226 int state;
227 {
228 static int list_index, len;
229 char *name;
230
231 /* If this is a new word to complete, initialize now. This includes
232 saving the length of TEXT for efficiency, and initializing the index
233 variable to 0. */
234 if (!state)
235 {
236 list_index = 0;
237 len = strlen (text);
238 }
239
240 /* Return the next name which partially matches from the command list. */
241 while (name = commands[list_index].name)
242 {
243 list_index++;
244
245 if (strncmp (name, text, len) == 0)
246 return (dupstr(name));
247 }
248
249 /* If no names matched, then return NULL. */
250 return ((char *)NULL);
251 }
252
253 /* **************************************************************** */
254 /* */
255 /* FileMan Commands */
256 /* */
257 /* **************************************************************** */
258
259 /* String to pass to system (). This is for the LIST, VIEW and RENAME
260 commands. */
261 static char syscom[1024];
262
263 /* List the file(s) named in arg. */
264 com_list (arg)
265 char *arg;
266 {
267 if (!arg)
268 arg = "";
269
270 sprintf (syscom, "ls -FClg %s", arg);
271 return (system (syscom));
272 }
273
274 com_view (arg)
275 char *arg;
276 {
277 if (!valid_argument ("view", arg))
278 return 1;
279
280 sprintf (syscom, "more %s", arg);
281 return (system (syscom));
282 }
283
284 com_rename (arg)
285 char *arg;
286 {
287 too_dangerous ("rename");
288 return (1);
289 }
290
291 com_stat (arg)
292 char *arg;
293 {
294 struct stat finfo;
295
296 if (!valid_argument ("stat", arg))
297 return (1);
298
299 if (stat (arg, &finfo) == -1)
300 {
301 perror (arg);
302 return (1);
303 }
304
305 printf ("Statistics for `%s':\n", arg);
306
307 printf ("%s has %d link%s, and is %d byte%s in length.\n", arg,
308 finfo.st_nlink,
309 (finfo.st_nlink == 1) ? "" : "s",
310 finfo.st_size,
311 (finfo.st_size == 1) ? "" : "s");
312 printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime));
313 printf (" Last access at: %s", ctime (&finfo.st_atime));
314 printf (" Last modified at: %s", ctime (&finfo.st_mtime));
315 return (0);
316 }
317
318 com_delete (arg)
319 char *arg;
320 {
321 too_dangerous ("delete");
322 return (1);
323 }
324
325 /* Print out help for ARG, or for all of the commands if ARG is
326 not present. */
327 com_help (arg)
328 char *arg;
329 {
330 register int i;
331 int printed = 0;
332
333 for (i = 0; commands[i].name; i++)
334 {
335 if (!*arg || (strcmp (arg, commands[i].name) == 0))
336 {
337 printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
338 printed++;
339 }
340 }
341
342 if (!printed)
343 {
344 printf ("No commands match `%s'. Possibilties are:\n", arg);
345
346 for (i = 0; commands[i].name; i++)
347 {
348 /* Print in six columns. */
349 if (printed == 6)
350 {
351 printed = 0;
352 printf ("\n");
353 }
354
355 printf ("%s\t", commands[i].name);
356 printed++;
357 }
358
359 if (printed)
360 printf ("\n");
361 }
362 return (0);
363 }
364
365 /* Change to the directory ARG. */
366 com_cd (arg)
367 char *arg;
368 {
369 if (chdir (arg) == -1)
370 {
371 perror (arg);
372 return 1;
373 }
374
375 com_pwd ("");
376 return (0);
377 }
378
379 /* Print out the current working directory. */
380 com_pwd (ignore)
381 char *ignore;
382 {
383 char dir[1024], *s;
384
385 s = getwd (dir);
386 if (s == 0)
387 {
388 printf ("Error getting pwd: %s\n", dir);
389 return 1;
390 }
391
392 printf ("Current directory is %s\n", dir);
393 return 0;
394 }
395
396 /* The user wishes to quit using this program. Just set DONE non-zero. */
397 com_quit (arg)
398 char *arg;
399 {
400 done = 1;
401 return (0);
402 }
403
404 /* Function which tells you that you can't do this. */
405 too_dangerous (caller)
406 char *caller;
407 {
408 fprintf (stderr,
409 "%s: Too dangerous for me to distribute. Write it yourself.\n",
410 caller);
411 }
412
413 /* Return non-zero if ARG is a valid argument for CALLER, else print
414 an error message and return zero. */
415 int
416 valid_argument (caller, arg)
417 char *caller, *arg;
418 {
419 if (!arg || !*arg)
420 {
421 fprintf (stderr, "%s: Argument required.\n", caller);
422 return (0);
423 }
424
425 return (1);
426 }