LCOV - code coverage report
Current view: directory - port - cpl_path.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 261 210 80.5 %
Date: 2012-04-28 Functions: 18 16 88.9 %

       1                 : /**********************************************************************
       2                 :  * $Id: cpl_path.cpp 21583 2011-01-27 02:35:12Z warmerdam $
       3                 :  *
       4                 :  * Project:  CPL - Common Portability Library
       5                 :  * Purpose:  Portable filename/path parsing, and forming ala "Glob API".
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  **********************************************************************
       9                 :  * Copyright (c) 1999, Frank Warmerdam
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  * 
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  * 
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22                 :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "cpl_conv.h"
      31                 : #include "cpl_string.h"
      32                 : #include "cpl_multiproc.h"
      33                 : 
      34                 : CPL_CVSID("$Id: cpl_path.cpp 21583 2011-01-27 02:35:12Z warmerdam $");
      35                 : 
      36                 : 
      37                 : /* should be size of larged possible filename */
      38                 : #define CPL_PATH_BUF_SIZE 2048
      39                 : #define CPL_PATH_BUF_COUNT  10
      40                 : 
      41                 : #if defined(WIN32) || defined(WIN32CE)
      42                 : #define SEP_CHAR '\\'
      43                 : #define SEP_STRING "\\"
      44                 : #else
      45                 : #define SEP_CHAR '/'
      46                 : #define SEP_STRING "/"
      47                 : #endif
      48                 : 
      49               0 : static const char* CPLStaticBufferTooSmall(char *pszStaticResult)
      50                 : {
      51               0 :     CPLError(CE_Failure, CPLE_AppDefined, "Destination buffer too small");
      52               0 :     strcpy( pszStaticResult, "" );
      53               0 :     return pszStaticResult;
      54                 : }
      55                 : 
      56                 : /************************************************************************/
      57                 : /*                         CPLGetStaticResult()                         */
      58                 : /************************************************************************/
      59                 : 
      60          943362 : static char *CPLGetStaticResult()
      61                 : 
      62                 : {
      63          943362 :     char *pachBufRingInfo = (char *) CPLGetTLS( CTLS_PATHBUF );
      64          943362 :     if( pachBufRingInfo == NULL )
      65                 :     {
      66            1341 :         pachBufRingInfo = (char *) CPLCalloc(1, sizeof(int) + CPL_PATH_BUF_SIZE * CPL_PATH_BUF_COUNT);
      67            1341 :         CPLSetTLS( CTLS_PATHBUF, pachBufRingInfo, TRUE );
      68                 :     }
      69                 : 
      70                 : /* -------------------------------------------------------------------- */
      71                 : /*      Work out which string in the "ring" we want to use this         */
      72                 : /*      time.                                                           */
      73                 : /* -------------------------------------------------------------------- */
      74          943362 :     int *pnBufIndex = (int *) pachBufRingInfo;
      75          943362 :     int nOffset = sizeof(int) + *pnBufIndex * CPL_PATH_BUF_SIZE;
      76          943362 :     char *pachBuffer = pachBufRingInfo + nOffset;
      77                 : 
      78          943362 :     *pnBufIndex = (*pnBufIndex + 1) % CPL_PATH_BUF_COUNT;
      79                 : 
      80          943362 :     return pachBuffer;
      81                 : }
      82                 : 
      83                 : 
      84                 : /************************************************************************/
      85                 : /*                        CPLFindFilenameStart()                        */
      86                 : /************************************************************************/
      87                 : 
      88          940713 : static int CPLFindFilenameStart( const char * pszFilename )
      89                 : 
      90                 : {
      91                 :     size_t  iFileStart;
      92                 : 
      93        23230154 :     for( iFileStart = strlen(pszFilename);
      94                 :          iFileStart > 0
      95        11550295 :              && pszFilename[iFileStart-1] != '/'
      96        10739146 :              && pszFilename[iFileStart-1] != '\\';
      97                 :          iFileStart-- ) {}
      98                 : 
      99          940713 :     return (int)iFileStart;
     100                 : }
     101                 : 
     102                 : /************************************************************************/
     103                 : /*                             CPLGetPath()                             */
     104                 : /************************************************************************/
     105                 : 
     106                 : /**
     107                 :  * Extract directory path portion of filename.
     108                 :  *
     109                 :  * Returns a string containing the directory path portion of the passed
     110                 :  * filename.  If there is no path in the passed filename an empty string
     111                 :  * will be returned (not NULL).
     112                 :  *
     113                 :  * <pre>
     114                 :  * CPLGetPath( "abc/def.xyz" ) == "abc"
     115                 :  * CPLGetPath( "/abc/def/" ) == "/abc/def"
     116                 :  * CPLGetPath( "/" ) == "/"
     117                 :  * CPLGetPath( "/abc/def" ) == "/abc"
     118                 :  * CPLGetPath( "abc" ) == ""
     119                 :  * </pre>
     120                 :  *
     121                 :  * @param pszFilename the filename potentially including a path.
     122                 :  *
     123                 :  *  @return Path in an internal string which must not be freed.  The string
     124                 :  * may be destroyed by the next CPL filename handling call.  The returned
     125                 :  * will generally not contain a trailing path separator.
     126                 :  */
     127                 : 
     128           12809 : const char *CPLGetPath( const char *pszFilename )
     129                 : 
     130                 : {
     131           12809 :     int         iFileStart = CPLFindFilenameStart(pszFilename);
     132           12809 :     char       *pszStaticResult = CPLGetStaticResult();
     133                 : 
     134           12809 :     if( iFileStart >= CPL_PATH_BUF_SIZE )
     135               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     136                 : 
     137           12809 :     CPLAssert( ! (pszFilename >= pszStaticResult && pszFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     138                 : 
     139           12809 :     if( iFileStart == 0 )
     140                 :     {
     141             128 :         strcpy( pszStaticResult, "" );
     142             128 :         return pszStaticResult;
     143                 :     }
     144                 : 
     145           12681 :     CPLStrlcpy( pszStaticResult, pszFilename, iFileStart+1 );
     146                 : 
     147           25362 :     if( iFileStart > 1
     148           12681 :         && (pszStaticResult[iFileStart-1] == '/'
     149               0 :             || pszStaticResult[iFileStart-1] == '\\') )
     150           12681 :         pszStaticResult[iFileStart-1] = '\0';
     151                 : 
     152           12681 :     return pszStaticResult;
     153                 : }
     154                 : 
     155                 : /************************************************************************/
     156                 : /*                             CPLGetDirname()                          */
     157                 : /************************************************************************/
     158                 : 
     159                 : /**
     160                 :  * Extract directory path portion of filename.
     161                 :  *
     162                 :  * Returns a string containing the directory path portion of the passed
     163                 :  * filename.  If there is no path in the passed filename the dot will be
     164                 :  * returned.  It is the only difference from CPLGetPath().
     165                 :  *
     166                 :  * <pre>
     167                 :  * CPLGetDirname( "abc/def.xyz" ) == "abc"
     168                 :  * CPLGetDirname( "/abc/def/" ) == "/abc/def"
     169                 :  * CPLGetDirname( "/" ) == "/"
     170                 :  * CPLGetDirname( "/abc/def" ) == "/abc"
     171                 :  * CPLGetDirname( "abc" ) == "."
     172                 :  * </pre>
     173                 :  *
     174                 :  * @param pszFilename the filename potentially including a path.
     175                 :  *
     176                 :  * @return Path in an internal string which must not be freed.  The string
     177                 :  * may be destroyed by the next CPL filename handling call.  The returned
     178                 :  * will generally not contain a trailing path separator.
     179                 :  */
     180                 : 
     181           17228 : const char *CPLGetDirname( const char *pszFilename )
     182                 : 
     183                 : {
     184           17228 :     int         iFileStart = CPLFindFilenameStart(pszFilename);
     185           17228 :     char       *pszStaticResult = CPLGetStaticResult();
     186                 : 
     187           17228 :     if( iFileStart >= CPL_PATH_BUF_SIZE )
     188               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     189                 : 
     190           17228 :     CPLAssert( ! (pszFilename >= pszStaticResult && pszFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     191                 : 
     192           17228 :     if( iFileStart == 0 )
     193                 :     {
     194              10 :         strcpy( pszStaticResult, "." );
     195              10 :         return pszStaticResult;
     196                 :     }
     197                 : 
     198           17218 :     CPLStrlcpy( pszStaticResult, pszFilename, iFileStart+1 );
     199                 : 
     200           34438 :     if( iFileStart > 1
     201           17218 :         && (pszStaticResult[iFileStart-1] == '/'
     202               2 :             || pszStaticResult[iFileStart-1] == '\\') )
     203           17218 :         pszStaticResult[iFileStart-1] = '\0';
     204                 : 
     205           17218 :     return pszStaticResult;
     206                 : }
     207                 : 
     208                 : /************************************************************************/
     209                 : /*                           CPLGetFilename()                           */
     210                 : /************************************************************************/
     211                 : 
     212                 : /**
     213                 :  * Extract non-directory portion of filename.
     214                 :  *
     215                 :  * Returns a string containing the bare filename portion of the passed
     216                 :  * filename.  If there is no filename (passed value ends in trailing directory
     217                 :  * separator) an empty string is returned.
     218                 :  *
     219                 :  * <pre>
     220                 :  * CPLGetFilename( "abc/def.xyz" ) == "def.xyz"
     221                 :  * CPLGetFilename( "/abc/def/" ) == ""
     222                 :  * CPLGetFilename( "abc/def" ) == "def"
     223                 :  * </pre>
     224                 :  *
     225                 :  * @param pszFullFilename the full filename potentially including a path.
     226                 :  *
     227                 :  *  @return just the non-directory portion of the path (points back into original string).
     228                 :  */
     229                 : 
     230          123995 : const char *CPLGetFilename( const char *pszFullFilename )
     231                 : 
     232                 : {
     233          123995 :     int iFileStart = CPLFindFilenameStart( pszFullFilename );
     234                 : 
     235          123995 :     return pszFullFilename + iFileStart;
     236                 : }
     237                 : 
     238                 : /************************************************************************/
     239                 : /*                           CPLGetBasename()                           */
     240                 : /************************************************************************/
     241                 : 
     242                 : /**
     243                 :  * Extract basename (non-directory, non-extension) portion of filename.
     244                 :  *
     245                 :  * Returns a string containing the file basename portion of the passed
     246                 :  * name.  If there is no basename (passed value ends in trailing directory
     247                 :  * separator, or filename starts with a dot) an empty string is returned.
     248                 :  *
     249                 :  * <pre>
     250                 :  * CPLGetBasename( "abc/def.xyz" ) == "def"
     251                 :  * CPLGetBasename( "abc/def" ) == "def"
     252                 :  * CPLGetBasename( "abc/def/" ) == ""
     253                 :  * </pre>
     254                 :  *
     255                 :  * @param pszFullFilename the full filename potentially including a path.
     256                 :  *
     257                 :  * @return just the non-directory, non-extension portion of the path in
     258                 :  * an internal string which must not be freed.  The string
     259                 :  * may be destroyed by the next CPL filename handling call.
     260                 :  */
     261                 : 
     262          539984 : const char *CPLGetBasename( const char *pszFullFilename )
     263                 : 
     264                 : {
     265          539984 :     size_t  iFileStart = CPLFindFilenameStart( pszFullFilename );
     266                 :     size_t  iExtStart, nLength;
     267          539984 :     char    *pszStaticResult = CPLGetStaticResult();
     268                 : 
     269          539984 :     CPLAssert( ! (pszFullFilename >= pszStaticResult && pszFullFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     270                 : 
     271         3245558 :     for( iExtStart = strlen(pszFullFilename);
     272         2705574 :          iExtStart > iFileStart && pszFullFilename[iExtStart] != '.';
     273                 :          iExtStart-- ) {}
     274                 : 
     275          539984 :     if( iExtStart == iFileStart )
     276            4746 :         iExtStart = strlen(pszFullFilename);
     277                 : 
     278          539984 :     nLength = iExtStart - iFileStart;
     279                 : 
     280          539984 :     if (nLength >= CPL_PATH_BUF_SIZE)
     281               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     282                 : 
     283          539984 :     CPLStrlcpy( pszStaticResult, pszFullFilename + iFileStart, nLength + 1 );
     284                 : 
     285          539984 :     return pszStaticResult;
     286                 : }
     287                 : 
     288                 : 
     289                 : /************************************************************************/
     290                 : /*                           CPLGetExtension()                          */
     291                 : /************************************************************************/
     292                 : 
     293                 : /**
     294                 :  * Extract filename extension from full filename.
     295                 :  *
     296                 :  * Returns a string containing the extention portion of the passed
     297                 :  * name.  If there is no extension (the filename has no dot) an empty string
     298                 :  * is returned.  The returned extension will not include the period.
     299                 :  *
     300                 :  * <pre>
     301                 :  * CPLGetExtension( "abc/def.xyz" ) == "xyz"
     302                 :  * CPLGetExtension( "abc/def" ) == ""
     303                 :  * </pre>
     304                 :  *
     305                 :  * @param pszFullFilename the full filename potentially including a path.
     306                 :  *
     307                 :  * @return just the extension portion of the path in
     308                 :  * an internal string which must not be freed.  The string
     309                 :  * may be destroyed by the next CPL filename handling call.
     310                 :  */
     311                 : 
     312          246697 : const char *CPLGetExtension( const char *pszFullFilename )
     313                 : 
     314                 : {
     315          246697 :     size_t  iFileStart = CPLFindFilenameStart( pszFullFilename );
     316                 :     size_t  iExtStart;
     317          246697 :     char    *pszStaticResult = CPLGetStaticResult();
     318                 : 
     319          246697 :     CPLAssert( ! (pszFullFilename >= pszStaticResult && pszFullFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     320                 : 
     321         1751717 :     for( iExtStart = strlen(pszFullFilename);
     322         1505020 :          iExtStart > iFileStart && pszFullFilename[iExtStart] != '.';
     323                 :          iExtStart-- ) {}
     324                 : 
     325          246697 :     if( iExtStart == iFileStart )
     326          138986 :         iExtStart = strlen(pszFullFilename)-1;
     327                 : 
     328          246697 :     if (CPLStrlcpy( pszStaticResult, pszFullFilename+iExtStart+1, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     329               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     330                 : 
     331          246697 :     return pszStaticResult;
     332                 : }
     333                 : 
     334                 : /************************************************************************/
     335                 : /*                         CPLGetCurrentDir()                           */
     336                 : /************************************************************************/
     337                 : 
     338                 : /**
     339                 :  * Get the current working directory name.
     340                 :  *
     341                 :  * @return a pointer to buffer, containing current working directory path
     342                 :  * or NULL in case of error.  User is responsible to free that buffer
     343                 :  * after usage with CPLFree() function.
     344                 :  * If HAVE_GETCWD macro is not defined, the function returns NULL.
     345                 :  **/
     346                 : 
     347               0 : char *CPLGetCurrentDir()
     348                 : 
     349                 : {
     350                 :     size_t  nPathMax;
     351                 :     char    *pszDirPath;
     352                 : 
     353                 : # ifdef _MAX_PATH
     354                 :     nPathMax = _MAX_PATH;
     355                 : # elif PATH_MAX
     356               0 :     nPathMax = PATH_MAX;
     357                 : # else
     358                 :     nPathMax = 8192;
     359                 : # endif
     360                 : 
     361               0 :     pszDirPath = (char*)CPLMalloc( nPathMax );
     362               0 :     if ( !pszDirPath )
     363               0 :         return NULL;
     364                 : 
     365                 : #ifdef HAVE_GETCWD
     366               0 :     return getcwd( pszDirPath, nPathMax );
     367                 : #else
     368                 :     return NULL;
     369                 : #endif /* HAVE_GETCWD */
     370                 : }
     371                 : 
     372                 : /************************************************************************/
     373                 : /*                         CPLResetExtension()                          */
     374                 : /************************************************************************/
     375                 : 
     376                 : /**
     377                 :  * Replace the extension with the provided one.
     378                 :  *
     379                 :  * @param pszPath the input path, this string is not altered.
     380                 :  * @param pszExt the new extension to apply to the given path.
     381                 :  *
     382                 :  * @return an altered filename with the new extension.    Do not
     383                 :  * modify or free the returned string.  The string may be destroyed by the
     384                 :  * next CPL call.
     385                 :  */
     386                 : 
     387           83390 : const char *CPLResetExtension( const char *pszPath, const char *pszExt )
     388                 : 
     389                 : {
     390           83390 :     char    *pszStaticResult = CPLGetStaticResult();
     391                 :     size_t  i;
     392                 : 
     393           83390 :     CPLAssert( ! (pszPath >= pszStaticResult && pszPath < pszStaticResult + CPL_PATH_BUF_SIZE) );
     394                 : 
     395                 : /* -------------------------------------------------------------------- */
     396                 : /*      First, try and strip off any existing extension.                */
     397                 : /* -------------------------------------------------------------------- */
     398           83390 :     if (CPLStrlcpy( pszStaticResult, pszPath, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     399               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     400                 : 
     401           83390 :     if (*pszStaticResult)
     402                 :     {
     403          354724 :         for( i = strlen(pszStaticResult) - 1; i > 0; i-- )
     404                 :         {
     405          354044 :             if( pszStaticResult[i] == '.' )
     406                 :             {
     407           74810 :                 pszStaticResult[i] = '\0';
     408           74810 :                 break;
     409                 :             }
     410                 : 
     411          550584 :             if( pszStaticResult[i] == '/' || pszStaticResult[i] == '\\' 
     412          271350 :                 || pszStaticResult[i] == ':' )
     413            7888 :                 break;
     414                 :         }
     415                 :     }
     416                 : 
     417                 : /* -------------------------------------------------------------------- */
     418                 : /*      Append the new extension.                                       */
     419                 : /* -------------------------------------------------------------------- */
     420           83390 :     if (CPLStrlcat( pszStaticResult, ".", CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     421                 :         CPLStrlcat( pszStaticResult, pszExt, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE)
     422               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     423                 : 
     424           83390 :     return pszStaticResult;
     425                 : }
     426                 : 
     427                 : /************************************************************************/
     428                 : /*                          CPLFormFilename()                           */
     429                 : /************************************************************************/
     430                 : 
     431                 : /**
     432                 :  * Build a full file path from a passed path, file basename and extension.
     433                 :  *
     434                 :  * The path, and extension are optional.  The basename may in fact contain
     435                 :  * an extension if desired.
     436                 :  *
     437                 :  * <pre>
     438                 :  * CPLFormFilename("abc/xyz","def", ".dat" ) == "abc/xyz/def.dat"
     439                 :  * CPLFormFilename(NULL,"def", NULL ) == "def"
     440                 :  * CPLFormFilename(NULL,"abc/def.dat", NULL ) == "abc/def.dat"
     441                 :  * CPLFormFilename("/abc/xyz/","def.dat", NULL ) == "/abc/xyz/def.dat"
     442                 :  * </pre>
     443                 :  *
     444                 :  * @param pszPath directory path to the directory containing the file.  This
     445                 :  * may be relative or absolute, and may have a trailing path separator or
     446                 :  * not.  May be NULL.
     447                 :  *
     448                 :  * @param pszBasename file basename.  May optionally have path and/or
     449                 :  * extension.  May not be NULL. 
     450                 :  *
     451                 :  * @param pszExtension file extension, optionally including the period.  May
     452                 :  * be NULL.
     453                 :  *
     454                 :  * @return a fully formed filename in an internal static string.  Do not
     455                 :  * modify or free the returned string.  The string may be destroyed by the
     456                 :  * next CPL call.
     457                 :  */
     458                 : 
     459           42576 : const char *CPLFormFilename( const char * pszPath,
     460                 :                              const char * pszBasename,
     461                 :                              const char * pszExtension )
     462                 : 
     463                 : {
     464           42576 :     char *pszStaticResult = CPLGetStaticResult();
     465           42576 :     const char  *pszAddedPathSep = "";
     466           42576 :     const char  *pszAddedExtSep = "";
     467                 : 
     468           42576 :     CPLAssert( ! (pszPath >= pszStaticResult && pszPath < pszStaticResult + CPL_PATH_BUF_SIZE) );
     469           42576 :     CPLAssert( ! (pszBasename >= pszStaticResult && pszBasename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     470                 : 
     471           42576 :     if( pszPath == NULL )
     472            9906 :         pszPath = "";
     473           98000 :     else if( strlen(pszPath) > 0
     474           32668 :              && pszPath[strlen(pszPath)-1] != '/'
     475           32662 :              && pszPath[strlen(pszPath)-1] != '\\' )
     476                 :     {
     477                 :         /* FIXME? would be better to ask the filesystems what they */
     478                 :         /* prefer as directory separator */
     479           32662 :         if (strncmp(pszPath, "/vsicurl/", 9) == 0)
     480              38 :             pszAddedPathSep = "/";
     481                 :         else
     482           32624 :             pszAddedPathSep = SEP_STRING;
     483                 :     }
     484                 : 
     485           42576 :     if( pszExtension == NULL )
     486           29866 :         pszExtension = "";
     487           12710 :     else if( pszExtension[0] != '.' && strlen(pszExtension) > 0 )
     488           12050 :         pszAddedExtSep = ".";
     489                 : 
     490           42576 :     if (CPLStrlcpy( pszStaticResult, pszPath, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     491                 :         CPLStrlcat( pszStaticResult, pszAddedPathSep, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     492                 :         CPLStrlcat( pszStaticResult, pszBasename, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     493                 :         CPLStrlcat( pszStaticResult, pszAddedExtSep, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     494                 :         CPLStrlcat( pszStaticResult, pszExtension, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE)
     495               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     496                 : 
     497           42576 :     return pszStaticResult;
     498                 : }
     499                 : 
     500                 : /************************************************************************/
     501                 : /*                          CPLFormCIFilename()                         */
     502                 : /************************************************************************/
     503                 : 
     504                 : /**
     505                 :  * Case insensitive file searching, returing full path.
     506                 :  *
     507                 :  * This function tries to return the path to a file regardless of
     508                 :  * whether the file exactly matches the basename, and extension case, or
     509                 :  * is all upper case, or all lower case.  The path is treated as case 
     510                 :  * sensitive.  This function is equivelent to CPLFormFilename() on 
     511                 :  * case insensitive file systems (like Windows).
     512                 :  *
     513                 :  * @param pszPath directory path to the directory containing the file.  This
     514                 :  * may be relative or absolute, and may have a trailing path separator or
     515                 :  * not.  May be NULL.
     516                 :  *
     517                 :  * @param pszBasename file basename.  May optionally have path and/or
     518                 :  * extension.  May not be NULL. 
     519                 :  *
     520                 :  * @param pszExtension file extension, optionally including the period.  May
     521                 :  * be NULL.
     522                 :  *
     523                 :  * @return a fully formed filename in an internal static string.  Do not
     524                 :  * modify or free the returned string.  The string may be destroyed by the
     525                 :  * next CPL call.
     526                 :  */
     527                 : 
     528            2360 : const char *CPLFormCIFilename( const char * pszPath,
     529                 :                                const char * pszBasename,
     530                 :                                const char * pszExtension )
     531                 : 
     532                 : {
     533                 :     // On case insensitive filesystems, just default to
     534                 :     // CPLFormFilename()
     535            2360 :     if( !VSIIsCaseSensitiveFS(pszPath) )
     536               0 :         return CPLFormFilename( pszPath, pszBasename, pszExtension );
     537                 : 
     538            2360 :     const char  *pszAddedExtSep = "";
     539                 :     char        *pszFilename;
     540                 :     const char  *pszFullPath;
     541            2360 :     int         nLen = strlen(pszBasename)+2, i;
     542                 :     VSIStatBufL sStatBuf;
     543                 :     int         nStatRet;
     544                 : 
     545            2360 :     if( pszExtension != NULL )
     546            1964 :         nLen += strlen(pszExtension);
     547                 : 
     548            2360 :     pszFilename = (char *) CPLMalloc(nLen);
     549                 : 
     550            2360 :     if( pszExtension == NULL )
     551             396 :         pszExtension = "";
     552            1964 :     else if( pszExtension[0] != '.' && strlen(pszExtension) > 0 )
     553            1502 :         pszAddedExtSep = ".";
     554                 : 
     555                 :     sprintf( pszFilename, "%s%s%s", 
     556            2360 :              pszBasename, pszAddedExtSep, pszExtension );
     557                 : 
     558            2360 :     pszFullPath = CPLFormFilename( pszPath, pszFilename, NULL );
     559            2360 :     nStatRet = VSIStatExL( pszFullPath, &sStatBuf, VSI_STAT_EXISTS_FLAG );
     560            2360 :     if( nStatRet != 0 )
     561                 :     {
     562           19940 :         for( i = 0; pszFilename[i] != '\0'; i++ )
     563                 :         {
     564           18198 :             if( islower(pszFilename[i]) )
     565           12302 :                 pszFilename[i] = (char) toupper(pszFilename[i]);
     566                 :         }
     567                 : 
     568            1742 :         pszFullPath = CPLFormFilename( pszPath, pszFilename, NULL );
     569            1742 :         nStatRet = VSIStatExL( pszFullPath, &sStatBuf, VSI_STAT_EXISTS_FLAG );
     570                 :     }
     571                 : 
     572            2360 :     if( nStatRet != 0 )
     573                 :     {
     574           19908 :         for( i = 0; pszFilename[i] != '\0'; i++ )
     575                 :         {
     576           18170 :             if( isupper(pszFilename[i]) )
     577           14808 :                 pszFilename[i] = (char) tolower(pszFilename[i]);
     578                 :         }
     579                 : 
     580            1738 :         pszFullPath = CPLFormFilename( pszPath, pszFilename, NULL );
     581            1738 :         nStatRet = VSIStatExL( pszFullPath, &sStatBuf, VSI_STAT_EXISTS_FLAG );
     582                 :     }
     583                 : 
     584            2360 :     if( nStatRet != 0 )
     585            1732 :         pszFullPath = CPLFormFilename( pszPath, pszBasename, pszExtension );
     586                 : 
     587            2360 :     CPLFree( pszFilename );
     588                 : 
     589            2360 :     return pszFullPath;
     590                 : }
     591                 : 
     592                 : /************************************************************************/
     593                 : /*                     CPLProjectRelativeFilename()                     */
     594                 : /************************************************************************/
     595                 : 
     596                 : /**
     597                 :  * Find a file relative to a project file. 
     598                 :  *
     599                 :  * Given the path to a "project" directory, and a path to a secondary file
     600                 :  * referenced from that project, build a path to the secondary file
     601                 :  * that the current application can use.  If the secondary path is already
     602                 :  * absolute, rather than relative, then it will be returned unaltered. 
     603                 :  * 
     604                 :  * Examples:
     605                 :  * <pre>
     606                 :  * CPLProjectRelativeFilename("abc/def","tmp/abc.gif") == "abc/def/tmp/abc.gif"
     607                 :  * CPLProjectRelativeFilename("abc/def","/tmp/abc.gif") == "/tmp/abc.gif"
     608                 :  * CPLProjectRelativeFilename("/xy", "abc.gif") == "/xy/abc.gif"
     609                 :  * CPLProjectRelativeFilename("/abc/def","../abc.gif") == "/abc/def/../abc.gif"
     610                 :  * CPLProjectRelativeFilename("C:\WIN","abc.gif") == "C:\WIN\abc.gif"
     611                 :  * </pre>
     612                 :  *
     613                 :  * @param pszProjectDir the directory relative to which the secondary files 
     614                 :  * path should be interpreted.
     615                 :  * @param pszSecondaryFilename the filename (potentially with path) that
     616                 :  * is to be interpreted relative to the project directory.
     617                 :  *
     618                 :  * @return a composed path to the secondary file.  The returned string is
     619                 :  * internal and should not be altered, freed, or depending on past the next
     620                 :  * CPL call. 
     621                 :  */
     622                 : 
     623             664 : const char *CPLProjectRelativeFilename( const char *pszProjectDir, 
     624                 :                                         const char *pszSecondaryFilename )
     625                 : 
     626                 : {
     627             664 :     char *pszStaticResult = CPLGetStaticResult();
     628                 : 
     629             664 :     CPLAssert( ! (pszProjectDir >= pszStaticResult && pszProjectDir < pszStaticResult + CPL_PATH_BUF_SIZE) );
     630             664 :     CPLAssert( ! (pszSecondaryFilename >= pszStaticResult && pszSecondaryFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     631                 : 
     632             664 :     if( !CPLIsFilenameRelative( pszSecondaryFilename ) )
     633               0 :         return pszSecondaryFilename;
     634                 : 
     635             664 :     if( pszProjectDir == NULL || strlen(pszProjectDir) == 0 )
     636               0 :         return pszSecondaryFilename;
     637                 : 
     638             664 :     if (CPLStrlcpy( pszStaticResult, pszProjectDir, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     639               0 :         goto error;
     640                 : 
     641            1328 :     if( pszProjectDir[strlen(pszProjectDir)-1] != '/' 
     642             664 :         && pszProjectDir[strlen(pszProjectDir)-1] != '\\' )
     643                 :     {
     644                 :         /* FIXME? would be better to ask the filesystems what they */
     645                 :         /* prefer as directory separator */
     646                 :         const char* pszAddedPathSep;
     647             664 :         if (strncmp(pszStaticResult, "/vsicurl/", 9) == 0)
     648               0 :             pszAddedPathSep = "/";
     649                 :         else
     650             664 :             pszAddedPathSep = SEP_STRING;
     651             664 :         if (CPLStrlcat( pszStaticResult, pszAddedPathSep, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     652               0 :             goto error;
     653                 :     }
     654                 : 
     655             664 :     if (CPLStrlcat( pszStaticResult, pszSecondaryFilename, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     656               0 :         goto error;
     657                 : 
     658             664 :     return pszStaticResult;
     659                 : error:
     660               0 :     return CPLStaticBufferTooSmall(pszStaticResult);
     661                 : }
     662                 : 
     663                 : 
     664                 : /************************************************************************/
     665                 : /*                       CPLIsFilenameRelative()                        */
     666                 : /************************************************************************/
     667                 : 
     668                 : /**
     669                 :  * Is filename relative or absolute?
     670                 :  *
     671                 :  * The test is filesystem convention agnostic.  That is it will test for
     672                 :  * Unix style and windows style path conventions regardless of the actual
     673                 :  * system in use.  
     674                 :  *
     675                 :  * @param pszFilename the filename with path to test.
     676                 :  *
     677                 :  * @return TRUE if the filename is relative or FALSE if it is absolute. 
     678                 :  */
     679                 : 
     680            1120 : int CPLIsFilenameRelative( const char *pszFilename )
     681                 : 
     682                 : {
     683            3360 :     if( (strlen(pszFilename) > 2
     684                 :          && (strncmp(pszFilename+1,":\\",2) == 0
     685                 :              || strncmp(pszFilename+1,":/",2) == 0))
     686            1120 :         || pszFilename[0] == '\\'
     687            1120 :         || pszFilename[0] == '/' )
     688               0 :         return FALSE;
     689                 :     else
     690            1120 :         return TRUE;
     691                 : }
     692                 : 
     693                 : /************************************************************************/
     694                 : /*                       CPLExtractRelativePath()                       */
     695                 : /************************************************************************/
     696                 : 
     697                 : /**
     698                 :  * Get relative path from directory to target file.
     699                 :  *
     700                 :  * Computes a relative path for pszTarget relative to pszBaseDir. 
     701                 :  * Currently this only works if they share a common base path.  The returned
     702                 :  * path is normally into the pszTarget string.  It should only be considered
     703                 :  * valid as long as pszTarget is valid or till the next call to 
     704                 :  * this function, whichever comes first. 
     705                 :  *
     706                 :  * @param pszBaseDir the name of the directory relative to which the path 
     707                 :  * should be computed.  pszBaseDir may be NULL in which case the original
     708                 :  * target is returned without relitivizing.
     709                 :  * 
     710                 :  * @param pszTarget the filename to be changed to be relative to pszBaseDir.
     711                 :  *
     712                 :  * @param pbGotRelative Pointer to location in which a flag is placed 
     713                 :  * indicating that the returned path is relative to the basename (TRUE) or
     714                 :  * not (FALSE).  This pointer may be NULL if flag is not desired.
     715                 :  *
     716                 :  * @return an adjusted path or the original if it could not be made relative
     717                 :  * to the pszBaseFile's path. 
     718                 :  **/
     719                 : 
     720             394 : const char *CPLExtractRelativePath( const char *pszBaseDir, 
     721                 :                                     const char *pszTarget,
     722                 :                                     int *pbGotRelative )
     723                 : 
     724                 : {
     725                 :     size_t nBasePathLen;
     726                 : 
     727                 : /* -------------------------------------------------------------------- */
     728                 : /*      If we don't have a basedir, then we can't relativize the path.  */
     729                 : /* -------------------------------------------------------------------- */
     730             394 :     if( pszBaseDir == NULL )
     731                 :     {
     732               0 :         if( pbGotRelative != NULL )
     733               0 :             *pbGotRelative = FALSE;
     734                 : 
     735               0 :         return pszTarget;
     736                 :     }
     737                 : 
     738             394 :     nBasePathLen = strlen(pszBaseDir);
     739                 : 
     740                 : /* -------------------------------------------------------------------- */
     741                 : /*      One simple case is when the base dir is '.' and the target      */
     742                 : /*      filename is relative.                                           */
     743                 : /* -------------------------------------------------------------------- */
     744             394 :     if( (nBasePathLen == 0 || EQUAL(pszBaseDir,"."))
     745                 :         && CPLIsFilenameRelative(pszTarget) )
     746                 :     {
     747               0 :         if( pbGotRelative != NULL )
     748               0 :             *pbGotRelative = TRUE;
     749                 : 
     750               0 :         return pszTarget;
     751                 :     }
     752                 : 
     753                 : /* -------------------------------------------------------------------- */
     754                 : /*      By this point, if we don't have a base path, we can't have a    */
     755                 : /*      meaningful common prefix.                                       */
     756                 : /* -------------------------------------------------------------------- */
     757             394 :     if( nBasePathLen == 0 )
     758                 :     {
     759               0 :         if( pbGotRelative != NULL )
     760               0 :             *pbGotRelative = FALSE;
     761                 : 
     762               0 :         return pszTarget;
     763                 :     }
     764                 : 
     765                 : /* -------------------------------------------------------------------- */
     766                 : /*      If we don't have a common path prefix, then we can't get a      */
     767                 : /*      relative path.                                                  */
     768                 : /* -------------------------------------------------------------------- */
     769             626 :     if( !EQUALN(pszBaseDir,pszTarget,nBasePathLen) 
     770             116 :         || (pszTarget[nBasePathLen] != '\\' 
     771             116 :             && pszTarget[nBasePathLen] != '/') )
     772                 :     {
     773             278 :         if( pbGotRelative != NULL )
     774             278 :             *pbGotRelative = FALSE;
     775                 : 
     776             278 :         return pszTarget;
     777                 :     }
     778                 : 
     779                 : /* -------------------------------------------------------------------- */
     780                 : /*      We have a relative path.  Strip it off to get a string to       */
     781                 : /*      return.                                                         */
     782                 : /* -------------------------------------------------------------------- */
     783             116 :     if( pbGotRelative != NULL )
     784             116 :         *pbGotRelative = TRUE;
     785                 : 
     786             116 :     return pszTarget + nBasePathLen + 1;
     787                 : }
     788                 : 
     789                 : /************************************************************************/
     790                 : /*                            CPLCleanTrailingSlash()                   */
     791                 : /************************************************************************/
     792                 : 
     793                 : /**
     794                 :  * Remove trailing forward/backward slash from the path for unix/windows resp.
     795                 :  *
     796                 :  * Returns a string containing the portion of the passed path string with 
     797                 :  * trailing slash removed. If there is no path in the passed filename 
     798                 :  * an empty string will be returned (not NULL).
     799                 :  *
     800                 :  * <pre>
     801                 :  * CPLCleanTrailingSlash( "abc/def/" ) == "abc/def"
     802                 :  * CPLCleanTrailingSlash( "abc/def" ) == "abc/def"
     803                 :  * CPLCleanTrailingSlash( "c:\abc\def\" ) == "c:\abc\def"
     804                 :  * CPLCleanTrailingSlash( "c:\abc\def" ) == "c:\abc\def"
     805                 :  * CPLCleanTrailingSlash( "abc" ) == "abc"
     806                 :  * </pre>
     807                 :  *
     808                 :  * @param pszPath the path to be cleaned up
     809                 :  *
     810                 :  *  @return Path in an internal string which must not be freed.  The string
     811                 :  * may be destroyed by the next CPL filename handling call.
     812                 :  */
     813                 : 
     814              14 : const char *CPLCleanTrailingSlash( const char *pszPath )
     815                 : 
     816                 : {
     817              14 :     char       *pszStaticResult = CPLGetStaticResult();
     818              14 :     int        iPathLength = strlen(pszPath);
     819                 : 
     820              14 :     CPLAssert( ! (pszPath >= pszStaticResult && pszPath < pszStaticResult + CPL_PATH_BUF_SIZE) );
     821                 : 
     822              14 :     if (iPathLength >= CPL_PATH_BUF_SIZE)
     823               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     824                 : 
     825              14 :     CPLStrlcpy( pszStaticResult, pszPath, iPathLength+1 );
     826                 : 
     827              42 :     if( iPathLength > 0 
     828              14 :         && (pszStaticResult[iPathLength-1] == '\\' 
     829              14 :             || pszStaticResult[iPathLength-1] == '/'))
     830               0 :         pszStaticResult[iPathLength-1] = '\0';
     831                 : 
     832              14 :     return pszStaticResult;
     833                 : }
     834                 : 
     835                 : /************************************************************************/
     836                 : /*                       CPLCorrespondingPaths()                        */
     837                 : /************************************************************************/
     838                 : 
     839                 : /**
     840                 :  * Identify corresponding paths.
     841                 :  *
     842                 :  * Given a prototype old and new filename this function will attempt
     843                 :  * to determine corresponding names for a set of other old filenames that
     844                 :  * will rename them in a similar manner.  This correspondance assumes there
     845                 :  * are two possibly kinds of renaming going on.  A change of path, and a 
     846                 :  * change of filename stem. 
     847                 :  * 
     848                 :  * If a consistent renaming cannot be established for all the files this
     849                 :  * function will return indicating an error.  
     850                 :  *
     851                 :  * The returned file list becomes owned by the caller and should be destroyed
     852                 :  * with CSLDestroy(). 
     853                 :  *
     854                 :  * @param pszOldFilename path to old prototype file. 
     855                 :  * @param pszNewFilename path to new prototype file. 
     856                 :  * @param papszFileList list of other files associated with pszOldFilename to 
     857                 :  * rename similarly.
     858                 :  * 
     859                 :  * @return a list of files corresponding to papszFileList but renamed to 
     860                 :  * correspond to pszNewFilename.
     861                 :  */
     862                 : 
     863               4 : char **CPLCorrespondingPaths( const char *pszOldFilename, 
     864                 :                               const char *pszNewFilename, 
     865                 :                               char **papszFileList )
     866                 : 
     867                 : {
     868               4 :     CPLString osOldPath = CPLGetPath( pszOldFilename );
     869               4 :     CPLString osNewPath = CPLGetPath( pszNewFilename );
     870               4 :     CPLString osOldBasename = CPLGetBasename( pszOldFilename );
     871               4 :     CPLString osNewBasename = CPLGetBasename( pszNewFilename );
     872                 :     int i;
     873                 : 
     874               4 :     if( CSLCount(papszFileList) == 0 )
     875               0 :         return NULL;
     876                 : 
     877                 : /* -------------------------------------------------------------------- */
     878                 : /*      There is a special case for a one item list which exactly       */
     879                 : /*      matches the old name, to rename to the new name.                */
     880                 : /* -------------------------------------------------------------------- */
     881               4 :     if( CSLCount(papszFileList) == 1 
     882               0 :         && strcmp(pszOldFilename,papszFileList[0]) == 0 )
     883                 :     {
     884               0 :         return CSLAddString( NULL, pszNewFilename );
     885                 :     }
     886                 : 
     887                 : /* -------------------------------------------------------------------- */
     888                 : /*      If the basename is changing, verify that all source files       */
     889                 : /*      have the same starting basename.                                */
     890                 : /* -------------------------------------------------------------------- */
     891               4 :     if( osOldBasename != osNewBasename )
     892                 :     {
     893               4 :         for( i=0; papszFileList[i] != NULL; i++ )
     894                 :         {
     895              16 :             if( osOldBasename == CPLGetBasename( papszFileList[i] ) )
     896              16 :                 continue;
     897                 : 
     898               0 :             CPLString osFilePath, osFileName;
     899                 : 
     900               0 :             osFilePath = CPLGetPath( papszFileList[i] );
     901               0 :             osFileName = CPLGetFilename( papszFileList[i] );
     902                 : 
     903               0 :             if( !EQUALN(osFileName,osOldBasename,osOldBasename.size())
     904                 :                 || !EQUAL(osFilePath,osOldPath)
     905                 :                 || osFileName[osOldBasename.size()] != '.' )
     906                 :             {
     907                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     908               0 :                           "Unable to rename fileset due irregular basenames.");
     909               0 :                 return NULL;
     910                 :             }
     911                 :         }
     912                 :     }
     913                 : 
     914                 : /* -------------------------------------------------------------------- */
     915                 : /*      If the filename portions differs, ensure they only differ in    */
     916                 : /*      basename.                                                       */
     917                 : /* -------------------------------------------------------------------- */
     918               4 :     if( osOldBasename != osNewBasename )
     919                 :     {
     920                 :         CPLString osOldExtra = CPLGetFilename(pszOldFilename) 
     921               4 :             + strlen(osOldBasename);
     922                 :         CPLString osNewExtra = CPLGetFilename(pszNewFilename) 
     923               4 :             + strlen(osNewBasename);
     924                 : 
     925               4 :         if( osOldExtra != osNewExtra )
     926                 :         {
     927                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     928               0 :                       "Unable to rename fileset due to irregular filename correspondence." );
     929               0 :             return NULL;
     930               0 :         }
     931                 :     }
     932                 : 
     933                 : /* -------------------------------------------------------------------- */
     934                 : /*      Generate the new filenames.                                     */
     935                 : /* -------------------------------------------------------------------- */
     936               4 :     char **papszNewList = NULL;
     937                 : 
     938              20 :     for( i=0; papszFileList[i] != NULL; i++ )
     939                 :     {
     940              16 :         CPLString osNewFilename;
     941              16 :         CPLString osOldFilename = CPLGetFilename( papszFileList[i] );
     942                 : 
     943              16 :         if( osOldBasename == osNewBasename )
     944                 :             osNewFilename = 
     945               0 :                 CPLFormFilename( osNewPath, osOldFilename, NULL );
     946                 :         else
     947                 :             osNewFilename = 
     948                 :                 CPLFormFilename( osNewPath, osNewBasename, 
     949              16 :                                  osOldFilename.c_str()+strlen(osOldBasename));
     950                 : 
     951              16 :         papszNewList = CSLAddString( papszNewList, osNewFilename );
     952                 :     }
     953                 : 
     954               4 :     return papszNewList;
     955                 : }
     956                 : 
     957                 : /************************************************************************/
     958                 : /*                      CPLGenerateTempFilename()                       */
     959                 : /************************************************************************/
     960                 : 
     961                 : /**
     962                 :  * Generate temporary file name.
     963                 :  * 
     964                 :  * Returns a filename that may be used for a temporary file.  The location
     965                 :  * of the file tries to follow operating system semantics but may be
     966                 :  * forced via the CPL_TMPDIR configuration option.  
     967                 :  *
     968                 :  * @param pszStem if non-NULL this will be part of the filename.
     969                 :  * 
     970                 :  * @return a filename which is valid till the next CPL call in this thread.
     971                 :  */
     972                 : 
     973              72 : const char *CPLGenerateTempFilename( const char *pszStem )
     974                 : 
     975                 : {
     976              72 :     const char *pszDir = CPLGetConfigOption( "CPL_TMPDIR", NULL );
     977                 :     static volatile int nTempFileCounter = 0;
     978                 : 
     979              72 :     if( pszDir == NULL )
     980              72 :         pszDir = CPLGetConfigOption( "TMPDIR", NULL );
     981                 : 
     982              72 :     if( pszDir == NULL )
     983              72 :         pszDir = CPLGetConfigOption( "TEMP", NULL );
     984                 : 
     985              72 :     if( pszDir == NULL )
     986              72 :         pszDir = ".";
     987                 : 
     988              72 :     CPLString osFilename;
     989                 : 
     990              72 :     if( pszStem == NULL )
     991              56 :         pszStem = "";
     992                 : 
     993                 :     osFilename.Printf( "%s%u_%d", pszStem, 
     994              72 :                        (int) CPLGetPID(), nTempFileCounter++ );
     995                 : 
     996              72 :     return CPLFormFilename( pszDir, osFilename, NULL );
     997                 : }

Generated by: LCOV version 1.7