1 /* fileman.c - file manager example for readline library. */
3 /* Copyright (C) 1987-2009 Free Software Foundation, Inc.
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.
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.
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.
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/>.
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. */
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_FILE_H
32 # include <sys/file.h>
44 #if defined (HAVE_STRING_H)
46 #else /* !HAVE_STRING_H */
48 #endif /* !HAVE_STRING_H */
56 #ifdef READLINE_LIBRARY
57 # include "readline.h"
60 # include <readline/readline.h>
61 # include <readline/history.h>
64 extern char *xmalloc
PARAMS((size_t));
66 void initialize_readline
PARAMS((void));
67 void too_dangerous
PARAMS((char *));
69 int execute_line
PARAMS((char *));
70 int valid_argument
PARAMS((char *, char *));
72 /* The names of functions that actually do the manipulation. */
73 int com_list
PARAMS((char *));
74 int com_view
PARAMS((char *));
75 int com_rename
PARAMS((char *));
76 int com_stat
PARAMS((char *));
77 int com_pwd
PARAMS((char *));
78 int com_delete
PARAMS((char *));
79 int com_help
PARAMS((char *));
80 int com_cd
PARAMS((char *));
81 int com_quit
PARAMS((char *));
83 /* A structure which contains information on the commands this program
87 char *name
; /* User printable name of the function. */
88 rl_icpfunc_t
*func
; /* Function to call to do the job. */
89 char *doc
; /* Documentation for this function. */
92 COMMAND commands
[] = {
93 { "cd", com_cd
, "Change to directory DIR" },
94 { "delete", com_delete
, "Delete FILE" },
95 { "help", com_help
, "Display this text" },
96 { "?", com_help
, "Synonym for `help'" },
97 { "list", com_list
, "List files in DIR" },
98 { "ls", com_list
, "Synonym for `list'" },
99 { "pwd", com_pwd
, "Print the current working directory" },
100 { "quit", com_quit
, "Quit using Fileman" },
101 { "rename", com_rename
, "Rename FILE to NEWNAME" },
102 { "stat", com_stat
, "Print out statistics on FILE" },
103 { "view", com_view
, "View the contents of FILE" },
104 { (char *)NULL
, (rl_icpfunc_t
*)NULL
, (char *)NULL
}
107 /* Forward declarations. */
109 COMMAND
*find_command ();
111 /* The name of this program, as taken from argv[0]. */
114 /* When non-zero, this global means the user is done using this program. */
123 r
= xmalloc (strlen (s
) + 1);
137 initialize_readline (); /* Bind our completer. */
139 /* Loop reading and executing lines until the user quits. */
142 line
= readline ("FileMan: ");
147 /* Remove leading and trailing whitespace from the line.
148 Then, if there is anything left, add it to the history list
150 s
= stripwhite (line
);
163 /* Execute a command line. */
172 /* Isolate the command word. */
174 while (line
[i
] && whitespace (line
[i
]))
178 while (line
[i
] && !whitespace (line
[i
]))
184 command
= find_command (word
);
188 fprintf (stderr
, "%s: No such command for FileMan.\n", word
);
192 /* Get argument to command, if any. */
193 while (whitespace (line
[i
]))
198 /* Call the function. */
199 return ((*(command
->func
)) (word
));
202 /* Look up NAME as the name of a command, and return a pointer to that
203 command. Return a NULL pointer if NAME isn't a command name. */
210 for (i
= 0; commands
[i
].name
; i
++)
211 if (strcmp (name
, commands
[i
].name
) == 0)
212 return (&commands
[i
]);
214 return ((COMMAND
*)NULL
);
217 /* Strip whitespace from the start and end of STRING. Return a pointer
223 register char *s
, *t
;
225 for (s
= string
; whitespace (*s
); s
++)
231 t
= s
+ strlen (s
) - 1;
232 while (t
> s
&& whitespace (*t
))
239 /* **************************************************************** */
241 /* Interface to Readline Completion */
243 /* **************************************************************** */
245 char *command_generator
PARAMS((const char *, int));
246 char **fileman_completion
PARAMS((const char *, int, int));
248 /* Tell the GNU Readline library how to complete. We want to try to complete
249 on command names if this is the first word in the line, or on filenames
252 initialize_readline ()
254 /* Allow conditional parsing of the ~/.inputrc file. */
255 rl_readline_name
= "FileMan";
257 /* Tell the completer that we want a crack first. */
258 rl_attempted_completion_function
= fileman_completion
;
261 /* Attempt to complete on the contents of TEXT. START and END bound the
262 region of rl_line_buffer that contains the word to complete. TEXT is
263 the word to complete. We can use the entire contents of rl_line_buffer
264 in case we want to do some simple parsing. Return the array of matches,
265 or NULL if there aren't any. */
267 fileman_completion (text
, start
, end
)
273 matches
= (char **)NULL
;
275 /* If this word is at the start of the line, then it is a command
276 to complete. Otherwise it is the name of a file in the current
279 matches
= rl_completion_matches (text
, command_generator
);
284 /* Generator function for command completion. STATE lets us know whether
285 to start from scratch; without any state (i.e. STATE == 0), then we
286 start at the top of the list. */
288 command_generator (text
, state
)
292 static int list_index
, len
;
295 /* If this is a new word to complete, initialize now. This includes
296 saving the length of TEXT for efficiency, and initializing the index
304 /* Return the next name which partially matches from the command list. */
305 while (name
= commands
[list_index
].name
)
309 if (strncmp (name
, text
, len
) == 0)
310 return (dupstr(name
));
313 /* If no names matched, then return NULL. */
314 return ((char *)NULL
);
317 /* **************************************************************** */
319 /* FileMan Commands */
321 /* **************************************************************** */
323 /* String to pass to system (). This is for the LIST, VIEW and RENAME
325 static char syscom
[1024];
327 /* List the file(s) named in arg. */
335 sprintf (syscom
, "ls -FClg %s", arg
);
336 return (system (syscom
));
343 if (!valid_argument ("view", arg
))
346 #if defined (__MSDOS__)
347 /* more.com doesn't grok slashes in pathnames */
348 sprintf (syscom
, "less %s", arg
);
350 sprintf (syscom
, "more %s", arg
);
352 return (system (syscom
));
359 too_dangerous ("rename");
369 if (!valid_argument ("stat", arg
))
372 if (stat (arg
, &finfo
) == -1)
378 printf ("Statistics for `%s':\n", arg
);
380 printf ("%s has %d link%s, and is %d byte%s in length.\n",
383 (finfo
.st_nlink
== 1) ? "" : "s",
385 (finfo
.st_size
== 1) ? "" : "s");
386 printf ("Inode Last Change at: %s", ctime (&finfo
.st_ctime
));
387 printf (" Last access at: %s", ctime (&finfo
.st_atime
));
388 printf (" Last modified at: %s", ctime (&finfo
.st_mtime
));
396 too_dangerous ("delete");
400 /* Print out help for ARG, or for all of the commands if ARG is
409 for (i
= 0; commands
[i
].name
; i
++)
411 if (!*arg
|| (strcmp (arg
, commands
[i
].name
) == 0))
413 printf ("%s\t\t%s.\n", commands
[i
].name
, commands
[i
].doc
);
420 printf ("No commands match `%s'. Possibilties are:\n", arg
);
422 for (i
= 0; commands
[i
].name
; i
++)
424 /* Print in six columns. */
431 printf ("%s\t", commands
[i
].name
);
441 /* Change to the directory ARG. */
446 if (chdir (arg
) == -1)
456 /* Print out the current working directory. */
463 s
= getcwd (dir
, sizeof(dir
) - 1);
466 printf ("Error getting pwd: %s\n", dir
);
470 printf ("Current directory is %s\n", dir
);
474 /* The user wishes to quit using this program. Just set DONE non-zero. */
483 /* Function which tells you that you can't do this. */
485 too_dangerous (caller
)
489 "%s: Too dangerous for me to distribute. Write it yourself.\n",
493 /* Return non-zero if ARG is a valid argument for CALLER, else print
494 an error message and return zero. */
496 valid_argument (caller
, arg
)
501 fprintf (stderr
, "%s: Argument required.\n", caller
);