xref: /openbsd-src/gnu/lib/libreadline/examples/fileman.c (revision 15b117eae8ea0caffec2fbd5cbd366a5ccee20ab)
1*15b117eaSkettenis /* Copyright (C) 1987-2002 Free Software Foundation, Inc.
2*15b117eaSkettenis 
3*15b117eaSkettenis    This file is part of the GNU Readline Library, a library for
4*15b117eaSkettenis    reading lines of text with interactive input and history editing.
5*15b117eaSkettenis 
6*15b117eaSkettenis    The GNU Readline Library is free software; you can redistribute it
7*15b117eaSkettenis    and/or modify it under the terms of the GNU General Public License
8*15b117eaSkettenis    as published by the Free Software Foundation; either version 2, or
9*15b117eaSkettenis    (at your option) any later version.
10*15b117eaSkettenis 
11*15b117eaSkettenis    The GNU Readline Library is distributed in the hope that it will be
12*15b117eaSkettenis    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13*15b117eaSkettenis    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*15b117eaSkettenis    GNU General Public License for more details.
15*15b117eaSkettenis 
16*15b117eaSkettenis    The GNU General Public License is often shipped with GNU software, and
17*15b117eaSkettenis    is generally kept in a file called COPYING or LICENSE.  If you do not
18*15b117eaSkettenis    have a copy of the license, write to the Free Software Foundation,
19*15b117eaSkettenis    59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20*15b117eaSkettenis 
211acd27e7Smillert /* fileman.c -- A tiny application which demonstrates how to use the
221acd27e7Smillert    GNU Readline library.  This application interactively allows users
231acd27e7Smillert    to manipulate files and their modes. */
241acd27e7Smillert 
251acd27e7Smillert #ifdef HAVE_CONFIG_H
261acd27e7Smillert #  include <config.h>
271acd27e7Smillert #endif
281acd27e7Smillert 
291acd27e7Smillert #include <sys/types.h>
301acd27e7Smillert #ifdef HAVE_SYS_FILE_H
311acd27e7Smillert #  include <sys/file.h>
321acd27e7Smillert #endif
331acd27e7Smillert #include <sys/stat.h>
341acd27e7Smillert 
351acd27e7Smillert #ifdef HAVE_UNISTD_H
361acd27e7Smillert #  include <unistd.h>
371acd27e7Smillert #endif
381acd27e7Smillert 
391acd27e7Smillert #include <fcntl.h>
401acd27e7Smillert #include <stdio.h>
411acd27e7Smillert #include <errno.h>
421acd27e7Smillert 
431acd27e7Smillert #if defined (HAVE_STRING_H)
441acd27e7Smillert #  include <string.h>
451acd27e7Smillert #else /* !HAVE_STRING_H */
461acd27e7Smillert #  include <strings.h>
471acd27e7Smillert #endif /* !HAVE_STRING_H */
481acd27e7Smillert 
491acd27e7Smillert #ifdef HAVE_STDLIB_H
501acd27e7Smillert #  include <stdlib.h>
511acd27e7Smillert #endif
521acd27e7Smillert 
531acd27e7Smillert #ifdef READLINE_LIBRARY
541acd27e7Smillert #  include "readline.h"
551acd27e7Smillert #  include "history.h"
561acd27e7Smillert #else
571acd27e7Smillert #  include <readline/readline.h>
581acd27e7Smillert #  include <readline/history.h>
591acd27e7Smillert #endif
601acd27e7Smillert 
611acd27e7Smillert extern char *xmalloc ();
621acd27e7Smillert 
631acd27e7Smillert /* The names of functions that actually do the manipulation. */
64*15b117eaSkettenis int com_list PARAMS((char *));
65*15b117eaSkettenis int com_view PARAMS((char *));
66*15b117eaSkettenis int com_rename PARAMS((char *));
67*15b117eaSkettenis int com_stat PARAMS((char *));
68*15b117eaSkettenis int com_pwd PARAMS((char *));
69*15b117eaSkettenis int com_delete PARAMS((char *));
70*15b117eaSkettenis int com_help PARAMS((char *));
71*15b117eaSkettenis int com_cd PARAMS((char *));
72*15b117eaSkettenis int com_quit PARAMS((char *));
731acd27e7Smillert 
741acd27e7Smillert /* A structure which contains information on the commands this program
751acd27e7Smillert    can understand. */
761acd27e7Smillert 
771acd27e7Smillert typedef struct {
781acd27e7Smillert   char *name;			/* User printable name of the function. */
79*15b117eaSkettenis   rl_icpfunc_t *func;		/* Function to call to do the job. */
801acd27e7Smillert   char *doc;			/* Documentation for this function.  */
811acd27e7Smillert } COMMAND;
821acd27e7Smillert 
831acd27e7Smillert COMMAND commands[] = {
841acd27e7Smillert   { "cd", com_cd, "Change to directory DIR" },
851acd27e7Smillert   { "delete", com_delete, "Delete FILE" },
861acd27e7Smillert   { "help", com_help, "Display this text" },
871acd27e7Smillert   { "?", com_help, "Synonym for `help'" },
881acd27e7Smillert   { "list", com_list, "List files in DIR" },
891acd27e7Smillert   { "ls", com_list, "Synonym for `list'" },
901acd27e7Smillert   { "pwd", com_pwd, "Print the current working directory" },
911acd27e7Smillert   { "quit", com_quit, "Quit using Fileman" },
921acd27e7Smillert   { "rename", com_rename, "Rename FILE to NEWNAME" },
931acd27e7Smillert   { "stat", com_stat, "Print out statistics on FILE" },
941acd27e7Smillert   { "view", com_view, "View the contents of FILE" },
95*15b117eaSkettenis   { (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL }
961acd27e7Smillert };
971acd27e7Smillert 
981acd27e7Smillert /* Forward declarations. */
991acd27e7Smillert char *stripwhite ();
1001acd27e7Smillert COMMAND *find_command ();
1011acd27e7Smillert 
1021acd27e7Smillert /* The name of this program, as taken from argv[0]. */
1031acd27e7Smillert char *progname;
1041acd27e7Smillert 
1051acd27e7Smillert /* When non-zero, this global means the user is done using this program. */
1061acd27e7Smillert int done;
1071acd27e7Smillert 
1081acd27e7Smillert char *
dupstr(s)1091acd27e7Smillert dupstr (s)
1101acd27e7Smillert      char *s;
1111acd27e7Smillert {
1121acd27e7Smillert   char *r;
1131acd27e7Smillert 
1141acd27e7Smillert   r = xmalloc (strlen (s) + 1);
1151acd27e7Smillert   strcpy (r, s);
1161acd27e7Smillert   return (r);
1171acd27e7Smillert }
1181acd27e7Smillert 
main(argc,argv)1191acd27e7Smillert main (argc, argv)
1201acd27e7Smillert      int argc;
1211acd27e7Smillert      char **argv;
1221acd27e7Smillert {
1231acd27e7Smillert   char *line, *s;
1241acd27e7Smillert 
1251acd27e7Smillert   progname = argv[0];
1261acd27e7Smillert 
1271acd27e7Smillert   initialize_readline ();	/* Bind our completer. */
1281acd27e7Smillert 
1291acd27e7Smillert   /* Loop reading and executing lines until the user quits. */
1301acd27e7Smillert   for ( ; done == 0; )
1311acd27e7Smillert     {
1321acd27e7Smillert       line = readline ("FileMan: ");
1331acd27e7Smillert 
1341acd27e7Smillert       if (!line)
1351acd27e7Smillert         break;
1361acd27e7Smillert 
1371acd27e7Smillert       /* Remove leading and trailing whitespace from the line.
1381acd27e7Smillert          Then, if there is anything left, add it to the history list
1391acd27e7Smillert          and execute it. */
1401acd27e7Smillert       s = stripwhite (line);
1411acd27e7Smillert 
1421acd27e7Smillert       if (*s)
1431acd27e7Smillert         {
1441acd27e7Smillert           add_history (s);
1451acd27e7Smillert           execute_line (s);
1461acd27e7Smillert         }
1471acd27e7Smillert 
1481acd27e7Smillert       free (line);
1491acd27e7Smillert     }
1501acd27e7Smillert   exit (0);
1511acd27e7Smillert }
1521acd27e7Smillert 
1531acd27e7Smillert /* Execute a command line. */
1541acd27e7Smillert int
execute_line(line)1551acd27e7Smillert execute_line (line)
1561acd27e7Smillert      char *line;
1571acd27e7Smillert {
1581acd27e7Smillert   register int i;
1591acd27e7Smillert   COMMAND *command;
1601acd27e7Smillert   char *word;
1611acd27e7Smillert 
1621acd27e7Smillert   /* Isolate the command word. */
1631acd27e7Smillert   i = 0;
1641acd27e7Smillert   while (line[i] && whitespace (line[i]))
1651acd27e7Smillert     i++;
1661acd27e7Smillert   word = line + i;
1671acd27e7Smillert 
1681acd27e7Smillert   while (line[i] && !whitespace (line[i]))
1691acd27e7Smillert     i++;
1701acd27e7Smillert 
1711acd27e7Smillert   if (line[i])
1721acd27e7Smillert     line[i++] = '\0';
1731acd27e7Smillert 
1741acd27e7Smillert   command = find_command (word);
1751acd27e7Smillert 
1761acd27e7Smillert   if (!command)
1771acd27e7Smillert     {
1781acd27e7Smillert       fprintf (stderr, "%s: No such command for FileMan.\n", word);
1791acd27e7Smillert       return (-1);
1801acd27e7Smillert     }
1811acd27e7Smillert 
1821acd27e7Smillert   /* Get argument to command, if any. */
1831acd27e7Smillert   while (whitespace (line[i]))
1841acd27e7Smillert     i++;
1851acd27e7Smillert 
1861acd27e7Smillert   word = line + i;
1871acd27e7Smillert 
1881acd27e7Smillert   /* Call the function. */
1891acd27e7Smillert   return ((*(command->func)) (word));
1901acd27e7Smillert }
1911acd27e7Smillert 
1921acd27e7Smillert /* Look up NAME as the name of a command, and return a pointer to that
1931acd27e7Smillert    command.  Return a NULL pointer if NAME isn't a command name. */
1941acd27e7Smillert COMMAND *
find_command(name)1951acd27e7Smillert find_command (name)
1961acd27e7Smillert      char *name;
1971acd27e7Smillert {
1981acd27e7Smillert   register int i;
1991acd27e7Smillert 
2001acd27e7Smillert   for (i = 0; commands[i].name; i++)
2011acd27e7Smillert     if (strcmp (name, commands[i].name) == 0)
2021acd27e7Smillert       return (&commands[i]);
2031acd27e7Smillert 
2041acd27e7Smillert   return ((COMMAND *)NULL);
2051acd27e7Smillert }
2061acd27e7Smillert 
2071acd27e7Smillert /* Strip whitespace from the start and end of STRING.  Return a pointer
2081acd27e7Smillert    into STRING. */
2091acd27e7Smillert char *
stripwhite(string)2101acd27e7Smillert stripwhite (string)
2111acd27e7Smillert      char *string;
2121acd27e7Smillert {
2131acd27e7Smillert   register char *s, *t;
2141acd27e7Smillert 
2151acd27e7Smillert   for (s = string; whitespace (*s); s++)
2161acd27e7Smillert     ;
2171acd27e7Smillert 
2181acd27e7Smillert   if (*s == 0)
2191acd27e7Smillert     return (s);
2201acd27e7Smillert 
2211acd27e7Smillert   t = s + strlen (s) - 1;
2221acd27e7Smillert   while (t > s && whitespace (*t))
2231acd27e7Smillert     t--;
2241acd27e7Smillert   *++t = '\0';
2251acd27e7Smillert 
2261acd27e7Smillert   return s;
2271acd27e7Smillert }
2281acd27e7Smillert 
2291acd27e7Smillert /* **************************************************************** */
2301acd27e7Smillert /*                                                                  */
2311acd27e7Smillert /*                  Interface to Readline Completion                */
2321acd27e7Smillert /*                                                                  */
2331acd27e7Smillert /* **************************************************************** */
2341acd27e7Smillert 
235*15b117eaSkettenis char *command_generator PARAMS((const char *, int));
236*15b117eaSkettenis char **fileman_completion PARAMS((const char *, int, int));
2371acd27e7Smillert 
2381acd27e7Smillert /* Tell the GNU Readline library how to complete.  We want to try to complete
2391acd27e7Smillert    on command names if this is the first word in the line, or on filenames
2401acd27e7Smillert    if not. */
initialize_readline()2411acd27e7Smillert initialize_readline ()
2421acd27e7Smillert {
2431acd27e7Smillert   /* Allow conditional parsing of the ~/.inputrc file. */
2441acd27e7Smillert   rl_readline_name = "FileMan";
2451acd27e7Smillert 
2461acd27e7Smillert   /* Tell the completer that we want a crack first. */
247*15b117eaSkettenis   rl_attempted_completion_function = fileman_completion;
2481acd27e7Smillert }
2491acd27e7Smillert 
2501acd27e7Smillert /* Attempt to complete on the contents of TEXT.  START and END bound the
2511acd27e7Smillert    region of rl_line_buffer that contains the word to complete.  TEXT is
2521acd27e7Smillert    the word to complete.  We can use the entire contents of rl_line_buffer
2531acd27e7Smillert    in case we want to do some simple parsing.  Return the array of matches,
2541acd27e7Smillert    or NULL if there aren't any. */
2551acd27e7Smillert char **
fileman_completion(text,start,end)2561acd27e7Smillert fileman_completion (text, start, end)
257*15b117eaSkettenis      const char *text;
2581acd27e7Smillert      int start, end;
2591acd27e7Smillert {
2601acd27e7Smillert   char **matches;
2611acd27e7Smillert 
2621acd27e7Smillert   matches = (char **)NULL;
2631acd27e7Smillert 
2641acd27e7Smillert   /* If this word is at the start of the line, then it is a command
2651acd27e7Smillert      to complete.  Otherwise it is the name of a file in the current
2661acd27e7Smillert      directory. */
2671acd27e7Smillert   if (start == 0)
268*15b117eaSkettenis     matches = rl_completion_matches (text, command_generator);
2691acd27e7Smillert 
2701acd27e7Smillert   return (matches);
2711acd27e7Smillert }
2721acd27e7Smillert 
2731acd27e7Smillert /* Generator function for command completion.  STATE lets us know whether
2741acd27e7Smillert    to start from scratch; without any state (i.e. STATE == 0), then we
2751acd27e7Smillert    start at the top of the list. */
2761acd27e7Smillert char *
command_generator(text,state)2771acd27e7Smillert command_generator (text, state)
278*15b117eaSkettenis      const char *text;
2791acd27e7Smillert      int state;
2801acd27e7Smillert {
2811acd27e7Smillert   static int list_index, len;
2821acd27e7Smillert   char *name;
2831acd27e7Smillert 
2841acd27e7Smillert   /* If this is a new word to complete, initialize now.  This includes
2851acd27e7Smillert      saving the length of TEXT for efficiency, and initializing the index
2861acd27e7Smillert      variable to 0. */
2871acd27e7Smillert   if (!state)
2881acd27e7Smillert     {
2891acd27e7Smillert       list_index = 0;
2901acd27e7Smillert       len = strlen (text);
2911acd27e7Smillert     }
2921acd27e7Smillert 
2931acd27e7Smillert   /* Return the next name which partially matches from the command list. */
2941acd27e7Smillert   while (name = commands[list_index].name)
2951acd27e7Smillert     {
2961acd27e7Smillert       list_index++;
2971acd27e7Smillert 
2981acd27e7Smillert       if (strncmp (name, text, len) == 0)
2991acd27e7Smillert         return (dupstr(name));
3001acd27e7Smillert     }
3011acd27e7Smillert 
3021acd27e7Smillert   /* If no names matched, then return NULL. */
3031acd27e7Smillert   return ((char *)NULL);
3041acd27e7Smillert }
3051acd27e7Smillert 
3061acd27e7Smillert /* **************************************************************** */
3071acd27e7Smillert /*                                                                  */
3081acd27e7Smillert /*                       FileMan Commands                           */
3091acd27e7Smillert /*                                                                  */
3101acd27e7Smillert /* **************************************************************** */
3111acd27e7Smillert 
3121acd27e7Smillert /* String to pass to system ().  This is for the LIST, VIEW and RENAME
3131acd27e7Smillert    commands. */
3141acd27e7Smillert static char syscom[1024];
3151acd27e7Smillert 
3161acd27e7Smillert /* List the file(s) named in arg. */
com_list(arg)3171acd27e7Smillert com_list (arg)
3181acd27e7Smillert      char *arg;
3191acd27e7Smillert {
3201acd27e7Smillert   if (!arg)
3211acd27e7Smillert     arg = "";
3221acd27e7Smillert 
3231acd27e7Smillert   sprintf (syscom, "ls -FClg %s", arg);
3241acd27e7Smillert   return (system (syscom));
3251acd27e7Smillert }
3261acd27e7Smillert 
com_view(arg)3271acd27e7Smillert com_view (arg)
3281acd27e7Smillert      char *arg;
3291acd27e7Smillert {
3301acd27e7Smillert   if (!valid_argument ("view", arg))
3311acd27e7Smillert     return 1;
3321acd27e7Smillert 
3331acd27e7Smillert #if defined (__MSDOS__)
3341acd27e7Smillert   /* more.com doesn't grok slashes in pathnames */
3351acd27e7Smillert   sprintf (syscom, "less %s", arg);
3361acd27e7Smillert #else
3371acd27e7Smillert   sprintf (syscom, "more %s", arg);
3381acd27e7Smillert #endif
3391acd27e7Smillert   return (system (syscom));
3401acd27e7Smillert }
3411acd27e7Smillert 
com_rename(arg)3421acd27e7Smillert com_rename (arg)
3431acd27e7Smillert      char *arg;
3441acd27e7Smillert {
3451acd27e7Smillert   too_dangerous ("rename");
3461acd27e7Smillert   return (1);
3471acd27e7Smillert }
3481acd27e7Smillert 
com_stat(arg)3491acd27e7Smillert com_stat (arg)
3501acd27e7Smillert      char *arg;
3511acd27e7Smillert {
3521acd27e7Smillert   struct stat finfo;
3531acd27e7Smillert 
3541acd27e7Smillert   if (!valid_argument ("stat", arg))
3551acd27e7Smillert     return (1);
3561acd27e7Smillert 
3571acd27e7Smillert   if (stat (arg, &finfo) == -1)
3581acd27e7Smillert     {
3591acd27e7Smillert       perror (arg);
3601acd27e7Smillert       return (1);
3611acd27e7Smillert     }
3621acd27e7Smillert 
3631acd27e7Smillert   printf ("Statistics for `%s':\n", arg);
3641acd27e7Smillert 
3651acd27e7Smillert   printf ("%s has %d link%s, and is %d byte%s in length.\n",
3661acd27e7Smillert 	  arg,
3671acd27e7Smillert           finfo.st_nlink,
3681acd27e7Smillert           (finfo.st_nlink == 1) ? "" : "s",
3691acd27e7Smillert           finfo.st_size,
3701acd27e7Smillert           (finfo.st_size == 1) ? "" : "s");
3711acd27e7Smillert   printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime));
3721acd27e7Smillert   printf ("      Last access at: %s", ctime (&finfo.st_atime));
3731acd27e7Smillert   printf ("    Last modified at: %s", ctime (&finfo.st_mtime));
3741acd27e7Smillert   return (0);
3751acd27e7Smillert }
3761acd27e7Smillert 
com_delete(arg)3771acd27e7Smillert com_delete (arg)
3781acd27e7Smillert      char *arg;
3791acd27e7Smillert {
3801acd27e7Smillert   too_dangerous ("delete");
3811acd27e7Smillert   return (1);
3821acd27e7Smillert }
3831acd27e7Smillert 
3841acd27e7Smillert /* Print out help for ARG, or for all of the commands if ARG is
3851acd27e7Smillert    not present. */
com_help(arg)3861acd27e7Smillert com_help (arg)
3871acd27e7Smillert      char *arg;
3881acd27e7Smillert {
3891acd27e7Smillert   register int i;
3901acd27e7Smillert   int printed = 0;
3911acd27e7Smillert 
3921acd27e7Smillert   for (i = 0; commands[i].name; i++)
3931acd27e7Smillert     {
3941acd27e7Smillert       if (!*arg || (strcmp (arg, commands[i].name) == 0))
3951acd27e7Smillert         {
3961acd27e7Smillert           printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
3971acd27e7Smillert           printed++;
3981acd27e7Smillert         }
3991acd27e7Smillert     }
4001acd27e7Smillert 
4011acd27e7Smillert   if (!printed)
4021acd27e7Smillert     {
4031acd27e7Smillert       printf ("No commands match `%s'.  Possibilties are:\n", arg);
4041acd27e7Smillert 
4051acd27e7Smillert       for (i = 0; commands[i].name; i++)
4061acd27e7Smillert         {
4071acd27e7Smillert           /* Print in six columns. */
4081acd27e7Smillert           if (printed == 6)
4091acd27e7Smillert             {
4101acd27e7Smillert               printed = 0;
4111acd27e7Smillert               printf ("\n");
4121acd27e7Smillert             }
4131acd27e7Smillert 
4141acd27e7Smillert           printf ("%s\t", commands[i].name);
4151acd27e7Smillert           printed++;
4161acd27e7Smillert         }
4171acd27e7Smillert 
4181acd27e7Smillert       if (printed)
4191acd27e7Smillert         printf ("\n");
4201acd27e7Smillert     }
4211acd27e7Smillert   return (0);
4221acd27e7Smillert }
4231acd27e7Smillert 
4241acd27e7Smillert /* Change to the directory ARG. */
com_cd(arg)4251acd27e7Smillert com_cd (arg)
4261acd27e7Smillert      char *arg;
4271acd27e7Smillert {
4281acd27e7Smillert   if (chdir (arg) == -1)
4291acd27e7Smillert     {
4301acd27e7Smillert       perror (arg);
4311acd27e7Smillert       return 1;
4321acd27e7Smillert     }
4331acd27e7Smillert 
4341acd27e7Smillert   com_pwd ("");
4351acd27e7Smillert   return (0);
4361acd27e7Smillert }
4371acd27e7Smillert 
4381acd27e7Smillert /* Print out the current working directory. */
com_pwd(ignore)4391acd27e7Smillert com_pwd (ignore)
4401acd27e7Smillert      char *ignore;
4411acd27e7Smillert {
4421acd27e7Smillert   char dir[1024], *s;
4431acd27e7Smillert 
4441acd27e7Smillert   s = getcwd (dir, sizeof(dir) - 1);
4451acd27e7Smillert   if (s == 0)
4461acd27e7Smillert     {
4471acd27e7Smillert       printf ("Error getting pwd: %s\n", dir);
4481acd27e7Smillert       return 1;
4491acd27e7Smillert     }
4501acd27e7Smillert 
4511acd27e7Smillert   printf ("Current directory is %s\n", dir);
4521acd27e7Smillert   return 0;
4531acd27e7Smillert }
4541acd27e7Smillert 
4551acd27e7Smillert /* The user wishes to quit using this program.  Just set DONE non-zero. */
com_quit(arg)4561acd27e7Smillert com_quit (arg)
4571acd27e7Smillert      char *arg;
4581acd27e7Smillert {
4591acd27e7Smillert   done = 1;
4601acd27e7Smillert   return (0);
4611acd27e7Smillert }
4621acd27e7Smillert 
4631acd27e7Smillert /* Function which tells you that you can't do this. */
too_dangerous(caller)4641acd27e7Smillert too_dangerous (caller)
4651acd27e7Smillert      char *caller;
4661acd27e7Smillert {
4671acd27e7Smillert   fprintf (stderr,
4681acd27e7Smillert            "%s: Too dangerous for me to distribute.  Write it yourself.\n",
4691acd27e7Smillert            caller);
4701acd27e7Smillert }
4711acd27e7Smillert 
4721acd27e7Smillert /* Return non-zero if ARG is a valid argument for CALLER, else print
4731acd27e7Smillert    an error message and return zero. */
4741acd27e7Smillert int
valid_argument(caller,arg)4751acd27e7Smillert valid_argument (caller, arg)
4761acd27e7Smillert      char *caller, *arg;
4771acd27e7Smillert {
4781acd27e7Smillert   if (!arg || !*arg)
4791acd27e7Smillert     {
4801acd27e7Smillert       fprintf (stderr, "%s: Argument required.\n", caller);
4811acd27e7Smillert       return (0);
4821acd27e7Smillert     }
4831acd27e7Smillert 
4841acd27e7Smillert   return (1);
4851acd27e7Smillert }
486