27 Commits
Author SHA1 Message Date
Danny Greenstein 7d16bc814c Merge pull request #34 from jayvdb/readme-shield
README: Add repology shield
2022-09-26 17:28:46 -07:00
Danny Greenstein 1f56d0f745 Merge pull request #37 from imageworks/grdanny-ci-tests
adding ci.yml with cross platform tests.
2022-09-25 16:58:33 -07:00
Daniel Greenstein 87f735237b additional comment for future self 2022-08-22 00:47:39 +01:00
Daniel Greenstein e7b4ab950a trying out dynamic build type again 2022-08-22 00:44:57 +01:00
Daniel Greenstein 3b85d48cf1 adding aswf ci yaml file 2022-08-22 00:39:52 +01:00
Danny Greenstein 089194ddaf Merge pull request #18 from chadrik/patch-1
Allow default values in Makefile to be overridden
2022-07-23 19:46:38 -07:00
Danny Greenstein 7631f72651 Merge pull request #15 from clhsieh/direct_return_wrapper
Implement the wrapper for direct return vector<string> for issue #12
2022-07-23 19:46:18 -07:00
Danny Greenstein b62203a4b6 Merge pull request #36 from imageworks/basic_cmake_setup
initial version of cmake config
2022-07-17 09:41:02 -07:00
Daniel Greenstein fd8b46f79b moving cmake version to 3.2 2022-07-11 23:38:17 +01:00
Daniel Greenstein bf5cd2d3b1 initial version of cmake config 2022-07-11 01:26:19 +01:00
John Vandenberg 22839311d1 README: Add repology shield 2022-06-13 12:08:27 +08:00
Larry Gritz cce54a1bcb Revise license formatting to match other modern projects. (#33)
No change to the fact that this project is BSD-3-clause licensed.

But this slight rewording/reformatting:

* Brings the notices in line with the exact wording we use in other
  projects such as OSL.

* Now will be correctly recognized by GitHub and other automated
  license checkers as being EXACTLY the same as the canonical BSD
  3-clause license.

This was approved by SPI legal.
2022-06-08 21:51:45 -07:00
Danny Greenstein 281419de2f Merge pull request #26 from grdanny/master
#25 declaring global string constants for performance improvement
2020-02-03 22:24:44 -08:00
Daniel Greenstein 9bfc0b94ec more efficient comparison with the colon string 2020-02-04 06:19:00 +00:00
Daniel Greenstein b9b2a2eb46 declaring global string constants for performance improvement 2020-02-04 05:32:18 +00:00
Danny Greenstein 4af4a86520 Merge pull request #24 from imageworks/issue_20_deadlock_in_split_path
accepting fix proposed in issue #20 - for deadlock in path split when…
2019-03-20 21:17:31 -07:00
Daniel Greenstein 8c0f1738fc accepting fix proposed in issue #20 - for deadlock in path split when the path ends in a double slash 2019-03-04 02:20:11 +00:00
Danny Greenstein 20dac44746 Merge pull request #23 from grdanny/abspath-tests-for-both-nt-and-posix
testing both posix and nt version of the abspath call
2019-02-25 22:30:16 -08:00
Daniel Greenstein 3670fab511 testing both posix and nt version of the abspath call 2019-02-24 19:01:53 +00:00
Chad Dombrova 851abee07a Allow default values in Makefile to be overridden
This is handy when building this within an automated build system where creating and applying a patch is a PITA.
2015-10-21 16:03:04 -07:00
Changlin Hsieh 8d1bdb2e43 Implement the wrapper for direct return vector<string> for issue #12 2014-02-11 11:12:29 +08:00
Jeremy Selan c2de99deb4 fix replace on empty strings 2012-10-16 14:31:17 -07:00
Jeremy Selan f38e93591b fix rsplit for non-space characters 2012-10-16 14:30:43 -07:00
Jeremy Selan 9dc73e8533 switch ssize_t -> Py_ssize_t for windows friendliness 2012-04-13 10:19:29 -07:00
Jeremy Selan ae50dda1ea exposed all os::path posix vs. nt varients 2012-04-10 17:05:23 -07:00
Jeremy Selan a5c3cfa274 do_strip windows bugfix
switched to use ssize_t (signed) for internal counters, to match the python
source.  (see Modules/stropmodule.c : do_strip)

This addresses a bug uncovered by Laszlo Sebo on Windows, when stripping an
empty string.
2012-04-10 16:29:12 -07:00
Jeremy Selan 6c7eadc6c2 added os::path::abspath 2011-10-25 10:52:49 -07:00
10 changed files with 1290 additions and 345 deletions
+481
View File
@@ -0,0 +1,481 @@
# borrowed this from:
# https://raw.githubusercontent.com/AcademySoftwareFoundation/Imath/main/.github/workflows/ci_workflow.yml
# with some slight simplification
name: CI
on:
push:
# Jobs are skipped when ONLY Markdown (*.md) files are changed
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
jobs:
# Linux jobs run in Docker containers, so the latest OS version is OK. macOS
# and Windows jobs need to be locked to specific virtual environment
# versions to mitigate issues from OS updates, and will require maintenance
# as OS versions are retired.
#
# GH Actions (Free plan) supports 20 concurrent jobs, with 5 concurrent macOS
# jobs. This workflow tries to utilize (but not exceed) that budget to
# promote timely CI.
# ---------------------------------------------------------------------------
# Linux
# ---------------------------------------------------------------------------
# TODO: Add ARM build. Add sanitize build.
linux:
name: 'Linux CentOS 7 VFX CY${{ matrix.vfx-cy }}
<${{ matrix.compiler-desc }} ,
config=${{ matrix.build-type }},
shared=${{ matrix.build-shared }},
cxx=${{ matrix.cxx-standard }}>'
# GH-hosted VM. The build runs in CentOS 7 'container' defined below.
runs-on: ubuntu-latest
container:
# DockerHub: https://hub.docker.com/u/aswf
# Source: https://github.com/AcademySoftwareFoundation/aswf-docker
image: aswf/ci-openexr:${{ matrix.vfx-cy }}
strategy:
matrix:
build: [1, 2, 3, 4, 9, 10, 11, 12, 13, 14, 15, 20, 21, 22]
include:
# -------------------------------------------------------------------
# GCC, VFX CY2022
# -------------------------------------------------------------------
# C++17, Python 3.9
- build: 1
build-type: Release
build-shared: 'ON'
cxx-standard: 17
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: gcc9.3.1
vfx-cy: 2022
# C++17, Python 3.9.7, Debug
- build: 2
build-type: Debug
build-shared: 'ON'
cxx-standard: 17
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: gcc9.3.1
vfx-cy: 2022
# C++17, Python 3.9.7, Static
- build: 3
build-type: Release
build-shared: 'OFF'
cxx-standard: 17
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: gcc9.3.1
vfx-cy: 2022
# C++14, Python 3.9.7, Static
- build: 4
build-type: Release
build-shared: 'ON'
cxx-standard: 14
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: gcc9.3.1
vfx-cy: 2022
# C++17, no Python
# - build: 5
# build-type: Release
# build-shared: 'ON'
# cxx-standard: 17
# cxx-compiler: g++
# cc-compiler: gcc
# compiler-desc: gcc9.3.1
# python: 'OFF'
# python-desc: no python
# vfx-cy: 2022
# -------------------------------------------------------------------
# GCC, VFX CY2021
# -------------------------------------------------------------------
# C++17, Python 3.7.9
- build: 9
build-type: Release
build-shared: 'ON'
cxx-standard: 17
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: gcc9.3.1
python: 'ON'
vfx-cy: 2021
# -------------------------------------------------------------------
# GCC, VFX CY2020
# -------------------------------------------------------------------
# C++14, Python 3.7
- build: 10
build-type: Release
build-shared: 'ON'
cxx-standard: 14
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: gcc6.3.1
vfx-cy: 2020
# -------------------------------------------------------------------
# GCC, VFX CY2019
# -------------------------------------------------------------------
# C++11, Python 2.7
- build: 11
build-type: Release
build-shared: 'ON'
cxx-standard: 11
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: gcc6.3.1
vfx-cy: 2019
# -------------------------------------------------------------------
# Clang, VFX CY2022
# -------------------------------------------------------------------
# C++17, Python 3.9
- build: 12
build-type: Release
build-shared: 'ON'
cxx-standard: 17
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: clang10.4
vfx-cy: 2022
# C++17, Python 3.9.7, Debug
- build: 13
build-type: Debug
build-shared: 'ON'
cxx-standard: 17
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: clang10.4
vfx-cy: 2022
# C++17, Python 3.9.7, Static
- build: 14
build-type: Release
build-shared: 'OFF'
cxx-standard: 17
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: clang10.4
vfx-cy: 2022
# C++14, Python 3.9.7, Static
- build: 15
build-type: Release
build-shared: 'ON'
cxx-standard: 14
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: clang10.4
vfx-cy: 2022
# -------------------------------------------------------------------
# Clang, VFX CY2021
# -------------------------------------------------------------------
# C++17, Python 3.7.9
- build: 20
build-type: Release
build-shared: 'ON'
cxx-standard: 17
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: clang10.4
vfx-cy: 2021
# -------------------------------------------------------------------
# Clang, VFX CY2020
# -------------------------------------------------------------------
# C++14, Python 3.7
- build: 21
build-type: Release
build-shared: 'ON'
cxx-standard: 14
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: clang7.8
vfx-cy: 2020
# -------------------------------------------------------------------
# Clang, VFX CY2019
# -------------------------------------------------------------------
# C++11, Python 2.7
- build: 22
build-type: Release
build-shared: 'ON'
cxx-standard: 11
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: clang7.8
vfx-cy: 2019
env:
CXX: ${{ matrix.cxx-compiler }}
CC: ${{ matrix.cc-compiler }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Create build directories
run: |
mkdir _install
mkdir _build
- name: Configure
run: |
cmake .. \
-DCMAKE_INSTALL_PREFIX=../_install \
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
-DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
-DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \
-DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \
-DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \
working-directory: _build
- name: Build
run: |
cmake --build . \
--target install \
--config ${{ matrix.build-type }}
working-directory: _build
- name: Test
run: |
ctest -C ${{ matrix.build_type }}
working-directory: _build
# ---------------------------------------------------------------------------
# macOS
# ---------------------------------------------------------------------------
macos_no_python:
name: 'macOS 10.15
<AppleClang 11.0
config=${{ matrix.build-type }},
shared=${{ matrix.build-shared }},
cxx=${{ matrix.cxx-standard }},
docs=${{ matrix.build-docs }}>'
runs-on: macos-10.15
strategy:
matrix:
build: [1, 2, 3, 4, 5]
include:
# C++11
- build: 1
build-type: Release
build-shared: 'ON'
build-docs: 'ON'
cxx-standard: 17
exclude-tests:
# Debug
- build: 2
build-type: Debug
build-shared: 'ON'
build-docs: 'OFF'
cxx-standard: 17
exclude-tests:
# Static
- build: 3
build-type: Debug
build-shared: 'OFF'
build-docs: 'OFF'
cxx-standard: 17
exclude-tests:
# C++14
- build: 4
build-type: Release
build-shared: 'ON'
build-docs: 'OFF'
cxx-standard: 14
exclude-tests:
# C++11
- build: 5
build-type: Release
build-shared: 'ON'
build-docs: 'OFF'
cxx-standard: 11
exclude-tests:
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Create build directories
run: |
mkdir _install
mkdir _build
- name: Configure
run: |
cmake ../. \
-DCMAKE_INSTALL_PREFIX=../_install \
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
-DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
-DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \
-DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \
-DBUILD_SHARED_LIBS=${{ matrix.build-shared }}
working-directory: _build
- name: Build
run: |
cmake --build . \
--target install \
--config ${{ matrix.build-type }} \
-- -j2
working-directory: _build
- name: Test
run: |
ctest -C ${{ matrix.build_type }}
working-directory: _build
# ---------------------------------------------------------------------------
# Windows
# ---------------------------------------------------------------------------
windows:
name: 'Windows 2019
<${{ matrix.compiler-desc }},
config=${{ matrix.build-type }},
shared=${{ matrix.build-shared }},
cxx=${{ matrix.cxx-standard }},
docs=${{ matrix.build-docs }}>'
runs-on: windows-${{ matrix.osver }}
strategy:
matrix:
build: [1, 3, 4, 6, 7, 8]
include:
# -------------------------------------------------------------------
# VFX CY2022 - C++17 - Windows 2019
# -------------------------------------------------------------------
# C++17, Release Shared
- build: 1
build-type: Release
build-shared: 'ON'
build-docs: 'ON'
compiler-desc: msvc16.11
cxx-standard: 17
vfx-cy: 2022
exclude-tests:
osver: 2019
# C++17, Debug -
## - build: 2
## build-type: Debug
## build-shared: 'ON'
## build-docs: 'OFF'
## cxx-standard: 17
## exclude-tests:
# C++17, Release Static
- build: 3
build-type: Release
build-shared: 'OFF'
build-docs: 'OFF'
compiler-desc: msvc16.11
cxx-standard: 17
vfx-cy: 2022
exclude-tests:
osver: 2019
# -------------------------------------------------------------------
# VFX CY2022 - C++17 - Windows 2022
# -------------------------------------------------------------------
# C++17, Release Shared
- build: 4
build-type: Release
build-shared: 'ON'
build-docs: 'ON'
compiler-desc: msvc17.1
cxx-standard: 17
vfx-cy: 2022
exclude-tests:
osver: 2022
# C++17, Debug -
## - build: 5
## build-type: Debug
## build-shared: 'ON'
## build-docs: 'OFF'
## cxx-standard: 17
## exclude-tests:
# C++17, Release Static
- build: 6
build-type: Release
build-shared: 'OFF'
build-docs: 'OFF'
compiler-desc: msvc17.1
cxx-standard: 17
vfx-cy: 2022
exclude-tests:
osver: 2022
# -------------------------------------------------------------------
# VFX CY2020 - C++14 - Windows 2019
# -------------------------------------------------------------------
# C++14, Release Shared
- build: 7
build-type: Release
build-shared: 'ON'
build-docs: 'OFF'
compiler-desc: msvc16.11
cxx-standard: 14
vfx-cy: 2020
exclude-tests:
osver: 2019
# -------------------------------------------------------------------
# VFX CY2019 - C++11 - Windows 2019
# -------------------------------------------------------------------
# C++11, Release Shared
- build: 8
build-type: Release
build-shared: 'ON'
build-docs: 'OFF'
compiler-desc: msvc16.11
cxx-standard: 11
exclude-tests:
osver: 2019
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Create build directories
run: |
mkdir _install
mkdir _build
shell: bash
- name: Configure
# the windows build needs the -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS to work
run: |
cmake ../. \
-DCMAKE_INSTALL_PREFIX=../_install \
-DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS='ON'\
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
-DCMAKE_CXX_STANDARD=${{ matrix.cxx-standard }} \
-DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \
-DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \
-DBUILD_SHARED_LIBS=${{ matrix.build-shared }}
shell: bash
working-directory: _build
- name: Build
run: |
cmake --build . \
--target install \
--config ${{ matrix.build-type }}
shell: bash
working-directory: _build
- name: Test
run: |
ctest -C ${{ matrix.build-type }}
shell: bash
working-directory: _build
+22
View File
@@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.2)
project(pystring CXX)
set(BUILD_SHARED_LIBS YES)
add_library(pystring
pystring.cpp
pystring.h
)
add_executable (pystring_test test.cpp)
TARGET_LINK_LIBRARIES (pystring_test pystring)
enable_testing()
add_test(NAME PyStringTest COMMAND pystring_test)
include(GNUInstallDirs)
install(TARGETS pystring
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
+24 -27
View File
@@ -1,30 +1,27 @@
Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
All rights reserved.
Copyright (c) 2008-present Contributors to the Pystring project.
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the organization Sony Pictures Imageworks nor the
names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+4 -4
View File
@@ -1,7 +1,7 @@
LIBTOOL = libtool
LIBDIR = /usr/lib
CXX = g++
CXXFLAGS = -g -O3 -Wall -Wextra -Wshadow -Wconversion -Wcast-qual -Wformat=2
LIBTOOL ?= libtool
LIBDIR ?= /usr/lib
CXX ?= g++
CXXFLAGS ?= -g -O3 -Wall -Wextra -Wshadow -Wconversion -Wcast-qual -Wformat=2
all: libpystring.la
-8
View File
@@ -1,8 +0,0 @@
Pystring is a collection of C++ functions which match the interface and behavior of python's string class methods using std::string. Implemented in C++, it does not require or make use of a python interpreter. It provides convenience and familiarity for common string operations not included in the standard C++ library. It's also useful in environments where both C++ and python are used.
Overlapping functionality (such as index and slice/substr) of std::string is included to match python interfaces.
Originally developed at Sony Pictures Imageworks.
http://opensource.imageworks.com/
Note: Despite the infrequent updates, this repo is not dead/abandoned - just stable! We use it every day at Imageworks.
+17
View File
@@ -0,0 +1,17 @@
[![Repology](https://img.shields.io/repology/repositories/pystring)](https://repology.org/project/pystring/versions)
Pystring is a collection of C++ functions which match the interface and
behavior of python's string class methods using std::string. Implemented in
C++, it does not require or make use of a python interpreter. It provides
convenience and familiarity for common string operations not included in the
standard C++ library. It's also useful in environments where both C++ and
python are used.
Overlapping functionality (such as index and slice/substr) of std::string is
included to match python interfaces.
Originally developed at Sony Pictures Imageworks.
http://opensource.imageworks.com/
Note: Despite the infrequent updates, this repo is not dead/abandoned - just
stable! We use it every day at Imageworks.
+159 -239
View File
@@ -1,35 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the organization Sony Pictures Imageworks nor the
// names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
// Copyright Contributors to the Pystring project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/imageworks/pystring/blob/master/LICENSE
#include "pystring.h"
@@ -56,6 +28,15 @@ namespace pystring
// This must also equal the size used in the end = MAX_32BIT_INT default arg.
typedef int Py_ssize_t;
const std::string forward_slash = "/";
const std::string double_forward_slash = "//";
const std::string triple_forward_slash = "///";
const std::string double_back_slash = "\\";
const std::string empty_string = "";
const std::string dot = ".";
const std::string double_dot = "..";
const std::string colon = ":";
/* helper macro to fixup start/end slice values */
#define ADJUST_INDICES(start, end, len) \
@@ -202,7 +183,7 @@ typedef int Py_ssize_t;
{
if ( maxsplit < 0 )
{
split( str, result, sep, 0 );
split( str, result, sep, maxsplit );
return;
}
@@ -214,11 +195,11 @@ typedef int Py_ssize_t;
return;
}
std::string::size_type i,j, len = str.size(), n = sep.size();
Py_ssize_t i,j, len = (Py_ssize_t) str.size(), n = (Py_ssize_t) sep.size();
i = j = len;
while ( i > n )
while ( i >= n )
{
if ( str[i - 1] == sep[n - 1] && str.substr( i - n, n ) == sep )
{
@@ -249,7 +230,7 @@ typedef int Py_ssize_t;
///
std::string do_strip( const std::string & str, int striptype, const std::string & chars )
{
std::string::size_type len = str.size(), i, j, charslen = chars.size();
Py_ssize_t len = (Py_ssize_t) str.size(), i, j, charslen = (Py_ssize_t) chars.size();
if ( charslen == 0 )
{
@@ -324,8 +305,8 @@ typedef int Py_ssize_t;
if ( index < 0 )
{
result[0] = str;
result[1] = "";
result[2] = "";
result[1] = empty_string;
result[2] = empty_string;
}
else
{
@@ -344,8 +325,8 @@ typedef int Py_ssize_t;
int index = rfind( str, sep );
if ( index < 0 )
{
result[0] = "";
result[1] = "";
result[0] = empty_string;
result[1] = empty_string;
result[2] = str;
}
else
@@ -387,7 +368,7 @@ typedef int Py_ssize_t;
{
std::vector< std::string >::size_type seqlen = seq.size(), i;
if ( seqlen == 0 ) return "";
if ( seqlen == 0 ) return empty_string;
if ( seqlen == 1 ) return seq[0];
std::string result( seq[0] );
@@ -838,7 +819,7 @@ typedef int Py_ssize_t;
std::string slice( const std::string & str, int start, int end )
{
ADJUST_INDICES(start, end, (int) str.size());
if ( start >= end ) return "";
if ( start >= end ) return empty_string;
return str.substr( start, end - start );
}
@@ -922,7 +903,7 @@ typedef int Py_ssize_t;
}
else
{
s.replace( i + offset, 1, "" );
s.replace( i + offset, 1, empty_string );
offset -= 1;
}
@@ -967,6 +948,7 @@ typedef int Py_ssize_t;
//////////////////////////////////////////////////////////////////////////////////////////////
///
///
std::string replace( const std::string & str, const std::string & oldstr, const std::string & newstr, int count )
{
int sofar = 0;
@@ -974,8 +956,10 @@ typedef int Py_ssize_t;
std::string s( str );
std::string::size_type oldlen = oldstr.size(), newlen = newstr.size();
cursor = find( s, oldstr, cursor );
while ( ( cursor = find( s, oldstr, cursor ) ) != -1 )
while ( cursor != -1 && cursor <= (int)s.size() )
{
if ( count > -1 && sofar >= count )
{
@@ -983,15 +967,25 @@ typedef int Py_ssize_t;
}
s.replace( cursor, oldlen, newstr );
cursor += (int) newlen;
if ( oldlen != 0)
{
cursor = find( s, oldstr, cursor );
}
else
{
++cursor;
}
++sofar;
}
return s;
}
//////////////////////////////////////////////////////////////////////////////////////////////
///
///
@@ -1038,7 +1032,7 @@ typedef int Py_ssize_t;
std::string mul( const std::string & str, int n )
{
// Early exits
if (n <= 0) return "";
if (n <= 0) return empty_string;
if (n == 1) return str;
std::ostringstream os;
@@ -1067,7 +1061,7 @@ namespace path
void splitdrive_nt(std::string & drivespec, std::string & pathspec,
const std::string & p)
{
if(pystring::slice(p, 1, 2) == ":")
if (p.size() >= 2 && p[1] == ':')
{
std::string path = p; // In case drivespec == p
drivespec = pystring::slice(path, 0, 2);
@@ -1075,7 +1069,7 @@ namespace path
}
else
{
drivespec = "";
drivespec = empty_string;
pathspec = p;
}
}
@@ -1084,7 +1078,7 @@ namespace path
void splitdrive_posix(std::string & drivespec, std::string & pathspec,
const std::string & path)
{
drivespec = "";
drivespec = empty_string;
pathspec = path;
}
@@ -1115,7 +1109,7 @@ namespace path
bool isabs_posix(const std::string & s)
{
return pystring::startswith(s, "/");
return pystring::startswith(s, forward_slash);
}
bool isabs(const std::string & path)
@@ -1128,13 +1122,41 @@ namespace path
}
//////////////////////////////////////////////////////////////////////////////////////////////
///
///
std::string abspath_nt(const std::string & path, const std::string & cwd)
{
std::string p = path;
if(!isabs_nt(p)) p = join_nt(cwd, p);
return normpath_nt(p);
}
std::string abspath_posix(const std::string & path, const std::string & cwd)
{
std::string p = path;
if(!isabs_posix(p)) p = join_posix(cwd, p);
return normpath_posix(p);
}
std::string abspath(const std::string & path, const std::string & cwd)
{
#ifdef WINDOWS
return abspath_nt(path, cwd);
#else
return abspath_posix(path, cwd);
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////////
///
///
std::string join_nt(const std::vector< std::string > & paths)
{
if(paths.empty()) return "";
if(paths.empty()) return empty_string;
if(paths.size() == 1) return paths[0];
std::string path = paths[0];
@@ -1159,15 +1181,15 @@ namespace path
// 4. join('c:', 'd:/') = 'd:/'
// 5. join('c:/', 'd:/') = 'd:/'
if( (pystring::slice(path, 1, 2) != ":") ||
(pystring::slice(b, 1, 2) == ":") )
if ((path.size() >= 2 && path[1] != ':') || (b.size() >= 2 && b[1] == ':'))
{
// Path doesnt start with a drive letter
b_nts = true;
}
// Else path has a drive letter, and b doesn't but is absolute.
else if((path.size()>3) ||
((path.size()==3) && !pystring::endswith(path, "/") && !pystring::endswith(path, "\\")))
((path.size()==3) && !pystring::endswith(path, forward_slash) && !pystring::endswith(path, double_back_slash)))
{
b_nts = true;
}
@@ -1181,9 +1203,9 @@ namespace path
{
// Join, and ensure there's a separator.
// assert len(path) > 0
if( pystring::endswith(path, "/") || pystring::endswith(path, "\\"))
if( pystring::endswith(path, forward_slash) || pystring::endswith(path, double_back_slash))
{
if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
if(pystring::startswith(b,forward_slash) || pystring::startswith(b,double_back_slash))
{
path += pystring::slice(b, 1);
}
@@ -1192,19 +1214,19 @@ namespace path
path += b;
}
}
else if(pystring::endswith(path, ":"))
else if(pystring::endswith(path, colon))
{
path += b;
}
else if(!b.empty())
{
if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
if(pystring::startswith(b, forward_slash) || pystring::startswith(b,double_back_slash))
{
path += b;
}
else
{
path += "\\" + b;
path += double_back_slash + b;
}
}
else
@@ -1213,7 +1235,7 @@ namespace path
// but b is empty; since, e.g., split('a/') produces
// ('a', ''), it's best if join() adds a backslash in
// this case.
path += "\\";
path += double_back_slash;
}
}
}
@@ -1221,7 +1243,7 @@ namespace path
return path;
}
// Join two or more pathname components, inserting "\\" as needed.
// Join two or more pathname components, inserting double_back_slash as needed.
std::string join_nt(const std::string & a, const std::string & b)
{
std::vector< std::string > paths(2);
@@ -1238,7 +1260,7 @@ namespace path
std::string join_posix(const std::vector< std::string > & paths)
{
if(paths.empty()) return "";
if(paths.empty()) return empty_string;
if(paths.size() == 1) return paths[0];
std::string path = paths[0];
@@ -1246,17 +1268,17 @@ namespace path
for(unsigned int i=1; i<paths.size(); ++i)
{
std::string b = paths[i];
if(pystring::startswith(b, "/"))
if(pystring::startswith(b, forward_slash))
{
path = b;
}
else if(path.empty() || pystring::endswith(path, "/"))
else if(path.empty() || pystring::endswith(path, forward_slash))
{
path += b;
}
else
{
path += "/" + b;
path += forward_slash + b;
}
}
@@ -1306,7 +1328,8 @@ namespace path
// set i to index beyond p's last slash
int i = (int)p.size();
// walk back to find the index of the first slash from the end
while(i>0 && (p[i-1] != '\\') && (p[i-1] != '/'))
{
i = i - 1;
@@ -1317,10 +1340,10 @@ namespace path
// remove trailing slashes from head, unless it's all slashes
std::string head2 = head;
while(!head2.empty() && ((pystring::slice(head2,-1) == "/") ||
(pystring::slice(head2,-1) == "\\")))
while(!head2.empty() && ((pystring::slice(head2,-1) == forward_slash) ||
(pystring::slice(head2,-1) == double_back_slash)))
{
head2 = pystring::slice(head,0,-1);
head2 = pystring::slice(head2,0,-1);
}
if(!head2.empty()) head = head2;
@@ -1335,14 +1358,14 @@ namespace path
void split_posix(std::string & head, std::string & tail, const std::string & p)
{
int i = pystring::rfind(p, "/") + 1;
int i = pystring::rfind(p, forward_slash) + 1;
head = pystring::slice(p,0,i);
tail = pystring::slice(p,i);
if(!head.empty() && (head != pystring::mul("/", (int) head.size())))
if(!head.empty() && (head != pystring::mul(forward_slash, (int) head.size())))
{
head = pystring::rstrip(head, "/");
head = pystring::rstrip(head, forward_slash);
}
}
@@ -1360,19 +1383,51 @@ namespace path
///
///
std::string basename(const std::string & path)
std::string basename_nt(const std::string & path)
{
std::string head, tail;
split(head, tail, path);
split_nt(head, tail, path);
return tail;
}
std::string dirname(const std::string & path)
std::string basename_posix(const std::string & path)
{
std::string head, tail;
split(head, tail, path);
split_posix(head, tail, path);
return tail;
}
std::string basename(const std::string & path)
{
#ifdef WINDOWS
return basename_nt(path);
#else
return basename_posix(path);
#endif
}
std::string dirname_nt(const std::string & path)
{
std::string head, tail;
split_nt(head, tail, path);
return head;
}
std::string dirname_posix(const std::string & path)
{
std::string head, tail;
split_posix(head, tail, path);
return head;
}
std::string dirname(const std::string & path)
{
#ifdef WINDOWS
return dirname_nt(path);
#else
return dirname_posix(path);
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////////
@@ -1383,7 +1438,7 @@ namespace path
std::string normpath_nt(const std::string & p)
{
std::string path = p;
path = pystring::replace(path, "/","\\");
path = pystring::replace(path, forward_slash,double_back_slash);
std::string prefix;
splitdrive_nt(prefix, path, path);
@@ -1401,41 +1456,41 @@ namespace path
if(prefix.empty())
{
// No drive letter - preserve initial backslashes
while(pystring::slice(path,0,1) == "\\")
while(pystring::slice(path,0,1) == double_back_slash)
{
prefix = prefix + "\\";
prefix = prefix + double_back_slash;
path = pystring::slice(path,1);
}
}
else
{
// We have a drive letter - collapse initial backslashes
if(pystring::startswith(path, "\\"))
if(pystring::startswith(path, double_back_slash))
{
prefix = prefix + "\\";
path = pystring::lstrip(path, "\\");
prefix = prefix + double_back_slash;
path = pystring::lstrip(path, double_back_slash);
}
}
std::vector<std::string> comps;
pystring::split(path, comps, "\\");
pystring::split(path, comps, double_back_slash);
int i = 0;
while(i<(int)comps.size())
{
if(comps[i].empty() || comps[i] == ".")
if(comps[i].empty() || comps[i] == dot)
{
comps.erase(comps.begin()+i);
}
else if(comps[i] == "..")
else if(comps[i] == double_dot)
{
if(i>0 && comps[i-1] != "..")
if(i>0 && comps[i-1] != double_dot)
{
comps.erase(comps.begin()+i-1, comps.begin()+i+1);
i -= 1;
}
else if(i == 0 && pystring::endswith(prefix, "\\"))
else if(i == 0 && pystring::endswith(prefix, double_back_slash))
{
comps.erase(comps.begin()+i);
}
@@ -1453,10 +1508,10 @@ namespace path
// If the path is now empty, substitute '.'
if(prefix.empty() && comps.empty())
{
comps.push_back(".");
comps.push_back(dot);
}
return prefix + pystring::join("\\", comps);
return prefix + pystring::join(double_back_slash, comps);
}
// Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
@@ -1466,30 +1521,30 @@ namespace path
std::string normpath_posix(const std::string & p)
{
if(p.empty()) return ".";
if(p.empty()) return dot;
std::string path = p;
int initial_slashes = pystring::startswith(path,"/") ? 1 : 0;
int initial_slashes = pystring::startswith(path, forward_slash) ? 1 : 0;
// POSIX allows one or two initial slashes, but treats three or more
// as single slash.
if (initial_slashes && pystring::startswith(path,"//")
&& !pystring::startswith(path,"///"))
if (initial_slashes && pystring::startswith(path, double_forward_slash)
&& !pystring::startswith(path, triple_forward_slash))
initial_slashes = 2;
std::vector<std::string> comps, new_comps;
pystring::split(path, comps, "/");
pystring::split(path, comps, forward_slash);
for(unsigned int i=0; i<comps.size(); ++i)
{
std::string comp = comps[i];
if(comp.empty() || comp == ".")
if(comp.empty() || comp == dot)
continue;
if( (comp != "..") || ((initial_slashes == 0) && new_comps.empty()) ||
(!new_comps.empty() && new_comps[new_comps.size()-1] == ".."))
if( (comp != double_dot) || ((initial_slashes == 0) && new_comps.empty()) ||
(!new_comps.empty() && new_comps[new_comps.size()-1] == double_dot))
{
new_comps.push_back(comp);
}
@@ -1499,12 +1554,12 @@ namespace path
}
}
path = pystring::join("/", new_comps);
path = pystring::join(forward_slash, new_comps);
if (initial_slashes > 0)
path = pystring::mul("/",initial_slashes) + path;
path = pystring::mul(forward_slash, initial_slashes) + path;
if(path.empty()) return ".";
if(path.empty()) return dot;
return path;
}
@@ -1559,19 +1614,19 @@ namespace path
}
root = p;
ext = "";
ext = empty_string;
}
void splitext_nt(std::string & root, std::string & ext, const std::string & path)
{
return splitext_generic(root, ext, path,
"\\", "/", ".");
double_back_slash, forward_slash, dot);
}
void splitext_posix(std::string & root, std::string & ext, const std::string & path)
{
return splitext_generic(root, ext, path,
"/", "", ".");
forward_slash, empty_string, dot);
}
void splitext(std::string & root, std::string & ext, const std::string & path)
@@ -1590,138 +1645,3 @@ namespace path
}//namespace pystring
#ifdef PYSTRING_UNITTEST
#include "unittest.h"
PYSTRING_ADD_TEST(pystring_os_path, splitdrive)
{
using namespace pystring::os::path;
std::string drivespec, pathspec;
splitdrive_posix(drivespec, pathspec, "/Users/test"); PYSTRING_CHECK_EQUAL(drivespec, ""); PYSTRING_CHECK_EQUAL(pathspec, "/Users/test");
splitdrive_nt(drivespec, pathspec, "C:\\Users\\test"); PYSTRING_CHECK_EQUAL(drivespec, "C:" ); PYSTRING_CHECK_EQUAL(pathspec, "\\Users\\test" );
splitdrive_nt(drivespec, pathspec, "\\Users\\test"); PYSTRING_CHECK_EQUAL(drivespec, "" ); PYSTRING_CHECK_EQUAL(pathspec, "\\Users\\test" );
}
PYSTRING_ADD_TEST(pystring_os_path, isabs)
{
using namespace pystring::os::path;
PYSTRING_CHECK_EQUAL(isabs_posix("/Users/test"), true );
PYSTRING_CHECK_EQUAL(isabs_posix("\\Users\\test"), false);
PYSTRING_CHECK_EQUAL(isabs_posix("../Users"), false);
PYSTRING_CHECK_EQUAL(isabs_posix("Users"), false);
PYSTRING_CHECK_EQUAL(isabs_nt("C:\\Users\\test"), true);
PYSTRING_CHECK_EQUAL(isabs_nt("C:/Users"), true);
PYSTRING_CHECK_EQUAL(isabs_nt("/Users"), true);
PYSTRING_CHECK_EQUAL(isabs_nt("../Users"), false);
PYSTRING_CHECK_EQUAL(isabs_nt("..\\Users"), false);
}
PYSTRING_ADD_TEST(pystring_os_path, join)
{
using namespace pystring::os::path;
PYSTRING_CHECK_EQUAL(join_posix("a","b"), "a/b" );
PYSTRING_CHECK_EQUAL(join_posix("/a","b"), "/a/b" );
PYSTRING_CHECK_EQUAL(join_posix("/a","/b"), "/b" );
PYSTRING_CHECK_EQUAL(join_posix("a","/b"), "/b" );
PYSTRING_CHECK_EQUAL(join_posix("//a","b"), "//a/b" );
PYSTRING_CHECK_EQUAL(join_posix("//a","b//"), "//a/b//" );
PYSTRING_CHECK_EQUAL(join_posix("../a","/b"), "/b" );
PYSTRING_CHECK_EQUAL(join_posix("../a","b"), "../a/b" );
std::vector< std::string > paths;
PYSTRING_CHECK_EQUAL(join_posix(paths), "" );
paths.push_back("/a");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/a" );
paths.push_back("b");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/a/b" );
paths.push_back("c/");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/a/b/c/" );
paths.push_back("d");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/a/b/c/d" );
paths.push_back("/e");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/e" );
PYSTRING_CHECK_EQUAL(join_nt("c:","/a"), "c:/a" );
PYSTRING_CHECK_EQUAL(join_nt("c:/","/a"), "c:/a" );
PYSTRING_CHECK_EQUAL(join_nt("c:/a","/b"), "/b" );
PYSTRING_CHECK_EQUAL(join_nt("c:","d:/"), "d:/" );
PYSTRING_CHECK_EQUAL(join_nt("c:/","d:/"), "d:/" );
PYSTRING_CHECK_EQUAL(join_nt("a","b"), "a\\b" );
PYSTRING_CHECK_EQUAL(join_nt("\\a","b"), "\\a\\b" );
PYSTRING_CHECK_EQUAL(join_nt("c:\\a","b"), "c:\\a\\b" );
PYSTRING_CHECK_EQUAL(join_nt("c:\\a","c:\\b"), "c:\\b" );
PYSTRING_CHECK_EQUAL(join_nt("..\\a","b"), "..\\a\\b" );
}
PYSTRING_ADD_TEST(pystring_os_path, normpath)
{
using namespace pystring::os::path;
PYSTRING_CHECK_EQUAL(normpath_posix("A//B"), "A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("A/./B"), "A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("A/foo/../B"), "A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("/A//B"), "/A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("//A//B"), "//A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("///A//B"), "/A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("../A"), "../A" );
PYSTRING_CHECK_EQUAL(normpath_posix("../A../"), "../A.." );
PYSTRING_CHECK_EQUAL(normpath_posix("FOO/../A../././B"), "A../B" );
PYSTRING_CHECK_EQUAL(normpath_nt(""), "." );
PYSTRING_CHECK_EQUAL(normpath_nt("A"), "A" );
PYSTRING_CHECK_EQUAL(normpath_nt("A./B"), "A.\\B" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:\\"), "C:\\" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:\\A"), "C:\\A" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:/A"), "C:\\A" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:/A..\\"), "C:\\A.." );
PYSTRING_CHECK_EQUAL(normpath_nt("C:/A..\\..\\"), "C:\\" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:\\\\A"), "C:\\A" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:\\\\\\A\\\\B"), "C:\\A\\B" );
}
PYSTRING_ADD_TEST(pystring_os_path, split)
{
using namespace pystring::os::path;
std::string head, tail;
split_posix(head, tail, ""); PYSTRING_CHECK_EQUAL(head, "" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "/"); PYSTRING_CHECK_EQUAL(head, "/" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "a"); PYSTRING_CHECK_EQUAL(head, "" ); PYSTRING_CHECK_EQUAL(tail, "a" );
split_posix(head, tail, "a/"); PYSTRING_CHECK_EQUAL(head, "a" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "/a"); PYSTRING_CHECK_EQUAL(head, "/" ); PYSTRING_CHECK_EQUAL(tail, "a" );
split_posix(head, tail, "/a/b/"); PYSTRING_CHECK_EQUAL(head, "/a/b" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "/a/b"); PYSTRING_CHECK_EQUAL(head, "/a" ); PYSTRING_CHECK_EQUAL(tail, "b" );
split_nt(head, tail, ""); PYSTRING_CHECK_EQUAL(head, "" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_nt(head, tail, "\\"); PYSTRING_CHECK_EQUAL(head, "\\" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_nt(head, tail, "a"); PYSTRING_CHECK_EQUAL(head, "" ); PYSTRING_CHECK_EQUAL(tail, "a" );
split_nt(head, tail, "a\\"); PYSTRING_CHECK_EQUAL(head, "a" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_nt(head, tail, "c:\\a"); PYSTRING_CHECK_EQUAL(head, "c:\\" ); PYSTRING_CHECK_EQUAL(tail, "a" );
split_nt(head, tail, "c:\\a\\b"); PYSTRING_CHECK_EQUAL(head, "c:\\a" ); PYSTRING_CHECK_EQUAL(tail, "b" );
split_nt(head, tail, "c:\\a\\b\\"); PYSTRING_CHECK_EQUAL(head, "c:\\a\\b" ); PYSTRING_CHECK_EQUAL(tail, "" );
}
PYSTRING_ADD_TEST(pystring_os_path, splitext)
{
using namespace pystring::os::path;
std::string root, ext;
splitext_nt(root, ext, ""); PYSTRING_CHECK_EQUAL(root, ""); PYSTRING_CHECK_EQUAL(ext, "");
splitext_nt(root, ext, "."); PYSTRING_CHECK_EQUAL(root, "."); PYSTRING_CHECK_EQUAL(ext, "");
splitext_nt(root, ext, ".foo"); PYSTRING_CHECK_EQUAL(root, ".foo"); PYSTRING_CHECK_EQUAL(ext, "");
splitext_nt(root, ext, ".foo."); PYSTRING_CHECK_EQUAL(root, ".foo"); PYSTRING_CHECK_EQUAL(ext, ".");
splitext_nt(root, ext, ".foo.e"); PYSTRING_CHECK_EQUAL(root, ".foo"); PYSTRING_CHECK_EQUAL(ext, ".e");
splitext_nt(root, ext, "c"); PYSTRING_CHECK_EQUAL(root, "c"); PYSTRING_CHECK_EQUAL(ext, "");
splitext_nt(root, ext, "a_b.c"); PYSTRING_CHECK_EQUAL(root, "a_b"); PYSTRING_CHECK_EQUAL(ext, ".c");
splitext_nt(root, ext, "c:\\a.b.c"); PYSTRING_CHECK_EQUAL(root, "c:\\a.b"); PYSTRING_CHECK_EQUAL(ext, ".c");
splitext_nt(root, ext, "c:\\a_b.c"); PYSTRING_CHECK_EQUAL(root, "c:\\a_b"); PYSTRING_CHECK_EQUAL(ext, ".c");
}
#endif
+84 -34
View File
@@ -1,35 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the organization Sony Pictures Imageworks nor the
// names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
// Copyright Contributors to the Pystring project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/imageworks/pystring/blob/master/LICENSE
#ifndef INCLUDED_PYSTRING_H
#define INCLUDED_PYSTRING_H
@@ -178,6 +150,12 @@ namespace pystring
/// not found, the original string will be returned with two empty strings.
///
void partition( const std::string & str, const std::string & sep, std::vector< std::string > & result );
inline std::vector< std::string > partition( const std::string & str, const std::string & sep )
{
std::vector< std::string > result;
partition( str, sep, result );
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Return a copy of the string with all occurrences of substring old replaced by new. If
@@ -211,6 +189,12 @@ namespace pystring
/// not found, the original string will be returned with two empty strings.
///
void rpartition( const std::string & str, const std::string & sep, std::vector< std::string > & result );
inline std::vector< std::string > rpartition ( const std::string & str, const std::string & sep )
{
std::vector< std::string > result;
rpartition( str, sep, result );
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Return a copy of the string with trailing characters removed. If chars is "", whitespace
@@ -225,6 +209,12 @@ namespace pystring
/// any whitespace string is a separator.
///
void split( const std::string & str, std::vector< std::string > & result, const std::string & sep = "", int maxsplit = -1);
inline std::vector< std::string > split( const std::string & str, const std::string & sep = "", int maxsplit = -1)
{
std::vector< std::string > result;
split( str, result, sep, maxsplit );
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Fills the "result" list with the words in the string, using sep as the delimiter string.
@@ -234,12 +224,24 @@ namespace pystring
/// any whitespace string is a separator.
///
void rsplit( const std::string & str, std::vector< std::string > & result, const std::string & sep = "", int maxsplit = -1);
inline std::vector< std::string > rsplit( const std::string & str, const std::string & sep = "", int maxsplit = -1)
{
std::vector< std::string > result;
rsplit( str, result, sep, maxsplit);
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Return a list of the lines in the string, breaking at line boundaries. Line breaks
/// are not included in the resulting list unless keepends is given and true.
///
void splitlines( const std::string & str, std::vector< std::string > & result, bool keepends = false );
inline std::vector< std::string > splitlines( const std::string & str, bool keepends = false )
{
std::vector< std::string > result;
splitlines( str, result, keepends);
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Return True if string starts with the prefix, otherwise return False. With optional start,
@@ -298,6 +300,23 @@ namespace os
{
namespace path
{
// All of the function below have three versions.
// Example:
// join(...)
// join_nt(...)
// join_posix(...)
//
// The regular function dispatches to the other versions - based on the OS
// at compile time - to match the result you'd get from the python
// interepreter on the same operating system
//
// Should you want to 'lock off' to a particular version of the string
// manipulation across *all* operating systems, use the version with the
// _OS you are interested in. I.e., you can use posix style path joining,
// even on Windows, with join_posix.
//
// The naming, (nt, posix) matches the cpython source implementation.
//////////////////////////////////////////////////////////////////////////////////////////////
/// @defgroup functions pystring::os::path
/// @{
@@ -309,12 +328,16 @@ namespace path
/// empty string ('').
std::string basename(const std::string & path);
std::string basename_nt(const std::string & path);
std::string basename_posix(const std::string & path);
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Return the directory name of pathname path. This is the first half of the pair
/// returned by split(path).
std::string dirname(const std::string & path);
std::string dirname_nt(const std::string & path);
std::string dirname_posix(const std::string & path);
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Return True if path is an absolute pathname. On Unix, that means it begins with a
@@ -322,6 +345,19 @@ namespace path
/// letter.
bool isabs(const std::string & path);
bool isabs_nt(const std::string & path);
bool isabs_posix(const std::string & s);
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Return a normalized absolutized version of the pathname path.
///
/// NOTE: This differs from the interface of the python equivalent in that it requires you
/// to pass in the current working directory as an argument.
std::string abspath(const std::string & path, const std::string & cwd);
std::string abspath_nt(const std::string & path, const std::string & cwd);
std::string abspath_posix(const std::string & path, const std::string & cwd);
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Join one or more path components intelligently. If any component is an absolute
@@ -332,8 +368,14 @@ namespace path
/// directory for each drive, os.path.join("c:", "foo") represents a path relative to the
/// current directory on drive C: (c:foo), not c:\foo.
/// This dispatches based on the compilation OS
std::string join(const std::string & path1, const std::string & path2);
std::string join_nt(const std::string & path1, const std::string & path2);
std::string join_posix(const std::string & path1, const std::string & path2);
std::string join(const std::vector< std::string > & paths);
std::string join_nt(const std::vector< std::string > & paths);
std::string join_posix(const std::vector< std::string > & paths);
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Normalize a pathname. This collapses redundant separators and up-level references
@@ -343,6 +385,8 @@ namespace path
/// symbolic links!
std::string normpath(const std::string & path);
std::string normpath_nt(const std::string & path);
std::string normpath_posix(const std::string & path);
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Split the pathname path into a pair, (head, tail) where tail is the last pathname
@@ -354,21 +398,27 @@ namespace path
/// differ).
void split(std::string & head, std::string & tail, const std::string & path);
void split_nt(std::string & head, std::string & tail, const std::string & path);
void split_posix(std::string & head, std::string & tail, const std::string & path);
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Split the pathname path into a pair (drive, tail) where drive is either a drive
/// specification or the empty string. On systems which do not use drive specifications,
/// drive will always be the empty string. In all cases, drive + tail will be the same as
/// path.
void splitdrive(std::string & drivespec, std::string & pathspec, const std::string & path);
void splitdrive_nt(std::string & drivespec, std::string & pathspec, const std::string & p);
void splitdrive_posix(std::string & drivespec, std::string & pathspec, const std::string & path);
//////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Split the pathname path into a pair (root, ext) such that root + ext == path, and
/// ext is empty or begins with a period and contains at most one period. Leading periods on
/// the basename are ignored; splitext('.cshrc') returns ('.cshrc', '').
void splitext(std::string & root, std::string & ext, const std::string & path);
void splitext_nt(std::string & root, std::string & ext, const std::string & path);
void splitext_posix(std::string & root, std::string & ext, const std::string & path);
///
/// @ }
+496 -1
View File
@@ -1,3 +1,7 @@
// Copyright Contributors to the Pystring project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/imageworks/pystring/blob/master/LICENSE
#include <iostream>
#include "pystring.h"
@@ -5,7 +9,6 @@
PYSTRING_TEST_APP(PyStringUnitTests)
PYSTRING_ADD_TEST(pystring, endswith)
{
PYSTRING_CHECK_EQUAL(pystring::endswith("", ""), true);
@@ -95,6 +98,16 @@ PYSTRING_ADD_TEST(pystring, rfind)
PYSTRING_CHECK_EQUAL(pystring::rfind("abcabcabc", "abc", 6, 8), -1);
}
PYSTRING_ADD_TEST(pystring, replace)
{
PYSTRING_CHECK_EQUAL(pystring::replace("abcdef", "foo", "bar"), "abcdef");
PYSTRING_CHECK_EQUAL(pystring::replace("abcdef", "ab", "cd"), "cdcdef");
PYSTRING_CHECK_EQUAL(pystring::replace("abcdef", "ab", ""), "cdef");
PYSTRING_CHECK_EQUAL(pystring::replace("abcabc", "ab", ""), "cc");
PYSTRING_CHECK_EQUAL(pystring::replace("abcdef", "", ""), "abcdef");
PYSTRING_CHECK_EQUAL(pystring::replace("abcdef", "", "."), ".a.b.c.d.e.f.");
}
PYSTRING_ADD_TEST(pystring, slice)
{
PYSTRING_CHECK_EQUAL(pystring::slice(""), "");
@@ -123,6 +136,343 @@ PYSTRING_ADD_TEST(pystring, slice)
PYSTRING_CHECK_EQUAL(pystring::slice("abcdef",0,-1), "abcde");
}
PYSTRING_ADD_TEST(pystring, split)
{
std::vector< std::string > result;
{
result.clear();
pystring::split("", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 1);
if(result.size()==1)
{
PYSTRING_CHECK_EQUAL(result[0], "");
}
}
{
result.clear();
pystring::split("/", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "");
}
}
{
result.clear();
pystring::split(" ", result, " ", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "");
}
}
{
result.clear();
pystring::split(" /", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], " ");
PYSTRING_CHECK_EQUAL(result[1], "");
}
}
{
result.clear();
pystring::split(" //", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], " ");
PYSTRING_CHECK_EQUAL(result[1], "/");
}
}
{
result.clear();
pystring::split("a ", result, " ", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "a");
PYSTRING_CHECK_EQUAL(result[1], " ");
}
}
{
result.clear();
pystring::split("//as//rew//gdf", result, "//");
PYSTRING_CHECK_EQUAL(result.size(), 4);
if(result.size()==4)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "as");
PYSTRING_CHECK_EQUAL(result[2], "rew");
PYSTRING_CHECK_EQUAL(result[3], "gdf");
}
}
{
result.clear();
pystring::split("/root", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "root");
}
}
{
result.clear();
pystring::split("/root/world", result, "/", 0);
PYSTRING_CHECK_EQUAL(result.size(), 1);
if(result.size()==1)
{
PYSTRING_CHECK_EQUAL(result[0], "/root/world");
}
}
{
result.clear();
pystring::split("/root/world", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "root/world");
}
}
{
result.clear();
pystring::split("/root/world", result, "/", 2);
PYSTRING_CHECK_EQUAL(result.size(), 3);
if(result.size()==3)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "root");
PYSTRING_CHECK_EQUAL(result[2], "world");
}
}
{
result.clear();
pystring::split("/root/world", result, "/", -1);
PYSTRING_CHECK_EQUAL(result.size(), 3);
if(result.size()==3)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "root");
PYSTRING_CHECK_EQUAL(result[2], "world");
}
}
}
PYSTRING_ADD_TEST(pystring, rsplit)
{
std::vector< std::string > result;
{
result.clear();
pystring::rsplit("", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 1);
if(result.size()==1)
{
PYSTRING_CHECK_EQUAL(result[0], "");
}
}
{
// "".rsplit(None, 1)
result.clear();
pystring::rsplit("", result, "", 1);
PYSTRING_CHECK_EQUAL(result.size(), 0);
}
{
// " ".rsplit(None, 1)
result.clear();
pystring::rsplit(" ", result, "", 1);
PYSTRING_CHECK_EQUAL(result.size(), 0);
}
{
result.clear();
pystring::rsplit(" ", result, "", 1);
PYSTRING_CHECK_EQUAL(result.size(), 0);
}
{
result.clear();
pystring::rsplit("/", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "");
}
}
{
result.clear();
pystring::rsplit(" /", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], " ");
PYSTRING_CHECK_EQUAL(result[1], "");
}
}
{
result.clear();
pystring::rsplit(" //", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], " /");
PYSTRING_CHECK_EQUAL(result[1], "");
}
}
{
result.clear();
pystring::rsplit("/root", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "root");
}
}
{
result.clear();
pystring::rsplit("/root/world", result, "/", 0);
PYSTRING_CHECK_EQUAL(result.size(), 1);
if(result.size()==1)
{
PYSTRING_CHECK_EQUAL(result[0], "/root/world");
}
}
{
result.clear();
pystring::rsplit("/root/world", result, "/", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "/root");
PYSTRING_CHECK_EQUAL(result[1], "world");
}
}
{
result.clear();
pystring::rsplit("/root/world", result, "/", 2);
PYSTRING_CHECK_EQUAL(result.size(), 3);
if(result.size()==3)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "root");
PYSTRING_CHECK_EQUAL(result[2], "world");
}
}
{
result.clear();
pystring::rsplit("/root/world", result, "/", -1);
PYSTRING_CHECK_EQUAL(result.size(), 3);
if(result.size()==3)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "root");
PYSTRING_CHECK_EQUAL(result[2], "world");
}
}
{
// " root world".rsplit(None, 0)
result.clear();
pystring::rsplit(" root world", result, "", 0);
PYSTRING_CHECK_EQUAL(result.size(), 1);
if(result.size()==1)
{
PYSTRING_CHECK_EQUAL(result[0], " root world");
}
}
{
// " root world".rsplit(None, 1)
result.clear();
pystring::rsplit(" root world", result, "", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], " root");
PYSTRING_CHECK_EQUAL(result[1], "world");
}
}
{
// " root world".rsplit(None, 2)
result.clear();
pystring::rsplit(" root world", result, "", 2);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], "root");
PYSTRING_CHECK_EQUAL(result[1], "world");
}
}
{
// " root world".rsplit(" ", 0)
result.clear();
pystring::rsplit(" root world", result, " ", 0);
PYSTRING_CHECK_EQUAL(result.size(), 1);
if(result.size()==1)
{
PYSTRING_CHECK_EQUAL(result[0], " root world");
}
}
{
// " root world".rsplit(" ", 1)
result.clear();
pystring::rsplit(" root world", result, " ", 1);
PYSTRING_CHECK_EQUAL(result.size(), 2);
if(result.size()==2)
{
PYSTRING_CHECK_EQUAL(result[0], " root");
PYSTRING_CHECK_EQUAL(result[1], "world");
}
}
{
// " root world".rsplit(" ", 2)
result.clear();
pystring::rsplit(" root world", result, " ", 2);
PYSTRING_CHECK_EQUAL(result.size(), 3);
if(result.size()==3)
{
PYSTRING_CHECK_EQUAL(result[0], "");
PYSTRING_CHECK_EQUAL(result[1], "root");
PYSTRING_CHECK_EQUAL(result[2], "world");
}
}
}
PYSTRING_ADD_TEST(pystring, startswith)
{
PYSTRING_CHECK_EQUAL(pystring::startswith("", ""), true);
@@ -163,3 +513,148 @@ PYSTRING_ADD_TEST(pystring, translate)
PYSTRING_CHECK_EQUAL(pystring::translate("", t2), "");
PYSTRING_CHECK_EQUAL(pystring::translate("cheese", t2), "chooso");
}
PYSTRING_ADD_TEST(pystring, abspath)
{
PYSTRING_CHECK_EQUAL(pystring::os::path::abspath_posix("", "/net"), "/net");
PYSTRING_CHECK_EQUAL(pystring::os::path::abspath_posix("../jeremys", "/net/soft_scratch/users/stevel"), "/net/soft_scratch/users/jeremys");
PYSTRING_CHECK_EQUAL(pystring::os::path::abspath_posix("../../../../tmp/a", "/net/soft_scratch/users/stevel"), "/tmp/a");
PYSTRING_CHECK_EQUAL(pystring::os::path::abspath_nt("", "c:\\net"), "c:\\net");
PYSTRING_CHECK_EQUAL(pystring::os::path::abspath_nt("..\\jeremys", "c:\\net\\soft_scratch\\users\\stevel"), "c:\\net\\soft_scratch\\users\\jeremys");
PYSTRING_CHECK_EQUAL(pystring::os::path::abspath_nt("..\\..\\..\\..\\tmp\\a", "c:\\net\\soft_scratch\\users\\stevel"), "c:\\tmp\\a");
}
PYSTRING_ADD_TEST(pystring_os_path, splitdrive)
{
using namespace pystring::os::path;
std::string drivespec, pathspec;
splitdrive_posix(drivespec, pathspec, "/Users/test"); PYSTRING_CHECK_EQUAL(drivespec, ""); PYSTRING_CHECK_EQUAL(pathspec, "/Users/test");
splitdrive_nt(drivespec, pathspec, "C:\\Users\\test"); PYSTRING_CHECK_EQUAL(drivespec, "C:" ); PYSTRING_CHECK_EQUAL(pathspec, "\\Users\\test" );
splitdrive_nt(drivespec, pathspec, "\\Users\\test"); PYSTRING_CHECK_EQUAL(drivespec, "" ); PYSTRING_CHECK_EQUAL(pathspec, "\\Users\\test" );
}
PYSTRING_ADD_TEST(pystring_os_path, isabs)
{
using namespace pystring::os::path;
PYSTRING_CHECK_EQUAL(isabs_posix("/Users/test"), true );
PYSTRING_CHECK_EQUAL(isabs_posix("\\Users\\test"), false);
PYSTRING_CHECK_EQUAL(isabs_posix("../Users"), false);
PYSTRING_CHECK_EQUAL(isabs_posix("Users"), false);
PYSTRING_CHECK_EQUAL(isabs_nt("C:\\Users\\test"), true);
PYSTRING_CHECK_EQUAL(isabs_nt("C:/Users"), true);
PYSTRING_CHECK_EQUAL(isabs_nt("/Users"), true);
PYSTRING_CHECK_EQUAL(isabs_nt("../Users"), false);
PYSTRING_CHECK_EQUAL(isabs_nt("..\\Users"), false);
}
PYSTRING_ADD_TEST(pystring_os_path, join)
{
using namespace pystring::os::path;
PYSTRING_CHECK_EQUAL(join_posix("a","b"), "a/b" );
PYSTRING_CHECK_EQUAL(join_posix("/a","b"), "/a/b" );
PYSTRING_CHECK_EQUAL(join_posix("/a","/b"), "/b" );
PYSTRING_CHECK_EQUAL(join_posix("a","/b"), "/b" );
PYSTRING_CHECK_EQUAL(join_posix("//a","b"), "//a/b" );
PYSTRING_CHECK_EQUAL(join_posix("//a","b//"), "//a/b//" );
PYSTRING_CHECK_EQUAL(join_posix("../a","/b"), "/b" );
PYSTRING_CHECK_EQUAL(join_posix("../a","b"), "../a/b" );
std::vector< std::string > paths;
PYSTRING_CHECK_EQUAL(join_posix(paths), "" );
paths.push_back("/a");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/a" );
paths.push_back("b");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/a/b" );
paths.push_back("c/");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/a/b/c/" );
paths.push_back("d");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/a/b/c/d" );
paths.push_back("/e");
PYSTRING_CHECK_EQUAL(join_posix(paths), "/e" );
PYSTRING_CHECK_EQUAL(join_nt("c:","/a"), "c:/a" );
PYSTRING_CHECK_EQUAL(join_nt("c:/","/a"), "c:/a" );
PYSTRING_CHECK_EQUAL(join_nt("c:/a","/b"), "/b" );
PYSTRING_CHECK_EQUAL(join_nt("c:","d:/"), "d:/" );
PYSTRING_CHECK_EQUAL(join_nt("c:/","d:/"), "d:/" );
PYSTRING_CHECK_EQUAL(join_nt("a","b"), "a\\b" );
PYSTRING_CHECK_EQUAL(join_nt("\\a","b"), "\\a\\b" );
PYSTRING_CHECK_EQUAL(join_nt("c:\\a","b"), "c:\\a\\b" );
PYSTRING_CHECK_EQUAL(join_nt("c:\\a","c:\\b"), "c:\\b" );
PYSTRING_CHECK_EQUAL(join_nt("..\\a","b"), "..\\a\\b" );
}
PYSTRING_ADD_TEST(pystring_os_path, normpath)
{
using namespace pystring::os::path;
PYSTRING_CHECK_EQUAL(normpath_posix("A//B"), "A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("A/./B"), "A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("A/foo/../B"), "A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("/A//B"), "/A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("//A//B"), "//A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("///A//B"), "/A/B" );
PYSTRING_CHECK_EQUAL(normpath_posix("../A"), "../A" );
PYSTRING_CHECK_EQUAL(normpath_posix("../A../"), "../A.." );
PYSTRING_CHECK_EQUAL(normpath_posix("FOO/../A../././B"), "A../B" );
PYSTRING_CHECK_EQUAL(normpath_nt(""), "." );
PYSTRING_CHECK_EQUAL(normpath_nt("A"), "A" );
PYSTRING_CHECK_EQUAL(normpath_nt("A./B"), "A.\\B" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:\\"), "C:\\" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:\\A"), "C:\\A" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:/A"), "C:\\A" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:/A..\\"), "C:\\A.." );
PYSTRING_CHECK_EQUAL(normpath_nt("C:/A..\\..\\"), "C:\\" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:\\\\A"), "C:\\A" );
PYSTRING_CHECK_EQUAL(normpath_nt("C:\\\\\\A\\\\B"), "C:\\A\\B" );
}
PYSTRING_ADD_TEST(pystring_os_path, split)
{
using namespace pystring::os::path;
std::string head, tail;
split_posix(head, tail, ""); PYSTRING_CHECK_EQUAL(head, "" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "/"); PYSTRING_CHECK_EQUAL(head, "/" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "a"); PYSTRING_CHECK_EQUAL(head, "" ); PYSTRING_CHECK_EQUAL(tail, "a" );
split_posix(head, tail, "a/"); PYSTRING_CHECK_EQUAL(head, "a" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "/a"); PYSTRING_CHECK_EQUAL(head, "/" ); PYSTRING_CHECK_EQUAL(tail, "a" );
split_posix(head, tail, "/a/b/"); PYSTRING_CHECK_EQUAL(head, "/a/b" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "/a/b"); PYSTRING_CHECK_EQUAL(head, "/a" ); PYSTRING_CHECK_EQUAL(tail, "b" );
split_posix(head, tail, "/a/b//"); PYSTRING_CHECK_EQUAL(head, "/a/b" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_posix(head, tail, "/a/b/////////////"); PYSTRING_CHECK_EQUAL(head, "/a/b" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_nt(head, tail, ""); PYSTRING_CHECK_EQUAL(head, "" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_nt(head, tail, "\\"); PYSTRING_CHECK_EQUAL(head, "\\" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_nt(head, tail, "a"); PYSTRING_CHECK_EQUAL(head, "" ); PYSTRING_CHECK_EQUAL(tail, "a" );
split_nt(head, tail, "a\\"); PYSTRING_CHECK_EQUAL(head, "a" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_nt(head, tail, "c:\\a"); PYSTRING_CHECK_EQUAL(head, "c:\\" ); PYSTRING_CHECK_EQUAL(tail, "a" );
split_nt(head, tail, "c:\\a\\b"); PYSTRING_CHECK_EQUAL(head, "c:\\a" ); PYSTRING_CHECK_EQUAL(tail, "b" );
split_nt(head, tail, "c:\\a\\b\\"); PYSTRING_CHECK_EQUAL(head, "c:\\a\\b" ); PYSTRING_CHECK_EQUAL(tail, "" );
split_nt(head, tail, "D:\\dir\\\\"); PYSTRING_CHECK_EQUAL(head, "D:\\dir" ); PYSTRING_CHECK_EQUAL(tail, "" );
}
PYSTRING_ADD_TEST(pystring_os_path, splitext)
{
using namespace pystring::os::path;
std::string root, ext;
splitext_nt(root, ext, ""); PYSTRING_CHECK_EQUAL(root, ""); PYSTRING_CHECK_EQUAL(ext, "");
splitext_nt(root, ext, "."); PYSTRING_CHECK_EQUAL(root, "."); PYSTRING_CHECK_EQUAL(ext, "");
splitext_nt(root, ext, ".foo"); PYSTRING_CHECK_EQUAL(root, ".foo"); PYSTRING_CHECK_EQUAL(ext, "");
splitext_nt(root, ext, ".foo."); PYSTRING_CHECK_EQUAL(root, ".foo"); PYSTRING_CHECK_EQUAL(ext, ".");
splitext_nt(root, ext, ".foo.e"); PYSTRING_CHECK_EQUAL(root, ".foo"); PYSTRING_CHECK_EQUAL(ext, ".e");
splitext_nt(root, ext, "c"); PYSTRING_CHECK_EQUAL(root, "c"); PYSTRING_CHECK_EQUAL(ext, "");
splitext_nt(root, ext, "a_b.c"); PYSTRING_CHECK_EQUAL(root, "a_b"); PYSTRING_CHECK_EQUAL(ext, ".c");
splitext_nt(root, ext, "c:\\a.b.c"); PYSTRING_CHECK_EQUAL(root, "c:\\a.b"); PYSTRING_CHECK_EQUAL(ext, ".c");
splitext_nt(root, ext, "c:\\a_b.c"); PYSTRING_CHECK_EQUAL(root, "c:\\a_b"); PYSTRING_CHECK_EQUAL(ext, ".c");
}
+3 -32
View File
@@ -1,35 +1,6 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// Neither the name of the organization Sony Pictures Imageworks nor the
// names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
// Copyright Contributors to the Pystring project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/imageworks/pystring/blob/master/LICENSE
#ifndef INCLUDED_PYSTRING_UNITTEST_H
#define INCLUDED_PYSTRING_UNITTEST_H