core/vul/vul_temp_filename.cxx
Go to the documentation of this file.
00001 // This is core/vul/vul_temp_filename.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 
00006 #include "vul_temp_filename.h"
00007 #include <vcl_string.h>
00008 #include <vcl_ctime.h>
00009 #include <vcl_cstdlib.h> // for rand/srand
00010 
00011 #if defined(VCL_BORLAND) || defined (VCL_VC) || defined(__MINGW32__)
00012 # include <vcl_cstdio.h> // for _tempnam on borland (and stlport5 with VC8)
00013 # include <Windows.h>
00014 #else
00015 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
00016   // Helper functions for Unix
00017 
00018   #include <stdio.h>  // for P_tmpdir
00019   #include <unistd.h> // for unlink
00020   #include <fcntl.h>  // for O_CREATE,...
00021 
00022   namespace {
00023     // The filename is okay if it doesn't exist and can be opened for
00024     // writing.
00025     bool is_okay( const vcl_string& name )
00026     {
00027       bool okay = true;
00028       int fd = open( name.c_str(), O_CREAT|O_EXCL, 0600 );
00029       if ( fd == -1 ) {
00030         okay = false;
00031       } else {
00032         unlink( name.c_str() );
00033         close( fd );
00034       }
00035       return okay;
00036     }
00037 
00038 
00039     // Initialise the random number seed with the time.  Maybe need to
00040     // include things like (Unix) process id, but I don't think the
00041     // randomness is that crucial.
00042     int init_randomizer()
00043     {
00044       vcl_srand( vcl_time( 0 ) );
00045       return 0;
00046     }
00047     static int random_seed_trigger = init_randomizer();
00048 
00049     char random_letter()
00050     {
00051       // Make sure the random character is a letter.
00052       int r = vcl_rand() % (26+26); // 26 uppercase and 26 lowercase letters
00053       return (r<26) ? char('A'+r) : char('a'+r-26);
00054     }
00055 
00056     char random_char()
00057     {
00058       // Make sure the random character is a letter or number.
00059       int r = vcl_rand() % (26+26+10); // 2x26 letters, 10 digits
00060       return (r<26) ? char('A'+r) : (r<52) ? char('a'+r-26) : char('0'+r-52);
00061     }
00062   }
00063 #else
00064 # warning "This is neither unix nor MS-windows - please add specifics to " __FILE__
00065 #endif
00066 #endif
00067 
00068 vcl_string
00069 vul_temp_filename( )
00070 {
00071 #if defined(VCL_VC) || defined(VCL_BORLAND) || defined(__MINGW32__)
00072   char path[ _MAX_PATH ];
00073   char* file;
00074   if ( GetTempPath( _MAX_PATH, path ) == 0 )
00075     return "";
00076   // Can't use GetTempFileName, because the function actually creates the
00077   // temporary file! This would mean that every call to this function creates
00078   // yet another file that will lie around if the caller doesn't use the generated
00079   // filename. And I don't trust the implementation enough to just unlink the file
00080   // before returning.
00081 # if defined(VCL_BORLAND_56)
00082   file = std::_tempnam( path, "" );
00083 # else
00084   file = _tempnam( path, "" );
00085 # endif
00086   if ( file == 0 )
00087     return "";
00088   return file;
00089 #else
00090 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
00091   // Don't use tmpnam, since it causes linker warnings (and sometimes
00092   // linker errors). Instead reimplement. Sigh.
00093   const unsigned int num_char_in_filename = 7+1; // should always be at least 1
00094   vcl_string filename;
00095   vcl_string tempdir;
00096   unsigned int count = 0;
00097   bool okay = false;
00098 
00099   if ( vcl_getenv( "TMP" ) ) {
00100     tempdir = vcl_getenv( "TMP" );
00101   } else {
00102     tempdir = P_tmpdir; // defined in stdio.h
00103   }
00104   char lastchar = ( tempdir.size() > 0 ) ? tempdir[tempdir.size()-1] : ' ';
00105   if (lastchar != '/' && lastchar != '\\')
00106     tempdir += "/";
00107 
00108   while ( !okay && count < 10 ) {
00109     char buf[ num_char_in_filename+1 ];
00110     buf[0] = random_letter(); // make sure first char is a letter
00111     for ( unsigned int i=1; i < num_char_in_filename; ++i )
00112       buf[i] = random_char();
00113     buf[num_char_in_filename] = '\0';
00114     filename = tempdir + buf;
00115     ++count;
00116     okay = is_okay( filename );
00117   };
00118 
00119   if ( okay )
00120     return filename;
00121   else
00122     return "";
00123 #else
00124 # warning "This is neither unix nor MS-windows - please add specifics to " __FILE__
00125 #endif
00126 #endif
00127 }