Back to index

tetex-bin  3.0
xgetcwd.c
Go to the documentation of this file.
00001 /* xgetcwd.c: a from-scratch version of getwd.  Ideas from the tcsh 5.20
00002    source, apparently uncopyrighted.
00003 
00004 Copyright (C) 1992, 94, 96 Free Software Foundation, Inc.
00005 
00006 This program is free software; you can redistribute it and/or modify
00007 it under the terms of the GNU General Public License as published by
00008 the Free Software Foundation; either version 2, or (at your option)
00009 any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with this program; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00019 
00020 #include <kpathsea/config.h>
00021 
00022 #if defined (HAVE_GETCWD) || defined (HAVE_GETWD)
00023 #include <kpathsea/c-pathmx.h>
00024 #else /* not HAVE_GETCWD && not HAVE_GETWD*/
00025 #include <kpathsea/c-dir.h>
00026 #include <kpathsea/xopendir.h>
00027 #include <kpathsea/xstat.h>
00028 
00029 
00030 static void
00031 xchdir P1C(string, dirname)
00032 {
00033   if (chdir (dirname) != 0)
00034     FATAL_PERROR (dirname);
00035 }
00036 
00037 #endif /* not HAVE_GETCWD && not HAVE_GETWD */
00038 
00039 
00040 /* Return the pathname of the current directory, or give a fatal error.  */
00041 
00042 string
00043 xgetcwd P1H(void)
00044 {
00045   /* If the system provides getcwd, use it.  If not, use getwd if
00046      available.  But provide a way not to use getcwd: on some systems
00047      getcwd forks, which is expensive and may in fact be impossible for
00048      large programs like tex.  If your system needs this define and it
00049      is not detected by configure, let me know.
00050                                        -- Olaf Weber <infovore@xs4all.nl */
00051 #if defined (HAVE_GETCWD) && !defined (GETCWD_FORKS)
00052   string path = (string)xmalloc (PATH_MAX + 1);
00053   
00054   if (getcwd (path, PATH_MAX + 1) == 0)
00055     {
00056       fprintf (stderr, "getcwd: %s", path);
00057       exit (1);
00058     }
00059   
00060   return path;
00061 #elif defined (HAVE_GETWD)
00062   string path = (string)xmalloc (PATH_MAX + 1);
00063   
00064   if (getwd (path) == 0)
00065     {
00066       fprintf (stderr, "getwd: %s", path);
00067       exit (1);
00068     }
00069   
00070   return path;
00071 #else /* not HAVE_GETCWD && not HAVE_GETWD */
00072   struct stat root_stat, cwd_stat;
00073   string cwd_path = (string)xmalloc (2); /* In case we assign "/" below.  */
00074   
00075   *cwd_path = 0;
00076   
00077   /* Find the inodes of the root and current directories.  */
00078   root_stat = xstat ("/");
00079   cwd_stat = xstat (".");
00080 
00081   /* Go up the directory hierarchy until we get to root, prepending each
00082      directory we pass through to `cwd_path'.  */
00083   while (!SAME_FILE_P (root_stat, cwd_stat))
00084     {
00085       struct dirent *e;
00086       DIR *parent_dir;
00087       boolean found = false;
00088       
00089       xchdir ("..");
00090       parent_dir = xopendir (".");
00091 
00092       /* Look through the parent directory for the entry with the same
00093          inode, so we can get its name.  */
00094       while ((e = readdir (parent_dir)) != NULL && !found)
00095         {
00096           struct stat test_stat;
00097           test_stat = xlstat (e->d_name);
00098           
00099           if (SAME_FILE_P (test_stat, cwd_stat))
00100             {
00101               /* We've found it.  Prepend the pathname.  */
00102               string temp = cwd_path;
00103               cwd_path = concat3 ("/", e->d_name, cwd_path);
00104               free (temp);
00105               
00106               /* Set up to test the next parent.  */
00107               cwd_stat = xstat (".");
00108               
00109               /* Stop reading this directory.  */
00110               found = true;
00111             }
00112         }
00113       if (!found)
00114         FATAL2 ("No inode %d/device %d in parent directory",
00115                 cwd_stat.st_ino, cwd_stat.st_dev);
00116       
00117       xclosedir (parent_dir);
00118     }
00119   
00120   /* If the current directory is the root, cwd_path will be the empty
00121      string, and we will have not gone through the loop.  */
00122   if (*cwd_path == 0)
00123     strcpy (cwd_path, "/");
00124   else
00125     /* Go back to where we were.  */
00126     xchdir (cwd_path);
00127 
00128 #ifdef DOSISH
00129   /* Prepend the drive letter to CWD_PATH, since this technique
00130      never tells us what the drive is.
00131  
00132      Note that on MS-DOS/MS-Windows, the branch that works around
00133      missing `getwd' will probably only work for DJGPP (which does
00134      have `getwd'), because only DJGPP reports meaningful
00135      st_ino numbers.  But someday, somebody might need this...  */
00136   {
00137     char drive[3];
00138     string temp = cwd_path;
00139 
00140     /* Make the drive letter lower-case, unless it is beyond Z: (yes,
00141        there ARE such drives, in case of Novell Netware on MS-DOS).  */
00142     drive[0] = root_stat.st_dev + (root_stat.st_dev < 26 ? 'a' : 'A');
00143     drive[1] = ':';
00144     drive[2] = '\0';
00145 
00146     cwd_path = concat (drive, cwd_path);
00147     free (temp);
00148   }
00149 #endif
00150 
00151   return cwd_path;
00152 #endif /* not HAVE_GETCWD && not HAVE_GETWD */
00153 }