home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-base.tgz / octave-1.1.1p1-base.tar / fsf / octave / src / dirfns.cc < prev    next >
C/C++ Source or Header  |  1995-02-14  |  10KB  |  502 lines

  1. // dirfns.cc                                           -*- C++ -*-
  2. /*
  3.  
  4. Copyright (C) 1992, 1993, 1994, 1995 John W. Eaton
  5.  
  6. This file is part of Octave.
  7.  
  8. Octave is free software; you can redistribute it and/or modify it
  9. under the terms of the GNU General Public License as published by the
  10. Free Software Foundation; either version 2, or (at your option) any
  11. later version.
  12.  
  13. Octave is distributed in the hope that it will be useful, but WITHOUT
  14. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with Octave; see the file COPYING.  If not, write to the Free
  20. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22. */
  23.  
  24. /*
  25.  
  26. The functions listed below were adapted from a similar functions
  27. from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991
  28. Free Software Foundation, Inc.
  29.  
  30.   polite_directory_format  absolute_pathname
  31.   absolute_program         base_pathname
  32.   make_absolute            pathname_backup
  33.   change_to_directory      get_working_directory
  34.  
  35. */ 
  36.  
  37. #ifdef HAVE_CONFIG_H
  38. #include "config.h"
  39. #endif
  40.  
  41. #include <sys/types.h>
  42. #ifdef HAVE_UNISTD_H
  43. #include <unistd.h>
  44. #endif
  45. #include <errno.h>
  46. #include <stdio.h>
  47. #include <stddef.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <strstream.h>
  51. #include <sys/param.h>
  52.  
  53. // This mess suggested by the autoconf manual.
  54. // unistd.h defines _POSIX_VERSION on POSIX.1 systems.
  55. #if defined (HAVE_DIRENT_H) || defined (_POSIX_VERSION)
  56. #include <dirent.h>
  57. #define NLENGTH(dirent) (strlen((dirent)->d_name))
  58. #else
  59. #define dirent direct
  60. #define NLENGTH(dirent) ((dirent)->d_namlen)
  61. #if defined (HAVE_SYS_NDIR_H)
  62. #include <sys/ndir.h>
  63. #endif
  64. #if defined (HAVE_SYS_DIR_H)
  65. #include <sys/dir.h>
  66. #endif
  67. #if defined (HAVE_NDIR_H)
  68. #include <ndir.h>
  69. #endif
  70. #endif
  71.  
  72. #include "statdefs.h"
  73. #include "procstream.h"
  74. #include "tree-const.h"
  75. #include "oct-obj.h"
  76. #include "sysdep.h"
  77. #include "octave.h"
  78. #include "dirfns.h"
  79. #include "pager.h"
  80. #include "error.h"
  81. #include "utils.h"
  82. #include "defun.h"
  83.  
  84. extern "C"
  85. {
  86. #include <readline/tilde.h>
  87. extern char *strerror (int);
  88. }
  89.  
  90. #ifndef MAXPATHLEN
  91. #define MAXPATHLEN 1024
  92. #endif
  93.  
  94. // Temp storage for a path.
  95. static char tdir[MAXPATHLEN];
  96.  
  97. // Non-zero means follow symbolic links that point to directories just
  98. // as if they are real directories.
  99. static int follow_symbolic_links = 1;
  100.  
  101. // Non-zero means that pwd always give verbatim directory, regardless
  102. // of symbolic link following.
  103. static int verbatim_pwd = 1;
  104.  
  105. // Remove the last N directories from PATH.  Do not PATH blank.
  106. // PATH must contain enough space for MAXPATHLEN characters.
  107.  
  108. void
  109. pathname_backup (char *path, int n)
  110. {
  111.   register char *p;
  112.  
  113.   if (! *path)
  114.     return;
  115.  
  116.   p = path + (strlen (path) - 1);
  117.  
  118.   while (n--)
  119.     {
  120.       while (*p == '/' && p != path)
  121.     p--;
  122.  
  123.       while (*p != '/' && p != path)
  124.     p--;
  125.  
  126.       *++p = '\0';
  127.     }
  128. }
  129.  
  130. // Return a pretty pathname.  If the first part of the pathname is the
  131. // same as $HOME, then replace that with `~'.
  132.  
  133. char *
  134. polite_directory_format (char *name)
  135. {
  136.   int l = home_directory ? strlen (home_directory) : 0;
  137.  
  138.   if (l > 1 && strncmp (home_directory, name, l) == 0
  139.       && (! name[l] || name[l] == '/'))
  140.     {
  141.       strcpy (tdir + 1, name + l);
  142.       tdir[0] = '~';
  143.       return (tdir);
  144.     }
  145.   else
  146.     return name;
  147. }
  148.  
  149. // Return 1 if STRING contains an absolute pathname, else 0.
  150.  
  151. int
  152. absolute_pathname (const char *string)
  153. {
  154.   if (! string || ! *string)
  155.     return 0;
  156.  
  157.   if (*string == '/')
  158.     return 1;
  159.  
  160.   if (*string++ == '.')
  161.     {
  162.       if ((! *string) || *string == '/')
  163.     return 1;
  164.  
  165.       if (*string++ == '.')
  166.     if (! *string || *string == '/')
  167.       return 1;
  168.     }
  169.   return 0;
  170. }
  171.  
  172. // Return 1 if STRING is an absolute program name; it is absolute if
  173. // it contains any slashes.  This is used to decide whether or not to
  174. // look up through $PATH.
  175.  
  176. int
  177. absolute_program (const char *string)
  178. {
  179.   return (strchr (string, '/') != 0);
  180. }
  181.  
  182. // Return the `basename' of the pathname in STRING (the stuff after
  183. // the last '/').  If STRING is not a full pathname, simply return it.
  184.  
  185. char *
  186. base_pathname (char *string)
  187. {
  188.   char *p = strrchr (string, '/');
  189.  
  190.   if (! absolute_pathname (string))
  191.     return (string);
  192.  
  193.   if (p)
  194.     return (++p);
  195.   else
  196.     return (string);
  197. }
  198.  
  199. // Turn STRING (a pathname) into an absolute pathname, assuming that
  200. // DOT_PATH contains the symbolic location of '.'.  This always
  201. // returns a new string, even if STRING was an absolute pathname to
  202. // begin with.
  203.  
  204. char *
  205. make_absolute (const char *string, const char *dot_path)
  206. {
  207.   static char current_path[MAXPATHLEN];
  208.   register char *cp;
  209.  
  210.   if (! dot_path || *string == '/')
  211.     return strsave (string);
  212.  
  213.   strcpy (current_path, dot_path);
  214.  
  215.   if (! current_path[0])
  216.     strcpy (current_path, "./");
  217.  
  218.   cp = current_path + (strlen (current_path) - 1);
  219.  
  220.   if (*cp++ != '/')
  221.     *cp++ = '/';
  222.  
  223.   *cp = '\0';
  224.  
  225.   while (*string)
  226.     {
  227.       if (*string == '.')
  228.     {
  229.       if (! string[1])
  230.         return strsave (current_path);
  231.  
  232.       if (string[1] == '/')
  233.         {
  234.           string += 2;
  235.           continue;
  236.         }
  237.  
  238.       if (string[1] == '.' && (string[2] == '/' || ! string[2]))
  239.         {
  240.           string += 2;
  241.  
  242.           if (*string)
  243.         string++;
  244.  
  245.           pathname_backup (current_path, 1);
  246.           cp = current_path + strlen (current_path);
  247.           continue;
  248.         }
  249.     }
  250.  
  251.       while (*string && *string != '/')
  252.     *cp++ = *string++;
  253.  
  254.       if (*string)
  255.     *cp++ = *string++;
  256.  
  257.       *cp = '\0';
  258.     }
  259.   return strsave (current_path);
  260. }
  261.  
  262. // Has file `A' been modified after time `T'?
  263. //
  264. // case:
  265. //
  266. //   a newer than t         returns    1
  267. //   a older than t         returns    0
  268. //   stat on a fails        returns   -1
  269.  
  270. int
  271. is_newer (const char *fa, time_t t)
  272. {
  273.   struct stat fa_sb;
  274.   register int fa_stat;
  275.   register int status = 0;
  276.  
  277.   fa_stat = stat (fa, &fa_sb);
  278.   if (fa_stat != 0)
  279.     status = -1;
  280.  
  281.   if (status != 0)
  282.     return status;
  283.  
  284.   return (fa_sb.st_mtime > t);
  285. }
  286.  
  287. // Return a consed string which is the current working directory.
  288. // FOR_WHOM is the name of the caller for error printing.
  289.  
  290. char *
  291. get_working_directory (const char *for_whom)
  292. {
  293.   if (! follow_symbolic_links)
  294.     {
  295.       if (the_current_working_directory)
  296.     delete [] the_current_working_directory;
  297.  
  298.       the_current_working_directory = 0;
  299.     }
  300.  
  301.   if (! the_current_working_directory)
  302.     {
  303.       char *directory;
  304.  
  305.       the_current_working_directory = new char [MAXPATHLEN];
  306.       directory = octave_getcwd (the_current_working_directory, MAXPATHLEN);
  307.       if (! directory)
  308.     {
  309.       message (for_whom, the_current_working_directory);
  310.       delete [] the_current_working_directory;
  311.       the_current_working_directory = 0;
  312.       return 0;
  313.     }
  314.     }
  315.  
  316.   return the_current_working_directory;
  317. }
  318.  
  319. // Do the work of changing to the directory NEWDIR.  Handle symbolic
  320. // link following, etc.
  321.  
  322. static int
  323. change_to_directory (const char *newdir)
  324. {
  325.   char *t;
  326.  
  327.   if (follow_symbolic_links)
  328.     {
  329.       if (! the_current_working_directory)
  330.     get_working_directory ("cd_links");
  331.  
  332.       if (the_current_working_directory)
  333.     t = make_absolute (newdir, the_current_working_directory);
  334.       else
  335.     t = strsave (newdir);
  336.  
  337. // Get rid of trailing `/'.
  338.       {
  339.     register int len_t = strlen (t);
  340.     if (len_t > 1)
  341.       {
  342.         --len_t;
  343.         if (t[len_t] == '/')
  344.           t[len_t] = '\0';
  345.       }
  346.       }
  347.  
  348.       if (octave_chdir (t) < 0)
  349.     {
  350.       delete [] t;
  351.       return 0;
  352.     }
  353.  
  354.       if (the_current_working_directory)
  355.     strcpy (the_current_working_directory, t);
  356.  
  357.       delete [] t;
  358.       return 1;
  359.     }
  360.   else
  361.     {
  362.       if (octave_chdir (newdir) < 0)
  363.     return 0;
  364.       else
  365.     return 1;
  366.     }
  367. }
  368.  
  369. DEFUN_TEXT ("cd", Fcd, Scd, 2, 1,
  370.   "cd [dir]\n\
  371. \n\
  372. change current working directory\n\
  373. if no arguments are given, the current directory is changed to the\n\
  374. users home directory")
  375. {
  376.   Octave_object retval;
  377.  
  378.   DEFINE_ARGV("cd");
  379.  
  380.   if (argc > 1)
  381.     {
  382.       static char *dirname = 0;
  383.  
  384.       if (dirname)
  385.     free (dirname);
  386.  
  387.       dirname = tilde_expand (argv[1]);
  388.  
  389.       if (dirname && ! change_to_directory (dirname))
  390.     {
  391.       error ("%s: %s", dirname, strerror (errno));
  392.       DELETE_ARGV;
  393.       return retval;
  394.     }
  395.     }
  396.   else
  397.     {
  398.       if (!home_directory)
  399.     {
  400.       DELETE_ARGV;
  401.       return retval;
  402.     }
  403.  
  404.       if (!change_to_directory (home_directory))
  405.     {
  406.           error ("%s: %s", home_directory, strerror (errno));
  407.       DELETE_ARGV;
  408.       return retval;
  409.     }
  410.     }
  411.  
  412.  
  413.   char *directory = get_working_directory ("cd");
  414.   tree_constant *dir = new tree_constant (directory);
  415.   bind_builtin_variable ("PWD", dir, 1);
  416.  
  417.   DELETE_ARGV;
  418.  
  419.   return retval;
  420. }
  421.  
  422. DEFALIAS (chdir, cd);
  423.  
  424. // Get a directory listing.
  425.  
  426. DEFUN_TEXT ("ls", Fls, Sls, -1, 1,
  427.   "ls [options]\n\
  428. \n\
  429. print a directory listing")
  430. {
  431.   Octave_object retval;
  432.  
  433.   DEFINE_ARGV("ls");
  434.  
  435.   ostrstream ls_buf;
  436.  
  437.   ls_buf << "ls -C ";
  438.   for (int i = 1; i < argc; i++)
  439.     ls_buf << tilde_expand (argv[i]) << " ";
  440.  
  441.   ls_buf << ends;
  442.  
  443.   char *ls_command = ls_buf.str ();
  444.  
  445.   iprocstream cmd (ls_command);
  446.  
  447.   char ch;
  448.   ostrstream output_buf;
  449.   while (cmd.get (ch))
  450.     output_buf.put (ch);
  451.  
  452.   output_buf << ends;
  453.  
  454.   maybe_page_output (output_buf);
  455.   
  456.   delete [] ls_command;
  457.  
  458.   DELETE_ARGV;
  459.  
  460.   return retval;
  461. }
  462.  
  463. DEFALIAS (dir, ls);
  464.  
  465. DEFUN ("pwd", Fpwd, Spwd, 1, 0,
  466.   "pwd (): print current working directory")
  467. {
  468.   Octave_object retval;
  469.   char *directory;
  470.  
  471.   if (verbatim_pwd)
  472.     {
  473.       char *buffer = new char [MAXPATHLEN];
  474.       directory = octave_getcwd (buffer, MAXPATHLEN);
  475.  
  476.       if (!directory)
  477.     {
  478.       warning ("pwd: can't find working directory!");
  479.       delete buffer;
  480.     }
  481.     }
  482.   else
  483.     {
  484.       directory = get_working_directory ("pwd");
  485.     }
  486.  
  487.   if (directory)
  488.     {
  489.       char *s = strconcat (directory, "\n");
  490.       retval = s;
  491.       delete [] s;
  492.     }
  493.   return retval;
  494. }
  495.  
  496. /*
  497. ;;; Local Variables: ***
  498. ;;; mode: C++ ***
  499. ;;; page-delimiter: "^/\\*" ***
  500. ;;; End: ***
  501. */
  502.