LCOV - code coverage report
Current view: directory - port - cpl_path.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 263 213 81.0 %
Date: 2012-12-26 Functions: 18 16 88.9 %

       1                 : /**********************************************************************
       2                 :  * $Id: cpl_path.cpp 25181 2012-10-27 11:52:46Z rouault $
       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 25181 2012-10-27 11:52:46Z rouault $");
      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          510616 : static char *CPLGetStaticResult()
      61                 : 
      62                 : {
      63          510616 :     char *pachBufRingInfo = (char *) CPLGetTLS( CTLS_PATHBUF );
      64          510616 :     if( pachBufRingInfo == NULL )
      65                 :     {
      66             712 :         pachBufRingInfo = (char *) CPLCalloc(1, sizeof(int) + CPL_PATH_BUF_SIZE * CPL_PATH_BUF_COUNT);
      67             712 :         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          510616 :     int *pnBufIndex = (int *) pachBufRingInfo;
      75          510616 :     int nOffset = sizeof(int) + *pnBufIndex * CPL_PATH_BUF_SIZE;
      76          510616 :     char *pachBuffer = pachBufRingInfo + nOffset;
      77                 : 
      78          510616 :     *pnBufIndex = (*pnBufIndex + 1) % CPL_PATH_BUF_COUNT;
      79                 : 
      80          510616 :     return pachBuffer;
      81                 : }
      82                 : 
      83                 : 
      84                 : /************************************************************************/
      85                 : /*                        CPLFindFilenameStart()                        */
      86                 : /************************************************************************/
      87                 : 
      88          504174 : static int CPLFindFilenameStart( const char * pszFilename )
      89                 : 
      90                 : {
      91                 :     size_t  iFileStart;
      92                 : 
      93        12274387 :     for( iFileStart = strlen(pszFilename);
      94                 :          iFileStart > 0
      95         6100640 :              && pszFilename[iFileStart-1] != '/'
      96         5669573 :              && pszFilename[iFileStart-1] != '\\';
      97                 :          iFileStart-- ) {}
      98                 : 
      99          504174 :     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            9495 : const char *CPLGetPath( const char *pszFilename )
     129                 : 
     130                 : {
     131            9495 :     int         iFileStart = CPLFindFilenameStart(pszFilename);
     132            9495 :     char       *pszStaticResult = CPLGetStaticResult();
     133                 : 
     134            9495 :     if( iFileStart >= CPL_PATH_BUF_SIZE )
     135               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     136                 : 
     137            9495 :     CPLAssert( ! (pszFilename >= pszStaticResult && pszFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     138                 : 
     139            9495 :     if( iFileStart == 0 )
     140                 :     {
     141              64 :         strcpy( pszStaticResult, "" );
     142              64 :         return pszStaticResult;
     143                 :     }
     144                 : 
     145            9431 :     CPLStrlcpy( pszStaticResult, pszFilename, iFileStart+1 );
     146                 : 
     147           18862 :     if( iFileStart > 1
     148            9431 :         && (pszStaticResult[iFileStart-1] == '/'
     149               0 :             || pszStaticResult[iFileStart-1] == '\\') )
     150            9431 :         pszStaticResult[iFileStart-1] = '\0';
     151                 : 
     152            9431 :     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            9173 : const char *CPLGetDirname( const char *pszFilename )
     182                 : 
     183                 : {
     184            9173 :     int         iFileStart = CPLFindFilenameStart(pszFilename);
     185            9173 :     char       *pszStaticResult = CPLGetStaticResult();
     186                 : 
     187            9173 :     if( iFileStart >= CPL_PATH_BUF_SIZE )
     188               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     189                 : 
     190            9173 :     CPLAssert( ! (pszFilename >= pszStaticResult && pszFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     191                 : 
     192            9173 :     if( iFileStart == 0 )
     193                 :     {
     194               5 :         strcpy( pszStaticResult, "." );
     195               5 :         return pszStaticResult;
     196                 :     }
     197                 : 
     198            9168 :     CPLStrlcpy( pszStaticResult, pszFilename, iFileStart+1 );
     199                 : 
     200           18337 :     if( iFileStart > 1
     201            9168 :         && (pszStaticResult[iFileStart-1] == '/'
     202               1 :             || pszStaticResult[iFileStart-1] == '\\') )
     203            9168 :         pszStaticResult[iFileStart-1] = '\0';
     204                 : 
     205            9168 :     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           65357 : const char *CPLGetFilename( const char *pszFullFilename )
     231                 : 
     232                 : {
     233           65357 :     int iFileStart = CPLFindFilenameStart( pszFullFilename );
     234                 : 
     235           65357 :     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          272087 : const char *CPLGetBasename( const char *pszFullFilename )
     263                 : 
     264                 : {
     265          272087 :     size_t  iFileStart = CPLFindFilenameStart( pszFullFilename );
     266                 :     size_t  iExtStart, nLength;
     267          272087 :     char    *pszStaticResult = CPLGetStaticResult();
     268                 : 
     269          272087 :     CPLAssert( ! (pszFullFilename >= pszStaticResult && pszFullFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     270                 : 
     271         1631510 :     for( iExtStart = strlen(pszFullFilename);
     272         1359423 :          iExtStart > iFileStart && pszFullFilename[iExtStart] != '.';
     273                 :          iExtStart-- ) {}
     274                 : 
     275          272087 :     if( iExtStart == iFileStart )
     276            1181 :         iExtStart = strlen(pszFullFilename);
     277                 : 
     278          272087 :     nLength = iExtStart - iFileStart;
     279                 : 
     280          272087 :     if (nLength >= CPL_PATH_BUF_SIZE)
     281               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     282                 : 
     283          272087 :     CPLStrlcpy( pszStaticResult, pszFullFilename + iFileStart, nLength + 1 );
     284                 : 
     285          272087 :     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          148062 : const char *CPLGetExtension( const char *pszFullFilename )
     313                 : 
     314                 : {
     315          148062 :     size_t  iFileStart = CPLFindFilenameStart( pszFullFilename );
     316                 :     size_t  iExtStart;
     317          148062 :     char    *pszStaticResult = CPLGetStaticResult();
     318                 : 
     319          148062 :     CPLAssert( ! (pszFullFilename >= pszStaticResult && pszFullFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     320                 : 
     321         1003201 :     for( iExtStart = strlen(pszFullFilename);
     322          855139 :          iExtStart > iFileStart && pszFullFilename[iExtStart] != '.';
     323                 :          iExtStart-- ) {}
     324                 : 
     325          148062 :     if( iExtStart == iFileStart )
     326           83569 :         iExtStart = strlen(pszFullFilename)-1;
     327                 : 
     328          148062 :     if (CPLStrlcpy( pszStaticResult, pszFullFilename+iExtStart+1, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     329               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     330                 : 
     331          148062 :     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           45621 : const char *CPLResetExtension( const char *pszPath, const char *pszExt )
     388                 : 
     389                 : {
     390           45621 :     char    *pszStaticResult = CPLGetStaticResult();
     391                 :     size_t  i;
     392                 : 
     393           45621 :     CPLAssert( ! (pszPath >= pszStaticResult && pszPath < pszStaticResult + CPL_PATH_BUF_SIZE) );
     394                 : 
     395                 : /* -------------------------------------------------------------------- */
     396                 : /*      First, try and strip off any existing extension.                */
     397                 : /* -------------------------------------------------------------------- */
     398           45621 :     if (CPLStrlcpy( pszStaticResult, pszPath, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     399               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     400                 : 
     401           45621 :     if (*pszStaticResult)
     402                 :     {
     403          191663 :         for( i = strlen(pszStaticResult) - 1; i > 0; i-- )
     404                 :         {
     405          191294 :             if( pszStaticResult[i] == '.' )
     406                 :             {
     407           42259 :                 pszStaticResult[i] = '\0';
     408           42259 :                 break;
     409                 :             }
     410                 : 
     411          295137 :             if( pszStaticResult[i] == '/' || pszStaticResult[i] == '\\' 
     412          146102 :                 || pszStaticResult[i] == ':' )
     413            2987 :                 break;
     414                 :         }
     415                 :     }
     416                 : 
     417                 : /* -------------------------------------------------------------------- */
     418                 : /*      Append the new extension.                                       */
     419                 : /* -------------------------------------------------------------------- */
     420           45621 :     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           45621 :     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.  Must *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           25652 : const char *CPLFormFilename( const char * pszPath,
     460                 :                              const char * pszBasename,
     461                 :                              const char * pszExtension )
     462                 : 
     463                 : {
     464           25652 :     char *pszStaticResult = CPLGetStaticResult();
     465           25652 :     const char  *pszAddedPathSep = "";
     466           25652 :     const char  *pszAddedExtSep = "";
     467                 : 
     468           25652 :     CPLAssert( ! (pszPath >= pszStaticResult && pszPath < pszStaticResult + CPL_PATH_BUF_SIZE) );
     469           25652 :     CPLAssert( ! (pszBasename >= pszStaticResult && pszBasename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     470                 : 
     471           25652 :     if( pszBasename[0] == '.' && pszBasename[1] == '/' )
     472               0 :         pszBasename += 2;
     473                 : 
     474           25652 :     if( pszPath == NULL )
     475            6383 :         pszPath = "";
     476           57800 :     else if( strlen(pszPath) > 0
     477           19268 :              && pszPath[strlen(pszPath)-1] != '/'
     478           19263 :              && pszPath[strlen(pszPath)-1] != '\\' )
     479                 :     {
     480                 :         /* FIXME? would be better to ask the filesystems what they */
     481                 :         /* prefer as directory separator */
     482           19263 :         if (strncmp(pszPath, "/vsicurl/", 9) == 0)
     483              19 :             pszAddedPathSep = "/";
     484                 :         else
     485           19244 :             pszAddedPathSep = SEP_STRING;
     486                 :     }
     487                 : 
     488           25652 :     if( pszExtension == NULL )
     489           17790 :         pszExtension = "";
     490            7862 :     else if( pszExtension[0] != '.' && strlen(pszExtension) > 0 )
     491            7482 :         pszAddedExtSep = ".";
     492                 : 
     493           25652 :     if (CPLStrlcpy( pszStaticResult, pszPath, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     494                 :         CPLStrlcat( pszStaticResult, pszAddedPathSep, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     495                 :         CPLStrlcat( pszStaticResult, pszBasename, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     496                 :         CPLStrlcat( pszStaticResult, pszAddedExtSep, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE ||
     497                 :         CPLStrlcat( pszStaticResult, pszExtension, CPL_PATH_BUF_SIZE) >= CPL_PATH_BUF_SIZE)
     498               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     499                 : 
     500           25652 :     return pszStaticResult;
     501                 : }
     502                 : 
     503                 : /************************************************************************/
     504                 : /*                          CPLFormCIFilename()                         */
     505                 : /************************************************************************/
     506                 : 
     507                 : /**
     508                 :  * Case insensitive file searching, returing full path.
     509                 :  *
     510                 :  * This function tries to return the path to a file regardless of
     511                 :  * whether the file exactly matches the basename, and extension case, or
     512                 :  * is all upper case, or all lower case.  The path is treated as case 
     513                 :  * sensitive.  This function is equivelent to CPLFormFilename() on 
     514                 :  * case insensitive file systems (like Windows).
     515                 :  *
     516                 :  * @param pszPath directory path to the directory containing the file.  This
     517                 :  * may be relative or absolute, and may have a trailing path separator or
     518                 :  * not.  May be NULL.
     519                 :  *
     520                 :  * @param pszBasename file basename.  May optionally have path and/or
     521                 :  * extension.  May not be NULL. 
     522                 :  *
     523                 :  * @param pszExtension file extension, optionally including the period.  May
     524                 :  * be NULL.
     525                 :  *
     526                 :  * @return a fully formed filename in an internal static string.  Do not
     527                 :  * modify or free the returned string.  The string may be destroyed by the
     528                 :  * next CPL call.
     529                 :  */
     530                 : 
     531            1199 : const char *CPLFormCIFilename( const char * pszPath,
     532                 :                                const char * pszBasename,
     533                 :                                const char * pszExtension )
     534                 : 
     535                 : {
     536                 :     // On case insensitive filesystems, just default to
     537                 :     // CPLFormFilename()
     538            1199 :     if( !VSIIsCaseSensitiveFS(pszPath) )
     539               0 :         return CPLFormFilename( pszPath, pszBasename, pszExtension );
     540                 : 
     541            1199 :     const char  *pszAddedExtSep = "";
     542                 :     char        *pszFilename;
     543                 :     const char  *pszFullPath;
     544            1199 :     int         nLen = strlen(pszBasename)+2, i;
     545                 :     VSIStatBufL sStatBuf;
     546                 :     int         nStatRet;
     547                 : 
     548            1199 :     if( pszExtension != NULL )
     549             995 :         nLen += strlen(pszExtension);
     550                 : 
     551            1199 :     pszFilename = (char *) CPLMalloc(nLen);
     552                 : 
     553            1199 :     if( pszExtension == NULL )
     554             204 :         pszExtension = "";
     555             995 :     else if( pszExtension[0] != '.' && strlen(pszExtension) > 0 )
     556             757 :         pszAddedExtSep = ".";
     557                 : 
     558                 :     sprintf( pszFilename, "%s%s%s", 
     559            1199 :              pszBasename, pszAddedExtSep, pszExtension );
     560                 : 
     561            1199 :     pszFullPath = CPLFormFilename( pszPath, pszFilename, NULL );
     562            1199 :     nStatRet = VSIStatExL( pszFullPath, &sStatBuf, VSI_STAT_EXISTS_FLAG );
     563            1199 :     if( nStatRet != 0 )
     564                 :     {
     565           10033 :         for( i = 0; pszFilename[i] != '\0'; i++ )
     566                 :         {
     567            9155 :             if( islower(pszFilename[i]) )
     568            6200 :                 pszFilename[i] = (char) toupper(pszFilename[i]);
     569                 :         }
     570                 : 
     571             878 :         pszFullPath = CPLFormFilename( pszPath, pszFilename, NULL );
     572             878 :         nStatRet = VSIStatExL( pszFullPath, &sStatBuf, VSI_STAT_EXISTS_FLAG );
     573                 :     }
     574                 : 
     575            1199 :     if( nStatRet != 0 )
     576                 :     {
     577           10017 :         for( i = 0; pszFilename[i] != '\0'; i++ )
     578                 :         {
     579            9141 :             if( isupper(pszFilename[i]) )
     580            7453 :                 pszFilename[i] = (char) tolower(pszFilename[i]);
     581                 :         }
     582                 : 
     583             876 :         pszFullPath = CPLFormFilename( pszPath, pszFilename, NULL );
     584             876 :         nStatRet = VSIStatExL( pszFullPath, &sStatBuf, VSI_STAT_EXISTS_FLAG );
     585                 :     }
     586                 : 
     587            1199 :     if( nStatRet != 0 )
     588             873 :         pszFullPath = CPLFormFilename( pszPath, pszBasename, pszExtension );
     589                 : 
     590            1199 :     CPLFree( pszFilename );
     591                 : 
     592            1199 :     return pszFullPath;
     593                 : }
     594                 : 
     595                 : /************************************************************************/
     596                 : /*                     CPLProjectRelativeFilename()                     */
     597                 : /************************************************************************/
     598                 : 
     599                 : /**
     600                 :  * Find a file relative to a project file. 
     601                 :  *
     602                 :  * Given the path to a "project" directory, and a path to a secondary file
     603                 :  * referenced from that project, build a path to the secondary file
     604                 :  * that the current application can use.  If the secondary path is already
     605                 :  * absolute, rather than relative, then it will be returned unaltered. 
     606                 :  * 
     607                 :  * Examples:
     608                 :  * <pre>
     609                 :  * CPLProjectRelativeFilename("abc/def","tmp/abc.gif") == "abc/def/tmp/abc.gif"
     610                 :  * CPLProjectRelativeFilename("abc/def","/tmp/abc.gif") == "/tmp/abc.gif"
     611                 :  * CPLProjectRelativeFilename("/xy", "abc.gif") == "/xy/abc.gif"
     612                 :  * CPLProjectRelativeFilename("/abc/def","../abc.gif") == "/abc/def/../abc.gif"
     613                 :  * CPLProjectRelativeFilename("C:\WIN","abc.gif") == "C:\WIN\abc.gif"
     614                 :  * </pre>
     615                 :  *
     616                 :  * @param pszProjectDir the directory relative to which the secondary files 
     617                 :  * path should be interpreted.
     618                 :  * @param pszSecondaryFilename the filename (potentially with path) that
     619                 :  * is to be interpreted relative to the project directory.
     620                 :  *
     621                 :  * @return a composed path to the secondary file.  The returned string is
     622                 :  * internal and should not be altered, freed, or depending on past the next
     623                 :  * CPL call. 
     624                 :  */
     625                 : 
     626             519 : const char *CPLProjectRelativeFilename( const char *pszProjectDir, 
     627                 :                                         const char *pszSecondaryFilename )
     628                 : 
     629                 : {
     630             519 :     char *pszStaticResult = CPLGetStaticResult();
     631                 : 
     632             519 :     CPLAssert( ! (pszProjectDir >= pszStaticResult && pszProjectDir < pszStaticResult + CPL_PATH_BUF_SIZE) );
     633             519 :     CPLAssert( ! (pszSecondaryFilename >= pszStaticResult && pszSecondaryFilename < pszStaticResult + CPL_PATH_BUF_SIZE) );
     634                 : 
     635             519 :     if( !CPLIsFilenameRelative( pszSecondaryFilename ) )
     636             100 :         return pszSecondaryFilename;
     637                 : 
     638             419 :     if( pszProjectDir == NULL || strlen(pszProjectDir) == 0 )
     639               0 :         return pszSecondaryFilename;
     640                 : 
     641             419 :     if (CPLStrlcpy( pszStaticResult, pszProjectDir, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     642               0 :         goto error;
     643                 : 
     644             838 :     if( pszProjectDir[strlen(pszProjectDir)-1] != '/' 
     645             419 :         && pszProjectDir[strlen(pszProjectDir)-1] != '\\' )
     646                 :     {
     647                 :         /* FIXME? would be better to ask the filesystems what they */
     648                 :         /* prefer as directory separator */
     649                 :         const char* pszAddedPathSep;
     650             419 :         if (strncmp(pszStaticResult, "/vsicurl/", 9) == 0)
     651               0 :             pszAddedPathSep = "/";
     652                 :         else
     653             419 :             pszAddedPathSep = SEP_STRING;
     654             419 :         if (CPLStrlcat( pszStaticResult, pszAddedPathSep, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     655               0 :             goto error;
     656                 :     }
     657                 : 
     658             419 :     if (CPLStrlcat( pszStaticResult, pszSecondaryFilename, CPL_PATH_BUF_SIZE ) >= CPL_PATH_BUF_SIZE)
     659               0 :         goto error;
     660                 : 
     661             419 :     return pszStaticResult;
     662                 : error:
     663               0 :     return CPLStaticBufferTooSmall(pszStaticResult);
     664                 : }
     665                 : 
     666                 : 
     667                 : /************************************************************************/
     668                 : /*                       CPLIsFilenameRelative()                        */
     669                 : /************************************************************************/
     670                 : 
     671                 : /**
     672                 :  * Is filename relative or absolute?
     673                 :  *
     674                 :  * The test is filesystem convention agnostic.  That is it will test for
     675                 :  * Unix style and windows style path conventions regardless of the actual
     676                 :  * system in use.  
     677                 :  *
     678                 :  * @param pszFilename the filename with path to test.
     679                 :  *
     680                 :  * @return TRUE if the filename is relative or FALSE if it is absolute. 
     681                 :  */
     682                 : 
     683             747 : int CPLIsFilenameRelative( const char *pszFilename )
     684                 : 
     685                 : {
     686            2241 :     if( (strlen(pszFilename) > 2
     687                 :          && (strncmp(pszFilename+1,":\\",2) == 0
     688                 :              || strncmp(pszFilename+1,":/",2) == 0))
     689             747 :         || pszFilename[0] == '\\'
     690             747 :         || pszFilename[0] == '/' )
     691             100 :         return FALSE;
     692                 :     else
     693             647 :         return TRUE;
     694                 : }
     695                 : 
     696                 : /************************************************************************/
     697                 : /*                       CPLExtractRelativePath()                       */
     698                 : /************************************************************************/
     699                 : 
     700                 : /**
     701                 :  * Get relative path from directory to target file.
     702                 :  *
     703                 :  * Computes a relative path for pszTarget relative to pszBaseDir. 
     704                 :  * Currently this only works if they share a common base path.  The returned
     705                 :  * path is normally into the pszTarget string.  It should only be considered
     706                 :  * valid as long as pszTarget is valid or till the next call to 
     707                 :  * this function, whichever comes first. 
     708                 :  *
     709                 :  * @param pszBaseDir the name of the directory relative to which the path 
     710                 :  * should be computed.  pszBaseDir may be NULL in which case the original
     711                 :  * target is returned without relitivizing.
     712                 :  * 
     713                 :  * @param pszTarget the filename to be changed to be relative to pszBaseDir.
     714                 :  *
     715                 :  * @param pbGotRelative Pointer to location in which a flag is placed 
     716                 :  * indicating that the returned path is relative to the basename (TRUE) or
     717                 :  * not (FALSE).  This pointer may be NULL if flag is not desired.
     718                 :  *
     719                 :  * @return an adjusted path or the original if it could not be made relative
     720                 :  * to the pszBaseFile's path. 
     721                 :  **/
     722                 : 
     723             203 : const char *CPLExtractRelativePath( const char *pszBaseDir, 
     724                 :                                     const char *pszTarget,
     725                 :                                     int *pbGotRelative )
     726                 : 
     727                 : {
     728                 :     size_t nBasePathLen;
     729                 : 
     730                 : /* -------------------------------------------------------------------- */
     731                 : /*      If we don't have a basedir, then we can't relativize the path.  */
     732                 : /* -------------------------------------------------------------------- */
     733             203 :     if( pszBaseDir == NULL )
     734                 :     {
     735               0 :         if( pbGotRelative != NULL )
     736               0 :             *pbGotRelative = FALSE;
     737                 : 
     738               0 :         return pszTarget;
     739                 :     }
     740                 : 
     741             203 :     nBasePathLen = strlen(pszBaseDir);
     742                 : 
     743                 : /* -------------------------------------------------------------------- */
     744                 : /*      One simple case is when the base dir is '.' and the target      */
     745                 : /*      filename is relative.                                           */
     746                 : /* -------------------------------------------------------------------- */
     747             203 :     if( (nBasePathLen == 0 || EQUAL(pszBaseDir,"."))
     748                 :         && CPLIsFilenameRelative(pszTarget) )
     749                 :     {
     750               0 :         if( pbGotRelative != NULL )
     751               0 :             *pbGotRelative = TRUE;
     752                 : 
     753               0 :         return pszTarget;
     754                 :     }
     755                 : 
     756                 : /* -------------------------------------------------------------------- */
     757                 : /*      By this point, if we don't have a base path, we can't have a    */
     758                 : /*      meaningful common prefix.                                       */
     759                 : /* -------------------------------------------------------------------- */
     760             203 :     if( nBasePathLen == 0 )
     761                 :     {
     762               0 :         if( pbGotRelative != NULL )
     763               0 :             *pbGotRelative = FALSE;
     764                 : 
     765               0 :         return pszTarget;
     766                 :     }
     767                 : 
     768                 : /* -------------------------------------------------------------------- */
     769                 : /*      If we don't have a common path prefix, then we can't get a      */
     770                 : /*      relative path.                                                  */
     771                 : /* -------------------------------------------------------------------- */
     772             327 :     if( !EQUALN(pszBaseDir,pszTarget,nBasePathLen) 
     773              62 :         || (pszTarget[nBasePathLen] != '\\' 
     774              62 :             && pszTarget[nBasePathLen] != '/') )
     775                 :     {
     776             141 :         if( pbGotRelative != NULL )
     777             141 :             *pbGotRelative = FALSE;
     778                 : 
     779             141 :         return pszTarget;
     780                 :     }
     781                 : 
     782                 : /* -------------------------------------------------------------------- */
     783                 : /*      We have a relative path.  Strip it off to get a string to       */
     784                 : /*      return.                                                         */
     785                 : /* -------------------------------------------------------------------- */
     786              62 :     if( pbGotRelative != NULL )
     787              62 :         *pbGotRelative = TRUE;
     788                 : 
     789              62 :     return pszTarget + nBasePathLen + 1;
     790                 : }
     791                 : 
     792                 : /************************************************************************/
     793                 : /*                            CPLCleanTrailingSlash()                   */
     794                 : /************************************************************************/
     795                 : 
     796                 : /**
     797                 :  * Remove trailing forward/backward slash from the path for unix/windows resp.
     798                 :  *
     799                 :  * Returns a string containing the portion of the passed path string with 
     800                 :  * trailing slash removed. If there is no path in the passed filename 
     801                 :  * an empty string will be returned (not NULL).
     802                 :  *
     803                 :  * <pre>
     804                 :  * CPLCleanTrailingSlash( "abc/def/" ) == "abc/def"
     805                 :  * CPLCleanTrailingSlash( "abc/def" ) == "abc/def"
     806                 :  * CPLCleanTrailingSlash( "c:\abc\def\" ) == "c:\abc\def"
     807                 :  * CPLCleanTrailingSlash( "c:\abc\def" ) == "c:\abc\def"
     808                 :  * CPLCleanTrailingSlash( "abc" ) == "abc"
     809                 :  * </pre>
     810                 :  *
     811                 :  * @param pszPath the path to be cleaned up
     812                 :  *
     813                 :  *  @return Path in an internal string which must not be freed.  The string
     814                 :  * may be destroyed by the next CPL filename handling call.
     815                 :  */
     816                 : 
     817               7 : const char *CPLCleanTrailingSlash( const char *pszPath )
     818                 : 
     819                 : {
     820               7 :     char       *pszStaticResult = CPLGetStaticResult();
     821               7 :     int        iPathLength = strlen(pszPath);
     822                 : 
     823               7 :     CPLAssert( ! (pszPath >= pszStaticResult && pszPath < pszStaticResult + CPL_PATH_BUF_SIZE) );
     824                 : 
     825               7 :     if (iPathLength >= CPL_PATH_BUF_SIZE)
     826               0 :         return CPLStaticBufferTooSmall(pszStaticResult);
     827                 : 
     828               7 :     CPLStrlcpy( pszStaticResult, pszPath, iPathLength+1 );
     829                 : 
     830              21 :     if( iPathLength > 0 
     831               7 :         && (pszStaticResult[iPathLength-1] == '\\' 
     832               7 :             || pszStaticResult[iPathLength-1] == '/'))
     833               0 :         pszStaticResult[iPathLength-1] = '\0';
     834                 : 
     835               7 :     return pszStaticResult;
     836                 : }
     837                 : 
     838                 : /************************************************************************/
     839                 : /*                       CPLCorrespondingPaths()                        */
     840                 : /************************************************************************/
     841                 : 
     842                 : /**
     843                 :  * Identify corresponding paths.
     844                 :  *
     845                 :  * Given a prototype old and new filename this function will attempt
     846                 :  * to determine corresponding names for a set of other old filenames that
     847                 :  * will rename them in a similar manner.  This correspondance assumes there
     848                 :  * are two possibly kinds of renaming going on.  A change of path, and a 
     849                 :  * change of filename stem. 
     850                 :  * 
     851                 :  * If a consistent renaming cannot be established for all the files this
     852                 :  * function will return indicating an error.  
     853                 :  *
     854                 :  * The returned file list becomes owned by the caller and should be destroyed
     855                 :  * with CSLDestroy(). 
     856                 :  *
     857                 :  * @param pszOldFilename path to old prototype file. 
     858                 :  * @param pszNewFilename path to new prototype file. 
     859                 :  * @param papszFileList list of other files associated with pszOldFilename to 
     860                 :  * rename similarly.
     861                 :  * 
     862                 :  * @return a list of files corresponding to papszFileList but renamed to 
     863                 :  * correspond to pszNewFilename.
     864                 :  */
     865                 : 
     866               2 : char **CPLCorrespondingPaths( const char *pszOldFilename, 
     867                 :                               const char *pszNewFilename, 
     868                 :                               char **papszFileList )
     869                 : 
     870                 : {
     871               2 :     CPLString osOldPath = CPLGetPath( pszOldFilename );
     872               2 :     CPLString osNewPath = CPLGetPath( pszNewFilename );
     873               2 :     CPLString osOldBasename = CPLGetBasename( pszOldFilename );
     874               2 :     CPLString osNewBasename = CPLGetBasename( pszNewFilename );
     875                 :     int i;
     876                 : 
     877               2 :     if( CSLCount(papszFileList) == 0 )
     878               0 :         return NULL;
     879                 : 
     880                 : /* -------------------------------------------------------------------- */
     881                 : /*      There is a special case for a one item list which exactly       */
     882                 : /*      matches the old name, to rename to the new name.                */
     883                 : /* -------------------------------------------------------------------- */
     884               2 :     if( CSLCount(papszFileList) == 1 
     885               0 :         && strcmp(pszOldFilename,papszFileList[0]) == 0 )
     886                 :     {
     887               0 :         return CSLAddString( NULL, pszNewFilename );
     888                 :     }
     889                 : 
     890                 : /* -------------------------------------------------------------------- */
     891                 : /*      If the basename is changing, verify that all source files       */
     892                 : /*      have the same starting basename.                                */
     893                 : /* -------------------------------------------------------------------- */
     894               2 :     if( osOldBasename != osNewBasename )
     895                 :     {
     896               2 :         for( i=0; papszFileList[i] != NULL; i++ )
     897                 :         {
     898               8 :             if( osOldBasename == CPLGetBasename( papszFileList[i] ) )
     899               8 :                 continue;
     900                 : 
     901               0 :             CPLString osFilePath, osFileName;
     902                 : 
     903               0 :             osFilePath = CPLGetPath( papszFileList[i] );
     904               0 :             osFileName = CPLGetFilename( papszFileList[i] );
     905                 : 
     906               0 :             if( !EQUALN(osFileName,osOldBasename,osOldBasename.size())
     907                 :                 || !EQUAL(osFilePath,osOldPath)
     908                 :                 || osFileName[osOldBasename.size()] != '.' )
     909                 :             {
     910                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     911               0 :                           "Unable to rename fileset due irregular basenames.");
     912               0 :                 return NULL;
     913                 :             }
     914                 :         }
     915                 :     }
     916                 : 
     917                 : /* -------------------------------------------------------------------- */
     918                 : /*      If the filename portions differs, ensure they only differ in    */
     919                 : /*      basename.                                                       */
     920                 : /* -------------------------------------------------------------------- */
     921               2 :     if( osOldBasename != osNewBasename )
     922                 :     {
     923                 :         CPLString osOldExtra = CPLGetFilename(pszOldFilename) 
     924               2 :             + strlen(osOldBasename);
     925                 :         CPLString osNewExtra = CPLGetFilename(pszNewFilename) 
     926               2 :             + strlen(osNewBasename);
     927                 : 
     928               2 :         if( osOldExtra != osNewExtra )
     929                 :         {
     930                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     931               0 :                       "Unable to rename fileset due to irregular filename correspondence." );
     932               0 :             return NULL;
     933               0 :         }
     934                 :     }
     935                 : 
     936                 : /* -------------------------------------------------------------------- */
     937                 : /*      Generate the new filenames.                                     */
     938                 : /* -------------------------------------------------------------------- */
     939               2 :     char **papszNewList = NULL;
     940                 : 
     941              10 :     for( i=0; papszFileList[i] != NULL; i++ )
     942                 :     {
     943               8 :         CPLString osNewFilename;
     944               8 :         CPLString osOldFilename = CPLGetFilename( papszFileList[i] );
     945                 : 
     946               8 :         if( osOldBasename == osNewBasename )
     947                 :             osNewFilename = 
     948               0 :                 CPLFormFilename( osNewPath, osOldFilename, NULL );
     949                 :         else
     950                 :             osNewFilename = 
     951                 :                 CPLFormFilename( osNewPath, osNewBasename, 
     952               8 :                                  osOldFilename.c_str()+strlen(osOldBasename));
     953                 : 
     954               8 :         papszNewList = CSLAddString( papszNewList, osNewFilename );
     955                 :     }
     956                 : 
     957               2 :     return papszNewList;
     958                 : }
     959                 : 
     960                 : /************************************************************************/
     961                 : /*                      CPLGenerateTempFilename()                       */
     962                 : /************************************************************************/
     963                 : 
     964                 : /**
     965                 :  * Generate temporary file name.
     966                 :  * 
     967                 :  * Returns a filename that may be used for a temporary file.  The location
     968                 :  * of the file tries to follow operating system semantics but may be
     969                 :  * forced via the CPL_TMPDIR configuration option.  
     970                 :  *
     971                 :  * @param pszStem if non-NULL this will be part of the filename.
     972                 :  * 
     973                 :  * @return a filename which is valid till the next CPL call in this thread.
     974                 :  */
     975                 : 
     976              36 : const char *CPLGenerateTempFilename( const char *pszStem )
     977                 : 
     978                 : {
     979              36 :     const char *pszDir = CPLGetConfigOption( "CPL_TMPDIR", NULL );
     980                 :     static volatile int nTempFileCounter = 0;
     981                 : 
     982              36 :     if( pszDir == NULL )
     983              36 :         pszDir = CPLGetConfigOption( "TMPDIR", NULL );
     984                 : 
     985              36 :     if( pszDir == NULL )
     986              36 :         pszDir = CPLGetConfigOption( "TEMP", NULL );
     987                 : 
     988              36 :     if( pszDir == NULL )
     989              36 :         pszDir = ".";
     990                 : 
     991              36 :     CPLString osFilename;
     992                 : 
     993              36 :     if( pszStem == NULL )
     994              28 :         pszStem = "";
     995                 : 
     996                 :     osFilename.Printf( "%s%u_%d", pszStem, 
     997              36 :                        (int) CPLGetPID(), nTempFileCounter++ );
     998                 : 
     999              36 :     return CPLFormFilename( pszDir, osFilename, NULL );
    1000                 : }

Generated by: LCOV version 1.7