Extract base path from a pathname in C

后端 未结 8 1768
南笙
南笙 2020-12-30 14:21

Question

How do you extract the base path from pathname in C?

Are there any functions built into the C language or the C-Runtime L

相关标签:
8条回答
  • 2020-12-30 15:12

    On Windows there is _splitpath.

    Example

    #include <Windows.h>
    #include <tchar.h>
    
    // Use your own error codes here
    #define SUCCESS                     0L
    #define FAILURE_NULL_ARGUMENT       1L
    #define FAILURE_API_CALL            2L
    #define FAILURE_INSUFFICIENT_BUFFER 3L
    
    DWORD GetBasePathFromPathName( LPCTSTR szPathName,
                                   LPTSTR  szBasePath,
                                   DWORD   dwBasePathSize )
    {
      TCHAR   szDrive[_MAX_DRIVE] = { 0 };
      TCHAR   szDir[_MAX_DIR]     = { 0 };
      TCHAR   szFname[_MAX_FNAME] = { 0 };
      TCHAR   szExt[_MAX_EXT]     = { 0 };
      size_t  PathLength;
      DWORD   dwReturnCode;
    
      // Parameter validation
      if( szPathName == NULL || szBasePath == NULL )
      {
        return FAILURE_NULL_ARGUMENT;
      }
    
      // Split the path into it's components
      dwReturnCode = _tsplitpath_s( szPathName, szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFname, _MAX_FNAME, szExt, _MAX_EXT );
      if( dwReturnCode != 0 )
      {
        _ftprintf( stderr, TEXT("Error splitting path. _tsplitpath_s returned %d.\n"), dwReturnCode );
        return FAILURE_API_CALL;
      }
    
      // Check that the provided buffer is large enough to store the results and a terminal null character
      PathLength = _tcslen( szDrive ) + _tcslen( szDir );
      if( ( PathLength + sizeof( TCHAR ) ) > dwBasePathSize )
      {
        _ftprintf( stderr, TEXT("Insufficient buffer. Required %d. Provided: %d\n"), PathLength, dwBasePathSize );
        return FAILURE_INSUFFICIENT_BUFFER;
      }
    
      // Copy the szDrive and szDir into the provide buffer to form the basepath
      if( ( dwReturnCode = _tcscpy_s( szBasePath, dwBasePathSize, szDrive ) ) != 0 )
      {
        _ftprintf( stderr, TEXT("Error copying string. _tcscpy_s returned %d\n"), dwReturnCode );
        return FAILURE_API_CALL;
      }
      if( ( dwReturnCode = _tcscat_s( szBasePath, dwBasePathSize, szDir ) ) != 0 )
      {
        _ftprintf( stderr, TEXT("Error copying string. _tcscat_s returned %d\n"), dwReturnCode );
        return FAILURE_API_CALL;
      }
      return SUCCESS;
    }
    
    0 讨论(0)
  • 2020-12-30 15:19

    I think the best solution on Windows is to use _splitpath as was suggested, to use something like basename on Linux (more on that here).

    That said, since someone has already suggested implementing my own (and since I had already done it while I was waiting for an answer), here is what I came up with. It is not cross-platform and it does not check for /valid/ paths or expand short or relative path names.

    // Retrieves the pathpath from a pathname.
    //
    // Returns: SUCCESS if the basepath is present and successfully copied to the p_base_path buffer
    //          FAILURE_NULL_ARGUMENT if any arguments are NULL
    //          FAILURE_INVALID_ARGUMENTS if either buffer size is less than 1
    //          FAILURE_BUFFER_TOO_SMALL if the p_basepath buffer is too small
    //          FAILURE_INVALID_PATH if the p_pathname doesn't have a path (e.g. C:, calc.exe, ?qwa)
    //          FAILURE_API_CALL if there is an error from the underlying API calls
    int get_base_path_from_pathname( const char*  const p_pathname,
                                     size_t             pathname_size,
                                     char* const        p_basepath,
                                     size_t             basepath_size );
    
    int get_base_path_from_pathname( const char*  const p_pathname,
                                     size_t             pathname_size,
                                     char* const        p_basepath,
                                     size_t             basepath_size )
    {
      char*  p_end_of_path;
      size_t path_length;
      int    return_code;
    
      // Parameter Validation
      if( p_pathname == NULL || p_basepath == NULL ) { return FAILURE_NULL_ARGUMENT; }
      if( pathname_size < 1 || basepath_size < 1 ) { return FAILURE_INVALID_ARGUMENTS; }
    
      // Returns a pointer to the last occurrence of \ in p_pathname or NULL if it is not found
      p_end_of_path = strrchr( p_pathname, '\\' );
      if( p_end_of_path == NULL )
      {
        // There is no path part
        return FAILURE_INVALID_PATH;
      } 
      else 
      {
        path_length = (size_t)( p_end_of_path - p_pathname + 1 );
    
        // Do some sanity checks on the length
        if( path_length < 1 ) { return FAILURE_INVALID_PATH; }
        if( ( path_length + 1 ) > basepath_size ) { return FAILURE_BUFFER_TOO_SMALL; }
    
        // Copy the base path into the out variable
        if( strncpy( p_basepath, p_pathname, path_length ) != 0 ) { return FAILURE_API_CALL; }
        p_basepath[path_length] = '\0';
      }
    
      return SUCCESS;
    }
    
    0 讨论(0)
提交回复
热议问题