LCOV - code coverage report
Current view: directory - port - cpl_path.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 235 167 71.1 %
Date: 2010-01-09 Functions: 18 15 83.3 %

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

Generated by: LCOV version 1.7