[
  {
    "path": ".bazelci/presubmit.yml",
    "content": "---\ntasks:\n  ubuntu1804:\n    name: \"Ubuntu 22.04\"\n    platform: ubuntu2204\n    build_flags:\n    - \"--features=layering_check\"\n    - \"--copt=-Werror\"\n    build_targets:\n    - \"//...\"\n    test_flags:\n    - \"--features=layering_check\"\n    - \"--copt=-Werror\"\n    test_targets:\n    - \"//...\"\n  macos:\n    name: \"macOS: latest Xcode\"\n    platform: macos\n    build_flags:\n    - \"--features=layering_check\"\n    - \"--copt=-Werror\"\n    build_targets:\n    - \"//...\"\n    test_flags:\n    - \"--features=layering_check\"\n    - \"--copt=-Werror\"\n    test_targets:\n    - \"//...\"\n  windows-msvc:\n    name: \"Windows: MSVC 2017\"\n    platform: windows\n    environment:\n      BAZEL_VC: \"C:\\\\Program Files (x86)\\\\Microsoft Visual Studio\\\\2017\\\\BuildTools\\\\VC\"\n    build_flags:\n    - \"--features=layering_check\"\n    - \"--copt=/WX\"\n    build_targets:\n    - \"//...\"\n    test_flags:\n    - \"--features=layering_check\"\n    - \"--copt=/WX\"\n    test_targets:\n    - \"//...\"\n  windows-clang-cl:\n    name: \"Windows: Clang\"\n    platform: windows\n    environment:\n      BAZEL_VC: \"C:\\\\Program Files (x86)\\\\Microsoft Visual Studio\\\\2017\\\\BuildTools\\\\VC\"\n    build_flags:\n    - \"--extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl\"\n    - \"--extra_execution_platforms=//:x64_windows-clang-cl\"\n    - \"--compiler=clang-cl\"\n    - \"--features=layering_check\"\n    build_targets:\n    - \"//...\"\n    test_flags:\n    - \"--extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl\"\n    - \"--extra_execution_platforms=//:x64_windows-clang-cl\"\n    - \"--compiler=clang-cl\"\n    - \"--features=layering_check\"\n    test_targets:\n    - \"//...\"\n"
  },
  {
    "path": ".clang-format",
    "content": "---\nLanguage:        Cpp\n# BasedOnStyle:  Google\nAccessModifierOffset: -1\nAlignAfterOpenBracket: Align\nAlignConsecutiveMacros: false\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlines: Left\nAlignOperands:   true\nAlignTrailingComments: true\nAllowAllArgumentsOnNextLine: true\nAllowAllConstructorInitializersOnNextLine: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: Never\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: All\nAllowShortLambdasOnASingleLine: All\nAllowShortIfStatementsOnASingleLine: WithoutElse\nAllowShortLoopsOnASingleLine: true\nAlwaysBreakAfterDefinitionReturnType: None\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: true\nAlwaysBreakTemplateDeclarations: Yes\nBinPackArguments: true\nBinPackParameters: true\nBraceWrapping:\n  AfterCaseLabel:  false\n  AfterClass:      false\n  AfterControlStatement: false\n  AfterEnum:       false\n  AfterFunction:   false\n  AfterNamespace:  false\n  AfterObjCDeclaration: false\n  AfterStruct:     false\n  AfterUnion:      false\n  AfterExternBlock: false\n  BeforeCatch:     false\n  BeforeElse:      false\n  IndentBraces:    false\n  SplitEmptyFunction: true\n  SplitEmptyRecord: true\n  SplitEmptyNamespace: true\nBreakBeforeBinaryOperators: None\nBreakBeforeBraces: Attach\nBreakBeforeInheritanceComma: false\nBreakInheritanceList: BeforeColon\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: false\nBreakConstructorInitializers: BeforeColon\nBreakAfterJavaFieldAnnotations: false\nBreakStringLiterals: true\nColumnLimit:     80\nCommentPragmas:  '^ IWYU pragma:'\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: true\nConstructorInitializerIndentWidth: 4\nContinuationIndentWidth: 4\nCpp11BracedListStyle: true\nDeriveLineEnding: true\nDerivePointerAlignment: false\nDisableFormat:   false\nExperimentalAutoDetectBinPacking: false\nFixNamespaceComments: true\nForEachMacros:\n  - foreach\n  - Q_FOREACH\n  - BOOST_FOREACH\nIncludeBlocks:   Regroup\nIncludeCategories:\n  - Regex:           '^<ext/.*\\.h>'\n    Priority:        2\n    SortPriority:    0\n  - Regex:           '^<.*\\.h>'\n    Priority:        1\n    SortPriority:    0\n  - Regex:           '^<.*'\n    Priority:        2\n    SortPriority:    0\n  - Regex:           '.*'\n    Priority:        3\n    SortPriority:    0\nIncludeIsMainRegex: '([-_](test|unittest))?$'\nIncludeIsMainSourceRegex: ''\nIndentCaseLabels: true\nIndentGotoLabels: true\nIndentPPDirectives: AfterHash\nIndentWidth:     2\nIndentWrappedFunctionNames: false\nJavaScriptQuotes: Leave\nJavaScriptWrapImports: true\nKeepEmptyLinesAtTheStartOfBlocks: false\nMacroBlockBegin: ''\nMacroBlockEnd:   ''\nMaxEmptyLinesToKeep: 1\nNamespaceIndentation: None\nObjCBinPackProtocolList: Never\nObjCBlockIndentWidth: 2\nObjCSpaceAfterProperty: false\nObjCSpaceBeforeProtocolList: true\nPenaltyBreakAssignment: 2\nPenaltyBreakBeforeFirstCallParameter: 1\nPenaltyBreakComment: 300\nPenaltyBreakFirstLessLess: 120\nPenaltyBreakString: 1000\nPenaltyBreakTemplateDeclaration: 10\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 200\nPointerAlignment: Left\nRawStringFormats:\n  - Language:        Cpp\n    Delimiters:\n      - cc\n      - CC\n      - cpp\n      - Cpp\n      - CPP\n      - 'c++'\n      - 'C++'\n    CanonicalDelimiter: ''\n    BasedOnStyle:    google\n  - Language:        TextProto\n    Delimiters:\n      - pb\n      - PB\n      - proto\n      - PROTO\n    EnclosingFunctions:\n      - EqualsProto\n      - EquivToProto\n      - PARSE_PARTIAL_TEXT_PROTO\n      - PARSE_TEST_PROTO\n      - PARSE_TEXT_PROTO\n      - ParseTextOrDie\n      - ParseTextProtoOrDie\n    CanonicalDelimiter: ''\n    BasedOnStyle:    google\nReflowComments:  true\nSortIncludes:    true\nSortUsingDeclarations: true\nSpaceAfterCStyleCast: false\nSpaceAfterLogicalNot: false\nSpaceAfterTemplateKeyword: true\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeCpp11BracedList: false\nSpaceBeforeCtorInitializerColon: true\nSpaceBeforeInheritanceColon: true\nSpaceBeforeParens: ControlStatements\nSpaceBeforeRangeBasedForLoopColon: true\nSpaceInEmptyBlock: false\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 2\nSpacesInAngles:  false\nSpacesInConditionalStatement: false\nSpacesInContainerLiterals: true\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nSpaceBeforeSquareBrackets: false\nStandard:        c++14\nStatementMacros:\n  - Q_UNUSED\n  - QT_REQUIRE_VERSION\nTabWidth:        8\nUseCRLF:         false\nUseTab:          Never\n...\n\n"
  },
  {
    "path": ".clang-tidy",
    "content": "---\nChecks:          'clang-diagnostic-*,clang-analyzer-*,google-*,modernize-*,-modernize-use-trailing-return-type,readability-*,portability-*,performance-*,bugprone-*,android-*,darwin-*,clang-analyzer-*'\nWarningsAsErrors: ''\nHeaderFilterRegex: ''\nFormatStyle:     file\nCheckOptions:\n  - key:             cert-dcl16-c.NewSuffixes\n    value:           'L;LL;LU;LLU'\n  - key:             cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField\n    value:           '0'\n  - key:             cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors\n    value:           '1'\n  - key:             cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic\n    value:           '1'\n  - key:             google-build-namespaces.HeaderFileExtensions\n    value:           ',h,hh,hpp,hxx'\n  - key:             google-global-names-in-headers.HeaderFileExtensions\n    value:           ',h,hh,hpp,hxx'\n  - key:             google-readability-braces-around-statements.ShortStatementLines\n    value:           '1'\n  - key:             google-readability-function-size.BranchThreshold\n    value:           '4294967295'\n  - key:             google-readability-function-size.LineThreshold\n    value:           '4294967295'\n  - key:             google-readability-function-size.NestingThreshold\n    value:           '4294967295'\n  - key:             google-readability-function-size.ParameterThreshold\n    value:           '4294967295'\n  - key:             google-readability-function-size.StatementThreshold\n    value:           '800'\n  - key:             google-readability-function-size.VariableThreshold\n    value:           '4294967295'\n  - key:             google-readability-namespace-comments.ShortNamespaceLines\n    value:           '10'\n  - key:             google-readability-namespace-comments.SpacesBeforeComments\n    value:           '2'\n  - key:             google-runtime-int.SignedTypePrefix\n    value:           int\n  - key:             google-runtime-int.TypeSuffix\n    value:           ''\n  - key:             google-runtime-int.UnsignedTypePrefix\n    value:           uint\n  - key:             google-runtime-references.WhiteListTypes\n    value:           ''\n  - key:             modernize-loop-convert.MaxCopySize\n    value:           '16'\n  - key:             modernize-loop-convert.MinConfidence\n    value:           reasonable\n  - key:             modernize-loop-convert.NamingStyle\n    value:           CamelCase\n  - key:             modernize-pass-by-value.IncludeStyle\n    value:           llvm\n  - key:             modernize-replace-auto-ptr.IncludeStyle\n    value:           llvm\n  - key:             modernize-use-nullptr.NullMacros\n    value:           'NULL'\n...\n\n"
  },
  {
    "path": ".gitattributes",
    "content": "*.h linguist-language=C++\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# Set update schedule for GitHub Actions\n\nversion: 2\nupdates:\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      # Check for updates to GitHub Actions every week\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/android.yml",
    "content": "name: Android\n\non: [push, pull_request]\n\njobs:\n  build-android:\n    name: NDK-C++${{matrix.std}}-${{matrix.abi}}-${{matrix.build_type}}\n    runs-on: ubuntu-22.04\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    defaults:\n      run:\n        shell: bash\n    env:\n      NDK_VERSION: 26.0.10792818\n    strategy:\n      fail-fast: true\n      matrix:\n        std: [14, 17, 20]\n        abi: [arm64-v8a, armeabi-v7a, x86_64, x86]\n        build_type: [Debug, Release]\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: cpp\n\n      - name: Setup Dependencies\n        run: |\n          sudo apt-get update\n          DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \\\n            cmake \\\n            ninja-build\n\n      - name: Setup NDK\n        env:\n          ANDROID_SDK_ROOT: /usr/local/lib/android/sdk\n        run: |\n          echo 'y' | ${{env.ANDROID_SDK_ROOT}}/cmdline-tools/latest/bin/sdkmanager --install 'ndk;${{env.NDK_VERSION}}'\n\n      - name: Configure\n        env:\n          CXXFLAGS: -Wall -Wextra -Wpedantic -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}\n        run: |\n          cmake -S . -B build_${{matrix.abi}} \\\n                -DCMAKE_ANDROID_API=28 \\\n                -DCMAKE_ANDROID_ARCH_ABI=${{matrix.abi}} \\\n                -DCMAKE_ANDROID_NDK=/usr/local/lib/android/sdk/ndk/${{env.NDK_VERSION}} \\\n                -DCMAKE_ANDROID_STL_TYPE=c++_shared \\\n                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \\\n                -DCMAKE_CXX_EXTENSIONS=OFF \\\n                -DCMAKE_CXX_STANDARD=${{matrix.std}} \\\n                -DCMAKE_CXX_STANDARD_REQUIRED=ON \\\n                -DCMAKE_SYSTEM_NAME=Android \\\n                -G Ninja \\\n                -Werror\n\n      - name: Build\n        run: |\n          cmake --build build_${{matrix.abi}} \\\n                --config ${{matrix.build_type}}\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": ".github/workflows/cifuzz.yml",
    "content": "name: CIFuzz\non: [pull_request]\njobs:\n  Fuzzing:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Build Fuzzers\n      id: build\n      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master\n      with:\n        oss-fuzz-project-name: 'glog'\n        dry-run: false\n        language: c++\n    - name: Run Fuzzers\n      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master\n      with:\n        oss-fuzz-project-name: 'glog'\n        fuzz-seconds: 60\n        dry-run: false\n        language: c++\n    - name: Upload Crash\n      uses: actions/upload-artifact@v4\n      if: failure() && steps.build.outcome == 'success'\n      with:\n        name: artifacts\n        path: ./out/artifacts\n"
  },
  {
    "path": ".github/workflows/emscripten.yml",
    "content": "name: Emscripten\n\non: [push, pull_request]\n\njobs:\n  build-linux:\n    defaults:\n      run:\n        shell: bash\n    name: Emscripten-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}\n    runs-on: ubuntu-22.04\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    container: emscripten/emsdk\n    strategy:\n      fail-fast: true\n      matrix:\n        build_type: [Release, Debug]\n        lib: [static]\n        std: [14, 17, 20, 23]\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: cpp\n\n      - name: Setup Dependencies\n        run: |\n          sudo apt-get update\n          DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \\\n            cmake \\\n            ninja-build\n\n      - name: Configure\n        env:\n          CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -Wno-error=wasm-exception-spec ${{env.CXXFLAGS}}\n        run: |\n          emcmake cmake -S . -B build_${{matrix.build_type}} \\\n            -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \\\n            -DCMAKE_CXX_STANDARD=${{matrix.std}} \\\n            -DCMAKE_CXX_STANDARD_REQUIRED=ON \\\n            -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \\\n            -G Ninja \\\n            -Werror\n\n      - name: Build\n        run: |\n          cmake --build build_${{matrix.build_type}} \\\n                --config ${{matrix.build_type}}\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": ".github/workflows/linux.yml",
    "content": "name: Linux\n\non: [push, pull_request]\n\njobs:\n  build-linux:\n    defaults:\n      run:\n        shell: bash\n    name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}\n    runs-on: ubuntu-22.04\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    strategy:\n      fail-fast: true\n      matrix:\n        build_type: [Release, Debug]\n        lib: [shared, static]\n        std: [14, 17, 20, 23]\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: cpp\n\n      - name: Setup Dependencies\n        run: |\n          sudo apt-get update\n          DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-suggests --no-install-recommends \\\n            g++ \\\n            cmake \\\n            gcovr \\\n            libgflags-dev \\\n            libgmock-dev \\\n            libgtest-dev \\\n            libunwind-dev \\\n            ninja-build\n\n      - name: Setup Environment\n        if: matrix.build_type == 'Debug'\n        run: |\n          echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV\n\n      - name: Configure\n        env:\n          CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}\n        run: |\n          cmake -S . -B build_${{matrix.build_type}} \\\n            -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \\\n            -DCMAKE_CXX_STANDARD=${{matrix.std}} \\\n            -DCMAKE_CXX_STANDARD_REQUIRED=ON \\\n            -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \\\n            -G Ninja \\\n            -Werror\n\n      - name: Build\n        run: |\n          cmake --build build_${{matrix.build_type}} \\\n                --config ${{matrix.build_type}}\n\n      - name: Install\n        run: |\n          cmake --build build_${{matrix.build_type}} \\\n                --config ${{matrix.build_type}} \\\n                --target install\n\n          cmake build_${{matrix.build_type}} \\\n                -DCMAKE_INSTALL_INCLUDEDIR=${{runner.workspace}}/foo/include \\\n                -DCMAKE_INSTALL_LIBDIR=${{runner.workspace}}/foo/lib \\\n                -DCMAKE_INSTALL_DATAROOTDIR=${{runner.workspace}}/foo/share\n          cmake --build build_${{matrix.build_type}} \\\n                --config ${{matrix.build_type}} \\\n                --target install\n\n      - name: Test CMake Package (relative GNUInstallDirs)\n        run: |\n          cmake -S src/package_config_unittest/working_config \\\n                -B build_${{matrix.build_type}}_package \\\n                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \\\n                -DCMAKE_PREFIX_PATH=${{github.workspace}}/install \\\n                -G Ninja\n          cmake --build build_${{matrix.build_type}}_package \\\n                --config ${{matrix.build_type}}\n\n      - name: Test CMake Package (absolute GNUInstallDirs)\n        run: |\n          cmake -S src/package_config_unittest/working_config \\\n                -B build_${{matrix.build_type}}_package_foo \\\n                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \\\n                -DCMAKE_PREFIX_PATH=${{runner.workspace}}/foo \\\n                -G Ninja\n          cmake --build build_${{matrix.build_type}}_package_foo \\\n                --config ${{matrix.build_type}}\n\n      - name: Test\n        run: |\n          ctest --test-dir build_${{matrix.build_type}} -j$(nproc) --output-on-failure\n\n      - name: Generate Coverage\n        if: matrix.build_type == 'Debug'\n        run: |\n          cd build_${{matrix.build_type}}\n          gcovr -r .. . -s --xml coverage.xml\n\n      - name: Upload Coverage to Codecov\n        if: matrix.build_type == 'Debug'\n        uses: codecov/codecov-action@v5\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          files: build_${{matrix.build_type}}/coverage.xml\n          fail_ci_if_error: true\n          verbose: true\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": ".github/workflows/macos.yml",
    "content": "name: macOS\n\non: [push, pull_request]\n\njobs:\n  build-macos:\n    name: AppleClang-C++${{matrix.std}}-${{matrix.build_type}}\n    runs-on: macos-12\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    strategy:\n      fail-fast: true\n      matrix:\n        std: [14, 17, 20, 23]\n        include:\n          - generator: Xcode\n          - build_type: Debug\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Dependencies\n        run: |\n          brew install ninja\n\n      - name: Setup Coverage Dependencies\n        if: matrix.build_type == 'Debug'\n        run: |\n          brew install gcovr\n\n      - name: Setup Environment\n        if: matrix.build_type == 'Debug'\n        run: |\n          echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV\n          echo 'LDFLAGS=--coverage' >> $GITHUB_ENV\n\n      - name: Configure\n        shell: bash\n        env:\n          CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -pedantic-errors ${{env.CXXFLAGS}}\n        run: |\n          cmake -S . -B build_${{matrix.build_type}} \\\n                -DCMAKE_CXX_EXTENSIONS=OFF \\\n                -DCMAKE_CXX_STANDARD=${{matrix.std}} \\\n                -DCMAKE_CXX_STANDARD_REQUIRED=ON \\\n                -G \"${{matrix.generator}}\" \\\n                -Werror\n\n      - name: Build\n        run: |\n          cmake --build build_${{matrix.build_type}} \\\n                --config ${{matrix.build_type}}\n\n      - name: Test\n        run: |\n          ctest --test-dir build_${{matrix.build_type}} \\\n                --build-config ${{matrix.build_type}} \\\n                --output-on-failure\n\n      - name: Generate Coverage\n        if: matrix.build_type == 'Debug'\n        run: |\n          cd build_${{matrix.build_type}}\n          rm -r Tests/\n          gcovr -r .. . -s --cobertura coverage.xml\n\n      - name: Upload Coverage to Codecov\n        if: matrix.build_type == 'Debug'\n        uses: codecov/codecov-action@v5\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          files: build_${{matrix.build_type}}/coverage.xml\n          fail_ci_if_error: true\n          verbose: true\n"
  },
  {
    "path": ".github/workflows/windows.yml",
    "content": "name: Windows\n\non: [push, pull_request]\n\njobs:\n  build-msvc:\n    name: ${{matrix.msvc}}-${{matrix.arch}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}\n    runs-on: ${{matrix.os}}\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    defaults:\n      run:\n        shell: powershell\n    env:\n      CL: /MP\n      CXXFLAGS: /WX /permissive-\n    strategy:\n      fail-fast: true\n      matrix:\n        arch: [Win32, x64]\n        build_type: [Debug, Release]\n        lib: [shared, static]\n        msvc: [VS-16-2019, VS-17-2022]\n        std: [14, 17, 20, 23]\n        include:\n          - msvc: VS-16-2019\n            os: windows-2019\n            generator: 'Visual Studio 16 2019'\n          - msvc: VS-17-2022\n            os: windows-2022\n            generator: 'Visual Studio 17 2022'\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: cpp\n\n      - name: Cache GTest\n        id: cache-gtest\n        uses: actions/cache@v4\n        with:\n          path: gtest/\n          key: ${{runner.os}}-gtest-1.14-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}\n\n      - name: Download GTest\n        if: steps.cache-gtest.outputs.cache-hit != 'true'\n        run: |\n          (New-Object System.Net.WebClient).DownloadFile(\"https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip\", \"v1.14.0.zip\")\n          Expand-Archive v1.14.0.zip .\n\n      - name: Build GTest\n        if: steps.cache-gtest.outputs.cache-hit != 'true'\n        run: |\n          cmake -S googletest-1.14.0 -B build-googletest `\n                -A ${{matrix.arch}} `\n                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `\n                -Dgtest_force_shared_crt=ON `\n                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gtest\n          cmake --build build-googletest `\n                --config ${{matrix.build_type}} `\n                --target install\n\n      - name: Cache gflags\n        id: cache-gflags\n        uses: actions/cache@v4\n        with:\n          path: gflags/\n          key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}\n\n      - name: Download gflags\n        if: steps.cache-gflags.outputs.cache-hit != 'true'\n        run: |\n          (New-Object System.Net.WebClient).DownloadFile(\"https://github.com/gflags/gflags/archive/refs/tags/v2.2.2.zip\", \"v2.2.2.zip\")\n          Expand-Archive v2.2.2.zip .\n\n      - name: Build gflags\n        if: steps.cache-gflags.outputs.cache-hit != 'true'\n        run: |\n          cmake -S gflags-2.2.2 -B build-gflags `\n                -A ${{matrix.arch}} `\n                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `\n                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gflags\n          cmake --build build-gflags `\n                --config ${{matrix.build_type}} `\n                --target install\n\n      - name: Setup Environment\n        run: |\n          echo \"GTest_ROOT=$((Get-Item .).FullName)/gtest\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n          echo \"gflags_ROOT=$((Get-Item .).FullName)/gflags\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n          echo \"${{github.workspace}}/gtest/bin\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append\n          echo \"${{github.workspace}}/gflags/bin\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append\n\n      - name: Setup Release Environment\n        if: matrix.build_type != 'Debug'\n        run: |\n          echo \"CXXFLAGS=/Zi ${{env.CXXFLAGS}}\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n\n      - name: Configure\n        run: |\n          cmake -S . -B build_${{matrix.build_type}} `\n                -A ${{matrix.arch}} `\n                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `\n                -DCMAKE_CXX_EXTENSIONS=OFF `\n                -DCMAKE_CXX_STANDARD=${{matrix.std}} `\n                -DCMAKE_CXX_STANDARD_REQUIRED=ON `\n                -DCMAKE_EXE_LINKER_FLAGS='/NOIMPLIB' `\n                -DCMAKE_EXE_LINKER_FLAGS_RELEASE='/INCREMENTAL:NO /DEBUG' `\n                -DCMAKE_INSTALL_PREFIX:PATH=./install `\n                -DCMAKE_MSVC_RUNTIME_LIBRARY='MultiThreaded$<$<CONFIG:Debug>:Debug>DLL' `\n                -G \"${{matrix.generator}}\" `\n                -Werror\n\n      - name: Build\n        run: cmake --build build_${{matrix.build_type}} `\n                   --config ${{matrix.build_type}}\n\n      - name: Test\n        env:\n          CTEST_OUTPUT_ON_FAILURE: 1\n        run: |\n          cmake --build build_${{matrix.build_type}}/ `\n                --config ${{matrix.build_type}} `\n                --target RUN_TESTS\n\n      - name: Install\n        run: |\n          cmake --build build_${{matrix.build_type}}/ `\n                --config ${{matrix.build_type}} `\n                --target install\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n        with:\n          category: language:cpp\n\n  build-mingw:\n    name: ${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}\n    runs-on: windows-2022\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    env:\n      BUILDDIR: 'build_${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}'\n    defaults:\n      run:\n        shell: msys2 {0}\n    strategy:\n      fail-fast: true\n      matrix:\n        build_type: [Debug]\n        lib: [shared, static]\n        std: [14, 17, 20, 23]\n        sys: [mingw32, mingw64]\n        include:\n         - sys: mingw32\n           env: i686\n         - sys: mingw64\n           env: x86_64\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: cpp\n\n      - uses: msys2/setup-msys2@v2\n        with:\n          msystem: ${{matrix.sys}}\n          install: >-\n            mingw-w64-${{matrix.env}}-cmake\n            mingw-w64-${{matrix.env}}-gcc\n            mingw-w64-${{matrix.env}}-gflags\n            mingw-w64-${{matrix.env}}-ninja\n            mingw-w64-${{matrix.env}}-python-jinja\n            mingw-w64-${{matrix.env}}-python-lxml\n            mingw-w64-${{matrix.env}}-python-pip\n            mingw-w64-${{matrix.env}}-python-pygments\n\n      - name: Setup Coverage Dependencies\n        if: matrix.build_type == 'Debug'\n        run: |\n          pip install 'gcovr==7.0'\n\n      - name: Setup Environment\n        if: matrix.build_type == 'Debug'\n        run: |\n          echo 'CXXFLAGS=--coverage ${{env.CXXFLAGS}}' >> $GITHUB_ENV\n\n      - name: Configure\n        env:\n          CXXFLAGS: -Wall -Wextra -Wpedantic -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}\n        run: |\n          cmake -S . -B build_${{matrix.build_type}}/ \\\n                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \\\n                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \\\n                -DCMAKE_CXX_EXTENSIONS=OFF \\\n                -DCMAKE_CXX_STANDARD=${{matrix.std}} \\\n                -DCMAKE_CXX_STANDARD_REQUIRED=ON \\\n                -DCMAKE_INSTALL_PREFIX:PATH=./install \\\n                -G Ninja \\\n                -Werror\n\n      - name: Build\n        run: |\n          cmake --build build_${{matrix.build_type}}/ --config ${{matrix.build_type}}\n\n      - name: Test\n        env:\n          CTEST_OUTPUT_ON_FAILURE: 1\n        run: |\n          cmake --build build_${{matrix.build_type}}/ --config ${{matrix.build_type}} \\\n                --target test\n\n      - name: Install\n        run: |\n          cmake --build build_${{matrix.build_type}}/ \\\n                --config ${{matrix.build_type}} \\\n                --target install\n\n      - name: Generate Coverage\n        if: matrix.build_type == 'Debug'\n        run: |\n          cd build_${{matrix.build_type}}\n          gcovr -r .. . -s --cobertura coverage.xml\n\n      - name: Upload Coverage to Codecov\n        if: matrix.build_type == 'Debug'\n        uses: codecov/codecov-action@v5\n        with:\n          token: ${{ secrets.CODECOV_TOKEN }}\n          files: build_${{matrix.build_type}}/coverage.xml\n          fail_ci_if_error: true\n          verbose: true\n\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": ".gitignore",
    "content": "*.orig\n/build*/\n/site/\nbazel-*\n# Bzlmod lockfile\n/MODULE.bazel.lock\n"
  },
  {
    "path": "AUTHORS",
    "content": "# This is the official list of glog authors for copyright purposes.\n# This file is distinct from the CONTRIBUTORS files.\n# See the latter for an explanation.\n#\n# Names should be added to this file as:\n#\tName or Organization <email address>\n# The email address is not required for organizations.\n#\n# Please keep the list sorted.\n\nAbhishek Dasgupta <abhi2743@gmail.com>\nAbhishek Parmar <abhishek@orng.net>\nAndrew Schwartzmeyer <andrew@schwartzmeyer.com>\nAndy Ying <andy@trailofbits.com>\nBrian Silverman <bsilver16384@gmail.com>\nDmitriy Arbitman <d.arbitman@gmail.com>\nGoogle Inc.\nGuillaume Dumont <dumont.guillaume@gmail.com>\nLingBin <lingbinlb@gmail.com>\nMarco Wang <m.aesophor@gmail.com>\nMichael Tanner <michael@tannertaxpro.com>\nMiniLight <MiniLightAR@Gmail.com>\nromange <romange@users.noreply.github.com>\nRoman Perepelitsa <roman.perepelitsa@gmail.com>\nSergiu Deitsch <sergiu.deitsch@gmail.com>\ntbennun <tbennun@gmail.com>\nTeddy Reed <teddy@prosauce.org>\nVijaymahantesh Sattigeri <vijaymahantesh016@gmail.com>\nZhongming Qu <qzmfranklin@gmail.com>\nZhuoran Shen <cmsflash99@gmail.com>\n"
  },
  {
    "path": "BUILD.bazel",
    "content": "licenses([\"notice\"])\n\nexports_files([\"COPYING\"])\n\nload(\":bazel/glog.bzl\", \"glog_library\")\n\nglog_library()\n\n# platform() to build with clang-cl on Bazel CI. This is enabled with\n# the flags in .bazelci/presubmit.yml:\n#\n#   --incompatible_enable_cc_toolchain_resolution\n#   --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl\n#   --extra_execution_platforms=//:x64_windows-clang-cl\nplatform(\n    name = \"x64_windows-clang-cl\",\n    constraint_values = [\n        \"@platforms//cpu:x86_64\",\n        \"@platforms//os:windows\",\n        \"@rules_cc//cc/private/toolchain:clang-cl\",\n    ],\n)\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required (VERSION 3.22)\nproject (glog\n  VERSION 0.8.0\n  DESCRIPTION \"C++ implementation of the Google logging module\"\n  HOMEPAGE_URL https://github.com/google/glog\n  LANGUAGES CXX\n)\n\nset (CPACK_PACKAGE_NAME glog)\nset (CPACK_PACKAGE_DESCRIPTION_SUMMARY \"Google logging library\")\nset (CPACK_PACKAGE_VERSION_MAJOR ${glog_VERSION_MAJOR})\nset (CPACK_PACKAGE_VERSION_MINOR ${glog_VERSION_MINOR})\nset (CPACK_PACKAGE_VERSION_PATCH ${glog_VERSION_PATCH})\nset (CPACK_PACKAGE_VERSION ${glog_VERSION})\n\nlist (APPEND CMAKE_MODULE_PATH ${glog_SOURCE_DIR}/cmake)\n\ninclude (CheckCXXSourceCompiles)\ninclude (CheckCXXSourceRuns)\ninclude (CheckCXXSymbolExists)\ninclude (CheckIncludeFileCXX)\ninclude (CheckStructHasMember)\ninclude (CheckTypeSize)\ninclude (CMakeDependentOption)\ninclude (CMakePackageConfigHelpers)\ninclude (CMakePushCheckState)\ninclude (CPack)\ninclude (CTest)\ninclude (DetermineGflagsNamespace)\ninclude (GenerateExportHeader)\ninclude (GetCacheVariables)\ninclude (GNUInstallDirs)\n\noption (BUILD_SHARED_LIBS \"Build shared libraries\" ON)\noption (BUILD_EXAMPLES \"Build examples\" ON)\noption (PRINT_UNSYMBOLIZED_STACK_TRACES\n  \"Print file offsets in traces instead of symbolizing\" OFF)\noption (WITH_GFLAGS \"Use gflags\" ON)\noption (WITH_GTEST \"Use Google Test\" ON)\noption (WITH_PKGCONFIG \"Enable pkg-config support\" OFF)\noption (WITH_SYMBOLIZE \"Enable symbolize module\" ON)\noption (WITH_TLS \"Enable Thread Local Storage (TLS) support\" ON)\n\nset (WITH_UNWIND libunwind CACHE STRING \"unwind driver\")\nset_property (CACHE WITH_UNWIND PROPERTY STRINGS none unwind libunwind)\n\ncmake_dependent_option (WITH_GMOCK \"Use Google Mock\" ON WITH_GTEST OFF)\n\nset (WITH_FUZZING none CACHE STRING \"Fuzzing engine\")\nset_property (CACHE WITH_FUZZING PROPERTY STRINGS none libfuzzer ossfuzz)\n\nif (WITH_UNWIND STREQUAL none)\n  set (CMAKE_DISABLE_FIND_PACKAGE_Unwind ON)\nendif (WITH_UNWIND STREQUAL none)\n\nif (NOT WITH_GTEST)\n  set (CMAKE_DISABLE_FIND_PACKAGE_GTest ON)\nendif (NOT WITH_GTEST)\n\nset (CMAKE_C_VISIBILITY_PRESET hidden)\nset (CMAKE_CXX_VISIBILITY_PRESET hidden)\nset (CMAKE_POSITION_INDEPENDENT_CODE ON)\nset (CMAKE_VISIBILITY_INLINES_HIDDEN ON)\n\nset (CMAKE_DEBUG_POSTFIX d)\n\nfind_package (GTest 1.11 COMPONENTS GTest OPTIONAL_COMPONENTS GMock NO_MODULE)\n\nif (GTest_FOUND)\n  set (HAVE_LIB_GTEST 1)\nendif (GTest_FOUND)\n\nif (WITH_GMOCK AND TARGET GTest::gmock)\n  set (HAVE_LIB_GMOCK 1)\nendif (WITH_GMOCK AND TARGET GTest::gmock)\n\nif (WITH_GFLAGS)\n  find_package (gflags 2.2.2)\n\n  if (gflags_FOUND)\n    set (HAVE_LIB_GFLAGS 1)\n    determine_gflags_namespace (gflags_NAMESPACE)\n  endif (gflags_FOUND)\nendif (WITH_GFLAGS)\n\nfind_package (Threads REQUIRED)\nfind_package (Unwind)\n\nif (Unwind_FOUND)\n  cmake_push_check_state (RESET)\n  set (CMAKE_REQUIRED_LIBRARIES unwind::unwind)\n\n  # Check whether linking actually succeeds. ARM toolchains of LLVM unwind\n  # implementation do not necessarily provide the _Unwind_Backtrace function\n  # which causes the previous check to succeed but the linking to fail.\n  check_cxx_symbol_exists (_Unwind_Backtrace unwind.h HAVE__UNWIND_BACKTRACE)\n  check_cxx_symbol_exists (_Unwind_GetIP unwind.h HAVE__UNWIND_GETIP)\n\n  check_cxx_symbol_exists (unw_get_reg libunwind.h HAVE_UNW_GET_REG)\n  check_cxx_symbol_exists (unw_getcontext libunwind.h HAVE_UNW_GETCONTEXT)\n  check_cxx_symbol_exists (unw_init_local libunwind.h HAVE_UNW_INIT_LOCAL)\n  check_cxx_symbol_exists (unw_step libunwind.h HAVE_UNW_STEP)\n\n  if (HAVE__UNWIND_BACKTRACE AND HAVE__UNWIND_GETIP)\n    set (_HAVE_UNWIND 1)\n  endif (HAVE__UNWIND_BACKTRACE AND HAVE__UNWIND_GETIP)\n\n  if (HAVE_UNW_GET_REG AND HAVE_UNW_GETCONTEXT AND HAVE_UNW_INIT_LOCAL AND HAVE_UNW_STEP)\n    set (_HAVE_LIBUNWIND 1)\n  endif (HAVE_UNW_GET_REG AND HAVE_UNW_GETCONTEXT AND HAVE_UNW_INIT_LOCAL AND HAVE_UNW_STEP)\n\n  if (WITH_UNWIND STREQUAL unwind)\n    if (_HAVE_UNWIND)\n      set (HAVE_UNWIND 1)\n    endif (_HAVE_UNWIND)\n  elseif (WITH_UNWIND STREQUAL libunwind)\n    if (_HAVE_LIBUNWIND)\n      set (HAVE_LIBUNWIND 1)\n    endif (_HAVE_LIBUNWIND)\n  endif (WITH_UNWIND STREQUAL unwind)\n\n  unset (_HAVE_LIBUNWIND)\n  unset (_HAVE_UNWIND)\n\n  cmake_pop_check_state ()\nendif (Unwind_FOUND)\n\ncheck_include_file_cxx (dlfcn.h HAVE_DLFCN_H)\ncheck_include_file_cxx (elf.h HAVE_ELF_H)\ncheck_include_file_cxx (glob.h HAVE_GLOB_H)\ncheck_include_file_cxx (link.h HAVE_LINK_H)\ncheck_include_file_cxx (pwd.h HAVE_PWD_H)\ncheck_include_file_cxx (sys/exec_elf.h HAVE_SYS_EXEC_ELF_H)\ncheck_include_file_cxx (sys/syscall.h HAVE_SYS_SYSCALL_H)\ncheck_include_file_cxx (sys/time.h HAVE_SYS_TIME_H)\ncheck_include_file_cxx (sys/types.h HAVE_SYS_TYPES_H)\ncheck_include_file_cxx (sys/utsname.h HAVE_SYS_UTSNAME_H)\ncheck_include_file_cxx (sys/wait.h HAVE_SYS_WAIT_H)\ncheck_include_file_cxx (syscall.h HAVE_SYSCALL_H)\ncheck_include_file_cxx (syslog.h HAVE_SYSLOG_H)\ncheck_include_file_cxx (ucontext.h HAVE_UCONTEXT_H)\ncheck_include_file_cxx (unistd.h HAVE_UNISTD_H)\n\ncheck_type_size (mode_t HAVE_MODE_T LANGUAGE CXX)\ncheck_type_size (ssize_t HAVE_SSIZE_T LANGUAGE CXX)\n\ncheck_cxx_symbol_exists (dladdr dlfcn.h HAVE_DLADDR)\ncheck_cxx_symbol_exists (fcntl fcntl.h HAVE_FCNTL)\ncheck_cxx_symbol_exists (posix_fadvise fcntl.h HAVE_POSIX_FADVISE)\ncheck_cxx_symbol_exists (pread unistd.h HAVE_PREAD)\ncheck_cxx_symbol_exists (pwrite unistd.h HAVE_PWRITE)\ncheck_cxx_symbol_exists (sigaction csignal HAVE_SIGACTION)\ncheck_cxx_symbol_exists (sigaltstack csignal HAVE_SIGALTSTACK)\n\ncheck_cxx_symbol_exists (backtrace execinfo.h HAVE_EXECINFO_BACKTRACE)\ncheck_cxx_symbol_exists (backtrace_symbols execinfo.h\n  HAVE_EXECINFO_BACKTRACE_SYMBOLS)\ncheck_cxx_symbol_exists (_chsize_s io.h HAVE__CHSIZE_S)\n\ncmake_push_check_state (RESET)\nset (CMAKE_REQUIRED_LIBRARIES dbghelp)\ncheck_cxx_symbol_exists (UnDecorateSymbolName \"windows.h;dbghelp.h\" HAVE_DBGHELP)\ncmake_pop_check_state ()\n\nif (WITH_FUZZING STREQUAL none)\n  # Disable compiler demangler if fuzzing is active; we only want to use the\n  # glog demangler then.\n  check_cxx_symbol_exists (abi::__cxa_demangle cxxabi.h HAVE___CXA_DEMANGLE)\nendif (WITH_FUZZING STREQUAL none)\n\ncheck_cxx_symbol_exists (__argv cstdlib HAVE___ARGV)\ncheck_cxx_symbol_exists (getprogname cstdlib HAVE_GETPROGNAME)\ncheck_cxx_symbol_exists (program_invocation_short_name cerrno HAVE_PROGRAM_INVOCATION_SHORT_NAME)\ncheck_cxx_source_compiles ([=[\n#include <cstdlib>\nextern char* __progname;\nint main() { return __progname != nullptr ? EXIT_SUCCESS : EXIT_FAILURE; }\n]=] HAVE___PROGNAME)\n\nif (WITH_TLS)\n  set (GLOG_THREAD_LOCAL_STORAGE 1)\nendif (WITH_TLS)\n\nset (_PC_FIELDS\n  \"uc_mcontext.gregs[REG_PC]\"          # Solaris x86 (32 + 64 bit)\n  \"uc_mcontext.gregs[REG_EIP]\"         # Linux (i386)\n  \"uc_mcontext.gregs[REG_RIP]\"         # Linux (x86_64)\n  \"uc_mcontext.sc_ip\"                  # Linux (ia64)\n  \"uc_mcontext.pc\"                     # Linux (mips)\n  \"uc_mcontext.uc_regs->gregs[PT_NIP]\" # Linux (ppc)\n  \"uc_mcontext.gregs[R15]\"             # Linux (arm old [untested])\n  \"uc_mcontext.arm_pc\"                 # Linux (arm arch 5)\n  \"uc_mcontext.gp_regs[PT_NIP]\"        # Suse SLES 11 (ppc64)\n  \"uc_mcontext.mc_eip\"                 # FreeBSD (i386)\n  \"uc_mcontext.mc_rip\"                 # FreeBSD (x86_64 [untested])\n  \"uc_mcontext.__gregs[_REG_EIP]\"      # NetBSD (i386)\n  \"uc_mcontext.__gregs[_REG_RIP]\"      # NetBSD (x86_64)\n  \"uc_mcontext->ss.eip\"                # OS X (i386, <=10.4)\n  \"uc_mcontext->__ss.__eip\"            # OS X (i386, >=10.5)\n  \"uc_mcontext->ss.rip\"                # OS X (x86_64)\n  \"uc_mcontext->__ss.__rip\"            # OS X (>=10.5 [untested])\n  \"uc_mcontext->ss.srr0\"               # OS X (ppc, ppc64 [untested])\n  \"uc_mcontext->__ss.__srr0\"           # OS X (>=10.5 [untested])\n)\n\nif (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT)\n  cmake_push_check_state (RESET)\n\n  set (CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)\n  set (_PC_HEADERS ucontext.h signal.h)\n\n  foreach (_PC_FIELD IN LISTS _PC_FIELDS)\n    foreach (_PC_HEADER IN LISTS _PC_HEADERS)\n      # Replace non-alphanumeric characters by underscores since the name will be\n      # used as preprocessor definition.\n      string (REGEX REPLACE \"[^a-zA-Z0-9]\" \"_\" HAVE_UCONTEXT_FIELD_NAME\n        \"HAVE_PC_FROM_UCONTEXT_${_PC_FIELD}\")\n      # Strip trailing underscores for readability\n      string (REGEX REPLACE \"_+$\" \"\" HAVE_UCONTEXT_FIELD_NAME\n        \"${HAVE_UCONTEXT_FIELD_NAME}\")\n\n      check_struct_has_member (ucontext_t ${_PC_FIELD} ${_PC_HEADER}\n        ${HAVE_UCONTEXT_FIELD_NAME} LANGUAGE CXX)\n\n      if (${HAVE_UCONTEXT_FIELD_NAME})\n        set (PC_FROM_UCONTEXT ${_PC_FIELD} CACHE STRING\n          \"<${_PC_HEADER}> ucontext_t PC member\")\n        mark_as_advanced (PC_FROM_UCONTEXT)\n        break ()\n      endif (${HAVE_UCONTEXT_FIELD_NAME})\n    endforeach (_PC_HEADER)\n\n    if (${HAVE_UCONTEXT_FIELD_NAME})\n      break ()\n    endif (${HAVE_UCONTEXT_FIELD_NAME})\n  endforeach (_PC_FIELD)\n\n  cmake_pop_check_state ()\nendif (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT)\n\nif (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)\n  set (HAVE_STACKTRACE 1)\nendif (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)\n\nif (WITH_SYMBOLIZE)\n  if (WIN32 OR CYGWIN)\n    cmake_push_check_state (RESET)\n    set (CMAKE_REQUIRED_LIBRARIES DbgHelp)\n\n    check_cxx_source_runs ([=[\n    #include <windows.h>\n    #include <dbghelp.h>\n    #include <cstdlib>\n\n    void foobar() { }\n\n    int main()\n    {\n        HANDLE process = GetCurrentProcess();\n\n        if (!SymInitialize(process, NULL, TRUE))\n            return EXIT_FAILURE;\n\n        char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];\n        SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(buf);\n        symbol->SizeOfStruct = sizeof(SYMBOL_INFO);\n        symbol->MaxNameLen = MAX_SYM_NAME;\n\n        void* const pc = reinterpret_cast<void*>(&foobar);\n        BOOL ret = SymFromAddr(process, reinterpret_cast<DWORD64>(pc), 0, symbol);\n\n        return ret ? EXIT_SUCCESS : EXIT_FAILURE;\n    }\n    ]=] HAVE_SYMBOLIZE)\n\n    cmake_pop_check_state ()\n\n    if (HAVE_SYMBOLIZE)\n      set (HAVE_STACKTRACE 1)\n    endif (HAVE_SYMBOLIZE)\n  elseif (APPLE AND HAVE_DLADDR)\n    set (HAVE_SYMBOLIZE 1)\n  elseif (UNIX)\n    if (HAVE_ELF_H OR HAVE_SYS_EXEC_ELF_H)\n      set (HAVE_SYMBOLIZE 1)\n    endif (HAVE_ELF_H OR HAVE_SYS_EXEC_ELF_H)\n  endif (WIN32 OR CYGWIN)\nendif (WITH_SYMBOLIZE)\n\n# CMake manages symbolize availability. The definition is necessary only when\n# building the library.\nadd_compile_definitions (GLOG_NO_SYMBOLIZE_DETECTION)\n\ncheck_cxx_symbol_exists (gmtime_r \"cstdlib;ctime\" HAVE_GMTIME_R)\ncheck_cxx_symbol_exists (localtime_r \"cstdlib;ctime\" HAVE_LOCALTIME_R)\n\nset (SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})\n\n# fopen/open on Cygwin can not handle unix-type paths like /home/....\n# therefore we translate TEST_SRC_DIR to windows-path.\nif (CYGWIN)\n  execute_process (COMMAND cygpath.exe -m ${glog_SOURCE_DIR}\n                   OUTPUT_STRIP_TRAILING_WHITESPACE\n                   OUTPUT_VARIABLE TEST_SRC_DIR)\n  set (TEST_SRC_DIR \\\"${TEST_SRC_DIR}\\\")\nelse (CYGWIN)\n  set (TEST_SRC_DIR \\\"${glog_SOURCE_DIR}\\\")\nendif (CYGWIN)\n\nconfigure_file (src/config.h.cmake.in config.h)\n\nset (_glog_CMake_BINDIR ${CMAKE_INSTALL_BINDIR})\nset (_glog_CMake_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})\nset (_glog_CMake_LIBDIR ${CMAKE_INSTALL_LIBDIR})\nset (_glog_CMake_INSTALLDIR ${_glog_CMake_LIBDIR}/cmake/glog)\n\nset (_glog_CMake_DIR glog/cmake)\nset (_glog_CMake_DATADIR ${CMAKE_INSTALL_DATAROOTDIR}/${_glog_CMake_DIR})\nset (_glog_BINARY_CMake_DATADIR\n  ${glog_BINARY_DIR}/${_glog_CMake_DATADIR})\n\n# Add additional CMake find modules here.\nset (_glog_CMake_MODULES)\n\nif (Unwind_FOUND)\n  # Copy the module only if libunwind is actually used.\n  list (APPEND _glog_CMake_MODULES ${glog_SOURCE_DIR}/cmake/FindUnwind.cmake)\nendif (Unwind_FOUND)\n\n# Generate file name for each module in the binary directory\nforeach (_file ${_glog_CMake_MODULES})\n  get_filename_component (_module \"${_file}\" NAME)\n\n  list (APPEND _glog_BINARY_CMake_MODULES\n    ${_glog_BINARY_CMake_DATADIR}/${_module})\nendforeach (_file)\n\nif (_glog_CMake_MODULES)\n  # Copy modules to binary directory during the build\n  add_custom_command (OUTPUT ${_glog_BINARY_CMake_MODULES}\n    COMMAND ${CMAKE_COMMAND} -E make_directory\n    ${_glog_BINARY_CMake_DATADIR}\n    COMMAND ${CMAKE_COMMAND} -E copy ${_glog_CMake_MODULES}\n    ${_glog_BINARY_CMake_DATADIR}\n    DEPENDS ${_glog_CMake_MODULES}\n    COMMENT \"Copying find modules...\"\n  )\nendif (_glog_CMake_MODULES)\n\nset (GLOG_PUBLIC_H\n  ${glog_BINARY_DIR}/glog/export.h\n  src/glog/log_severity.h\n  src/glog/logging.h\n  src/glog/platform.h\n  src/glog/raw_logging.h\n  src/glog/stl_logging.h\n  src/glog/types.h\n  src/glog/flags.h\n  src/glog/vlog_is_on.h\n)\n\nset (GLOG_SRCS\n  ${GLOG_PUBLIC_H}\n  src/base/commandlineflags.h\n  src/base/googleinit.h\n  src/demangle.cc\n  src/demangle.h\n  src/flags.cc\n  src/logging.cc\n  src/raw_logging.cc\n  src/signalhandler.cc\n  src/stacktrace.cc\n  src/stacktrace.h\n  src/symbolize.cc\n  src/symbolize.h\n  src/utilities.cc\n  src/utilities.h\n  src/vlog_is_on.cc\n)\n\n# NOTE MSYS2 defines both WIN32 and UNIX. Do not use windows port in this case.\nif ((CYGWIN OR WIN32) AND NOT UNIX)\n  list (APPEND GLOG_SRCS\n    src/windows/port.cc\n    src/windows/port.h\n  )\n  set (_glog_USE_WINDOWS_PORT TRUE)\nendif ((CYGWIN OR WIN32) AND NOT UNIX)\n\nadd_library (glog_internal OBJECT\n  ${_glog_BINARY_CMake_MODULES}\n  ${GLOG_SRCS}\n)\ntarget_compile_features (glog_internal PUBLIC $<TARGET_PROPERTY:glog,COMPILE_FEATURES>)\nset_target_properties (glog_internal PROPERTIES DEFINE_SYMBOL GOOGLE_GLOG_IS_A_DLL)\n\n# Some generators (such as Xcode) do not generate any output if the target does\n# not reference at least one source file.\nset (_glog_EMPTY_SOURCE ${glog_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/glog.cc)\n\nadd_custom_command (\n  OUTPUT ${_glog_EMPTY_SOURCE}\n  COMMAND ${CMAKE_COMMAND} -E touch ${_glog_EMPTY_SOURCE}\n)\n\nadd_library (glog\n  $<TARGET_OBJECTS:glog_internal>\n  ${_glog_EMPTY_SOURCE}\n)\ntarget_compile_features (glog PUBLIC cxx_std_14)\n\nadd_library (glog::glog ALIAS glog)\n\nset (glog_libraries_options_for_static_linking)\n\n# CMake always uses the generated export header\ntarget_compile_definitions (glog PUBLIC GLOG_USE_GLOG_EXPORT)\n\nif (_glog_USE_WINDOWS_PORT)\n  target_compile_definitions (glog PRIVATE GLOG_USE_WINDOWS_PORT)\nendif (_glog_USE_WINDOWS_PORT)\n\nunset (_glog_USE_WINDOWS_PORT)\n\nif (WIN32)\n  # Do not define min and max as macros\n  target_compile_definitions (glog PRIVATE NOMINMAX)\n  # Exclude unnecessary funcitonality\n  target_compile_definitions (glog PRIVATE WIN32_LEAN_AND_MEAN)\nendif (WIN32)\n\nif (HAVE_LIB_GFLAGS)\n  target_compile_definitions (glog PUBLIC GLOG_USE_GFLAGS)\nendif (HAVE_LIB_GFLAGS)\n\nif (Unwind_FOUND)\n  target_link_libraries (glog PRIVATE unwind::unwind)\n  set (glog_libraries_options_for_static_linking \"${glog_libraries_options_for_static_linking} -lunwind\")\n  set (Unwind_DEPENDENCY \"find_dependency (Unwind ${Unwind_VERSION})\")\nendif (Unwind_FOUND)\n\nif (HAVE_DBGHELP)\n  target_link_libraries (glog PRIVATE dbghelp)\n  set (glog_libraries_options_for_static_linking \"${glog_libraries_options_for_static_linking} -ldbghelp\")\nendif (HAVE_DBGHELP)\n\ntarget_link_libraries (glog PRIVATE Threads::Threads)\n\nif (CMAKE_THREAD_LIBS_INIT)\n  set (glog_libraries_options_for_static_linking \"${glog_libraries_options_for_static_linking} ${CMAKE_THREAD_LIBS_INIT}\")\nendif (CMAKE_THREAD_LIBS_INIT)\n\nif (gflags_FOUND)\n  # Prefer the gflags target that uses double colon convention\n  if (TARGET gflags::gflags)\n    target_link_libraries (glog PUBLIC gflags::gflags)\n  else (TARGET gflags::gflags)\n    target_link_libraries (glog PUBLIC gflags)\n  endif (TARGET gflags::gflags)\n\n  set (glog_libraries_options_for_static_linking \"${glog_libraries_options_for_static_linking} -lgflags\")\nendif (gflags_FOUND)\n\nif (ANDROID)\n  target_link_libraries (glog PRIVATE log)\n  set (glog_libraries_options_for_static_linking \"${glog_libraries_options_for_static_linking} -llog\")\nendif (ANDROID)\n\nset_target_properties (glog PROPERTIES VERSION ${glog_VERSION})\nset_target_properties (glog PROPERTIES SOVERSION 3)\n\nif (CYGWIN OR WIN32)\n  target_compile_definitions (glog PUBLIC GLOG_NO_ABBREVIATED_SEVERITIES)\nendif (CYGWIN OR WIN32)\n\nset_target_properties (glog PROPERTIES PUBLIC_HEADER \"${GLOG_PUBLIC_H}\")\n\ntarget_include_directories (glog BEFORE PUBLIC\n  \"$<BUILD_INTERFACE:${glog_BINARY_DIR}>\"\n  \"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src>\"\n  \"$<INSTALL_INTERFACE:${_glog_CMake_INCLUDE_DIR}>\"\n  PRIVATE ${glog_BINARY_DIR}\n  PRIVATE ${glog_SOURCE_DIR}/src)\n\nif (CYGWIN OR WIN32)\n  target_include_directories (glog_internal PUBLIC\n    \"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src/windows>\"\n    PRIVATE ${glog_SOURCE_DIR}/src/windows)\n\n  target_include_directories (glog PUBLIC\n    \"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src/windows>\"\n    PRIVATE ${glog_SOURCE_DIR}/src/windows)\nendif (CYGWIN OR WIN32)\n\nset_target_properties (glog PROPERTIES DEFINE_SYMBOL GOOGLE_GLOG_IS_A_DLL)\n\ntarget_include_directories (glog_internal PUBLIC\n  $<TARGET_PROPERTY:glog,INCLUDE_DIRECTORIES>)\ntarget_compile_definitions (glog_internal PUBLIC\n  $<TARGET_PROPERTY:glog,COMPILE_DEFINITIONS>\n  PRIVATE GOOGLE_GLOG_IS_A_DLL)\n\ngenerate_export_header (glog\n  EXPORT_MACRO_NAME GLOG_EXPORT\n  EXPORT_FILE_NAME ${glog_BINARY_DIR}/glog/export.h)\n\nstring (STRIP \"${glog_libraries_options_for_static_linking}\" glog_libraries_options_for_static_linking)\n\nif (WITH_PKGCONFIG)\n  set (VERSION ${glog_VERSION})\n  set (prefix ${CMAKE_INSTALL_PREFIX})\n  set (exec_prefix ${CMAKE_INSTALL_FULL_BINDIR})\n  set (libdir ${CMAKE_INSTALL_FULL_LIBDIR})\n  set (includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})\n\n  configure_file (\n    \"${glog_SOURCE_DIR}/libglog.pc.in\"\n    \"${glog_BINARY_DIR}/libglog.pc\"\n    @ONLY\n  )\n\n  unset (VERSION)\n  unset (prefix)\n  unset (exec_prefix)\n  unset (libdir)\n  unset (includedir)\nendif (WITH_PKGCONFIG)\n\n# Unit testing\n\nif (NOT WITH_FUZZING STREQUAL \"none\")\n  add_executable (fuzz_demangle\n    src/fuzz_demangle.cc\n  )\n\n  if (WITH_FUZZING STREQUAL \"ossfuzz\")\n    set (LIB_FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE})\n    target_link_libraries (fuzz_demangle PRIVATE glog ${LIB_FUZZING_ENGINE})\n  elseif (WITH_FUZZING STREQUAL \"libfuzzer\")\n    target_compile_options (fuzz_demangle PRIVATE -fsanitize=fuzzer)\n    target_link_libraries (fuzz_demangle PRIVATE glog)\n  else (WITH_FUZZING STREQUAL \"libfuzzer\")\n    message (FATAL_ERROR \"Unsupported fuzzing engine ${WITH_FUZZING}\")\n  endif (WITH_FUZZING STREQUAL \"ossfuzz\")\nendif (NOT WITH_FUZZING STREQUAL \"none\")\n\nif (BUILD_TESTING)\n  add_library (glog_test INTERFACE)\n  target_link_libraries (glog_test INTERFACE $<TARGET_OBJECTS:glog_internal> $<TARGET_PROPERTY:glog,LINK_LIBRARIES>)\n  target_compile_definitions (glog_test INTERFACE GLOG_STATIC_DEFINE $<TARGET_PROPERTY:glog,COMPILE_DEFINITIONS>)\n  target_include_directories (glog_test INTERFACE $<TARGET_PROPERTY:glog,INCLUDE_DIRECTORIES>)\n\n  if (HAVE_LIB_GTEST)\n    target_link_libraries (glog_test INTERFACE GTest::gtest)\n  endif (HAVE_LIB_GTEST)\n\n  if (HAVE_LIB_GMOCK)\n    target_link_libraries (glog_test INTERFACE GTest::gmock)\n  endif (HAVE_LIB_GMOCK)\n\n  add_executable (logging_unittest\n    src/logging_unittest.cc\n  )\n\n  target_link_libraries (logging_unittest PRIVATE glog_test)\n\n  add_executable (stl_logging_unittest\n    src/stl_logging_unittest.cc\n  )\n\n  target_link_libraries (stl_logging_unittest PRIVATE glog_test)\n\n  if (HAVE_SYMBOLIZE)\n    add_executable (symbolize_unittest\n      src/symbolize_unittest.cc\n    )\n\n    target_link_libraries (symbolize_unittest PRIVATE glog_test)\n  endif (HAVE_SYMBOLIZE)\n\n  add_executable (demangle_unittest\n    src/demangle_unittest.cc\n  )\n\n  target_link_libraries (demangle_unittest PRIVATE glog_test)\n\n  add_test (NAME demangle COMMAND demangle_unittest)\n\n  if (HAVE___CXA_DEMANGLE)\n    # Demangle tests use a different (reduced) representation of symbols\n    set_tests_properties (demangle PROPERTIES DISABLED ON)\n  endif (HAVE___CXA_DEMANGLE)\n\n  if (HAVE_STACKTRACE)\n    add_executable (stacktrace_unittest\n      src/stacktrace_unittest.cc\n    )\n\n    target_link_libraries (stacktrace_unittest PRIVATE glog_test)\n  endif (HAVE_STACKTRACE)\n\n  add_executable (utilities_unittest\n    src/utilities_unittest.cc\n  )\n\n  target_link_libraries (utilities_unittest PRIVATE glog_test)\n\n  if (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)\n    add_executable (signalhandler_unittest\n      src/signalhandler_unittest.cc\n    )\n\n    target_link_libraries (signalhandler_unittest PRIVATE glog_test)\n  endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)\n\n  add_test (NAME logging COMMAND logging_unittest)\n\n  set_tests_properties (logging PROPERTIES TIMEOUT 30)\n  # MacOS diff is not deterministic: use the output to determine whether the\n  # test passed.\n  set_tests_properties (logging PROPERTIES PASS_REGULAR_EXPRESSION \".*\\nPASS\\n.*\")\n\n  # FIXME: Skip flaky test\n  set_tests_properties (logging PROPERTIES SKIP_REGULAR_EXPRESSION\n    \"Check failed: time_ns within LogTimes::LOG_PERIOD_TOL_NS of LogTimes::LOG_PERIOD_NS\")\n\n  if (APPLE)\n    # FIXME: Skip flaky test\n    set_property (TEST logging APPEND PROPERTY SKIP_REGULAR_EXPRESSION\n      \"unexpected new.*PASS\\nTest with golden file failed. We'll try to show the diff:\")\n  endif (APPLE)\n\n  if (TARGET signalhandler_unittest)\n    add_test (NAME signalhandler COMMAND signalhandler_unittest)\n  endif (TARGET signalhandler_unittest)\n\n  if (TARGET stacktrace_unittest)\n    add_test (NAME stacktrace COMMAND stacktrace_unittest)\n    set_tests_properties (stacktrace PROPERTIES TIMEOUT 30)\n  endif (TARGET stacktrace_unittest)\n\n  add_test (NAME stl_logging COMMAND stl_logging_unittest)\n\n  if (TARGET symbolize_unittest)\n    add_test (NAME symbolize COMMAND symbolize_unittest)\n\n    # FIXME: Skip flaky test when compiled in C++20 mode\n    set_tests_properties (symbolize PROPERTIES SKIP_REGULAR_EXPRESSION\n      [=[Check failed: streq\\(\"nonstatic_func\"\\, TrySymbolize\\(\\(void \\*\\)\\(&nonstatic_func\\)\\)\\)]=])\n  endif (TARGET symbolize_unittest)\n\n  if (HAVE_LIB_GMOCK)\n    add_executable (mock-log_unittest\n      src/mock-log_unittest.cc\n      src/mock-log.h\n    )\n\n    target_link_libraries (mock-log_unittest PRIVATE glog_test)\n\n    add_test (NAME mock-log COMMAND mock-log_unittest)\n  endif (HAVE_LIB_GMOCK)\n\n  # Generate an initial cache\n\n  get_cache_variables (_CACHEVARS)\n\n  set (_INITIAL_CACHE\n    ${glog_BINARY_DIR}/test_package_config/glog_package_config_initial_cache.cmake)\n\n  # Package config test\n\n  add_test (NAME cmake_package_config_init COMMAND ${CMAKE_COMMAND}\n    -DTEST_BINARY_DIR=${glog_BINARY_DIR}/test_package_config\n    -DINITIAL_CACHE=${_INITIAL_CACHE}\n    -DCACHEVARS=${_CACHEVARS}\n    -P ${glog_SOURCE_DIR}/cmake/TestInitPackageConfig.cmake\n  )\n\n  add_test (NAME cmake_package_config_generate COMMAND ${CMAKE_COMMAND}\n    -DGENERATOR=${CMAKE_GENERATOR}\n    -DGENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}\n    -DGENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}\n    -DINITIAL_CACHE=${_INITIAL_CACHE}\n    -DPACKAGE_DIR=${glog_BINARY_DIR}\n    -DPATH=$ENV{PATH}\n    -DSOURCE_DIR=${glog_SOURCE_DIR}/src/package_config_unittest/working_config\n    -DTEST_BINARY_DIR=${glog_BINARY_DIR}/test_package_config/working_config\n    -P ${glog_SOURCE_DIR}/cmake/TestPackageConfig.cmake\n  )\n\n  add_test (NAME cmake_package_config_build COMMAND\n    ${CMAKE_COMMAND} --build ${glog_BINARY_DIR}/test_package_config/working_config\n                     --config $<CONFIG>\n  )\n\n  add_test (NAME cmake_package_config_cleanup COMMAND ${CMAKE_COMMAND} -E\n    remove_directory\n    ${glog_BINARY_DIR}/test_package_config\n  )\n\n  # Fixtures setup\n  set_tests_properties (cmake_package_config_init PROPERTIES FIXTURES_SETUP\n    cmake_package_config)\n  set_tests_properties (cmake_package_config_generate PROPERTIES FIXTURES_SETUP\n    cmake_package_config_working)\n\n  # Fixtures cleanup\n  set_tests_properties (cmake_package_config_cleanup PROPERTIES FIXTURES_CLEANUP\n    cmake_package_config)\n\n  # Fixture requirements\n  set_tests_properties (cmake_package_config_generate PROPERTIES\n    FIXTURES_REQUIRED cmake_package_config)\n  set_tests_properties (cmake_package_config_build PROPERTIES\n    FIXTURES_REQUIRED \"cmake_package_config;cmake_package_config_working\")\n\n  add_executable (cleanup_immediately_unittest\n    src/cleanup_immediately_unittest.cc)\n\n  target_link_libraries (cleanup_immediately_unittest PRIVATE glog_test)\n\n  add_executable (cleanup_with_absolute_prefix_unittest\n    src/cleanup_with_absolute_prefix_unittest.cc)\n\n  target_link_libraries (cleanup_with_absolute_prefix_unittest PRIVATE glog_test)\n\n  add_executable (cleanup_with_relative_prefix_unittest\n    src/cleanup_with_relative_prefix_unittest.cc)\n\n  target_link_libraries (cleanup_with_relative_prefix_unittest PRIVATE glog_test)\n\n  set (CLEANUP_LOG_DIR ${glog_BINARY_DIR}/cleanup_tests)\n\n  add_test (NAME cleanup_init COMMAND\n    ${CMAKE_COMMAND} -E make_directory ${CLEANUP_LOG_DIR})\n  add_test (NAME cleanup_logdir COMMAND\n    ${CMAKE_COMMAND} -E remove_directory ${CLEANUP_LOG_DIR})\n  add_test (NAME cleanup_immediately COMMAND\n    ${CMAKE_COMMAND}\n    -DLOGCLEANUP=$<TARGET_FILE:cleanup_immediately_unittest>\n    # NOTE The trailing slash is important\n    -DTEST_DIR=${CLEANUP_LOG_DIR}/\n    -P ${glog_SOURCE_DIR}/cmake/RunCleanerTest1.cmake\n    WORKING_DIRECTORY ${glog_BINARY_DIR})\n  add_test (NAME cleanup_with_absolute_prefix COMMAND\n    ${CMAKE_COMMAND}\n    -DLOGCLEANUP=$<TARGET_FILE:cleanup_with_absolute_prefix_unittest>\n    -DTEST_DIR=${glog_BINARY_DIR}/\n    -P ${glog_SOURCE_DIR}/cmake/RunCleanerTest2.cmake\n    WORKING_DIRECTORY ${glog_BINARY_DIR})\n  add_test (NAME cleanup_with_relative_prefix COMMAND\n    ${CMAKE_COMMAND}\n    -DLOGCLEANUP=$<TARGET_FILE:cleanup_with_relative_prefix_unittest>\n    -DTEST_DIR=${glog_BINARY_DIR}/\n    -DTEST_SUBDIR=test_subdir/\n    -P ${glog_SOURCE_DIR}/cmake/RunCleanerTest3.cmake\n    WORKING_DIRECTORY ${glog_BINARY_DIR})\n\n  # Fixtures setup\n  set_tests_properties (cleanup_init PROPERTIES FIXTURES_SETUP logcleanuptest)\n  ## Fixtures cleanup\n  set_tests_properties (cleanup_logdir PROPERTIES FIXTURES_CLEANUP logcleanuptest)\n  # Fixture requirements\n  set_tests_properties (cleanup_immediately PROPERTIES FIXTURES_REQUIRED logcleanuptest)\n  set_tests_properties (cleanup_with_absolute_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)\n  set_tests_properties (cleanup_with_relative_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)\n\n  add_executable (striplog0_unittest\n    src/striplog_unittest.cc\n  )\n  target_compile_definitions (striplog0_unittest PRIVATE GOOGLE_STRIP_LOG=0)\n  target_link_libraries (striplog0_unittest PRIVATE glog_test)\n\n  add_test (NAME striplog0 COMMAND striplog0_unittest)\n\n  add_executable (striplog2_unittest\n    src/striplog_unittest.cc\n  )\n  target_compile_definitions (striplog2_unittest PRIVATE GOOGLE_STRIP_LOG=2)\n  target_link_libraries (striplog2_unittest PRIVATE glog_test)\n\n  add_test (NAME striplog2 COMMAND striplog2_unittest)\n\n  add_executable (striplog10_unittest\n    src/striplog_unittest.cc\n  )\n  target_compile_definitions (striplog10_unittest PRIVATE GOOGLE_STRIP_LOG=10)\n  target_link_libraries (striplog10_unittest PRIVATE glog_test)\n\n  add_test (NAME striplog10 COMMAND striplog10_unittest)\n\n  set_tests_properties (\n    striplog0\n    striplog2\n    striplog10\n    PROPERTIES WILL_FAIL ON\n  )\n\n  add_test (NAME log_severity_constants COMMAND ${CMAKE_CTEST_COMMAND}\n    --build-config $<CONFIG>\n    --build-and-test\n    \"${glog_SOURCE_DIR}/src/log_severity_unittest\"\n    \"${glog_BINARY_DIR}/Tests/log_severity_constants\"\n    --build-generator ${CMAKE_GENERATOR}\n    --build-makeprogram ${CMAKE_MAKE_PROGRAM}\n    --build-target glog_log_severity_constants\n    --build-options\n    -DCMAKE_BUILD_TYPE=$<CONFIG>\n    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n    -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}\n    -DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}\n    -Dglog_DIR=${glog_BINARY_DIR}\n  )\n  set_tests_properties (log_severity_constants PROPERTIES\n    PASS_REGULAR_EXPRESSION \"COMPACT_GOOGLE_LOG_[1-3]\"\n  )\n\n  add_test (NAME log_severity_conversion COMMAND ${CMAKE_CTEST_COMMAND}\n    --build-config $<CONFIG>\n    --build-and-test\n    \"${glog_SOURCE_DIR}/src/log_severity_unittest\"\n    \"${glog_BINARY_DIR}/Tests/log_severity_conversion\"\n    --build-generator ${CMAKE_GENERATOR}\n    --build-makeprogram ${CMAKE_MAKE_PROGRAM}\n    --build-target glog_log_severity_conversion\n    --build-options\n    -DCMAKE_BUILD_TYPE=$<CONFIG>\n    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n    -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}\n    -DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}\n    -Dglog_DIR=${glog_BINARY_DIR}\n  )\n\n  if (CMAKE_COMPILER_IS_GNUCXX)\n    set_tests_properties (log_severity_conversion PROPERTIES\n      PASS_REGULAR_EXPRESSION \"error: invalid conversion from (‘|')int(’|')\"\n    )\n  elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)\n    set_tests_properties (log_severity_conversion PROPERTIES\n      PASS_REGULAR_EXPRESSION \"no known conversion from 'int'\"\n    )\n  elseif (MSVC)\n    set_tests_properties (log_severity_conversion PROPERTIES\n      PASS_REGULAR_EXPRESSION \"error C2440\"\n    )\n  else (CMAKE_COMPILER_IS_GNUCXX)\n    message (AUTHOR_WARNING\n      \"Unsupported C++ compiler ${CMAKE_CXX_COMPILER_ID}: \"\n      \"log_severity_conversion test will be disabled\"\n    )\n    set_tests_properties (log_severity_conversion DISABLED ON)\n  endif (CMAKE_COMPILER_IS_GNUCXX)\n\n  add_test (NAME includes_logging COMMAND ${CMAKE_CTEST_COMMAND}\n    --build-config $<CONFIG>\n    --build-and-test\n    \"${glog_SOURCE_DIR}/src/includes_unittest\"\n    \"${glog_BINARY_DIR}/Tests/includes_logging\"\n    --build-generator ${CMAKE_GENERATOR}\n    --build-makeprogram ${CMAKE_MAKE_PROGRAM}\n    --build-target glog_includes_logging\n    --build-options\n    -DCMAKE_BUILD_TYPE=$<CONFIG>\n    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n    -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}\n    -DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}\n    -Dglog_DIR=${glog_BINARY_DIR}\n  )\n\n  add_test (NAME includes_vlog_is_on COMMAND ${CMAKE_CTEST_COMMAND}\n    --build-config $<CONFIG>\n    --build-and-test\n    \"${glog_SOURCE_DIR}/src/includes_unittest\"\n    \"${glog_BINARY_DIR}/Tests/includes_vlog_is_on\"\n    --build-generator ${CMAKE_GENERATOR}\n    --build-makeprogram ${CMAKE_MAKE_PROGRAM}\n    --build-target glog_includes_vlog_is_on\n    --build-options\n    -DCMAKE_BUILD_TYPE=$<CONFIG>\n    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n    -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}\n    -DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}\n    -Dglog_DIR=${glog_BINARY_DIR}\n  )\n\n  add_test (NAME includes_raw_logging COMMAND ${CMAKE_CTEST_COMMAND}\n    --build-config $<CONFIG>\n    --build-and-test\n    \"${glog_SOURCE_DIR}/src/includes_unittest\"\n    \"${glog_BINARY_DIR}/Tests/includes_raw_logging\"\n    --build-generator ${CMAKE_GENERATOR}\n    --build-makeprogram ${CMAKE_MAKE_PROGRAM}\n    --build-target glog_includes_raw_logging\n    --build-options\n    -DCMAKE_BUILD_TYPE=$<CONFIG>\n    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n    -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}\n    -DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}\n    -Dglog_DIR=${glog_BINARY_DIR}\n  )\n\n  add_test (NAME includes_stl_logging COMMAND ${CMAKE_CTEST_COMMAND}\n    --build-config $<CONFIG>\n    --build-and-test\n    \"${glog_SOURCE_DIR}/src/includes_unittest\"\n    \"${glog_BINARY_DIR}/Tests/includes_stl_logging\"\n    --build-generator ${CMAKE_GENERATOR}\n    --build-makeprogram ${CMAKE_MAKE_PROGRAM}\n    --build-target glog_includes_stl_logging\n    --build-options\n    -DCMAKE_BUILD_TYPE=$<CONFIG>\n    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n    -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}\n    -DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}\n    -Dglog_DIR=${glog_BINARY_DIR}\n  )\n\n  add_test (NAME dcheck_on COMMAND ${CMAKE_CTEST_COMMAND}\n    --build-config Debug\n    --build-and-test\n    \"${glog_SOURCE_DIR}/src/dcheck_unittest\"\n    \"${glog_BINARY_DIR}/Tests/dcheck_on\"\n    --build-generator ${CMAKE_GENERATOR}\n    --build-generator-platform \"${CMAKE_GENERATOR_PLATFORM}\"\n    --build-generator-toolset \"${CMAKE_GENERATOR_TOOLSET}\"\n    --build-makeprogram ${CMAKE_MAKE_PROGRAM}\n    --build-target glog_dcheck\n    --build-options\n    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n    -DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON\n    -Dglog_DIR=${glog_BINARY_DIR}\n    --test-command glog_dcheck\n  )\n  set_tests_properties (dcheck_on PROPERTIES\n    DISABLED $<NOT:$<CONFIG:Debug,RelWithDebInfo>>\n    ENVIRONMENT_MODIFICATION \"PATH=path_list_prepend:$<TARGET_FILE_DIR:glog>\"\n    PASS_REGULAR_EXPRESSION \"Assert failed: false\"\n  )\n\n  add_test (NAME dcheck_off COMMAND ${CMAKE_CTEST_COMMAND}\n    --build-config Release\n    --build-and-test\n    \"${glog_SOURCE_DIR}/src/dcheck_unittest\"\n    \"${glog_BINARY_DIR}/Tests/dcheck_off\"\n    --build-generator ${CMAKE_GENERATOR}\n    --build-generator-platform \"${CMAKE_GENERATOR_PLATFORM}\"\n    --build-generator-toolset \"${CMAKE_GENERATOR_TOOLSET}\"\n    --build-makeprogram ${CMAKE_MAKE_PROGRAM}\n    --build-target glog_dcheck\n    --build-options\n    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}\n    -DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON\n    -Dglog_DIR=${glog_BINARY_DIR}\n    --test-command glog_dcheck\n  )\n  # There should be no output\n  set_tests_properties (dcheck_off PROPERTIES\n    DISABLED $<NOT:$<CONFIG:Release,MinSizeRel>>\n    ENVIRONMENT_MODIFICATION \"PATH=path_list_prepend:$<TARGET_FILE_DIR:glog>\"\n    PASS_REGULAR_EXPRESSION \"\"\n  )\nendif (BUILD_TESTING)\n\nif (BUILD_EXAMPLES)\n  add_executable (custom_sink_example examples/custom_sink.cc)\n  target_link_libraries (custom_sink_example PRIVATE glog::glog)\nendif (BUILD_EXAMPLES)\n\ninstall (TARGETS glog\n  EXPORT glog-targets\n  RUNTIME DESTINATION ${_glog_CMake_BINDIR}\n  PUBLIC_HEADER DESTINATION ${_glog_CMake_INCLUDE_DIR}/glog\n  LIBRARY DESTINATION ${_glog_CMake_LIBDIR}\n  ARCHIVE DESTINATION ${_glog_CMake_LIBDIR})\n\nif (WITH_PKGCONFIG)\n  install (\n    FILES \"${glog_BINARY_DIR}/libglog.pc\"\n    DESTINATION \"${_glog_CMake_LIBDIR}/pkgconfig\"\n  )\nendif (WITH_PKGCONFIG)\n\nset (glog_CMake_VERSION 3.0)\n\nif (gflags_FOUND)\n  # Ensure clients locate only the package config and not third party find\n  # modules having the same name. This avoid cmake_policy PUSH/POP errors.\n  if (CMAKE_VERSION VERSION_LESS 3.9)\n    set (gflags_DEPENDENCY \"find_dependency (gflags ${gflags_VERSION})\")\n  else (CMAKE_VERSION VERSION_LESS 3.9)\n    # Passing additional find_package arguments to find_dependency is possible\n    # starting with CMake 3.9.\n    set (glog_CMake_VERSION 3.9)\n    set (gflags_DEPENDENCY \"find_dependency (gflags ${gflags_VERSION} NO_MODULE)\")\n  endif (CMAKE_VERSION VERSION_LESS 3.9)\nendif (gflags_FOUND)\n\nconfigure_package_config_file (glog-config.cmake.in\n  ${glog_BINARY_DIR}/glog-config.cmake\n  INSTALL_DESTINATION ${_glog_CMake_INSTALLDIR}\n  NO_CHECK_REQUIRED_COMPONENTS_MACRO)\n\nwrite_basic_package_version_file (\n  ${glog_BINARY_DIR}/glog-config-version.cmake\n  COMPATIBILITY SameMajorVersion)\n\nexport (TARGETS glog NAMESPACE glog:: FILE glog-targets.cmake)\nexport (PACKAGE glog)\n\nget_filename_component (_PREFIX \"${CMAKE_INSTALL_PREFIX}\" ABSOLUTE)\n\n# Directory containing the find modules relative to the config install\n# directory.\nfile (RELATIVE_PATH glog_REL_CMake_MODULES\n  ${_PREFIX}/${_glog_CMake_INSTALLDIR}\n  ${_PREFIX}/${_glog_CMake_DATADIR}/glog-modules.cmake)\n\nget_filename_component (glog_REL_CMake_DATADIR ${glog_REL_CMake_MODULES}\n  DIRECTORY)\n\nset (glog_FULL_CMake_DATADIR\n  ${glog_BINARY_DIR}/${_glog_CMake_DATADIR})\n\nconfigure_file (glog-modules.cmake.in\n  ${glog_BINARY_DIR}/glog-modules.cmake @ONLY)\n\ninstall (CODE\n\"\nset (glog_FULL_CMake_DATADIR \\\"\\\\\\${CMAKE_CURRENT_LIST_DIR}/${glog_REL_CMake_DATADIR}\\\")\nset (glog_DATADIR_DESTINATION ${_glog_CMake_INSTALLDIR})\n\nif (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})\n  set (glog_DATADIR_DESTINATION \\\"\\${CMAKE_INSTALL_PREFIX}/\\${glog_DATADIR_DESTINATION}\\\")\nendif (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})\n\nconfigure_file (\\\"${glog_SOURCE_DIR}/glog-modules.cmake.in\\\"\n  \\\"${glog_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\\\" @ONLY)\nfile (INSTALL\n  \\\"${glog_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\\\"\n  DESTINATION\n  \\\"\\${glog_DATADIR_DESTINATION}\\\")\n\"\n  COMPONENT Development\n)\n\ninstall (FILES\n  ${glog_BINARY_DIR}/glog-config.cmake\n  ${glog_BINARY_DIR}/glog-config-version.cmake\n  DESTINATION ${_glog_CMake_INSTALLDIR})\n\n# Find modules in share/glog/cmake\ninstall (DIRECTORY ${_glog_BINARY_CMake_DATADIR}\n  DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/glog\n  COMPONENT Development\n  FILES_MATCHING PATTERN \"*.cmake\"\n)\n\ninstall (EXPORT glog-targets NAMESPACE glog:: DESTINATION\n  ${_glog_CMake_INSTALLDIR})\n"
  },
  {
    "path": "CONTRIBUTORS",
    "content": "# People who have agreed to one of the CLAs and can contribute patches.\n# The AUTHORS file lists the copyright holders; this file\n# lists people.  For example, Google employees are listed here\n# but not in AUTHORS, because Google holds the copyright.\n#\n# Names should be added to this file only after verifying that\n# the individual or the individual's organization has agreed to\n# the appropriate Contributor License Agreement, found here:\n#\n# https://developers.google.com/open-source/cla/individual\n# https://developers.google.com/open-source/cla/corporate\n#\n# The agreement for individuals can be filled out on the web.\n#\n# When adding J Random Contributor's name to this file,\n# either J's name or J's organization's name should be\n# added to the AUTHORS file, depending on whether the\n# individual or corporate CLA was used.\n#\n# Names should be added to this file as:\n#     Name <email address>\n#\n# Please keep the list sorted.\n\nAbhishek Dasgupta <abhi2743@gmail.com>\nAbhishek Parmar <abhishek@orng.net>\nAndrew Schwartzmeyer <andrew@schwartzmeyer.com>\nAndy Ying <andy@trailofbits.com>\nBret McKee <bretmckee@google.com>\nBrian Silverman <bsilver16384@gmail.com>\nDmitriy Arbitman <d.arbitman@gmail.com>\nEric Kilmer <eric.d.kilmer@gmail.com>\nFumitoshi Ukai <ukai@google.com>\nGuillaume Dumont <dumont.guillaume@gmail.com>\nHåkan L. S. Younes <hyounes@google.com>\nIvan Penkov <ivanpe@google.com>\nJacob Trimble <modmaker@google.com>\nJim Ray <jimray@google.com>\nLingBin <lingbinlb@gmail.com>\nMarco Wang <m.aesophor@gmail.com>\nMichael Darr <mdarr@matician.com>\nMichael Tanner <michael@tannertaxpro.com>\nMiniLight <MiniLightAR@Gmail.com>\nPeter Collingbourne <pcc@google.com>\nRodrigo Queiro <rodrigoq@google.com>\nromange <romange@users.noreply.github.com>\nRoman Perepelitsa <roman.perepelitsa@gmail.com>\nSergiu Deitsch <sergiu.deitsch@gmail.com>\nShinichiro Hamaji <hamaji@google.com>\ntbennun <tbennun@gmail.com>\nTeddy Reed <teddy@prosauce.org>\nVijaymahantesh Sattigeri <vijaymahantesh016@gmail.com>\nZhongming Qu <qzmfranklin@gmail.com>\nZhuoran Shen <cmsflash99@gmail.com>\n"
  },
  {
    "path": "ChangeLog",
    "content": "2024-06-08  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.7.1.\n\t* See git log for the details.\n\n2024-02-17  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.7.0.\n\t* See git log for the details.\n\n2022-04-05  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.6.0.\n\t* See git log for the details.\n\n2021-05-08  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.5.0.\n\t* See git log for the details.\n\n2019-01-22  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.4.0.\n\t* See git log for the details.\n\n2017-05-09  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.3.5\n\t* See git log for the details.\n\n2015-03-09  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.3.4\n\t* See git log for the details.\n\n2013-02-01  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.3.3\n\t* Add --disable-rtti option for configure.\n\t* Visual Studio build and test fix.\n\t* QNX build fix (thanks vanuan).\n\t* Reduce warnings.\n\t* Fixed LOG_SYSRESULT (thanks ukai).\n\t* FreeBSD build fix (thanks yyanagisawa).\n\t* Clang build fix.\n\t* Now users can re-initialize glog after ShutdownGoogleLogging.\n\t* Color output support by GLOG_colorlogtostderr (thanks alexs).\n\t* Now glog's ABI around flags are compatible with gflags.\n\t* Document mentions how to modify flags from user programs.\n\n2012-01-12  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.3.2\n\t* Clang support.\n\t* Demangler and stacktrace improvement for newer GCCs.\n\t* Now fork(2) doesn't mess up log files.\n\t* Make valgrind happier.\n\t* Reduce warnings for more -W options.\n\t* Provide a workaround for ERROR defined by windows.h.\n\n2010-06-15  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.3.1\n\t* GLOG_* environment variables now work even when gflags is installed.\n\t* Snow leopard support.\n\t* Now we can build and test from out side tree.\n\t* Add DCHECK_NOTNULL.\n\t* Add ShutdownGoogleLogging to close syslog (thanks DGunchev)\n\t* Fix --enable-frame-pointers option (thanks kazuki.ohta)\n\t* Fix libunwind detection (thanks giantchen)\n\n2009-07-30  Google Inc. <opensource@google.com>\n\n\t* google-glog: version 0.3.0\n\t* Fix a deadlock happened when user uses glog with recent gflags.\n\t* Suppress several unnecessary warnings (thanks keir).\n\t* NetBSD and OpenBSD support.\n\t* Use Win32API GetComputeNameA properly (thanks magila).\n\t* Fix user name detection for Windows (thanks ademin).\n\t* Fix several minor bugs.\n\n2009-04-10  Google Inc. <opensource@google.com>\n\t* google-glog: version 0.2.1\n\t* Fix timestamps of VC++ version.\n\t* Add pkg-config support (thanks Tomasz)\n\t* Fix build problem when building with gtest (thanks Michael)\n\t* Add --with-gflags option for configure (thanks Michael)\n\t* Fixes for GCC 4.4 (thanks John)\n\n2009-01-23  Google Inc. <opensource@google.com>\n\t* google-glog: version 0.2\n\t* Add initial Windows VC++ support.\n\t* Google testing/mocking frameworks integration.\n\t* Link pthread library automatically.\n\t* Flush logs in signal handlers.\n\t* Add macros LOG_TO_STRING, LOG_AT_LEVEL, DVLOG, and LOG_TO_SINK_ONLY.\n\t* Log microseconds.\n\t* Add --log_backtrace_at option.\n\t* Fix some minor bugs.\n\n2008-11-18  Google Inc. <opensource@google.com>\n\t* google-glog: version 0.1.2\n\t* Add InstallFailureSignalHandler(). (satorux)\n\t* Re-organize the way to produce stacktraces.\n\t* Don't define unnecessary macro DISALLOW_EVIL_CONSTRUCTORS.\n\n2008-10-15  Google Inc. <opensource@google.com>\n\t* google-glog: version 0.1.1\n\t* Support symbolize for MacOSX 10.5.\n\t* BUG FIX: --vmodule didn't work with gflags.\n\t* BUG FIX: symbolize_unittest failed with GCC 4.3.\n\t* Several fixes on the document.\n\n2008-10-07  Google Inc. <opensource@google.com>\n\n\t* google-glog: initial release:\n\tThe glog package contains a library that implements application-level\n\tlogging.  This library provides logging APIs based on C++-style\n\tstreams and various helper macros.\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright © 2024, Google Inc.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n* Redistributions in binary form must reproduce the above copyright notice, this\n  list of conditions and the following disclaimer in the documentation and/or\n  other materials provided with the distribution.\n* Neither the name of Google Inc. nor the names of its contributors may be used\n  to endorse or promote products derived from this software without specific\n  prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "MODULE.bazel",
    "content": "module(\n    name = \"glog\",\n    compatibility_level = 1,\n)\n\nbazel_dep(name = \"gflags\", version = \"2.2.2\")\nbazel_dep(name = \"googletest\", version = \"1.14.0\", dev_dependency = True)\nbazel_dep(name = \"platforms\", version = \"0.0.10\")\nbazel_dep(name = \"rules_cc\", version = \"0.0.12\")\n\n# Required for Windows clang-cl build: --extra_toolchains=@local_config_cc//:cc-toolchain-arm64_windows\ncc_configure = use_extension(\"@rules_cc//cc:extensions.bzl\", \"cc_configure_extension\")\nuse_repo(cc_configure, \"local_config_cc\")\n"
  },
  {
    "path": "README.rst",
    "content": "Google Logging Library\n======================\n\n**Deprecation notice**: This project is no longer maintained and will be archived on 2025-06-30.\nConsider using\n`ng-log <https://github.com/ng-log/ng-log>`_ (API-compatible,\ncommunity-maintained,\n`migration instructions <https://github.com/ng-log/ng-log/blob/master/docs/build.md>`_)\nor\n`Abseil Logging <https://abseil.io/docs/cpp/guides/logging>`_\n(Google-maintained) instead. Thank you for all the contributions!\n\nGoogle Logging (glog) was a C++14 library that implements application-level\nlogging. The library provided logging APIs based on C++-style streams and\nvarious helper macros.\n\nGetting Started\n---------------\n\nPlease refer to project's `documentation <https://google.github.io/glog/>`_.\n"
  },
  {
    "path": "WORKSPACE.bazel",
    "content": "# WORKSPACE marker file needed by Bazel\n"
  },
  {
    "path": "bazel/example/BUILD.bazel",
    "content": "cc_test(\n    name = \"main\",\n    size = \"small\",\n    srcs = [\"main.cc\"],\n    deps = [\n        \"//:glog\",\n        \"@gflags//:gflags\",\n    ],\n)\n"
  },
  {
    "path": "bazel/example/main.cc",
    "content": "#include <gflags/gflags.h>\n#include <glog/logging.h>\n#include <glog/stl_logging.h>\n\nint main(int argc, char* argv[]) {\n  // Initialize Google's logging library.\n  google::InitGoogleLogging(argv[0]);\n\n  // Optional: parse command line flags\n  gflags::ParseCommandLineFlags(&argc, &argv, true);\n\n  LOG(INFO) << \"Hello, world!\";\n\n  // glog/stl_logging.h allows logging STL containers.\n  std::vector<int> x;\n  x.push_back(1);\n  x.push_back(2);\n  x.push_back(3);\n  LOG(INFO) << \"ABC, it's easy as \" << x;\n\n  return 0;\n}\n"
  },
  {
    "path": "bazel/glog.bzl",
    "content": "# Implement a macro glog_library() that the BUILD.bazel file can load.\n\n# By default, glog is built with gflags support.  You can change this behavior\n# by using glog_library(with_gflags=0)\n#\n# This file is inspired by the following sample BUILD files:\n#       https://github.com/google/glog/issues/61\n#       https://github.com/google/glog/files/393474/BUILD.txt\n#\n# Known issue: the namespace parameter is not supported on Win32.\n\ndef expand_template_impl(ctx):\n    ctx.actions.expand_template(\n        template = ctx.file.template,\n        output = ctx.outputs.out,\n        substitutions = ctx.attr.substitutions,\n    )\n\nexpand_template = rule(\n    implementation = expand_template_impl,\n    attrs = {\n        \"template\": attr.label(mandatory = True, allow_single_file = True),\n        \"substitutions\": attr.string_dict(mandatory = True),\n        \"out\": attr.output(mandatory = True),\n    },\n)\n\ndef glog_library(with_gflags = 1, **kwargs):\n    if native.repository_name() != \"@\":\n        repo_name = native.repository_name()[1:]  # Strip the first leading @\n        gendir = \"$(GENDIR)/external/\" + repo_name\n        src_windows = \"external/%s/src/windows\" % repo_name\n    else:\n        gendir = \"$(GENDIR)\"\n        src_windows = \"src/windows\"\n\n    # Config setting for WebAssembly target.\n    native.config_setting(\n        name = \"wasm\",\n        values = {\"cpu\": \"wasm\"},\n    )\n\n    # Detect when building with clang-cl on Windows.\n    native.config_setting(\n        name = \"clang-cl\",\n        values = {\"compiler\": \"clang-cl\"},\n    )\n\n    common_copts = [\n        \"-std=c++14\",\n        \"-I%s/glog_internal\" % gendir,\n    ] + ([\"-DGLOG_USE_GFLAGS\"] if with_gflags else [])\n\n    wasm_copts = [\n        # Disable warnings that exists in glog.\n        \"-Wno-sign-compare\",\n        \"-Wno-unused-function\",\n        \"-Wno-unused-local-typedefs\",\n        \"-Wno-unused-variable\",\n        # Allows src/logging.cc to determine the host name.\n        \"-DHAVE_SYS_UTSNAME_H\",\n        # For src/utilities.cc.\n        \"-DHAVE_SYS_TIME_H\",\n        # NOTE: users could optionally patch -DHAVE_UNWIND off if\n        # stacktrace dumping is not needed\n        \"-DHAVE_UNWIND\",\n        # Enable dumping stacktrace upon sigaction.\n        \"-DHAVE_SIGACTION\",\n        # For logging.cc.\n        \"-DHAVE_PREAD\",\n        # -DHAVE_MODE_T prevent repeated typedef mode_t leading\n        # to emcc compilation failure\n        \"-DHAVE_MODE_T\",\n        \"-DHAVE_UNISTD_H\",\n    ]\n\n    linux_or_darwin_copts = wasm_copts + [\n        \"-DGLOG_EXPORT=__attribute__((visibility(\\\\\\\"default\\\\\\\")))\",\n        \"-DGLOG_NO_EXPORT=__attribute__((visibility(\\\\\\\"default\\\\\\\")))\",\n        \"-DHAVE_POSIX_FADVISE\",\n        \"-DHAVE_SSIZE_T\",\n        \"-DHAVE_SYS_TYPES_H\",\n        # For src/utilities.cc.\n        \"-DHAVE_SYS_SYSCALL_H\",\n        # For src/logging.cc to create symlinks.\n        \"-fvisibility-inlines-hidden\",\n        \"-fvisibility=hidden\",\n    ]\n\n    freebsd_only_copts = [\n        # Enable declaration of _Unwind_Backtrace\n        \"-D_GNU_SOURCE\",\n        \"-DHAVE_LINK_H\",\n        \"-DHAVE_SYMBOLIZE\",  # Supported by <link.h>\n    ]\n\n    linux_only_copts = [\n        # For utilities.h.\n        \"-DHAVE_EXECINFO_H\",\n        \"-DHAVE_LINK_H\",\n        \"-DHAVE_SYMBOLIZE\",  # Supported by <link.h>\n    ]\n\n    darwin_only_copts = [\n        # For stacktrace.\n        \"-DHAVE_DLADDR\",\n    ]\n\n    windows_only_copts = [\n        # Override -DGLOG_EXPORT= from the cc_library's defines.\n        \"-DGLOG_EXPORT=__declspec(dllexport)\",\n        \"-DGLOG_NO_ABBREVIATED_SEVERITIES\",\n        \"-DGLOG_NO_EXPORT=\",\n        \"-DGLOG_USE_WINDOWS_PORT\",\n        \"-DHAVE__CHSIZE_S\",\n        \"-DHAVE_DBGHELP\",\n        \"-I\" + src_windows,\n    ]\n\n    clang_cl_only_copts = [\n        # Allow the override of -DGLOG_EXPORT.\n        \"-Wno-macro-redefined\",\n    ]\n\n    windows_only_srcs = [\n        \"src/windows/dirent.h\",\n        \"src/windows/port.cc\",\n        \"src/windows/port.h\",\n    ]\n\n    gflags_deps = [\"@gflags//:gflags\"] if with_gflags else []\n\n    final_lib_defines = select({\n        # GLOG_EXPORT is normally set by export.h, but that's not\n        # generated for Bazel.\n        \"@bazel_tools//src/conditions:windows\": [\n            \"GLOG_DEPRECATED=__declspec(deprecated)\",\n            \"GLOG_EXPORT=\",\n            \"GLOG_NO_ABBREVIATED_SEVERITIES\",\n            \"GLOG_NO_EXPORT=\",\n        ],\n        \"//conditions:default\": [\n            \"GLOG_DEPRECATED=__attribute__((deprecated))\",\n            \"GLOG_EXPORT=__attribute__((visibility(\\\\\\\"default\\\\\\\")))\",\n            \"GLOG_NO_EXPORT=__attribute__((visibility(\\\\\\\"default\\\\\\\")))\",\n        ],\n    })\n\n    final_lib_copts = select({\n        \"@bazel_tools//src/conditions:windows\": common_copts + windows_only_copts,\n        \"@bazel_tools//src/conditions:darwin\": common_copts + linux_or_darwin_copts + darwin_only_copts,\n        \"@bazel_tools//src/conditions:freebsd\": common_copts + linux_or_darwin_copts + freebsd_only_copts,\n        \":wasm\": common_copts + wasm_copts,\n        \"//conditions:default\": common_copts + linux_or_darwin_copts + linux_only_copts,\n    }) + select({\n        \":clang-cl\": clang_cl_only_copts,\n        \"//conditions:default\": [],\n    })\n\n    # Needed to use these headers in `glog` and the test targets without exposing them as public targets in `glog`\n    native.filegroup(\n        name = \"shared_headers\",\n        srcs = [\n            \"src/base/commandlineflags.h\",\n            \"src/stacktrace.h\",\n            \"src/utilities.h\",\n        ]\n    )\n\n    native.cc_library(\n        name = \"glog\",\n        visibility = [\"//visibility:public\"],\n        srcs = [\n            \":config_h\",\n            \":shared_headers\",\n            \"src/base/googleinit.h\",\n            \"src/demangle.cc\",\n            \"src/demangle.h\",\n            \"src/flags.cc\",\n            \"src/logging.cc\",\n            \"src/raw_logging.cc\",\n            \"src/signalhandler.cc\",\n            \"src/stacktrace.cc\",\n            \"src/stacktrace.h\",\n            \"src/stacktrace_generic-inl.h\",\n            \"src/stacktrace_libunwind-inl.h\",\n            \"src/stacktrace_powerpc-inl.h\",\n            \"src/stacktrace_unwind-inl.h\",\n            \"src/stacktrace_windows-inl.h\",\n            \"src/stacktrace_x86-inl.h\",\n            \"src/symbolize.cc\",\n            \"src/symbolize.h\",\n            \"src/utilities.cc\",\n            \"src/utilities.h\",\n            \"src/vlog_is_on.cc\",\n        ] + select({\n            \"@bazel_tools//src/conditions:windows\": windows_only_srcs,\n            \"//conditions:default\": [],\n        }),\n        hdrs = [\n            \"src/glog/flags.h\",\n            \"src/glog/log_severity.h\",\n            \"src/glog/logging.h\",\n            \"src/glog/platform.h\",\n            \"src/glog/raw_logging.h\",\n            \"src/glog/stl_logging.h\",\n            \"src/glog/types.h\",\n            \"src/glog/vlog_is_on.h\",\n        ],\n        # https://github.com/google/glog/issues/837: Replacing\n        # `strip_include_prefix` with `includes` would avoid spamming\n        # downstream projects with compiler warnings, but would also leak\n        # private headers like stacktrace.h, because strip_include_prefix's\n        # implementation only creates symlinks for the public hdrs. I suspect\n        # the only way to avoid this is to refactor the project including the\n        # CMake build, so that the private headers are in a glog_internal\n        # subdirectory.\n        strip_include_prefix = \"src\",\n        defines = final_lib_defines,\n        copts = final_lib_copts,\n        deps = gflags_deps + select({\n            \"@bazel_tools//src/conditions:windows\": [\":strip_include_prefix_hack\"],\n            \"//conditions:default\": [],\n        }),\n        linkopts = select({\n            \"@bazel_tools//src/conditions:windows\": [\"dbghelp.lib\"],\n            \"//conditions:default\": [],\n        }),\n        **kwargs\n    )\n\n    test_list = [\n        \"cleanup_immediately\",\n        \"cleanup_with_absolute_prefix\",\n        \"cleanup_with_relative_prefix\",\n        # \"demangle\", # Broken\n        # \"logging\", # Broken\n        # \"mock-log\", # Broken\n        # \"signalhandler\", # Pointless\n        \"stacktrace\",\n        \"stl_logging\",\n        # \"symbolize\", # Broken\n        \"utilities\",\n    ]\n\n    test_only_copts = [\n        \"-DTEST_SRC_DIR=\\\\\\\"%s/tests\\\\\\\"\" % gendir,\n    ]\n\n    for test_name in test_list:\n        native.cc_test(\n            name = test_name + \"_test\",\n            visibility = [\"//visibility:public\"],\n            srcs = [\n                \":config_h\",\n                \":shared_headers\",\n                \"src/googletest.h\",\n                \"src/\" + test_name + \"_unittest.cc\",\n            ],\n            defines = final_lib_defines,\n            copts = final_lib_copts + test_only_copts,\n            deps = gflags_deps + [\n                \":glog\",\n                \"@googletest//:gtest\",\n            ],\n            **kwargs\n        )\n\n    # Workaround https://github.com/bazelbuild/bazel/issues/6337 by declaring\n    # the dependencies without strip_include_prefix.\n    native.cc_library(\n        name = \"strip_include_prefix_hack\",\n        hdrs = [\n            \"src/glog/flags.h\",\n            \"src/glog/log_severity.h\",\n            \"src/glog/logging.h\",\n            \"src/glog/platform.h\",\n            \"src/glog/raw_logging.h\",\n            \"src/glog/stl_logging.h\",\n            \"src/glog/types.h\",\n            \"src/glog/vlog_is_on.h\",\n        ],\n    )\n\n    expand_template(\n        name = \"config_h\",\n        template = \"src/config.h.cmake.in\",\n        out = \"glog_internal/config.h\",\n        substitutions = {\"#cmakedefine\": \"//cmakedefine\"},\n    )\n"
  },
  {
    "path": "cmake/DetermineGflagsNamespace.cmake",
    "content": "macro(determine_gflags_namespace VARIABLE)\n  if (NOT DEFINED \"${VARIABLE}\")\n    if (CMAKE_REQUIRED_INCLUDES)\n      set (CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS \"-DINCLUDE_DIRECTORIES=${CMAKE_REQUIRED_INCLUDES}\")\n    else ()\n      set (CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS)\n    endif ()\n\n    set(MACRO_CHECK_INCLUDE_FILE_FLAGS ${CMAKE_REQUIRED_FLAGS})\n\n    set(_NAMESPACES gflags google)\n    set(_check_code\n\"\n#include <gflags/gflags.h>\n\nint main(int argc, char**argv)\n{\n  GLOG_GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);\n}\n\")\n    if (NOT CMAKE_REQUIRED_QUIET)\n      message (STATUS \"Looking for gflags namespace\")\n    endif ()\n    if (${ARGC} EQUAL 3)\n      set (CMAKE_CXX_FLAGS_SAVE ${CMAKE_CXX_FLAGS})\n      set (CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} ${ARGV2}\")\n    endif ()\n\n    set (_check_file\n        ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/DetermineGflagsNamespace.cxx)\n\n    foreach (_namespace ${_NAMESPACES})\n      file (WRITE \"${_check_file}\" \"${_check_code}\")\n      try_compile (${VARIABLE}\n        \"${CMAKE_BINARY_DIR}\" \"${_check_file}\"\n        COMPILE_DEFINITIONS \"${CMAKE_REQUIRED_DEFINITIONS}\" -DGLOG_GFLAGS_NAMESPACE=${_namespace}\n        LINK_LIBRARIES gflags\n        CMAKE_FLAGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}\n        OUTPUT_VARIABLE OUTPUT)\n\n      if (${VARIABLE})\n        set (${VARIABLE} ${_namespace} CACHE INTERNAL \"gflags namespace\" FORCE)\n        break ()\n      else ()\n        file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log\n          \"Determining the gflags namespace ${_namespace} failed with the following output:\\n\"\n          \"${OUTPUT}\\n\\n\")\n      endif ()\n    endforeach (_namespace)\n\n    if (${ARGC} EQUAL 3)\n      set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_SAVE})\n    endif ()\n\n    if (${VARIABLE})\n      if (NOT CMAKE_REQUIRED_QUIET)\n        message (STATUS \"Looking for gflags namespace - ${${VARIABLE}}\")\n      endif ()\n      file (APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log\n        \"Determining the gflags namespace passed with the following output:\\n\"\n        \"${OUTPUT}\\n\\n\")\n    else ()\n      if (NOT CMAKE_REQUIRED_QUIET)\n        message (STATUS \"Looking for gflags namespace - failed\")\n      endif ()\n      set (${VARIABLE} ${_namespace} CACHE INTERNAL \"gflags namespace\")\n    endif ()\n  endif ()\nendmacro ()\n"
  },
  {
    "path": "cmake/FindUnwind.cmake",
    "content": "# - Try to find libunwind\n# Once done this will define\n#\n#  Unwind_FOUND - system has libunwind\n#  unwind::unwind - cmake target for libunwind\n\ninclude (FindPackageHandleStandardArgs)\n\nfind_path (Unwind_INCLUDE_DIR NAMES unwind.h libunwind.h DOC \"unwind include directory\")\nfind_library (Unwind_LIBRARY NAMES unwind DOC \"unwind library\")\n\nmark_as_advanced (Unwind_INCLUDE_DIR Unwind_LIBRARY)\n\n# Extract version information\nif (Unwind_LIBRARY)\n  set (_Unwind_VERSION_HEADER ${Unwind_INCLUDE_DIR}/libunwind-common.h)\n\n  if (EXISTS ${_Unwind_VERSION_HEADER})\n    file (READ ${_Unwind_VERSION_HEADER} _Unwind_VERSION_CONTENTS)\n\n    string (REGEX REPLACE \".*#define UNW_VERSION_MAJOR[ \\t]+([0-9]+).*\" \"\\\\1\"\n      Unwind_VERSION_MAJOR \"${_Unwind_VERSION_CONTENTS}\")\n    string (REGEX REPLACE \".*#define UNW_VERSION_MINOR[ \\t]+([0-9]+).*\" \"\\\\1\"\n      Unwind_VERSION_MINOR \"${_Unwind_VERSION_CONTENTS}\")\n    string (REGEX REPLACE \".*#define UNW_VERSION_EXTRA[ \\t]+([0-9]+).*\" \"\\\\1\"\n      Unwind_VERSION_PATCH \"${_Unwind_VERSION_CONTENTS}\")\n\n    set (Unwind_VERSION ${Unwind_VERSION_MAJOR}.${Unwind_VERSION_MINOR})\n\n    if (CMAKE_MATCH_0)\n      # Third version component may be empty\n      set (Unwind_VERSION ${Unwind_VERSION}.${Unwind_VERSION_PATCH})\n      set (Unwind_VERSION_COMPONENTS 3)\n    else (CMAKE_MATCH_0)\n      set (Unwind_VERSION_COMPONENTS 2)\n    endif (CMAKE_MATCH_0)\n  endif (EXISTS ${_Unwind_VERSION_HEADER})\nendif (Unwind_LIBRARY)\n\n# handle the QUIETLY and REQUIRED arguments and set Unwind_FOUND to TRUE\n# if all listed variables are TRUE\nfind_package_handle_standard_args (Unwind\n  REQUIRED_VARS Unwind_INCLUDE_DIR Unwind_LIBRARY\n  VERSION_VAR Unwind_VERSION\n)\n\nif (Unwind_FOUND)\n  if (NOT TARGET unwind::unwind)\n    add_library (unwind::unwind INTERFACE IMPORTED)\n\n    set_property (TARGET unwind::unwind PROPERTY\n      INTERFACE_INCLUDE_DIRECTORIES ${Unwind_INCLUDE_DIR}\n    )\n    set_property (TARGET unwind::unwind PROPERTY\n      INTERFACE_LINK_LIBRARIES ${Unwind_LIBRARY}\n    )\n    set_property (TARGET unwind::unwind PROPERTY\n      IMPORTED_CONFIGURATIONS RELEASE\n    )\n  endif (NOT TARGET unwind::unwind)\nendif (Unwind_FOUND)\n"
  },
  {
    "path": "cmake/GetCacheVariables.cmake",
    "content": "cmake_policy (PUSH)\ncmake_policy (VERSION 3.16...3.27)\n\ninclude (CMakeParseArguments)\n\nfunction (get_cache_variables _CACHEVARS)\n  set (_SINGLE)\n  set (_MULTI EXCLUDE)\n  set (_OPTIONS)\n\n  cmake_parse_arguments (_ARGS \"${_OPTIONS}\" \"${_SINGLE}\" \"${_MULTI}\" ${ARGS} ${ARGN})\n\n  get_cmake_property (_VARIABLES VARIABLES)\n\n  set (CACHEVARS)\n\n  foreach (_VAR ${_VARIABLES})\n    if (DEFINED _ARGS_EXCLUDE)\n      if (\"${_VAR}\" IN_LIST _ARGS_EXCLUDE)\n        continue ()\n      endif (\"${_VAR}\" IN_LIST _ARGS_EXCLUDE)\n    endif (DEFINED _ARGS_EXCLUDE)\n\n    get_property (_CACHEVARTYPE CACHE ${_VAR} PROPERTY TYPE)\n\n    if (\"${_CACHEVARTYPE}\" STREQUAL INTERNAL OR\n        \"${_CACHEVARTYPE}\" STREQUAL STATIC OR\n        \"${_CACHEVARTYPE}\" STREQUAL UNINITIALIZED)\n        continue ()\n    endif (\"${_CACHEVARTYPE}\" STREQUAL INTERNAL OR\n        \"${_CACHEVARTYPE}\" STREQUAL STATIC OR\n        \"${_CACHEVARTYPE}\" STREQUAL UNINITIALIZED)\n\n    get_property (_CACHEVARVAL CACHE ${_VAR} PROPERTY VALUE)\n\n    if (\"${_CACHEVARVAL}\" STREQUAL \"\")\n      continue ()\n    endif (\"${_CACHEVARVAL}\" STREQUAL \"\")\n\n    get_property (_CACHEVARDOC CACHE ${_VAR} PROPERTY HELPSTRING)\n\n    # Escape \" in values\n    string (REPLACE \"\\\"\" \"\\\\\\\"\" _CACHEVARVAL \"${_CACHEVARVAL}\")\n    # Escape \" in help strings\n    string (REPLACE \"\\\"\" \"\\\\\\\"\" _CACHEVARDOC \"${_CACHEVARDOC}\")\n    # Escape ; in values\n    string (REPLACE \";\" \"\\\\\\;\" _CACHEVARVAL \"${_CACHEVARVAL}\")\n    # Escape ; in help strings\n    string (REPLACE \";\" \"\\\\\\;\" _CACHEVARDOC \"${_CACHEVARDOC}\")\n    # Escape backslashes in values except those that are followed by a\n    # quote.\n    string (REGEX REPLACE \"\\\\\\\\([^\\\"])\" \"\\\\\\\\\\\\1\" _CACHEVARVAL \"${_CACHEVARVAL}\")\n    # Escape backslashes in values that are followed by a letter to avoid\n    # invalid escape sequence errors.\n    string (REGEX REPLACE \"\\\\\\\\([a-zA-Z])\" \"\\\\\\\\\\\\\\\\1\" _CACHEVARVAL \"${_CACHEVARVAL}\")\n    string (REPLACE \"\\\\\\\\\" \"\\\\\\\\\\\\\\\\\" _CACHEVARDOC \"${_CACHEVARDOC}\")\n\n    if (NOT \"${_CACHEVARTYPE}\" STREQUAL BOOL)\n      set (_CACHEVARVAL \"\\\"${_CACHEVARVAL}\\\"\")\n    endif (NOT \"${_CACHEVARTYPE}\" STREQUAL BOOL)\n\n    if (NOT \"${_CACHEVARTYPE}\" STREQUAL \"\" AND NOT \"${_CACHEVARVAL}\" STREQUAL \"\")\n      set (CACHEVARS \"${CACHEVARS}set (${_VAR} ${_CACHEVARVAL} CACHE ${_CACHEVARTYPE} \\\"${_CACHEVARDOC}\\\")\\n\")\n    endif (NOT \"${_CACHEVARTYPE}\" STREQUAL \"\" AND NOT \"${_CACHEVARVAL}\" STREQUAL \"\")\n  endforeach (_VAR)\n\n  set (${_CACHEVARS} ${CACHEVARS} PARENT_SCOPE)\nendfunction (get_cache_variables)\n\ncmake_policy (POP)\n"
  },
  {
    "path": "cmake/RunCleanerTest1.cmake",
    "content": "set (RUNS 3)\n\nforeach (iter RANGE 1 ${RUNS})\n  set (ENV{GOOGLE_LOG_DIR} ${TEST_DIR})\n  execute_process (COMMAND ${LOGCLEANUP} RESULT_VARIABLE _RESULT)\n\n  if (NOT _RESULT EQUAL 0)\n    message (FATAL_ERROR \"Failed to run logcleanup_unittest (error: ${_RESULT})\")\n  endif (NOT _RESULT EQUAL 0)\nendforeach (iter)\n\nfile (GLOB LOG_FILES ${TEST_DIR}/*.foobar)\nlist (LENGTH LOG_FILES NUM_FILES)\n\nif (WIN32)\n  # On Windows open files cannot be removed and will result in a permission\n  # denied error while unlinking such file. Therefore, the last file will be\n  # retained.\n  set (_expected 1)\n else (WIN32)\n  set (_expected 0)\nendif (WIN32)\n\nif (NOT NUM_FILES EQUAL _expected)\n  message (SEND_ERROR \"Expected ${_expected} log file in log directory but found ${NUM_FILES}\")\nendif (NOT NUM_FILES EQUAL _expected)\n"
  },
  {
    "path": "cmake/RunCleanerTest2.cmake",
    "content": "set (RUNS 3)\n\nforeach (iter RANGE 1 ${RUNS})\n  execute_process (COMMAND ${LOGCLEANUP} -log_dir=${TEST_DIR}\n    RESULT_VARIABLE _RESULT)\n\n  if (NOT _RESULT EQUAL 0)\n    message (FATAL_ERROR \"Failed to run logcleanup_unittest (error: ${_RESULT})\")\n  endif (NOT _RESULT EQUAL 0)\nendforeach (iter)\n\nfile (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo)\nlist (LENGTH LOG_FILES NUM_FILES)\n\nif (WIN32)\n  # On Windows open files cannot be removed and will result in a permission\n  # denied error while unlinking such file. Therefore, the last file will be\n  # retained.\n  set (_expected 1)\n else (WIN32)\n  set (_expected 0)\nendif (WIN32)\n\nif (NOT NUM_FILES EQUAL _expected)\n  message (SEND_ERROR \"Expected ${_expected} log file in log directory but found ${NUM_FILES}\")\nendif (NOT NUM_FILES EQUAL _expected)\n"
  },
  {
    "path": "cmake/RunCleanerTest3.cmake",
    "content": "set (RUNS 3)\n\n# Create the subdirectory required by this unit test.\nfile (MAKE_DIRECTORY ${TEST_DIR}/${TEST_SUBDIR})\n\nforeach (iter RANGE 1 ${RUNS})\n  execute_process (COMMAND ${LOGCLEANUP} -log_dir=${TEST_DIR}\n    RESULT_VARIABLE _RESULT)\n\n  if (NOT _RESULT EQUAL 0)\n    message (FATAL_ERROR \"Failed to run logcleanup_unittest (error: ${_RESULT})\")\n  endif (NOT _RESULT EQUAL 0)\nendforeach (iter)\n\nfile (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo)\nlist (LENGTH LOG_FILES NUM_FILES)\n\nif (WIN32)\n  # On Windows open files cannot be removed and will result in a permission\n  # denied error while unlinking such file. Therefore, the last file will be\n  # retained.\n  set (_expected 1)\n else (WIN32)\n  set (_expected 0)\nendif (WIN32)\n\nif (NOT NUM_FILES EQUAL _expected)\n  message (SEND_ERROR \"Expected ${_expected} log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}\")\nendif (NOT NUM_FILES EQUAL _expected)\n\n# Remove the subdirectory required by this unit test.\nfile (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR})\n"
  },
  {
    "path": "cmake/TestInitPackageConfig.cmake",
    "content": "# Create the build directory\nexecute_process (\n  COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_BINARY_DIR}\n  RESULT_VARIABLE _DIRECTORY_CREATED_SUCCEEDED\n)\n\nif (NOT _DIRECTORY_CREATED_SUCCEEDED EQUAL 0)\n  message (FATAL_ERROR \"Failed to create build directory\")\nendif (NOT _DIRECTORY_CREATED_SUCCEEDED EQUAL 0)\n\nfile (WRITE ${INITIAL_CACHE} \"${CACHEVARS}\")\n"
  },
  {
    "path": "cmake/TestPackageConfig.cmake",
    "content": "if (GENERATOR_TOOLSET)\n  list (APPEND _ADDITIONAL_ARGS -T ${GENERATOR_TOOLSET})\nendif (GENERATOR_TOOLSET)\n\nif (GENERATOR_PLATFORM)\n  list (APPEND _ADDITIONAL_ARGS -A ${GENERATOR_PLATFORM})\nendif (GENERATOR_PLATFORM)\n\n# Run CMake\nexecute_process (\n  # Capture the PATH environment variable content set during project generation\n  # stage. This is required because later during the build stage the PATH is\n  # modified again (e.g., for MinGW AppVeyor CI builds) by adding back the\n  # directory containing git.exe. Incidentally, the Git installation directory\n  # also contains sh.exe which causes MinGW Makefile generation to fail.\n  COMMAND ${CMAKE_COMMAND} -E env PATH=${PATH}\n  ${CMAKE_COMMAND} -C ${INITIAL_CACHE}\n    -G ${GENERATOR}\n    ${_ADDITIONAL_ARGS}\n    -DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON\n    -DCMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY=ON\n    -Dglog_ROOT=${PACKAGE_DIR}\n    -S ${SOURCE_DIR}\n    -B ${TEST_BINARY_DIR}\n  RESULT_VARIABLE _GENERATE_SUCCEEDED\n)\n\nif (NOT _GENERATE_SUCCEEDED EQUAL 0)\n  message (FATAL_ERROR \"Failed to generate project files using CMake\")\nendif (NOT _GENERATE_SUCCEEDED EQUAL 0)\n"
  },
  {
    "path": "codecov.yml",
    "content": "comment:\n  layout: \"diff, flags, files\"\n  behavior: default\n  require_changes: false\n  require_base: false\n  require_head: true\nignore:\n  - \"**/*_unittest.cc\"\n  - \"src/*_unittest/**\"\n  - \"src/googletest.h\"\n  - \"src/mock-log.h\"\n"
  },
  {
    "path": "docs/build.md",
    "content": "# Building from Source\n\n## Bazel\n\nTo use glog within a project which uses the [Bazel](https://bazel.build/) build\ntool, add the following lines to your `MODULE.bazel` file:\n\n``` bazel title=\"MODULE.bazel\"\nbazel_dep(name = \"glog\")\n\narchive_override(\n    module_name = \"glog\",\n    urls = \"https://github.com/google/glog/archive/cc0de6c200375b33d907ee7632eee2f173b33a09.tar.gz\",\n    strip_prefix = \"glog-cc0de6c200375b33d907ee7632eee2f173b33a09\",  # Latest commit as of 2024-06-08.\n    integrity = \"sha256-rUrv4EBkdc+4Wbhfxp+KoRstlj2Iw842/OpLfDq0ivg=\",\n)\n```\n\nYou can then add `@glog//:glog` to\nthe deps section of a `cc_binary` or\n`cc_library` rule, and `#!cpp #include <glog/logging.h>` to\ninclude it in your source code.\n\n!!! example \"Using glog in a Bazel project\"\n    ``` bazel\n    cc_binary(\n        name = \"main\",\n        srcs = [\"main.cc\"],\n        deps = [\"@glog//:glog\"],\n    )\n    ```\n\n## CMake\n\nglog can be compiled using [CMake](http://www.cmake.org) on a wide range of\nplatforms. The typical workflow for building glog on a Unix-like system with GNU\nMake as build tool is as follows:\n\n1.  Clone the repository and change into source directory.\n  ``` bash\n  git clone https://github.com/google/glog.git\n  cd glog\n  ```\n2.  Run CMake to configure the build tree.\n  ``` bash\n  cmake -S . -B build -G \"Unix Makefiles\"\n  ```\n  CMake provides different generators, and by default will pick the most\n  relevant one to your environment. If you need a specific version of Visual\n  Studio, use `#!bash cmake . -G <generator-name>`, and see `#!bash cmake\n  --help` for the available generators. Also see `-T <toolset-name>`, which can\n  be used to request the native x64 toolchain with `-T host=x64`.\n3.  Afterwards, generated files can be used to compile the project.\n  ``` bash\n  cmake --build build\n  ```\n4.  Test the build software (optional).\n  ``` bash\n  cmake --build build --target test\n  ```\n5.  Install the built files (optional).\n  ``` bash\n  cmake --build build --target install\n  ```\n\nOnce successfully built, glog can be [integrated into own projects](usage.md).\n"
  },
  {
    "path": "docs/contribute.md",
    "content": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project.\nThere are a just a few small guidelines you need to follow.\n\n## Contributor License Agreement (CLA)\n\nContributions to any Google project must be accompanied by a Contributor\nLicense Agreement. This is not a copyright **assignment**, it simply\ngives Google permission to use and redistribute your contributions as\npart of the project.\n\n-   If you are an individual writing original source code and you're\n    sure you own the intellectual property, then you'll need to sign an\n    [individual\n    CLA](https://developers.google.com/open-source/cla/individual).\n-   If you work for a company that wants to allow you to contribute your\n    work, then you'll need to sign a [corporate\n    CLA](https://developers.google.com/open-source/cla/corporate).\n\nYou generally only need to submit a CLA once, so if you've already\nsubmitted one (even if it was for a different project), you probably\ndon't need to do it again.\n\nOnce your CLA is submitted (or if you already submitted one for another Google\nproject), make a commit adding yourself to the\n[AUTHORS](https://github.com/google/glog/blob/master/AUTHORS) and\n[CONTRIBUTORS](https://github.com/google/glog/blob/master/CONTRIBUTORS) files.\nThis commit can be part of your first [pull\nrequest](https://help.github.com/articles/creating-a-pull-request).\n\n## Submitting a Patch\n\n1.  It's generally best to start by opening a new issue describing the\n    bug or feature you're intending to fix. Even if you think it's\n    relatively minor, it's helpful to know what people are working on.\n    Mention in the initial issue that you are planning to work on that\n    bug or feature so that it can be assigned to you.\n2.  Follow the normal process of\n    [forking](https://help.github.com/articles/fork-a-repo) the project,\n    and setup a new branch to work in. It's important that each group of\n    changes be done in separate branches in order to ensure that a pull\n    request only includes the commits related to that bug or feature.\n3.  Do your best to have [well-formed commit\n    messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)\n    for each change. This provides consistency throughout the project,\n    and ensures that commit messages are able to be formatted properly\n    by various git tools.\n4.  Finally, push the commits to your fork and submit a [pull\n    request](https://help.github.com/articles/creating-a-pull-request).\n"
  },
  {
    "path": "docs/failures.md",
    "content": "# Failure Signal Handler\n\n## Stacktrace as Default Failure Handler\n\nThe library provides a convenient signal handler that will dump useful\ninformation when the program crashes on certain signals such as `SIGSEGV`. The\nsignal handler can be installed by `#!cpp\ngoogle::InstallFailureSignalHandler()`. The following is an example of output\nfrom the signal handler.\n\n    *** Aborted at 1225095260 (unix time) try \"date -d @1225095260\" if you are using GNU date ***\n    *** SIGSEGV (@0x0) received by PID 17711 (TID 0x7f893090a6f0) from PID 0; stack trace: ***\n    PC: @           0x412eb1 TestWaitingLogSink::send()\n        @     0x7f892fb417d0 (unknown)\n        @           0x412eb1 TestWaitingLogSink::send()\n        @     0x7f89304f7f06 google::LogMessage::SendToLog()\n        @     0x7f89304f35af google::LogMessage::Flush()\n        @     0x7f89304f3739 google::LogMessage::~LogMessage()\n        @           0x408cf4 TestLogSinkWaitTillSent()\n        @           0x4115de main\n        @     0x7f892f7ef1c4 (unknown)\n        @           0x4046f9 (unknown)\n\n\n## Customizing Handler Output\n\nBy default, the signal handler writes the failure dump to the standard error.\nHowever, it is possible to customize the destination by installing a callback\nusing the `#!cpp google::InstallFailureWriter()` function. The function expects\na pointer to a function with the following signature:\n\n``` cpp\nvoid YourFailureWriter(const char* message/* (1)! */, std::size_t length/* (2)! */);\n```\n\n1. The pointer references the start of the failure message.\n\n    !!! danger\n        The string is **not null-terminated**.\n\n2. The message length in characters.\n\n!!! warning \"Possible overflow errors\"\n    Users should not expect the `message` string to be null-terminated.\n\n## User-defined Failure Function\n\n`FATAL` severity level messages or unsatisfied `CHECK` condition\nterminate your program. You can change the behavior of the termination\nby `google::InstallFailureFunction`.\n\n``` cpp\nvoid YourFailureFunction() {\n  // Reports something...\n  exit(EXIT_FAILURE);\n}\n\nint main(int argc, char* argv[]) {\n  google::InstallFailureFunction(&YourFailureFunction);\n}\n```\n\nBy default, glog tries to dump the stacktrace and calls `#!cpp std::abort`. The\nstacktrace is generated only when running the application on a system\nsupported[^1] by glog.\n\n[^1]: To extract the stack trace, glog currently supports the following targets:\n\n    * x86, x86_64,\n    * PowerPC architectures,\n    * `libunwind`,\n    * and the Debug Help Library (`dbghelp`) on Windows.\n\n"
  },
  {
    "path": "docs/flags.md",
    "content": "# Adjusting Output\n\nSeveral flags influence glog's output behavior.\n\n## Using Command-line Parameters and Environment Variables\n\nIf the [Google gflags\nlibrary](https://github.com/gflags/gflags) is installed on your machine,\nthe build system will automatically detect and use it, allowing you to\npass flags on the command line.\n\n!!! example \"Activate `--logtostderr` in an application from the command line\"\n    A binary `you_application` that uses glog can be started using\n    ``` bash\n    ./your_application --logtostderr=1\n    ```\n    to log to `stderr` instead of writing the output to a log file.\n\n!!! tip\n    You can set boolean flags to `true` by specifying `1`, `true`, or `yes`. To\n    set boolean flags to `false`, specify `0`, `false`, or `no`. In either case\n    the spelling is case-insensitive.\n\n\nIf the Google gflags library isn't installed, you set flags via\nenvironment variables, prefixing the flag name with `GLOG_`, e.g.,\n\n!!! example \"Activate `logtostderr` without gflags\"\n    ``` bash\n    GLOG_logtostderr=1 ./your_application\n    ```\n\nThe following flags are most commonly used:\n\n`logtostderr` (`bool`, default=`false`)\n\n:   Log messages to `stderr` instead of logfiles.\n\n`stderrthreshold` (`int`, default=2, which is `ERROR`)\n\n:   Copy log messages at or above this level to `stderr` in addition to\n    logfiles. The numbers of severity levels `INFO`, `WARNING`, `ERROR`,\n    and `FATAL` are 0, 1, 2, and 3, respectively.\n\n`minloglevel` (`int`, default=0, which is `INFO`)\n\n:   Log messages at or above this level. Again, the numbers of severity\n    levels `INFO`, `WARNING`, `ERROR`, and `FATAL` are 0, 1, 2, and 3,\n    respectively.\n\n`log_dir` (`string`, default=\"\")\n\n:   If specified, logfiles are written into this directory instead of\n    the default logging directory.\n\n`v` (`int`, default=0)\n\n:   Show all `#!cpp VLOG(m)` messages for `m` less or equal the value of this\n    flag. Overridable by `#!bash --vmodule`. Refer to [verbose\n    logging](logging.md#verbose-logging) for more detail.\n\n`vmodule` (`string`, default=\"\")\n\n:   Per-module verbose level. The argument has to contain a\n    comma-separated list of `<module name>=<log level>`. `<module name>` is a\n    glob pattern (e.g., `gfs*` for all modules whose name starts with \"gfs\"),\n    matched against the filename base (that is, name ignoring .cc/.h./-inl.h).\n    `<log level>` overrides any value given by `--v`. See also [verbose\n    logging](logging.md#verbose-logging) for more details.\n\nAdditional flags are defined in\n[flags.cc](https://github.com/google/glog/blob/master/src/flags.cc). Please see\nthe source for their complete list.\n\n## Modifying Flags Programmatically\n\nYou can also modify flag values in your program by modifying global variables\n`FLAGS_*`. Most settings start working immediately after you update `FLAGS_*`.\nThe exceptions are the flags related to destination files. For instance, you\nmight want to set `FLAGS_log_dir` before calling `google::InitGoogleLogging`.\n\n!!! example \"Setting `log_dir` at runtime\"\n    ``` cpp\n    LOG(INFO) << \"file\";\n    // Most flags work immediately after updating values.\n    FLAGS_logtostderr = 1;\n    LOG(INFO) << \"stderr\";\n    FLAGS_logtostderr = 0;\n    // This won’t change the log destination. If you want to set this\n    // value, you should do this before google::InitGoogleLogging .\n    FLAGS_log_dir = \"/some/log/directory\";\n    LOG(INFO) << \"the same file\";\n    ```\n"
  },
  {
    "path": "docs/index.md",
    "content": "# Google Logging Library\n\nGoogle Logging (glog) is a C++14 library that implements application-level\nlogging. The library provides logging APIs based on C++-style streams and\nvarious helper macros.\n\n# How to Use\n\nYou can log a message by simply streaming things to `LOG`(<a particular\n[severity level](logging.md#severity-levels)\\>), e.g.,\n\n``` cpp title=\"main.cpp\"\n#include <glog/logging.h>\n\nint main(int argc, char* argv[]) {\n    google::InitGoogleLogging(argv[0]); // (1)!\n    LOG(INFO) << \"Found \" << num_cookies << \" cookies\"; // (2)!\n}\n```\n\n1. Initialize the Google Logging Library\n2. Log a message with informational severity\n\nThe library can be installed using various [package managers](packages.md) or\ncompiled [from source](build.md). For a detailed overview of glog features and\ntheir usage, please refer to the [user guide](logging.md).\n\n!!! warning\n    The above example requires further [Bazel](build.md#bazel) or\n    [CMake](usage.md) setup for use in own projects.\n"
  },
  {
    "path": "docs/license.md",
    "content": "# The 3-Clause BSD License\n\n--8<-- \"LICENSE.md\"\n"
  },
  {
    "path": "docs/log_cleaner.md",
    "content": "# Automatically Remove Old Logs\n\nTo enable the log cleaner:\n\n``` cpp\nusing namespace std::chrono_literals;\ngoogle::EnableLogCleaner(24h * 3); // keep your logs for 3 days\n```\n\nIn C++20 (and later) this can be shortened to:\n\n``` cpp\nusing namespace std::chrono_literals;\ngoogle::EnableLogCleaner(3d); // keep your logs for 3 days\n```\n\nAnd then glog will check if there are overdue logs whenever a flush is\nperformed. In this example, any log file from your project whose last\nmodified time is greater than 3 days will be `unlink`()ed.\n\nThis feature can be disabled at any time (if it has been enabled) using\n``` cpp\ngoogle::DisableLogCleaner();\n```\n"
  },
  {
    "path": "docs/log_stripping.md",
    "content": "# Strip Logging Messages\n\nStrings used in log messages can increase the size of your binary and\npresent a privacy concern. You can therefore instruct glog to remove all\nstrings which fall below a certain severity level by using the\n`GOOGLE_STRIP_LOG` macro:\n\nIf your application has code like this:\n\n``` cpp\n#define GOOGLE_STRIP_LOG 1    // this must go before the #include!\n#include <glog/logging.h>\n```\n\nThe compiler will remove the log messages whose severities are less than\nthe specified integer value. Since `VLOG` logs at the severity level\n`INFO` (numeric value `0`), setting `GOOGLE_STRIP_LOG` to 1 or greater\nremoves all log messages associated with `VLOG`s as well as `INFO` log\nstatements.\n\n"
  },
  {
    "path": "docs/logging.md",
    "content": "# Logging\n\nglog defines a series of macros that simplify many common logging tasks. You can\nlog messages by [severity level](#severity-levels), [control logging](flags.md)\nbehavior from the command line, log based on\n[conditionals](#conditional-occasional-logging), abort the program when\n[expected conditions](#runtime-checks) are not met, introduce your [own logging\nlevels](#verbose-logging), [customize the prefix](#format-customization)\nattached to log messages, and more.\n\n\n## Severity Levels\n\nYou can specify one of the following severity levels (in increasing order of\nseverity):\n\n1.  `INFO`,\n2.  `WARNING`,\n3.  `ERROR`, and\n4.  `FATAL`.\n\nLogging a `FATAL` message terminates the program (after the message is logged).\n\n!!! note\n    Messages of a given severity are logged not only to corresponding severity\n    logfile but also to other logfiles of lower severity. For instance, a\n    message of severity `FATAL` will be logged to logfiles of severity `FATAL`,\n    `ERROR`, `WARNING`, and `INFO`.\n\nThe `DFATAL` severity logs a `FATAL` error in [debug mode](#debugging-support)\n(i.e., there is no `NDEBUG` macro defined), but avoids halting the program in\nproduction by automatically reducing the severity to `ERROR`.\n\n## Log Files\n\nUnless otherwise specified, glog uses the format\n\n    <tmp>/<program name>.<hostname>.<user name>.log.<severity level>.<date>-<time>.<pid>\n\nfor log filenames written to a directory designated as `<tmp>` and\ndetermined according to the following rules.\n\n**Windows**\n\n:   glog uses the\n    [GetTempPathA](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha)\n    API function to retrieve the directory for temporary files with a\n    fallback to\n\n    1.  `C:\\TMP\\`\n    2.  `C:\\TEMP\\`\n\n    (in the order given.)\n\n**non-Windows**\n\n:   The directory is determined by referencing the environment variables\n\n    1.  `TMPDIR`\n    2.  `TMP`\n\n    if set with a fallback to `/tmp/`.\n\nThe default path to a log file on Linux, for instance, could be\n\n    /tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474\n\nBy default, glog echos `ERROR` and `FATAL` messages to standard error in\naddition to log files.\n\n## Log Line Prefix Format\n\nLog lines have this form:\n\n    Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg...\n\nwhere the fields are defined as follows:\n\n  | Placeholder         | Meaning                                                               |\n  | ------------------- | ----------------------------------------------------------------------|\n  | `L`                 | A single character, representing the log level (e.g., `I` for `INFO`) |\n  | `yyyy`              | The year                                                              |\n  | `mm`                | The month (zero padded; i.e., May is `05`)                            |\n  | `dd`                | The day (zero padded)                                                 |\n  | `hh:mm:ss.uuuuuu`   | Time in hours, minutes and fractional seconds                         |\n  | `threadid`          | The space-padded thread ID                                            |\n  | `file`              | The file name                                                         |\n  | `line`              | The line number                                                       |\n  | `msg`               | The user-supplied message                                             |\n\n!!! example \"Default log line prefix format\"\n\n    ```\n    I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog\n    I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395\n    ```\n\n!!! note\n    Although microseconds are useful for comparing events on a single machine,\n    clocks on different machines may not be well synchronized. Hence, use with\n    caution when comparing the low bits of timestamps from different machines.\n\n### Format Customization\n\nThe predefined log line prefix can be replaced using a user-provided callback\nthat formats the corresponding output.\n\nFor each log entry, the callback will be invoked with a reference to a\n`google::LogMessage` instance containing the severity, filename, line\nnumber, thread ID, and time of the event. It will also be given a\nreference to the output stream, whose contents will be prepended to the actual\nmessage in the final log line.\n\nTo enable the use of a prefix formatter, use the\n\n``` cpp\ngoogle::InstallPrefixFormatter(&MyPrefixFormatter);\n```\n\nfunction to pass a pointer to the corresponding `MyPrefixFormatter` callback\nduring initialization. `InstallPrefixFormatter` takes a second optional argument\nof type `#!cpp void*` that allows supplying user data to the callback.\n\n!!! example \"Custom prefix formatter\"\n    The following function outputs a prefix that matches glog's default format.\n    The third parameter `data` can be used to access user-supplied data which\n    unless specified defaults to `#!cpp nullptr`.\n\n    ``` cpp\n    void MyPrefixFormatter(std::ostream& s, const google::LogMessage& m, void* /*data*/) {\n       s << google::GetLogSeverityName(m.severity())[0]\n       << setw(4) << 1900 + m.time().year()\n       << setw(2) << 1 + m.time().month()\n       << setw(2) << m.time().day()\n       << ' '\n       << setw(2) << m.time().hour() << ':'\n       << setw(2) << m.time().min()  << ':'\n       << setw(2) << m.time().sec() << \".\"\n       << setw(6) << m.time().usec()\n       << ' '\n       << setfill(' ') << setw(5)\n       << m.thread_id() << setfill('0')\n       << ' '\n       << m.basename() << ':' << m.line() << \"]\";\n    }\n    ```\n\n\n## Conditional / Occasional Logging\n\nSometimes, you may only want to log a message under certain conditions.\nYou can use the following macros to perform conditional logging:\n\n``` cpp\nLOG_IF(INFO, num_cookies > 10) << \"Got lots of cookies\";\n```\n\nThe \"Got lots of cookies\" message is logged only when the variable\n`num_cookies` exceeds 10. If a line of code is executed many times, it may be\nuseful to only log a message at certain intervals. This kind of logging is most\nuseful for informational messages.\n\n``` cpp\nLOG_EVERY_N(INFO, 10) << \"Got the \" << google::COUNTER << \"th cookie\";\n```\n\nThe above line outputs a log messages on the 1st, 11th, 21st, ... times\nit is executed.\n\n!!! note\n    The placeholder `#!cpp google::COUNTER` identifies the recurring repetition.\n\nYou can combine conditional and occasional logging with the following\nmacro.\n\n``` cpp\nLOG_IF_EVERY_N(INFO, (size > 1024), 10) << \"Got the \" << google::COUNTER\n                                        << \"th big cookie\";\n```\n\nInstead of outputting a message every nth time, you can also limit the\noutput to the first n occurrences:\n\n``` cpp\nLOG_FIRST_N(INFO, 20) << \"Got the \" << google::COUNTER << \"th cookie\";\n```\n\nOutputs log messages for the first 20 times it is executed. The `#!cpp\ngoogle::COUNTER` identifier indicates which repetition is happening.\n\nOther times, it is desired to only log a message periodically based on a\ntime. For instance, to log a message every 10ms:\n\n``` cpp\nLOG_EVERY_T(INFO, 0.01) << \"Got a cookie\";\n```\n\nOr every 2.35s:\n\n``` cpp\nLOG_EVERY_T(INFO, 2.35) << \"Got a cookie\";\n```\n\n## Verbose Logging\n\nWhen you are chasing difficult bugs, thorough log messages are very\nuseful. However, you may want to ignore too verbose messages in usual\ndevelopment. For such verbose logging, glog provides the `VLOG` macro, which\nallows you to define your own numeric logging levels.\n\nThe `#!bash --v` command line option controls which verbose messages are logged:\n\n``` cpp\nVLOG(1) << \"I’m printed when you run the program with --v=1 or higher\";\nVLOG(2) << \"I’m printed when you run the program with --v=2 or higher\";\n```\n\nWith `VLOG`, the lower the verbose level, the more likely messages are to be\nlogged. For example, if `#!bash --v==1`, `#!cpp VLOG(1)` will log, but `#!cpp\nVLOG(2)` will not log.\n\n!!! warning\n    The `VLOG` behavior is opposite of the severity level logging, where\n    `INFO`, `ERROR`, etc. are defined in increasing order and thus\n    `#!bash --minloglevel` of 1 will only log `WARNING` and above.\n\nThough you can specify any integers for both `VLOG` macro and `--v` flag, the\ncommon values for them are small positive integers. For example, if you write\n`#!cpp VLOG(0)`, you should specify `--v=-1` or lower to silence it. This is less\nuseful since we may not want verbose logs by default in most cases. The `VLOG`\nmacros always log at the `INFO` log level (when they log at all).\n\nVerbose logging can be controlled from the command line on a per-module basis:\n\n``` bash\n--vmodule=mapreduce=2,file=1,gfs*=3 --v=0\n```\n\nSpecifying these options will specifically:\n\n1.  Print `#!cpp VLOG(2)` and lower messages from mapreduce.{h,cc}\n2.  Print `#!cpp VLOG(1)` and lower messages from file.{h,cc}\n3.  Print `#!cpp VLOG(3)` and lower messages from files prefixed with \"gfs\"\n4.  Print `#!cpp VLOG(0)` and lower messages from elsewhere\n\nThe wildcarding functionality 3. supports both `*` (matches 0 or more\ncharacters) and `?` (matches any single character) wildcards. Please also refer\nto [command line flags](flags.md) for more information.\n\nThere's also `#!cpp VLOG_IS_ON(n)` \"verbose level\" condition macro. This macro\nreturns `#!cpp true` when the `--v` is equal to or greater than `n`. The macro can be\nused as follows:\n\n``` cpp\nif (VLOG_IS_ON(2)) {\n    // (1)\n}\n```\n\n1. Here we can perform some logging preparation and logging that can’t be\n   accomplished with just `#!cpp VLOG(2) << \"message ...\";`\n\nVerbose level condition macros `VLOG_IF`, `VLOG_EVERY_N` and `VLOG_IF_EVERY_N`\nbehave analogous to `LOG_IF`, `LOG_EVERY_N`, `LOG_IF_EVERY_N`, but accept a\nnumeric verbosity level as opposed to a severity level.\n\n``` cpp\nVLOG_IF(1, (size > 1024))\n   << \"I’m printed when size is more than 1024 and when you run the \"\n      \"program with --v=1 or more\";\nVLOG_EVERY_N(1, 10)\n   << \"I’m printed every 10th occurrence, and when you run the program \"\n      \"with --v=1 or more. Present occurrence is \" << google::COUNTER;\nVLOG_IF_EVERY_N(1, (size > 1024), 10)\n   << \"I’m printed on every 10th occurrence of case when size is more \"\n      \" than 1024, when you run the program with --v=1 or more. \";\n      \"Present occurrence is \" << google::COUNTER;\n```\n\n\n!!! info \"Performance\"\n    The conditional logging macros provided by glog (e.g., `CHECK`, `LOG_IF`,\n    `VLOG`, etc.) are carefully implemented and don't execute the right hand\n    side expressions when the conditions are false. So, the following check may\n    not sacrifice the performance of your application.\n\n    ``` cpp\n    CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();\n    ```\n\n## Debugging Support\n\nSpecial debug mode logging macros only have an effect in debug mode and are\ncompiled away to nothing for non-debug mode compiles. Use these macros to avoid\nslowing down your production application due to excessive logging.\n\n``` cpp\nDLOG(INFO) << \"Found cookies\";\nDLOG_IF(INFO, num_cookies > 10) << \"Got lots of cookies\";\nDLOG_EVERY_N(INFO, 10) << \"Got the \" << google::COUNTER << \"th cookie\";\nDLOG_FIRST_N(INFO, 10) << \"Got the \" << google::COUNTER << \"th cookie\";\nDLOG_EVERY_T(INFO, 0.01) << \"Got a cookie\";\n```\n\n## Runtime Checks\n\nIt is a good practice to check expected conditions in your program\nfrequently to detect errors as early as possible. The `CHECK` macro\nprovides the ability to abort the application when a condition is not met,\nsimilar to the `assert` macro defined in the standard C library.\n\n`CHECK` aborts the application if a condition is not true. Unlike\n`assert`, it is **not** controlled by `NDEBUG`, so the check will be executed\nregardless of compilation mode. Therefore, `fp->Write(x)` in the following\nexample is always executed:\n\n``` cpp\nCHECK(fp->Write(x) == 4) << \"Write failed!\";\n```\n\nThere are various helper macros for equality/inequality checks\n-`CHECK_EQ`, `CHECK_NE`, `CHECK_LE`, `CHECK_LT`, `CHECK_GE`, and\n`CHECK_GT`. They compare two values, and log a `FATAL` message including the two\nvalues when the result is not as expected. The values must have\n`#!cpp operator<<(ostream, ...)` defined.\n\nYou may append to the error message like so:\n\n``` cpp\nCHECK_NE(1, 2) << \": The world must be ending!\";\n```\n\nWe are very careful to ensure that each argument is evaluated exactly\nonce, and that anything which is legal to pass as a function argument is legal\nhere. In particular, the arguments may be temporary expressions which will end\nup being destroyed at the end of the apparent statement, for example:\n\n``` cpp\nCHECK_EQ(string(\"abc\")[1], ’b’);\n```\n\nThe compiler reports an error if one of the arguments is a pointer and the other\nis `#!cpp nullptr`. To work around this, simply `#!cpp static_cast` `#!cpp\nnullptr` to the type of the desired pointer.\n\n``` cpp\nCHECK_EQ(some_ptr, static_cast<SomeType*>(nullptr));\n```\n\nBetter yet, use the `CHECK_NOTNULL` macro:\n\n``` cpp\nCHECK_NOTNULL(some_ptr);\nsome_ptr->DoSomething();\n```\n\nSince this macro returns the given pointer, this is very useful in\nconstructor initializer lists.\n\n``` cpp\nstruct S {\n    S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}\n    Something* ptr_;\n};\n```\n\n!!! warning\n    Due to the argument forwarding, `CHECK_NOTNULL` cannot be used to\n    simultaneously stream an additional custom message. To provide a custom\n    message, one can use the macro `CHECK_EQ` prior to the failing check.\n\nIf you are comparing C strings (`#!cpp char *`), a handy set of macros performs\nboth case sensitive and insensitive comparisons - `CHECK_STREQ`, `CHECK_STRNE`,\n`CHECK_STRCASEEQ`, and `CHECK_STRCASENE`. The `CHECK_*CASE*` macro variants are\ncase-insensitive. You can safely pass `#!cpp nullptr` pointers to this macro.\nThey treat `#!cpp nullptr` and any non-`#!cpp nullptr` string as not equal. Two\n`#!cpp nullptr`s are equal.\n\n!!! note\n    Both arguments may be temporary objects which are destructed at the\n    end of the current *full expression*, such as\n\n    ``` cpp\n    CHECK_STREQ(Foo().c_str(), Bar().c_str());\n    ```\n\n    where `Foo` and `Bar` return `std::string`.\n\nThe `CHECK_DOUBLE_EQ` macro checks the equality of two floating point values,\naccepting a small error margin. `CHECK_NEAR` accepts a third floating point\nargument, which specifies the acceptable error margin.\n\n\n## Raw Logging\n\nThe header file `<glog/raw_logging.h>` can be used for thread-safe logging,\nwhich does not allocate any memory or acquire any locks. Therefore, the macros\ndefined in this header file can be used by low-level memory allocation and\nsynchronization code. Please check\n[src/glog/raw_logging.h](https://github.com/google/glog/blob/master/src/glog/raw_logging.h)\nfor detail.\n\n## Google Style `perror()`\n\n`PLOG()` and `PLOG_IF()` and `PCHECK()` behave exactly like their `LOG*` and\n`CHECK` equivalents with the addition that they append a description of the\ncurrent state of `errno` to their output lines. E.g.\n\n``` cpp\nPCHECK(write(1, nullptr, 2) >= 0) << \"Write nullptr failed\";\n```\n\nThis check fails with the following error message.\n\n    F0825 185142 test.cc:22] Check failed: write(1, nullptr, 2) >= 0 Write nullptr failed: Bad address [14]\n\n## Syslog\n\n`SYSLOG`, `SYSLOG_IF`, and `SYSLOG_EVERY_N` macros are available. These log to\nsyslog in addition to the normal logs. Be aware that logging to syslog can\ndrastically impact performance, especially if syslog is configured for remote\nlogging! Make sure you understand the implications of outputting to syslog\nbefore you use these macros. In general, it's wise to use these macros\nsparingly.\n"
  },
  {
    "path": "docs/overrides/main.html",
    "content": "{% extends \"base.html\" %}\n\n{% block outdated %}\n  You're not viewing the latest version.\n  <a href=\"{{ '../' ~ base_url }}\">\n    <strong>Click here to go to latest.</strong>\n  </a>\n{% endblock %}\n"
  },
  {
    "path": "docs/packages.md",
    "content": "# Installation using Package Managers\n\n## conan\n\nYou can download and install glog using the [conan](https://conan.io)\npackage manager:\n\n``` bash\npip install conan\nconan install -r conancenter glog/<glog-version>@\n```\n\nThe glog recipe in conan center is kept up to date by conan center index\ncommunity contributors. If the version is out of date, please create an\nissue or pull request on the\n[conan-center-index](https://github.com/conan-io/conan-center-index)\nrepository.\n\n## vcpkg\n\nYou can download and install glog using the\n[vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:\n\n``` bash\ngit clone https://github.com/Microsoft/vcpkg.git\ncd vcpkg\n./bootstrap-vcpkg.sh\n./vcpkg integrate install\n./vcpkg install glog\n```\n\nThe glog port in vcpkg is kept up to date by Microsoft team members and\ncommunity contributors. If the version is out of date, please create an\nissue or pull request on the vcpkg repository.\n"
  },
  {
    "path": "docs/requirements.txt",
    "content": "mike>=2.1.1\nmkdocs-git-committers-plugin-2>=2.3.0\nmkdocs-git-revision-date-localized-plugin>=1.2.6\nmkdocs-material-extensions>=1.3.1\nmkdocs-material>=9.5.26\nmkdocs>=1.6.0\n"
  },
  {
    "path": "docs/sinks.md",
    "content": "# Custom Sinks\n\nUnder certain circumstances, it is useful to send the log output to a\ndestination other than a file, `stderr` and/or `stdout`. In case, the library\nprovides the `#!cpp google::LogSink` interface whose implementations can be used\nto write the log output to arbitrary locations.\n\n## Basic Interface\n\nThe sink interface is defined as follows:\n\n``` cpp\nclass LogSink {\n public:\n  virtual void send(LogSeverity severity, const char* full_filename,\n                    const char* base_filename, int line,\n                    const LogMessageTime& time, const char* message,\n                    size_t message_len);\n};\n```\n\nThe user must implement `#!cpp google::LogSink::send`, which is called by the\nlibrary every time a message is logged.\n\n!!! warning \"Possible deadlock due to nested logging\"\n    This method can't use `LOG()` or `CHECK()` as logging system mutex(s) are\n    held during this call.\n\n## Registering Log Sinks\n\nTo use the custom sink and instance of the above interface implementation must\nbe registered using `google::AddLogSink` which expects a pointer to the\n`google::LogSink` instance. To unregister use `google::RemoveLogSink`. Both\nfunctions are thread-safe.\n\n!!! danger \"`LogSink` ownership\"\n    The `google::LogSink` instance must not be destroyed until the referencing\n    pointer is unregistered.\n\n## Direct Logging\n\nInstead of registering the sink, we can directly use to log messages. While `#!\nLOG_TO_SINK(sink, severity)` allows to log both to the sink and to a global log\nregistry, e.g., a file, `#!cpp LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity)`\nwill avoid the latter.\n\n!!! example \"Using a custom sink\"\n    ``` cpp title=\"custom_sink.cc\"\n    -8<- \"examples/custom_sink.cc:33:\"\n    ```\n\n    1. `MySink` implements a custom sink that sends log messages to `std::cout`.\n    2. The custom sink must be registered to for use with existing logging\n       macros.\n    3. Once the custom sink is no longer needed we remove it from the registry.\n    4. A sink does not need to be registered globally. However, then, messages\n       must be logged using dedicated macros.\n\n    Running the above example as `#!bash GLOG_log_dir=. ./custom_sink_example`\n    will produce\n\n    <div class=\"annotate\" markdown>\n\n    ``` title=\"Custom sink output\"\n    INFO custom_sink.cc:63 logging to MySink\n    INFO custom_sink.cc:68 direct logging\n    INFO custom_sink.cc:69 direct logging but not to file (1)\n    ```\n\n    </div>\n\n    1. This line is not present in the log file because we used\n       `LOG_TO_SINK_BUT_NOT_TO_LOGFILE` to log the message.\n\n    and the corresponding log file will contain\n\n    ``` title=\"Log file generated with the custom sink\"\n    Log file created at: 2024/06/11 13:24:27\n    Running on machine: pc\n    Running duration (h:mm:ss): 0:00:00\n    Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg\n    I20240611 13:24:27.476620 126237946035776 custom_sink.cc:63] logging to MySink\n    I20240611 13:24:27.476796 126237946035776 custom_sink.cc:68] direct logging\n    ```\n"
  },
  {
    "path": "docs/unwinder.md",
    "content": "# Installation Notes for 64-bit Linux Systems\n\n!!! note\n    The description on this page is possibly not up-to-date.\n\nThe [glibc built-in stack-unwinder](#glibc-built-in-stack-unwinder) on 64-bit\nsystems has some problems with glog. In particular, if you are using\n[`InstallFailureSignalHandler()`](failures.md), the signal may be raised in the\nmiddle of `malloc`, holding some `malloc`-related locks when they invoke the\nstack unwinder. The built-in stack unwinder may call `malloc` recursively, which\nmay require the thread to acquire a lock it already holds resulting in a\ndeadlock.\n\n## Recommended Approach: `libunwind`\n\nFor above reason, if you use a 64-bit system and you need\n`InstallFailureSignalHandler()`, we strongly recommend you install `libunwind`\nbefore trying to configure or install google glog. libunwind can be found\n[here](http://download.savannah.nongnu.org/releases/libunwind/libunwind-snap-070410.tar.gz).\n\nEven if you already have `libunwind` installed, you will probably still need to\ninstall from the snapshot to get the latest version.\n\n!!! warning\n    If you install libunwind from the URL above, be aware that you may have\n    trouble if you try to statically link your binary with glog: that is, if you\n    link with `gcc -static -lgcc_eh ...`. This is because both `libunwind` and\n    `libgcc` implement the same C++ exception handling APIs, but they implement\n    them differently on some platforms. This is not likely to be a problem on\n    ia64, but may be on x86-64.\n\nAlso, if you link binaries statically, make sure that you add\n`-Wl,--eh-frame-hdr` to your linker options. This is required so that\n`libunwind` can find the information generated by the compiler required for\nstack unwinding.\n\nUsing `-static` is rare, though, so unless you know this will affect you it\nprobably won't.\n\n## Alternative Stack-unwinder\n\nIf you cannot or do not wish to install `libunwind`, you can still try to use\ntwo kinds of stack-unwinder:\n\n### glibc Built-in Stack-unwinder\n\nAs we already mentioned, glibc's unwinder has a deadlock issue. However, if you\ndon't use `InstallFailureSignalHandler()` or you don't worry about the rare\npossibilities of deadlocks, you can use this stack-unwinder. If you specify no\noptions and `libunwind` isn't detected on your system, the configure script\nchooses this unwinder by default.\n\n### Frame Pointer based Stack-unwinder\n\nThe frame pointer based stack unwinder requires that your application, the glog\nlibrary, and system libraries like libc, all be compiled with a frame pointer.\nThis is *not* the default for x86-64.\n"
  },
  {
    "path": "docs/usage.md",
    "content": "# Using glog in a CMake Project\n\nAssuming that glog was previously [built using CMake](build.md#cmake) or\ninstalled using a package manager, you can use the CMake command `#!cmake\nfind_package` to build against glog in your CMake project as follows:\n\n``` cmake title=\"CMakeLists.txt\"\ncmake_minimum_required (VERSION 3.16)\nproject (myproj VERSION 1.0)\n\nfind_package (glog 0.8.0 REQUIRED)\n\nadd_executable (myapp main.cpp)\ntarget_link_libraries (myapp glog::glog)\n```\n\nCompile definitions and options will be added automatically to your target as\nneeded.\n\nAlternatively, glog can be incorporated into using the CMake command `#!cmake\nadd_subdirectory` to include glog directly from a subdirectory of your project\nby replacing the `#!cmake find_package` call from the previous snippet by\n`add_subdirectory`. The `#!cmake glog::glog` target is in this case an `#!cmake\nALIAS` library target for the `glog` library target.\n"
  },
  {
    "path": "docs/windows.md",
    "content": "# Notes for Windows Users\n\nglog defines the severity level `ERROR`, which is also defined by `windows.h`.\nYou can make glog not define `INFO`, `WARNING`, `ERROR`, and `FATAL` by defining\n`GLOG_NO_ABBREVIATED_SEVERITIES` before including `glog/logging.h`. Even with\nthis macro, you can still use the iostream like logging facilities:\n\n``` cpp\n#define GLOG_NO_ABBREVIATED_SEVERITIES\n#include <windows.h>\n#include <glog/logging.h>\n\n// ...\n\nLOG(ERROR) << \"This should work\";\nLOG_IF(ERROR, x > y) << \"This should be also OK\";\n```\n\nHowever, you cannot use `INFO`, `WARNING`, `ERROR`, and `FATAL` anymore for\nfunctions defined in `glog/logging.h`.\n\n``` cpp\n#define GLOG_NO_ABBREVIATED_SEVERITIES\n#include <windows.h>\n#include <glog/logging.h>\n\n// ...\n\n// This won’t work.\n// google::FlushLogFiles(google::ERROR);\n\n// Use this instead.\ngoogle::FlushLogFiles(google::GLOG_ERROR);\n```\n\nIf you don't need `ERROR` defined by `windows.h`, there are a couple of more\nworkarounds which sometimes don't work[^1]:\n\n-  `#!cpp #define WIN32_LEAN_AND_MEAN` or `NOGDI` **before**\n   `#!cpp #include <windows.h>`.\n-  `#!cpp #undef ERROR` **after** `#!cpp #include <windows.h>`.\n\n[^1]: For more information refer to [this\n      issue](http://code.google.com/p/google-glog/issues/detail?id=33).\n"
  },
  {
    "path": "examples/custom_sink.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergiu Deitsch\n//\n\n#include <glog/logging.h>\n\n#include <algorithm>\n#include <cstddef>\n#include <iostream>\n#include <iterator>\n\nnamespace {\n\nstruct MyLogSink : google::LogSink {  // (1)!\n  void send(google::LogSeverity severity, const char* /*full_filename*/,\n            const char* base_filename, int line,\n            const google::LogMessageTime& /*time*/, const char* message,\n            std::size_t message_len) override {\n    std::cout << google::GetLogSeverityName(severity) << ' ' << base_filename\n              << ':' << line << ' ';\n    std::copy_n(message, message_len,\n                std::ostreambuf_iterator<char>{std::cout});\n    std::cout << '\\n';\n  }\n};\n\n}  // namespace\n\nint main(int /*argc*/, char** argv) {\n  google::InitGoogleLogging(argv[0]);\n\n  MyLogSink sink;\n  google::AddLogSink(&sink);  // (2)!\n\n  LOG(INFO) << \"logging to MySink\";\n\n  google::RemoveLogSink(&sink);  // (3)!\n\n  // We can directly log to a sink without registering it\n  LOG_TO_SINK(&sink, INFO) << \"direct logging\";  // (4)!\n  LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)\n      << \"direct logging but not to file\";\n}\n"
  },
  {
    "path": "gcovr.cfg",
    "content": "exclude = src/.*_unittest\\.cc\nexclude = src/googletest\\.h\nexclude = src/mock-log\\.h\nexclude-directories = Tests/\nexclude-throw-branches = yes\nexclude-unreachable-branches = yes\nfilter = .*/glog/.*\\.h\nfilter = src/\n"
  },
  {
    "path": "glog-config.cmake.in",
    "content": "if (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)\n  message (FATAL_ERROR \"CMake >= @glog_CMake_VERSION@ required\")\nendif (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)\n\n@PACKAGE_INIT@\n\ninclude (CMakeFindDependencyMacro)\ninclude (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake)\n\nfind_dependency (Threads)\n\n@gflags_DEPENDENCY@\n@Unwind_DEPENDENCY@\n\ninclude (${CMAKE_CURRENT_LIST_DIR}/glog-targets.cmake)\n"
  },
  {
    "path": "glog-modules.cmake.in",
    "content": "cmake_policy (PUSH)\ncmake_policy (SET CMP0057 NEW)\n\nif (CMAKE_VERSION VERSION_LESS 3.3)\n  message (FATAL_ERROR \"glog-modules.cmake requires the consumer \"\n    \"to use CMake 3.3 (or newer)\")\nendif (CMAKE_VERSION VERSION_LESS 3.3)\n\nset (glog_MODULE_PATH \"@glog_FULL_CMake_DATADIR@\")\nlist (APPEND CMAKE_MODULE_PATH ${glog_MODULE_PATH})\n\nif (NOT glog_MODULE_PATH IN_LIST CMAKE_MODULE_PATH)\n  message (FATAL_ERROR \"Cannot add '${glog_MODULE_PATH}' to \"\n    \"CMAKE_MODULE_PATH. This will cause glog-config.cmake to fail at \"\n    \"locating required find modules. Make sure CMAKE_MODULE_PATH is not a cache variable.\")\nendif (NOT glog_MODULE_PATH IN_LIST CMAKE_MODULE_PATH)\n\ncmake_policy (POP)\n"
  },
  {
    "path": "libglog.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: libglog\nDescription: Google Log (glog) C++ logging framework\nVersion: @VERSION@\nLibs: -L${libdir} -lglog\nLibs.private: @glog_libraries_options_for_static_linking@\nCflags: -I${includedir}\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "---\nsite_name: Google Logging Library\nsite_url: https://google.github.io/glog/\nrepo_url: https://github.com/google/glog\nrepo_name: google/glog\nedit_uri: edit/master/docs/\ncopyright: Copyright &copy; 2024 Google Inc. &amp; contributors - <a href=\"#__consent\">Change cookie settings</a>\nmarkdown_extensions:\n  - admonition\n  - attr_list\n  - def_list\n  - footnotes\n  - md_in_html\n  - pymdownx.details\n  - pymdownx.highlight:\n      anchor_linenums: true\n      line_spans: __span\n      pygments_lang_class: true\n  - pymdownx.inlinehilite\n  - pymdownx.snippets:\n      base_path:\n        - '.'\n      check_paths: true\n  - pymdownx.superfences\n  - tables\n  - toc:\n      permalink: true\ntheme:\n  name: material\n  custom_dir: docs/overrides\n  icon:\n    annotation: material/chevron-right-circle\n    edit: material/pencil\n    repo: fontawesome/brands/git-alt\n    view: material/eye\n  language: en\n  features:\n    - content.action.edit\n    - content.code.annotate\n    - content.code.copy\n    - content.code.select\n    - header.autohide\n    - navigation.expand\n    - navigation.instant.preview\n    - navigation.instant.progress\n    - navigation.prune\n    - navigation.indexes\n    - toc.follow\n    - navigation.top\n    - navigation.path\n    # - navigation.sections\n    # - navigation.tabs\n    # - navigation.tabs.sticky\n    - navigation.tracking\n    - search.highlight\n    - search.share\n    - search.suggest\n  palette:\n    # Palette toggle for automatic mode\n    - media: \"(prefers-color-scheme)\"\n      toggle:\n        icon: material/brightness-auto\n        name: Switch to light mode\n    # Palette toggle for light mode\n    - media: \"(prefers-color-scheme: light)\"\n      scheme: default\n      primary: teal\n      accent: green\n      toggle:\n        icon: material/brightness-7\n        name: Switch to dark mode\n    # Palette toggle for dark mode\n    - media: \"(prefers-color-scheme: dark)\"\n      scheme: slate\n      primary: black\n      toggle:\n        icon: material/brightness-4\n        name: Switch to system preference\nplugins:\n  - git-revision-date-localized:\n      enable_creation_date: true\n  - git-committers:\n      repository: google/glog\n      branch: master\n  - privacy\n  - search\n  - tags\nextra:\n  version:\n    alias: true\n    default:\n      - dev\n      - stable\n    provider: mike\n  consent:\n    actions:\n      - manage\n      - accept\n      - reject\n    title: Cookie consent\n    description: >-\n      We use cookies to recognize your repeated visits and preferences, as well\n      as to measure the effectiveness of our documentation and whether users\n      find what they're searching for. With your consent, you're helping us to\n      make our documentation better.\nnav:\n  - Getting Started:\n      - Overview: index.md\n      - Usage in CMake Projects: usage.md\n      - Building from Source: build.md\n      - Installation using Package Managers: packages.md\n  - User Guide:\n      - Logging: logging.md\n      - Adjusting Output: flags.md\n      - Custom Sinks: sinks.md\n      - Failure Handler: failures.md\n      - Log Removal: log_cleaner.md\n      - Stripping Log Messages: log_stripping.md\n      - System-specific Considerations:\n          - Usage on Windows: windows.md\n          - Linux Unwinder: unwinder.md\n  - Contributing: contribute.md\n  - License: license.md\n"
  },
  {
    "path": "src/base/commandlineflags.h",
    "content": "// Copyright (c) 2008, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n// ---\n// This file is a compatibility layer that defines Google's version of\n// command line flags that are used for configuration.\n//\n// We put flags into their own namespace.  It is purposefully\n// named in an opaque way that people should have trouble typing\n// directly.  The idea is that DEFINE puts the flag in the weird\n// namespace, and DECLARE imports the flag from there into the\n// current namespace.  The net result is to force people to use\n// DECLARE to get access to a flag, rather than saying\n//   extern bool FLAGS_logtostderr;\n// or some such instead.  We want this so we can put extra\n// functionality (like sanity-checking) in DECLARE if we want,\n// and make sure it is picked up everywhere.\n//\n// We also put the type of the variable in the namespace, so that\n// people can't DECLARE_int32 something that they DEFINE_bool'd\n// elsewhere.\n#ifndef BASE_COMMANDLINEFLAGS_H__\n#define BASE_COMMANDLINEFLAGS_H__\n\n#include <cstdlib>  // for getenv\n#include <cstring>  // for memchr\n#include <string>\n\n#include \"config.h\"\n\n#ifdef GLOG_USE_GFLAGS\n\n#  include <gflags/gflags.h>\n\n#else\n\n#  include \"glog/logging.h\"\n\n#  define DECLARE_VARIABLE(type, shorttype, name, tn) \\\n    namespace fL##shorttype {                         \\\n      extern GLOG_EXPORT type FLAGS_##name;           \\\n    }                                                 \\\n    using fL##shorttype::FLAGS_##name\n#  define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \\\n    namespace fL##shorttype {                                        \\\n      GLOG_EXPORT type FLAGS_##name(value);                          \\\n      char FLAGS_no##name;                                           \\\n    }                                                                \\\n    using fL##shorttype::FLAGS_##name\n\n// bool specialization\n#  define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)\n#  define DEFINE_bool(name, value, meaning) \\\n    DEFINE_VARIABLE(bool, B, name, value, meaning, bool)\n\n// int32 specialization\n#  define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)\n#  define DEFINE_int32(name, value, meaning) \\\n    DEFINE_VARIABLE(google::int32, I, name, value, meaning, int32)\n\n// uint32 specialization\n#  ifndef DECLARE_uint32\n#    define DECLARE_uint32(name) \\\n      DECLARE_VARIABLE(google::uint32, U, name, uint32)\n#  endif  // DECLARE_uint64\n#  define DEFINE_uint32(name, value, meaning) \\\n    DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32)\n\n// Special case for string, because we have to specify the namespace\n// std::string, which doesn't play nicely with our FLAG__namespace hackery.\n#  define DECLARE_string(name)                    \\\n    namespace fLS {                               \\\n    extern GLOG_EXPORT std::string& FLAGS_##name; \\\n    }                                             \\\n    using fLS::FLAGS_##name\n#  define DEFINE_string(name, value, meaning)                   \\\n    namespace fLS {                                             \\\n    std::string FLAGS_##name##_buf(value);                      \\\n    GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \\\n    char FLAGS_no##name;                                        \\\n    }                                                           \\\n    using fLS::FLAGS_##name\n\n#endif  // GLOG_USE_GFLAGS\n\n// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we\n// have GLOG_* environ variables even if we have gflags installed.\n//\n// If both an environment variable and a flag are specified, the value\n// specified by a flag wins. E.g., if GLOG_v=0 and --v=1, the\n// verbosity will be 1, not 0.\n\n#define GLOG_DEFINE_bool(name, value, meaning) \\\n  DEFINE_bool(name, EnvToBool(\"GLOG_\" #name, value), meaning)\n\n#define GLOG_DEFINE_int32(name, value, meaning) \\\n  DEFINE_int32(name, EnvToInt(\"GLOG_\" #name, value), meaning)\n\n#define GLOG_DEFINE_uint32(name, value, meaning) \\\n  DEFINE_uint32(name, EnvToUInt(\"GLOG_\" #name, value), meaning)\n\n#define GLOG_DEFINE_string(name, value, meaning) \\\n  DEFINE_string(name, EnvToString(\"GLOG_\" #name, value), meaning)\n\n// These macros (could be functions, but I don't want to bother with a .cc\n// file), make it easier to initialize flags from the environment.\n\n#define EnvToString(envname, dflt) (!getenv(envname) ? (dflt) : getenv(envname))\n\n#define EnvToBool(envname, dflt) \\\n  (!getenv(envname) ? (dflt)     \\\n                    : memchr(\"tTyY1\\0\", getenv(envname)[0], 6) != nullptr)\n\n#define EnvToInt(envname, dflt) \\\n  (!getenv(envname) ? (dflt)    \\\n                    : static_cast<int>(strtol(getenv(envname), nullptr, 10)))\n\n#define EnvToUInt(envname, dflt) \\\n  (!getenv(envname)              \\\n       ? (dflt)                  \\\n       : static_cast<unsigned>(strtoul(getenv(envname), nullptr, 10)))\n\n#endif  // BASE_COMMANDLINEFLAGS_H__\n"
  },
  {
    "path": "src/base/googleinit.h",
    "content": "// Copyright (c) 2008, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n// ---\n// Author: Jacob Hoffman-Andrews\n\n#ifndef _GOOGLEINIT_H\n#define _GOOGLEINIT_H\n\nclass GoogleInitializer {\n public:\n  using void_function = void (*)();\n  GoogleInitializer(const char*, void_function f) { f(); }\n};\n\n#define REGISTER_MODULE_INITIALIZER(name, body)       \\\n  namespace {                                         \\\n  static void google_init_module_##name() { body; }   \\\n  GoogleInitializer google_initializer_module_##name( \\\n      #name, google_init_module_##name);              \\\n  }\n\n#endif /* _GOOGLEINIT_H */\n"
  },
  {
    "path": "src/cleanup_immediately_unittest.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#include \"base/commandlineflags.h\"\n#include \"glog/logging.h\"\n#include \"glog/raw_logging.h\"\n#include \"googletest.h\"\n\n#ifdef GLOG_USE_GFLAGS\n#  include <gflags/gflags.h>\nusing namespace GFLAGS_NAMESPACE;\n#endif\n\n#ifdef HAVE_LIB_GMOCK\n#  include <gmock/gmock.h>\n\n#  include \"mock-log.h\"\n// Introduce several symbols from gmock.\nusing google::glog_testing::ScopedMockLog;\nusing testing::_;\nusing testing::AllOf;\nusing testing::AnyNumber;\nusing testing::HasSubstr;\nusing testing::InitGoogleMock;\nusing testing::StrictMock;\nusing testing::StrNe;\n#endif\n\nusing namespace google;\n\nTEST(CleanImmediately, logging) {\n  using namespace std::chrono_literals;\n  google::SetLogFilenameExtension(\".foobar\");\n  google::EnableLogCleaner(0h);\n\n  for (unsigned i = 0; i < 1000; ++i) {\n    LOG(INFO) << \"cleanup test\";\n  }\n\n  google::DisableLogCleaner();\n}\n\nint main(int argc, char** argv) {\n  FLAGS_colorlogtostderr = false;\n  FLAGS_timestamp_in_logfile_name = true;\n#ifdef GLOG_USE_GFLAGS\n  ParseCommandLineFlags(&argc, &argv, true);\n#endif\n  // Make sure stderr is not buffered as stderr seems to be buffered\n  // on recent windows.\n  setbuf(stderr, nullptr);\n\n  // Test some basics before InitGoogleLogging:\n  CaptureTestStderr();\n  const string early_stderr = GetCapturedTestStderr();\n\n  EXPECT_FALSE(IsGoogleLoggingInitialized());\n\n  InitGoogleLogging(argv[0]);\n\n  EXPECT_TRUE(IsGoogleLoggingInitialized());\n\n  InitGoogleTest(&argc, argv);\n#ifdef HAVE_LIB_GMOCK\n  InitGoogleMock(&argc, argv);\n#endif\n\n  // so that death tests run before we use threads\n  CHECK_EQ(RUN_ALL_TESTS(), 0);\n}\n"
  },
  {
    "path": "src/cleanup_with_absolute_prefix_unittest.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#include \"base/commandlineflags.h\"\n#include \"glog/logging.h\"\n#include \"glog/raw_logging.h\"\n#include \"googletest.h\"\n\n#ifdef GLOG_USE_GFLAGS\n#  include <gflags/gflags.h>\nusing namespace GFLAGS_NAMESPACE;\n#endif\n\n#ifdef HAVE_LIB_GMOCK\n#  include <gmock/gmock.h>\n\n#  include \"mock-log.h\"\n// Introduce several symbols from gmock.\nusing google::glog_testing::ScopedMockLog;\nusing testing::_;\nusing testing::AllOf;\nusing testing::AnyNumber;\nusing testing::HasSubstr;\nusing testing::InitGoogleMock;\nusing testing::StrictMock;\nusing testing::StrNe;\n#endif\n\nusing namespace google;\n\nTEST(CleanImmediatelyWithAbsolutePrefix, logging) {\n  using namespace std::chrono_literals;\n  google::EnableLogCleaner(0h);\n  google::SetLogFilenameExtension(\".barfoo\");\n  google::SetLogDestination(GLOG_INFO, \"test_cleanup_\");\n\n  for (unsigned i = 0; i < 1000; ++i) {\n    LOG(INFO) << \"cleanup test\";\n  }\n\n  for (unsigned i = 0; i < 10; ++i) {\n    LOG(ERROR) << \"cleanup test\";\n  }\n\n  google::DisableLogCleaner();\n}\n\nint main(int argc, char** argv) {\n  FLAGS_colorlogtostderr = false;\n  FLAGS_timestamp_in_logfile_name = true;\n#ifdef GLOG_USE_GFLAGS\n  ParseCommandLineFlags(&argc, &argv, true);\n#endif\n  // Make sure stderr is not buffered as stderr seems to be buffered\n  // on recent windows.\n  setbuf(stderr, nullptr);\n\n  // Test some basics before InitGoogleLogging:\n  CaptureTestStderr();\n  const string early_stderr = GetCapturedTestStderr();\n\n  EXPECT_FALSE(IsGoogleLoggingInitialized());\n\n  InitGoogleLogging(argv[0]);\n\n  EXPECT_TRUE(IsGoogleLoggingInitialized());\n\n  InitGoogleTest(&argc, argv);\n#ifdef HAVE_LIB_GMOCK\n  InitGoogleMock(&argc, argv);\n#endif\n\n  // so that death tests run before we use threads\n  CHECK_EQ(RUN_ALL_TESTS(), 0);\n}\n"
  },
  {
    "path": "src/cleanup_with_relative_prefix_unittest.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#include \"base/commandlineflags.h\"\n#include \"glog/logging.h\"\n#include \"glog/raw_logging.h\"\n#include \"googletest.h\"\n\n#ifdef GLOG_USE_GFLAGS\n#  include <gflags/gflags.h>\nusing namespace GFLAGS_NAMESPACE;\n#endif\n\n#ifdef HAVE_LIB_GMOCK\n#  include <gmock/gmock.h>\n\n#  include \"mock-log.h\"\n// Introduce several symbols from gmock.\nusing google::glog_testing::ScopedMockLog;\nusing testing::_;\nusing testing::AllOf;\nusing testing::AnyNumber;\nusing testing::HasSubstr;\nusing testing::InitGoogleMock;\nusing testing::StrictMock;\nusing testing::StrNe;\n#endif\n\nusing namespace google;\n\nTEST(CleanImmediatelyWithRelativePrefix, logging) {\n  using namespace std::chrono_literals;\n  google::EnableLogCleaner(0h);\n  google::SetLogFilenameExtension(\".relativefoo\");\n  google::SetLogDestination(GLOG_INFO, \"test_subdir/test_cleanup_\");\n\n  for (unsigned i = 0; i < 1000; ++i) {\n    LOG(INFO) << \"cleanup test\";\n  }\n\n  google::DisableLogCleaner();\n}\n\nint main(int argc, char** argv) {\n  FLAGS_colorlogtostderr = false;\n  FLAGS_timestamp_in_logfile_name = true;\n#ifdef GLOG_USE_GFLAGS\n  ParseCommandLineFlags(&argc, &argv, true);\n#endif\n  // Make sure stderr is not buffered as stderr seems to be buffered\n  // on recent windows.\n  setbuf(stderr, nullptr);\n\n  // Test some basics before InitGoogleLogging:\n  CaptureTestStderr();\n  const string early_stderr = GetCapturedTestStderr();\n\n  EXPECT_FALSE(IsGoogleLoggingInitialized());\n\n  InitGoogleLogging(argv[0]);\n\n  EXPECT_TRUE(IsGoogleLoggingInitialized());\n\n  InitGoogleTest(&argc, argv);\n#ifdef HAVE_LIB_GMOCK\n  InitGoogleMock(&argc, argv);\n#endif\n\n  // so that death tests run before we use threads\n  CHECK_EQ(RUN_ALL_TESTS(), 0);\n}\n"
  },
  {
    "path": "src/config.h.cmake.in",
    "content": "#ifndef GLOG_CONFIG_H\n#define GLOG_CONFIG_H\n\n/* Define if you have the `dladdr' function */\n#cmakedefine HAVE_DLADDR\n\n/* Define to 1 if you have the <dlfcn.h> header file. */\n#cmakedefine HAVE_DLFCN_H\n\n/* Define if you have the `backtrace' function in <execinfo.h> */\n#cmakedefine HAVE_EXECINFO_BACKTRACE\n\n/* Define if you have the `backtrace_symbols' function in <execinfo.h> */\n#cmakedefine HAVE_EXECINFO_BACKTRACE_SYMBOLS\n\n/* Define if you have the `fcntl' function */\n#cmakedefine HAVE_FCNTL\n\n/* Define to 1 if you have the <glob.h> header file. */\n#cmakedefine HAVE_GLOB_H\n\n/* define if you have google gmock library */\n#cmakedefine HAVE_LIB_GMOCK\n\n/* define if you have google gtest library */\n#cmakedefine HAVE_LIB_GTEST\n\n/* define if you have dbghelp library */\n#cmakedefine HAVE_DBGHELP\n\n/* Define if you have the 'pread' function */\n#cmakedefine HAVE_PREAD\n\n/* Define if you have the 'posix_fadvise' function in <fcntl.h> */\n#cmakedefine HAVE_POSIX_FADVISE\n\n/* Define to 1 if you have the <pwd.h> header file. */\n#cmakedefine HAVE_PWD_H\n\n/* Define if you have the 'pwrite' function */\n#cmakedefine HAVE_PWRITE\n\n/* Define if you have the 'sigaction' function */\n#cmakedefine HAVE_SIGACTION\n\n/* Define if you have the `sigaltstack' function */\n#cmakedefine HAVE_SIGALTSTACK\n\n/* Define to 1 if you have the <syscall.h> header file. */\n#cmakedefine HAVE_SYSCALL_H\n\n/* Define to 1 if you have the <syslog.h> header file. */\n#cmakedefine HAVE_SYSLOG_H\n\n/* Define to 1 if you have the <elf.h> header file. */\n#cmakedefine HAVE_ELF_H\n\n/* Define to 1 if you have the <sys/exec_elf.h> header file. */\n#cmakedefine HAVE_SYS_EXEC_ELF_H\n\n/* Define to 1 if you have the <link.h> header file. */\n#cmakedefine HAVE_LINK_H\n\n/* Define to 1 if you have the <sys/syscall.h> header file. */\n#cmakedefine HAVE_SYS_SYSCALL_H\n\n/* Define to 1 if you have the <sys/time.h> header file. */\n#cmakedefine HAVE_SYS_TIME_H\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#cmakedefine HAVE_SYS_TYPES_H\n\n/* Define to 1 if you have the <sys/ucontext.h> header file. */\n#cmakedefine HAVE_SYS_UCONTEXT_H\n\n/* Define to 1 if you have the <sys/utsname.h> header file. */\n#cmakedefine HAVE_SYS_UTSNAME_H\n\n/* Define to 1 if you have the <sys/wait.h> header file. */\n#cmakedefine HAVE_SYS_WAIT_H\n\n/* Define to 1 if you have the <ucontext.h> header file. */\n#cmakedefine HAVE_UCONTEXT_H\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}\n\n/* define if you have unwind */\n#cmakedefine HAVE_UNWIND\n\n/* define if you have libunwind */\n#cmakedefine HAVE_LIBUNWIND\n\n/* define if symbolize support is available */\n#cmakedefine HAVE_SYMBOLIZE\n\n/* define if localtime_r is available in time.h */\n#cmakedefine HAVE_LOCALTIME_R\n\n/* define if gmtime_r is available in time.h */\n#cmakedefine HAVE_GMTIME_R\n\n/* define if _chsize_s is available in io.h */\n#cmakedefine HAVE__CHSIZE_S\n\n/* define if ssize_t is defined */\n#cmakedefine HAVE_SSIZE_T\n\n/* define if mode_t is defined */\n#cmakedefine HAVE_MODE_T\n\n/* How to access the PC from a struct ucontext */\n#cmakedefine PC_FROM_UCONTEXT ${PC_FROM_UCONTEXT}\n\n/* define if we should print file offsets in traces instead of symbolizing. */\n#cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES\n\n/* The size of `void *', as computed by sizeof. */\n#cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P}\n\n/* location of source code */\n#cmakedefine TEST_SRC_DIR ${TEST_SRC_DIR}\n\n/* Define if thread-local storage is enabled. */\n#cmakedefine GLOG_THREAD_LOCAL_STORAGE\n\n/* define if abi::__cxa_demangle is available in cxxabi.h */\n#cmakedefine HAVE___CXA_DEMANGLE\n\n/* define if __argv is available in cstdlib */\n#cmakedefine HAVE___ARGV\n\n/* define if __progname is available */\n#cmakedefine HAVE___PROGNAME\n\n/* define if getprogname is available in cstdlib */\n#cmakedefine HAVE_GETPROGNAME\n\n/* define if program_invocation_short_name is available in cerrno */\n#cmakedefine HAVE_PROGRAM_INVOCATION_SHORT_NAME\n\n#endif  // GLOG_CONFIG_H\n"
  },
  {
    "path": "src/dcheck_unittest/CMakeLists.txt",
    "content": "cmake_minimum_required (VERSION 3.16)\nproject (glog_log_severity LANGUAGES CXX)\n\nfind_package (glog REQUIRED NO_MODULE)\n\nadd_executable (glog_dcheck glog_dcheck.cc)\ntarget_link_libraries (glog_dcheck PRIVATE glog::glog)\n"
  },
  {
    "path": "src/dcheck_unittest/glog_dcheck.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergiu Deitsch\n\n#include <glog/logging.h>\n\nint main(int /*argc*/, char** argv) {\n  google::InitGoogleLogging(argv[0]);\n  google::InstallFailureSignalHandler();\n\n#if defined(_MSC_VER)\n  // Avoid presenting an interactive dialog that will cause the test to time\n  // out.\n  _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\n#endif  // defined(_MSC_VER)\n\n  DLOG(INFO) << \"no output\";\n  DLOG(WARNING) << \"no output\";\n  DLOG(ERROR) << \"no output\";\n\n  // Must not fail in release build\n  DLOG_ASSERT(false);\n\n  // Must be the last expression\n  DLOG(FATAL) << \"no output\";\n}\n"
  },
  {
    "path": "src/demangle.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Satoru Takabayashi\n//\n// For reference check out:\n// http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling\n//\n// Note that we only have partial C++0x support yet.\n\n#include \"demangle.h\"\n\n#include <algorithm>\n#include <cstdlib>\n#include <limits>\n\n#include \"utilities.h\"\n\n#if defined(HAVE___CXA_DEMANGLE)\n#  include <cxxabi.h>\n#endif\n\n#if defined(GLOG_OS_WINDOWS)\n#  include <dbghelp.h>\n#endif\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n#if !defined(GLOG_OS_WINDOWS) && !defined(HAVE___CXA_DEMANGLE)\nnamespace {\nstruct AbbrevPair {\n  const char* const abbrev;\n  const char* const real_name;\n};\n\n// List of operators from Itanium C++ ABI.\nconst AbbrevPair kOperatorList[] = {\n    {\"nw\", \"new\"},    {\"na\", \"new[]\"},    {\"dl\", \"delete\"}, {\"da\", \"delete[]\"},\n    {\"ps\", \"+\"},      {\"ng\", \"-\"},        {\"ad\", \"&\"},      {\"de\", \"*\"},\n    {\"co\", \"~\"},      {\"pl\", \"+\"},        {\"mi\", \"-\"},      {\"ml\", \"*\"},\n    {\"dv\", \"/\"},      {\"rm\", \"%\"},        {\"an\", \"&\"},      {\"or\", \"|\"},\n    {\"eo\", \"^\"},      {\"aS\", \"=\"},        {\"pL\", \"+=\"},     {\"mI\", \"-=\"},\n    {\"mL\", \"*=\"},     {\"dV\", \"/=\"},       {\"rM\", \"%=\"},     {\"aN\", \"&=\"},\n    {\"oR\", \"|=\"},     {\"eO\", \"^=\"},       {\"ls\", \"<<\"},     {\"rs\", \">>\"},\n    {\"lS\", \"<<=\"},    {\"rS\", \">>=\"},      {\"eq\", \"==\"},     {\"ne\", \"!=\"},\n    {\"lt\", \"<\"},      {\"gt\", \">\"},        {\"le\", \"<=\"},     {\"ge\", \">=\"},\n    {\"nt\", \"!\"},      {\"aa\", \"&&\"},       {\"oo\", \"||\"},     {\"pp\", \"++\"},\n    {\"mm\", \"--\"},     {\"cm\", \",\"},        {\"pm\", \"->*\"},    {\"pt\", \"->\"},\n    {\"cl\", \"()\"},     {\"ix\", \"[]\"},       {\"qu\", \"?\"},      {\"st\", \"sizeof\"},\n    {\"sz\", \"sizeof\"}, {nullptr, nullptr},\n};\n\n// List of builtin types from Itanium C++ ABI.\nconst AbbrevPair kBuiltinTypeList[] = {\n    {\"v\", \"void\"},        {\"w\", \"wchar_t\"},\n    {\"b\", \"bool\"},        {\"c\", \"char\"},\n    {\"a\", \"signed char\"}, {\"h\", \"unsigned char\"},\n    {\"s\", \"short\"},       {\"t\", \"unsigned short\"},\n    {\"i\", \"int\"},         {\"j\", \"unsigned int\"},\n    {\"l\", \"long\"},        {\"m\", \"unsigned long\"},\n    {\"x\", \"long long\"},   {\"y\", \"unsigned long long\"},\n    {\"n\", \"__int128\"},    {\"o\", \"unsigned __int128\"},\n    {\"f\", \"float\"},       {\"d\", \"double\"},\n    {\"e\", \"long double\"}, {\"g\", \"__float128\"},\n    {\"z\", \"ellipsis\"},    {\"Dn\", \"decltype(nullptr)\"},\n    {nullptr, nullptr}};\n\n// List of substitutions Itanium C++ ABI.\nconst AbbrevPair kSubstitutionList[] = {\n    {\"St\", \"\"},\n    {\"Sa\", \"allocator\"},\n    {\"Sb\", \"basic_string\"},\n    // std::basic_string<char, std::char_traits<char>,std::allocator<char> >\n    {\"Ss\", \"string\"},\n    // std::basic_istream<char, std::char_traits<char> >\n    {\"Si\", \"istream\"},\n    // std::basic_ostream<char, std::char_traits<char> >\n    {\"So\", \"ostream\"},\n    // std::basic_iostream<char, std::char_traits<char> >\n    {\"Sd\", \"iostream\"},\n    {nullptr, nullptr}};\n\n// State needed for demangling.\nstruct State {\n  const char* mangled_cur;   // Cursor of mangled name.\n  char* out_cur;             // Cursor of output string.\n  const char* out_begin;     // Beginning of output string.\n  const char* out_end;       // End of output string.\n  const char* prev_name;     // For constructors/destructors.\n  ssize_t prev_name_length;  // For constructors/destructors.\n  short nest_level;          // For nested names.\n  bool append;               // Append flag.\n  bool overflowed;           // True if output gets overflowed.\n  uint32 local_level;\n  uint32 expr_level;\n  uint32 arg_level;\n};\n\n// We don't use strlen() in libc since it's not guaranteed to be async\n// signal safe.\nsize_t StrLen(const char* str) {\n  size_t len = 0;\n  while (*str != '\\0') {\n    ++str;\n    ++len;\n  }\n  return len;\n}\n\n// Returns true if \"str\" has at least \"n\" characters remaining.\nbool AtLeastNumCharsRemaining(const char* str, ssize_t n) {\n  for (ssize_t i = 0; i < n; ++i) {\n    if (str[i] == '\\0') {\n      return false;\n    }\n  }\n  return true;\n}\n\n// Returns true if \"str\" has \"prefix\" as a prefix.\nbool StrPrefix(const char* str, const char* prefix) {\n  size_t i = 0;\n  while (str[i] != '\\0' && prefix[i] != '\\0' && str[i] == prefix[i]) {\n    ++i;\n  }\n  return prefix[i] == '\\0';  // Consumed everything in \"prefix\".\n}\n\nvoid InitState(State* state, const char* mangled, char* out, size_t out_size) {\n  state->mangled_cur = mangled;\n  state->out_cur = out;\n  state->out_begin = out;\n  state->out_end = out + out_size;\n  state->prev_name = nullptr;\n  state->prev_name_length = -1;\n  state->nest_level = -1;\n  state->append = true;\n  state->overflowed = false;\n  state->local_level = 0;\n  state->expr_level = 0;\n  state->arg_level = 0;\n}\n\n// Returns true and advances \"mangled_cur\" if we find \"one_char_token\"\n// at \"mangled_cur\" position.  It is assumed that \"one_char_token\" does\n// not contain '\\0'.\nbool ParseOneCharToken(State* state, const char one_char_token) {\n  if (state->mangled_cur[0] == one_char_token) {\n    ++state->mangled_cur;\n    return true;\n  }\n  return false;\n}\n\n// Returns true and advances \"mangled_cur\" if we find \"two_char_token\"\n// at \"mangled_cur\" position.  It is assumed that \"two_char_token\" does\n// not contain '\\0'.\nbool ParseTwoCharToken(State* state, const char* two_char_token) {\n  if (state->mangled_cur[0] == two_char_token[0] &&\n      state->mangled_cur[1] == two_char_token[1]) {\n    state->mangled_cur += 2;\n    return true;\n  }\n  return false;\n}\n\n// Returns true and advances \"mangled_cur\" if we find any character in\n// \"char_class\" at \"mangled_cur\" position.\nbool ParseCharClass(State* state, const char* char_class) {\n  const char* p = char_class;\n  for (; *p != '\\0'; ++p) {\n    if (state->mangled_cur[0] == *p) {\n      ++state->mangled_cur;\n      return true;\n    }\n  }\n  return false;\n}\n\n// This function is used for handling an optional non-terminal.\nbool Optional(bool) { return true; }\n\n// This function is used for handling <non-terminal>+ syntax.\nusing ParseFunc = bool (*)(State*);\nbool OneOrMore(ParseFunc parse_func, State* state) {\n  if (parse_func(state)) {\n    while (parse_func(state)) {\n    }\n    return true;\n  }\n  return false;\n}\n\n// This function is used for handling <non-terminal>* syntax. The function\n// always returns true and must be followed by a termination token or a\n// terminating sequence not handled by parse_func (e.g.\n// ParseOneCharToken(state, 'E')).\nbool ZeroOrMore(ParseFunc parse_func, State* state) {\n  while (parse_func(state)) {\n  }\n  return true;\n}\n\n// Append \"str\" at \"out_cur\".  If there is an overflow, \"overflowed\"\n// is set to true for later use.  The output string is ensured to\n// always terminate with '\\0' as long as there is no overflow.\nvoid Append(State* state, const char* const str, ssize_t length) {\n  if (state->out_cur == nullptr) {\n    state->overflowed = true;\n    return;\n  }\n  for (ssize_t i = 0; i < length; ++i) {\n    if (state->out_cur + 1 < state->out_end) {  // +1 for '\\0'\n      *state->out_cur = str[i];\n      ++state->out_cur;\n    } else {\n      state->overflowed = true;\n      break;\n    }\n  }\n  if (!state->overflowed) {\n    *state->out_cur = '\\0';  // Terminate it with '\\0'\n  }\n}\n\n// We don't use equivalents in libc to avoid locale issues.\nbool IsLower(char c) { return c >= 'a' && c <= 'z'; }\n\nbool IsAlpha(char c) {\n  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');\n}\n\nbool IsDigit(char c) { return c >= '0' && c <= '9'; }\n\n// Returns true if \"str\" is a function clone suffix.  These suffixes are used\n// by GCC 4.5.x and later versions to indicate functions which have been\n// cloned during optimization.  We treat any sequence (.<alpha>+.<digit>+)+ as\n// a function clone suffix.\nbool IsFunctionCloneSuffix(const char* str) {\n  size_t i = 0;\n  while (str[i] != '\\0') {\n    // Consume a single .<alpha>+.<digit>+ sequence.\n    if (str[i] != '.' || !IsAlpha(str[i + 1])) {\n      return false;\n    }\n    i += 2;\n    while (IsAlpha(str[i])) {\n      ++i;\n    }\n    if (str[i] != '.' || !IsDigit(str[i + 1])) {\n      return false;\n    }\n    i += 2;\n    while (IsDigit(str[i])) {\n      ++i;\n    }\n  }\n  return true;  // Consumed everything in \"str\".\n}\n\n// Append \"str\" with some tweaks, iff \"append\" state is true.\n// Returns true so that it can be placed in \"if\" conditions.\nvoid MaybeAppendWithLength(State* state, const char* const str,\n                           ssize_t length) {\n  if (state->append && length > 0) {\n    // Append a space if the output buffer ends with '<' and \"str\"\n    // starts with '<' to avoid <<<.\n    if (str[0] == '<' && state->out_begin < state->out_cur &&\n        state->out_cur[-1] == '<') {\n      Append(state, \" \", 1);\n    }\n    // Remember the last identifier name for ctors/dtors.\n    if (IsAlpha(str[0]) || str[0] == '_') {\n      state->prev_name = state->out_cur;\n      state->prev_name_length = length;\n    }\n    Append(state, str, length);\n  }\n}\n\n// A convenient wrapper around MaybeAppendWithLength().\nbool MaybeAppend(State* state, const char* const str) {\n  if (state->append) {\n    size_t length = StrLen(str);\n    MaybeAppendWithLength(state, str, static_cast<ssize_t>(length));\n  }\n  return true;\n}\n\n// This function is used for handling nested names.\nbool EnterNestedName(State* state) {\n  state->nest_level = 0;\n  return true;\n}\n\n// This function is used for handling nested names.\nbool LeaveNestedName(State* state, short prev_value) {\n  state->nest_level = prev_value;\n  return true;\n}\n\n// Disable the append mode not to print function parameters, etc.\nbool DisableAppend(State* state) {\n  state->append = false;\n  return true;\n}\n\n// Restore the append mode to the previous state.\nbool RestoreAppend(State* state, bool prev_value) {\n  state->append = prev_value;\n  return true;\n}\n\n// Increase the nest level for nested names.\nvoid MaybeIncreaseNestLevel(State* state) {\n  if (state->nest_level > -1) {\n    ++state->nest_level;\n  }\n}\n\n// Appends :: for nested names if necessary.\nvoid MaybeAppendSeparator(State* state) {\n  if (state->nest_level >= 1) {\n    MaybeAppend(state, \"::\");\n  }\n}\n\n// Cancel the last separator if necessary.\nvoid MaybeCancelLastSeparator(State* state) {\n  if (state->nest_level >= 1 && state->append &&\n      state->out_begin <= state->out_cur - 2) {\n    state->out_cur -= 2;\n    *state->out_cur = '\\0';\n  }\n}\n\n// Returns true if the identifier of the given length pointed to by\n// \"mangled_cur\" is anonymous namespace.\nbool IdentifierIsAnonymousNamespace(State* state, ssize_t length) {\n  const char anon_prefix[] = \"_GLOBAL__N_\";\n  return (length > static_cast<ssize_t>(sizeof(anon_prefix)) -\n                       1 &&  // Should be longer.\n          StrPrefix(state->mangled_cur, anon_prefix));\n}\n\n// Forward declarations of our parsing functions.\nbool ParseMangledName(State* state);\nbool ParseEncoding(State* state);\nbool ParseName(State* state);\nbool ParseUnscopedName(State* state);\nbool ParseUnscopedTemplateName(State* state);\nbool ParseNestedName(State* state);\nbool ParsePrefix(State* state);\nbool ParseUnqualifiedName(State* state);\nbool ParseSourceName(State* state);\nbool ParseLocalSourceName(State* state);\nbool ParseNumber(State* state, int* number_out);\nbool ParseFloatNumber(State* state);\nbool ParseSeqId(State* state);\nbool ParseIdentifier(State* state, ssize_t length);\nbool ParseAbiTags(State* state);\nbool ParseAbiTag(State* state);\nbool ParseOperatorName(State* state);\nbool ParseSpecialName(State* state);\nbool ParseCallOffset(State* state);\nbool ParseNVOffset(State* state);\nbool ParseVOffset(State* state);\nbool ParseCtorDtorName(State* state);\nbool ParseType(State* state);\nbool ParseCVQualifiers(State* state);\nbool ParseBuiltinType(State* state);\nbool ParseFunctionType(State* state);\nbool ParseBareFunctionType(State* state);\nbool ParseClassEnumType(State* state);\nbool ParseArrayType(State* state);\nbool ParsePointerToMemberType(State* state);\nbool ParseTemplateParam(State* state);\nbool ParseTemplateTemplateParam(State* state);\nbool ParseTemplateArgs(State* state);\nbool ParseTemplateArg(State* state);\nbool ParseExpression(State* state);\nbool ParseExprPrimary(State* state);\nbool ParseLocalName(State* state);\nbool ParseDiscriminator(State* state);\nbool ParseSubstitution(State* state);\n\n// Implementation note: the following code is a straightforward\n// translation of the Itanium C++ ABI defined in BNF with a couple of\n// exceptions.\n//\n// - Support GNU extensions not defined in the Itanium C++ ABI\n// - <prefix> and <template-prefix> are combined to avoid infinite loop\n// - Reorder patterns to shorten the code\n// - Reorder patterns to give greedier functions precedence\n//   We'll mark \"Less greedy than\" for these cases in the code\n//\n// Each parsing function changes the state and returns true on\n// success.  Otherwise, don't change the state and returns false.  To\n// ensure that the state isn't changed in the latter case, we save the\n// original state before we call more than one parsing functions\n// consecutively with &&, and restore the state if unsuccessful.  See\n// ParseEncoding() as an example of this convention.  We follow the\n// convention throughout the code.\n//\n// Originally we tried to do demangling without following the full ABI\n// syntax but it turned out we needed to follow the full syntax to\n// parse complicated cases like nested template arguments.  Note that\n// implementing a full-fledged demangler isn't trivial (libiberty's\n// cp-demangle.c has +4300 lines).\n//\n// Note that (foo) in <(foo) ...> is a modifier to be ignored.\n//\n// Reference:\n// - Itanium C++ ABI\n//   <http://www.codesourcery.com/cxx-abi/abi.html#mangling>\n\n// <mangled-name> ::= _Z <encoding>\nbool ParseMangledName(State* state) {\n  return ParseTwoCharToken(state, \"_Z\") && ParseEncoding(state);\n}\n\n// <encoding> ::= <(function) name> <bare-function-type>\n//            ::= <(data) name>\n//            ::= <special-name>\nbool ParseEncoding(State* state) {\n  State copy = *state;\n  if (ParseName(state) && ParseBareFunctionType(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseName(state) || ParseSpecialName(state)) {\n    return true;\n  }\n  return false;\n}\n\n// <name> ::= <nested-name>\n//        ::= <unscoped-template-name> <template-args>\n//        ::= <unscoped-name>\n//        ::= <local-name>\nbool ParseName(State* state) {\n  if (ParseNestedName(state) || ParseLocalName(state)) {\n    return true;\n  }\n\n  State copy = *state;\n  if (ParseUnscopedTemplateName(state) && ParseTemplateArgs(state)) {\n    return true;\n  }\n  *state = copy;\n\n  // Less greedy than <unscoped-template-name> <template-args>.\n  if (ParseUnscopedName(state)) {\n    return true;\n  }\n  return false;\n}\n\n// <unscoped-name> ::= <unqualified-name>\n//                 ::= St <unqualified-name>\nbool ParseUnscopedName(State* state) {\n  if (ParseUnqualifiedName(state)) {\n    return true;\n  }\n\n  State copy = *state;\n  if (ParseTwoCharToken(state, \"St\") && MaybeAppend(state, \"std::\") &&\n      ParseUnqualifiedName(state)) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <unscoped-template-name> ::= <unscoped-name>\n//                          ::= <substitution>\nbool ParseUnscopedTemplateName(State* state) {\n  return ParseUnscopedName(state) || ParseSubstitution(state);\n}\n\n// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E\n//               ::= N [<CV-qualifiers>] <template-prefix> <template-args> E\nbool ParseNestedName(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'N') && EnterNestedName(state) &&\n      Optional(ParseCVQualifiers(state)) && ParsePrefix(state) &&\n      LeaveNestedName(state, copy.nest_level) &&\n      ParseOneCharToken(state, 'E')) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// This part is tricky.  If we literally translate them to code, we'll\n// end up infinite loop.  Hence we merge them to avoid the case.\n//\n// <prefix> ::= <prefix> <unqualified-name>\n//          ::= <template-prefix> <template-args>\n//          ::= <template-param>\n//          ::= <substitution>\n//          ::= # empty\n// <template-prefix> ::= <prefix> <(template) unqualified-name>\n//                   ::= <template-param>\n//                   ::= <substitution>\nbool ParsePrefix(State* state) {\n  bool has_something = false;\n  while (true) {\n    MaybeAppendSeparator(state);\n    if (ParseTemplateParam(state) || ParseSubstitution(state) ||\n        ParseUnscopedName(state)) {\n      has_something = true;\n      MaybeIncreaseNestLevel(state);\n      continue;\n    }\n    MaybeCancelLastSeparator(state);\n    if (has_something && ParseTemplateArgs(state)) {\n      return ParsePrefix(state);\n    } else {\n      break;\n    }\n  }\n  return true;\n}\n\n// <unqualified-name> ::= <operator-name>\n//                    ::= <ctor-dtor-name>\n//                    ::= <source-name> [<abi-tags>]\n//                    ::= <local-source-name> [<abi-tags>]\nbool ParseUnqualifiedName(State* state) {\n  return (ParseOperatorName(state) || ParseCtorDtorName(state) ||\n          (ParseSourceName(state) && Optional(ParseAbiTags(state))) ||\n          (ParseLocalSourceName(state) && Optional(ParseAbiTags(state))));\n}\n\n// <source-name> ::= <positive length number> <identifier>\nbool ParseSourceName(State* state) {\n  State copy = *state;\n  int length = -1;\n  if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <local-source-name> ::= L <source-name> [<discriminator>]\n//\n// References:\n//   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775\n//   http://gcc.gnu.org/viewcvs?view=rev&revision=124467\nbool ParseLocalSourceName(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&\n      Optional(ParseDiscriminator(state))) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <number> ::= [n] <non-negative decimal integer>\n// If \"number_out\" is non-null, then *number_out is set to the value of the\n// parsed number on success.\nbool ParseNumber(State* state, int* number_out) {\n  int sign = 1;\n  if (ParseOneCharToken(state, 'n')) {\n    sign = -1;\n  }\n  const char* p = state->mangled_cur;\n  int number = 0;\n  constexpr int int_max_by_10 = std::numeric_limits<int>::max() / 10;\n  for (; *p != '\\0'; ++p) {\n    if (IsDigit(*p)) {\n      // Prevent signed integer overflow when multiplying\n      if (number > int_max_by_10) {\n        return false;\n      }\n\n      const int digit = *p - '0';\n      const int shifted = number * 10;\n\n      // Prevent signed integer overflow when summing\n      if (digit > std::numeric_limits<int>::max() - shifted) {\n        return false;\n      }\n\n      number = shifted + digit;\n    } else {\n      break;\n    }\n  }\n  if (p != state->mangled_cur) {  // Conversion succeeded.\n    state->mangled_cur = p;\n    if (number_out != nullptr) {\n      *number_out = number * sign;\n    }\n    return true;\n  }\n  return false;\n}\n\n// Floating-point literals are encoded using a fixed-length lowercase\n// hexadecimal string.\nbool ParseFloatNumber(State* state) {\n  const char* p = state->mangled_cur;\n  for (; *p != '\\0'; ++p) {\n    if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {\n      break;\n    }\n  }\n  if (p != state->mangled_cur) {  // Conversion succeeded.\n    state->mangled_cur = p;\n    return true;\n  }\n  return false;\n}\n\n// The <seq-id> is a sequence number in base 36,\n// using digits and upper case letters\nbool ParseSeqId(State* state) {\n  const char* p = state->mangled_cur;\n  for (; *p != '\\0'; ++p) {\n    if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {\n      break;\n    }\n  }\n  if (p != state->mangled_cur) {  // Conversion succeeded.\n    state->mangled_cur = p;\n    return true;\n  }\n  return false;\n}\n\n// <identifier> ::= <unqualified source code identifier> (of given length)\nbool ParseIdentifier(State* state, ssize_t length) {\n  if (length == -1 || !AtLeastNumCharsRemaining(state->mangled_cur, length)) {\n    return false;\n  }\n  if (IdentifierIsAnonymousNamespace(state, length)) {\n    MaybeAppend(state, \"(anonymous namespace)\");\n  } else {\n    MaybeAppendWithLength(state, state->mangled_cur, length);\n  }\n  if (length < 0 ||\n      static_cast<std::size_t>(length) > StrLen(state->mangled_cur)) {\n    return false;\n  }\n  state->mangled_cur += length;\n  return true;\n}\n\n// <abi-tags> ::= <abi-tag> [<abi-tags>]\nbool ParseAbiTags(State* state) {\n  State copy = *state;\n  DisableAppend(state);\n  if (OneOrMore(ParseAbiTag, state)) {\n    RestoreAppend(state, copy.append);\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <abi-tag> ::= B <source-name>\nbool ParseAbiTag(State* state) {\n  return ParseOneCharToken(state, 'B') && ParseSourceName(state);\n}\n\n// <operator-name> ::= nw, and other two letters cases\n//                 ::= cv <type>  # (cast)\n//                 ::= v  <digit> <source-name> # vendor extended operator\nbool ParseOperatorName(State* state) {\n  if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {\n    return false;\n  }\n  // First check with \"cv\" (cast) case.\n  State copy = *state;\n  if (ParseTwoCharToken(state, \"cv\") && MaybeAppend(state, \"operator \") &&\n      EnterNestedName(state) && ParseType(state) &&\n      LeaveNestedName(state, copy.nest_level)) {\n    return true;\n  }\n  *state = copy;\n\n  // Then vendor extended operators.\n  if (ParseOneCharToken(state, 'v') && ParseCharClass(state, \"0123456789\") &&\n      ParseSourceName(state)) {\n    return true;\n  }\n  *state = copy;\n\n  // Other operator names should start with a lower alphabet followed\n  // by a lower/upper alphabet.\n  if (!(IsLower(state->mangled_cur[0]) && IsAlpha(state->mangled_cur[1]))) {\n    return false;\n  }\n  // We may want to perform a binary search if we really need speed.\n  const AbbrevPair* p;\n  for (p = kOperatorList; p->abbrev != nullptr; ++p) {\n    if (state->mangled_cur[0] == p->abbrev[0] &&\n        state->mangled_cur[1] == p->abbrev[1]) {\n      MaybeAppend(state, \"operator\");\n      if (IsLower(*p->real_name)) {  // new, delete, etc.\n        MaybeAppend(state, \" \");\n      }\n      MaybeAppend(state, p->real_name);\n      state->mangled_cur += 2;\n      return true;\n    }\n  }\n  return false;\n}\n\n// <special-name> ::= TV <type>\n//                ::= TT <type>\n//                ::= TI <type>\n//                ::= TS <type>\n//                ::= Tc <call-offset> <call-offset> <(base) encoding>\n//                ::= GV <(object) name>\n//                ::= T <call-offset> <(base) encoding>\n// G++ extensions:\n//                ::= TC <type> <(offset) number> _ <(base) type>\n//                ::= TF <type>\n//                ::= TJ <type>\n//                ::= GR <name>\n//                ::= GA <encoding>\n//                ::= Th <call-offset> <(base) encoding>\n//                ::= Tv <call-offset> <(base) encoding>\n//\n// Note: we don't care much about them since they don't appear in\n// stack traces.  The are special data.\nbool ParseSpecialName(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, \"VTIS\") &&\n      ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"Tc\") && ParseCallOffset(state) &&\n      ParseCallOffset(state) && ParseEncoding(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"GV\") && ParseName(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&\n      ParseEncoding(state)) {\n    return true;\n  }\n  *state = copy;\n\n  // G++ extensions\n  if (ParseTwoCharToken(state, \"TC\") && ParseType(state) &&\n      ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&\n      DisableAppend(state) && ParseType(state)) {\n    RestoreAppend(state, copy.append);\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, \"FJ\") &&\n      ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"GR\") && ParseName(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"GA\") && ParseEncoding(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, \"hv\") &&\n      ParseCallOffset(state) && ParseEncoding(state)) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <call-offset> ::= h <nv-offset> _\n//               ::= v <v-offset> _\nbool ParseCallOffset(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) &&\n      ParseOneCharToken(state, '_')) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'v') && ParseVOffset(state) &&\n      ParseOneCharToken(state, '_')) {\n    return true;\n  }\n  *state = copy;\n\n  return false;\n}\n\n// <nv-offset> ::= <(offset) number>\nbool ParseNVOffset(State* state) { return ParseNumber(state, nullptr); }\n\n// <v-offset>  ::= <(offset) number> _ <(virtual offset) number>\nbool ParseVOffset(State* state) {\n  State copy = *state;\n  if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&\n      ParseNumber(state, nullptr)) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <ctor-dtor-name> ::= C1 | C2 | C3\n//                  ::= D0 | D1 | D2\nbool ParseCtorDtorName(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'C') && ParseCharClass(state, \"123\")) {\n    const char* const prev_name = state->prev_name;\n    const ssize_t prev_name_length = state->prev_name_length;\n    MaybeAppendWithLength(state, prev_name, prev_name_length);\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'D') && ParseCharClass(state, \"012\")) {\n    const char* const prev_name = state->prev_name;\n    const ssize_t prev_name_length = state->prev_name_length;\n    MaybeAppend(state, \"~\");\n    MaybeAppendWithLength(state, prev_name, prev_name_length);\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <type> ::= <CV-qualifiers> <type>\n//        ::= P <type>   # pointer-to\n//        ::= R <type>   # reference-to\n//        ::= O <type>   # rvalue reference-to (C++0x)\n//        ::= C <type>   # complex pair (C 2000)\n//        ::= G <type>   # imaginary (C 2000)\n//        ::= U <source-name> <type>  # vendor extended type qualifier\n//        ::= <builtin-type>\n//        ::= <function-type>\n//        ::= <class-enum-type>\n//        ::= <array-type>\n//        ::= <pointer-to-member-type>\n//        ::= <template-template-param> <template-args>\n//        ::= <template-param>\n//        ::= <substitution>\n//        ::= Dp <type>          # pack expansion of (C++0x)\n//        ::= Dt <expression> E  # decltype of an id-expression or class\n//                               # member access (C++0x)\n//        ::= DT <expression> E  # decltype of an expression (C++0x)\n//\nbool ParseType(State* state) {\n  // We should check CV-qualifers, and PRGC things first.\n  State copy = *state;\n  if (ParseCVQualifiers(state) && ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseCharClass(state, \"OPRCG\") && ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"Dp\") && ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'D') && ParseCharClass(state, \"tT\") &&\n      ParseExpression(state) && ParseOneCharToken(state, 'E')) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&\n      ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseBuiltinType(state) || ParseFunctionType(state) ||\n      ParseClassEnumType(state) || ParseArrayType(state) ||\n      ParsePointerToMemberType(state) || ParseSubstitution(state)) {\n    return true;\n  }\n\n  if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) {\n    return true;\n  }\n  *state = copy;\n\n  // Less greedy than <template-template-param> <template-args>.\n  if (ParseTemplateParam(state)) {\n    return true;\n  }\n\n  return false;\n}\n\n// <CV-qualifiers> ::= [r] [V] [K]\n// We don't allow empty <CV-qualifiers> to avoid infinite loop in\n// ParseType().\nbool ParseCVQualifiers(State* state) {\n  int num_cv_qualifiers = 0;\n  num_cv_qualifiers += ParseOneCharToken(state, 'r');\n  num_cv_qualifiers += ParseOneCharToken(state, 'V');\n  num_cv_qualifiers += ParseOneCharToken(state, 'K');\n  return num_cv_qualifiers > 0;\n}\n\n// <builtin-type> ::= v, etc.\n//                ::= u <source-name>\nbool ParseBuiltinType(State* state) {\n  const AbbrevPair* p;\n  for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {\n    if (state->mangled_cur[0] == p->abbrev[0]) {\n      MaybeAppend(state, p->real_name);\n      ++state->mangled_cur;\n      return true;\n    }\n  }\n\n  State copy = *state;\n  if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <function-type> ::= F [Y] <bare-function-type> E\nbool ParseFunctionType(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'F') &&\n      Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) &&\n      ParseOneCharToken(state, 'E')) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <bare-function-type> ::= <(signature) type>+\nbool ParseBareFunctionType(State* state) {\n  State copy = *state;\n  DisableAppend(state);\n  if (OneOrMore(ParseType, state)) {\n    RestoreAppend(state, copy.append);\n    MaybeAppend(state, \"()\");\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <class-enum-type> ::= <name>\nbool ParseClassEnumType(State* state) { return ParseName(state); }\n\n// <array-type> ::= A <(positive dimension) number> _ <(element) type>\n//              ::= A [<(dimension) expression>] _ <(element) type>\nbool ParseArrayType(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) &&\n      ParseOneCharToken(state, '_') && ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&\n      ParseOneCharToken(state, '_') && ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <pointer-to-member-type> ::= M <(class) type> <(member) type>\nbool ParsePointerToMemberType(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <template-param> ::= T_\n//                  ::= T <parameter-2 non-negative number> _\nbool ParseTemplateParam(State* state) {\n  if (ParseTwoCharToken(state, \"T_\")) {\n    MaybeAppend(state, \"?\");  // We don't support template substitutions.\n    return true;\n  }\n\n  State copy = *state;\n  if (ParseOneCharToken(state, 'T') && ParseNumber(state, nullptr) &&\n      ParseOneCharToken(state, '_')) {\n    MaybeAppend(state, \"?\");  // We don't support template substitutions.\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <template-template-param> ::= <template-param>\n//                           ::= <substitution>\nbool ParseTemplateTemplateParam(State* state) {\n  return (ParseTemplateParam(state) || ParseSubstitution(state));\n}\n\n// <template-args> ::= I <template-arg>+ E\nbool ParseTemplateArgs(State* state) {\n  State copy = *state;\n  DisableAppend(state);\n  if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) &&\n      ParseOneCharToken(state, 'E')) {\n    RestoreAppend(state, copy.append);\n    MaybeAppend(state, \"<>\");\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <template-arg>  ::= <type>\n//                 ::= <expr-primary>\n//                 ::= I <template-arg>* E        # argument pack\n//                 ::= J <template-arg>* E        # argument pack\n//                 ::= X <expression> E\nbool ParseTemplateArg(State* state) {\n  // Avoid recursion above max_levels\n  constexpr uint32 max_levels = 6;\n\n  if (state->arg_level > max_levels) {\n    return false;\n  }\n  ++state->arg_level;\n\n  State copy = *state;\n  if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) &&\n      ZeroOrMore(ParseTemplateArg, state) && ParseOneCharToken(state, 'E')) {\n    --state->arg_level;\n    return true;\n  }\n  *state = copy;\n\n  if (ParseType(state) || ParseExprPrimary(state)) {\n    --state->arg_level;\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&\n      ParseOneCharToken(state, 'E')) {\n    --state->arg_level;\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <expression> ::= <template-param>\n//              ::= <expr-primary>\n//              ::= <unary operator-name> <expression>\n//              ::= <binary operator-name> <expression> <expression>\n//              ::= <trinary operator-name> <expression> <expression>\n//                  <expression>\n//              ::= st <type>\n//              ::= sr <type> <unqualified-name> <template-args>\n//              ::= sr <type> <unqualified-name>\nbool ParseExpression(State* state) {\n  if (ParseTemplateParam(state) || ParseExprPrimary(state)) {\n    return true;\n  }\n\n  // Avoid recursion above max_levels\n  constexpr uint32 max_levels = 5;\n\n  if (state->expr_level > max_levels) {\n    return false;\n  }\n  ++state->expr_level;\n\n  State copy = *state;\n  if (ParseOperatorName(state) && ParseExpression(state) &&\n      ParseExpression(state) && ParseExpression(state)) {\n    --state->expr_level;\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOperatorName(state) && ParseExpression(state) &&\n      ParseExpression(state)) {\n    --state->expr_level;\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOperatorName(state) && ParseExpression(state)) {\n    --state->expr_level;\n    return true;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"st\") && ParseType(state)) {\n    return true;\n    --state->expr_level;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"sr\") && ParseType(state) &&\n      ParseUnqualifiedName(state) && ParseTemplateArgs(state)) {\n    --state->expr_level;\n    return true;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"sr\") && ParseType(state) &&\n      ParseUnqualifiedName(state)) {\n    --state->expr_level;\n    return true;\n  }\n  *state = copy;\n\n  // Pack expansion\n  if (ParseTwoCharToken(state, \"sp\") && ParseType(state)) {\n    --state->expr_level;\n    return true;\n  }\n  *state = copy;\n\n  return false;\n}\n\n// <expr-primary> ::= L <type> <(value) number> E\n//                ::= L <type> <(value) float> E\n//                ::= L <mangled-name> E\n//                // A bug in g++'s C++ ABI version 2 (-fabi-version=2).\n//                ::= LZ <encoding> E\nbool ParseExprPrimary(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, 'L') && ParseType(state) &&\n      ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'L') && ParseType(state) &&\n      ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&\n      ParseOneCharToken(state, 'E')) {\n    return true;\n  }\n  *state = copy;\n\n  if (ParseTwoCharToken(state, \"LZ\") && ParseEncoding(state) &&\n      ParseOneCharToken(state, 'E')) {\n    return true;\n  }\n  *state = copy;\n\n  return false;\n}\n\n// <local-name> := Z <(function) encoding> E <(entity) name>\n//                 [<discriminator>]\n//              := Z <(function) encoding> E s [<discriminator>]\nbool ParseLocalName(State* state) {\n  // Avoid recursion above max_levels\n  constexpr uint32 max_levels = 5;\n  if (state->local_level > max_levels) {\n    return false;\n  }\n  ++state->local_level;\n\n  State copy = *state;\n  if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&\n      ParseOneCharToken(state, 'E') && MaybeAppend(state, \"::\") &&\n      ParseName(state) && Optional(ParseDiscriminator(state))) {\n    --state->local_level;\n    return true;\n  }\n  *state = copy;\n\n  if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&\n      ParseTwoCharToken(state, \"Es\") && Optional(ParseDiscriminator(state))) {\n    --state->local_level;\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <discriminator> := _ <(non-negative) number>\nbool ParseDiscriminator(State* state) {\n  State copy = *state;\n  if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) {\n    return true;\n  }\n  *state = copy;\n  return false;\n}\n\n// <substitution> ::= S_\n//                ::= S <seq-id> _\n//                ::= St, etc.\nbool ParseSubstitution(State* state) {\n  if (ParseTwoCharToken(state, \"S_\")) {\n    MaybeAppend(state, \"?\");  // We don't support substitutions.\n    return true;\n  }\n\n  State copy = *state;\n  if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&\n      ParseOneCharToken(state, '_')) {\n    MaybeAppend(state, \"?\");  // We don't support substitutions.\n    return true;\n  }\n  *state = copy;\n\n  // Expand abbreviations like \"St\" => \"std\".\n  if (ParseOneCharToken(state, 'S')) {\n    const AbbrevPair* p;\n    for (p = kSubstitutionList; p->abbrev != nullptr; ++p) {\n      if (state->mangled_cur[0] == p->abbrev[1]) {\n        MaybeAppend(state, \"std\");\n        if (p->real_name[0] != '\\0') {\n          MaybeAppend(state, \"::\");\n          MaybeAppend(state, p->real_name);\n        }\n        ++state->mangled_cur;\n        return true;\n      }\n    }\n  }\n  *state = copy;\n  return false;\n}\n\n// Parse <mangled-name>, optionally followed by either a function-clone suffix\n// or version suffix.  Returns true only if all of \"mangled_cur\" was consumed.\nbool ParseTopLevelMangledName(State* state) {\n  if (ParseMangledName(state)) {\n    if (state->mangled_cur[0] != '\\0') {\n      // Drop trailing function clone suffix, if any.\n      if (IsFunctionCloneSuffix(state->mangled_cur)) {\n        return true;\n      }\n      // Append trailing version suffix if any.\n      // ex. _Z3foo@@GLIBCXX_3.4\n      if (state->mangled_cur[0] == '@') {\n        MaybeAppend(state, state->mangled_cur);\n        return true;\n      }\n      return ParseName(state);\n    }\n    return true;\n  }\n  return false;\n}\n}  // namespace\n#endif\n\n// The demangler entry point.\nbool Demangle(const char* mangled, char* out, size_t out_size) {\n#if defined(GLOG_OS_WINDOWS)\n#  if defined(HAVE_DBGHELP)\n  // When built with incremental linking, the Windows debugger\n  // library provides a more complicated `Symbol->Name` with the\n  // Incremental Linking Table offset, which looks like\n  // `@ILT+1105(?func@Foo@@SAXH@Z)`. However, the demangler expects\n  // only the mangled symbol, `?func@Foo@@SAXH@Z`. Fortunately, the\n  // mangled symbol is guaranteed not to have parentheses,\n  // so we search for `(` and extract up to `)`.\n  //\n  // Since we may be in a signal handler here, we cannot use `std::string`.\n  char buffer[1024];  // Big enough for a sane symbol.\n  const char* lparen = strchr(mangled, '(');\n  if (lparen) {\n    // Extract the string `(?...)`\n    const char* rparen = strchr(lparen, ')');\n    size_t length = static_cast<size_t>(rparen - lparen) - 1;\n    strncpy(buffer, lparen + 1, length);\n    buffer[length] = '\\0';\n    mangled = buffer;\n  }  // Else the symbol wasn't inside a set of parentheses\n  // We use the ANSI version to ensure the string type is always `char *`.\n  return UnDecorateSymbolName(mangled, out, out_size, UNDNAME_COMPLETE);\n#  else\n  (void)mangled;\n  (void)out;\n  (void)out_size;\n  return false;\n#  endif\n#elif defined(HAVE___CXA_DEMANGLE)\n  int status = -1;\n  std::size_t n = 0;\n  std::unique_ptr<char, decltype(&std::free)> unmangled{\n      abi::__cxa_demangle(mangled, nullptr, &n, &status), &std::free};\n\n  if (!unmangled) {\n    return false;\n  }\n\n  std::copy_n(unmangled.get(), std::min(n, out_size), out);\n  return status == 0;\n#else\n  State state;\n  InitState(&state, mangled, out, out_size);\n  return ParseTopLevelMangledName(&state) && !state.overflowed;\n#endif\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n"
  },
  {
    "path": "src/demangle.h",
    "content": "// Copyright (c) 2006, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Satoru Takabayashi\n//\n// An async-signal-safe and thread-safe demangler for Itanium C++ ABI\n// (aka G++ V3 ABI).\n\n// The demangler is implemented to be used in async signal handlers to\n// symbolize stack traces.  We cannot use libstdc++'s\n// abi::__cxa_demangle() in such signal handlers since it's not async\n// signal safe (it uses malloc() internally).\n//\n// Note that this demangler doesn't support full demangling.  More\n// specifically, it doesn't print types of function parameters and\n// types of template arguments.  It just skips them.  However, it's\n// still very useful to extract basic information such as class,\n// function, constructor, destructor, and operator names.\n//\n// See the implementation note in demangle.cc if you are interested.\n//\n// Example:\n//\n// | Mangled Name  | The Demangler | abi::__cxa_demangle()\n// |---------------|---------------|-----------------------\n// | _Z1fv         | f()           | f()\n// | _Z1fi         | f()           | f(int)\n// | _Z3foo3bar    | foo()         | foo(bar)\n// | _Z1fIiEvi     | f<>()         | void f<int>(int)\n// | _ZN1N1fE      | N::f          | N::f\n// | _ZN3Foo3BarEv | Foo::Bar()    | Foo::Bar()\n// | _Zrm1XS_\"     | operator%()   | operator%(X, X)\n// | _ZN3FooC1Ev   | Foo::Foo()    | Foo::Foo()\n// | _Z1fSs        | f()           | f(std::basic_string<char,\n// |               |               |   std::char_traits<char>,\n// |               |               |   std::allocator<char> >)\n//\n// See the unit test for more examples.\n//\n// Note: we might want to write demanglers for ABIs other than Itanium\n// C++ ABI in the future.\n//\n\n#ifndef GLOG_INTERNAL_DEMANGLE_H\n#define GLOG_INTERNAL_DEMANGLE_H\n\n#include <cstddef>\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_NO_EXPORT)\n#  error \"demangle.h\" was not included correctly.\n#endif\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n// Demangle \"mangled\".  On success, return true and write the\n// demangled symbol name to \"out\".  Otherwise, return false.\n// \"out\" is modified even if demangling is unsuccessful.\nbool GLOG_NO_EXPORT Demangle(const char* mangled, char* out, size_t out_size);\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#endif  // GLOG_INTERNAL_DEMANGLE_H\n"
  },
  {
    "path": "src/demangle_unittest.cc",
    "content": "// Copyright (c) 2006, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Satoru Takabayashi\n//\n// Unit tests for functions in demangle.c.\n\n#include \"demangle.h\"\n\n#include <fstream>\n#include <iostream>\n#include <string>\n\n#include \"config.h\"\n#include \"glog/logging.h\"\n#include \"googletest.h\"\n#include \"utilities.h\"\n\n#ifdef GLOG_USE_GFLAGS\n#  include <gflags/gflags.h>\nusing namespace GFLAGS_NAMESPACE;\n#endif\n\nGLOG_DEFINE_bool(demangle_filter, false,\n                 \"Run demangle_unittest in filter mode\");\n\nusing namespace std;\nusing namespace google;\n\n// A wrapper function for Demangle() to make the unit test simple.\nstatic const char* DemangleIt(const char* const mangled) {\n  static char demangled[4096];\n  if (Demangle(mangled, demangled, sizeof(demangled))) {\n    return demangled;\n  } else {\n    return mangled;\n  }\n}\n\n#if defined(GLOG_OS_WINDOWS)\n\n#  if defined(HAVE_DBGHELP) && !defined(NDEBUG)\nTEST(Demangle, Windows) {\n  EXPECT_STREQ(\"public: static void __cdecl Foo::func(int)\",\n               DemangleIt(\"?func@Foo@@SAXH@Z\"));\n  EXPECT_STREQ(\"public: static void __cdecl Foo::func(int)\",\n               DemangleIt(\"@ILT+1105(?func@Foo@@SAXH@Z)\"));\n  EXPECT_STREQ(\"int __cdecl foobarArray(int * const)\",\n               DemangleIt(\"?foobarArray@@YAHQAH@Z\"));\n}\n#  endif\n\n#else\n\n// Test corner cases of boundary conditions.\nTEST(Demangle, CornerCases) {\n  const size_t size = 10;\n  char tmp[size] = {0};\n  const char* demangled = \"foobar()\";\n  const char* mangled = \"_Z6foobarv\";\n  EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));\n  // sizeof(\"foobar()\") == size - 1\n  EXPECT_STREQ(demangled, tmp);\n  EXPECT_TRUE(Demangle(mangled, tmp, size - 1));\n  EXPECT_STREQ(demangled, tmp);\n  EXPECT_FALSE(Demangle(mangled, tmp, size - 2));  // Not enough.\n  EXPECT_FALSE(Demangle(mangled, tmp, 1));\n  EXPECT_FALSE(Demangle(mangled, tmp, 0));\n  EXPECT_FALSE(Demangle(mangled, nullptr, 0));  // Should not cause SEGV.\n}\n\n// Test handling of functions suffixed with .clone.N, which is used by GCC\n// 4.5.x, and .constprop.N and .isra.N, which are used by GCC 4.6.x.  These\n// suffixes are used to indicate functions which have been cloned during\n// optimization.  We ignore these suffixes.\nTEST(Demangle, Clones) {\n  char tmp[20];\n  EXPECT_TRUE(Demangle(\"_ZL3Foov\", tmp, sizeof(tmp)));\n  EXPECT_STREQ(\"Foo()\", tmp);\n  EXPECT_TRUE(Demangle(\"_ZL3Foov.clone.3\", tmp, sizeof(tmp)));\n  EXPECT_STREQ(\"Foo()\", tmp);\n  EXPECT_TRUE(Demangle(\"_ZL3Foov.constprop.80\", tmp, sizeof(tmp)));\n  EXPECT_STREQ(\"Foo()\", tmp);\n  EXPECT_TRUE(Demangle(\"_ZL3Foov.isra.18\", tmp, sizeof(tmp)));\n  EXPECT_STREQ(\"Foo()\", tmp);\n  EXPECT_TRUE(Demangle(\"_ZL3Foov.isra.2.constprop.18\", tmp, sizeof(tmp)));\n  EXPECT_STREQ(\"Foo()\", tmp);\n  // Invalid (truncated), should not demangle.\n  EXPECT_FALSE(Demangle(\"_ZL3Foov.clo\", tmp, sizeof(tmp)));\n  // Invalid (.clone. not followed by number), should not demangle.\n  EXPECT_FALSE(Demangle(\"_ZL3Foov.clone.\", tmp, sizeof(tmp)));\n  // Invalid (.clone. followed by non-number), should not demangle.\n  EXPECT_FALSE(Demangle(\"_ZL3Foov.clone.foo\", tmp, sizeof(tmp)));\n  // Invalid (.constprop. not followed by number), should not demangle.\n  EXPECT_FALSE(Demangle(\"_ZL3Foov.isra.2.constprop.\", tmp, sizeof(tmp)));\n}\n\nTEST(Demangle, FromFile) {\n  string test_file = FLAGS_test_srcdir + \"/src/demangle_unittest.txt\";\n  ifstream f(test_file.c_str());  // The file should exist.\n  EXPECT_FALSE(f.fail());\n\n  string line;\n  while (getline(f, line)) {\n    // Lines start with '#' are considered as comments.\n    if (line.empty() || line[0] == '#') {\n      continue;\n    }\n    // Each line should contain a mangled name and a demangled name\n    // separated by '\\t'.  Example: \"_Z3foo\\tfoo\"\n    string::size_type tab_pos = line.find('\\t');\n    EXPECT_NE(string::npos, tab_pos);\n    string mangled = line.substr(0, tab_pos);\n    string demangled = line.substr(tab_pos + 1);\n    EXPECT_EQ(demangled, DemangleIt(mangled.c_str()));\n  }\n}\n\n#endif\n\nint main(int argc, char** argv) {\n  InitGoogleTest(&argc, argv);\n#ifdef GLOG_USE_GFLAGS\n  ParseCommandLineFlags(&argc, &argv, true);\n#endif\n\n  FLAGS_logtostderr = true;\n  InitGoogleLogging(argv[0]);\n  if (FLAGS_demangle_filter) {\n    // Read from cin and write to cout.\n    string line;\n    while (getline(cin, line, '\\n')) {\n      cout << DemangleIt(line.c_str()) << endl;\n    }\n    return 0;\n  } else if (argc > 1) {\n    cout << DemangleIt(argv[1]) << endl;\n    return 0;\n  } else {\n    return RUN_ALL_TESTS();\n  }\n}\n"
  },
  {
    "path": "src/demangle_unittest.sh",
    "content": "#! /bin/sh\n#\n# Copyright (c) 2006, Google Inc.\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are\n# met:\n#\n#     * Redistributions of source code must retain the above copyright\n# notice, this list of conditions and the following disclaimer.\n#     * Redistributions in binary form must reproduce the above\n# copyright notice, this list of conditions and the following disclaimer\n# in the documentation and/or other materials provided with the\n# distribution.\n#     * Neither the name of Google Inc. nor the names of its\n# contributors may be used to endorse or promote products derived from\n# this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#\n# Author: Satoru Takabayashi\n#\n# Unit tests for demangle.c with a real binary.\n\nset -e\n\ndie () {\n    echo $1\n    exit 1\n}\n\nBINDIR=\".libs\"\nLIBGLOG=\"$BINDIR/libglog.so\"\n\nDEMANGLER=\"$BINDIR/demangle_unittest\"\n\nif test -e \"$DEMANGLER\"; then\n  # We need shared object.\n  export LD_LIBRARY_PATH=$BINDIR\n  export DYLD_LIBRARY_PATH=$BINDIR\nelse\n  # For windows\n  DEMANGLER=\"./demangle_unittest.exe\"\n  if ! test -e \"$DEMANGLER\"; then\n    echo \"We coundn't find demangle_unittest binary.\"\n    exit 1\n  fi\nfi\n\n# Extract C++ mangled symbols from libbase.so.\nNM_OUTPUT=\"demangle.nm\"\nnm \"$LIBGLOG\" | perl -nle 'print $1 if /\\s(_Z\\S+$)/' > \"$NM_OUTPUT\"\n\n# Check if mangled symbols exist. If there are none, we quit.\n# The binary is more likely compiled with GCC 2.95 or something old.\nif ! grep --quiet '^_Z' \"$NM_OUTPUT\"; then\n    echo \"PASS\"\n    exit 0\nfi\n\n# Demangle the symbols using our demangler.\nDM_OUTPUT=\"demangle.dm\"\nGLOG_demangle_filter=1 \"$DEMANGLER\" --demangle_filter < \"$NM_OUTPUT\" > \"$DM_OUTPUT\"\n\n# Calculate the numbers of lines.\nNM_LINES=`wc -l \"$NM_OUTPUT\" | awk '{ print $1 }'`\nDM_LINES=`wc -l \"$DM_OUTPUT\" | awk '{ print $1 }'`\n\n# Compare the numbers of lines.  They must be the same.\nif test \"$NM_LINES\" != \"$DM_LINES\"; then\n    die \"$NM_OUTPUT and $DM_OUTPUT don't have the same numbers of lines\"\nfi\n\n# Check if mangled symbols exist.  They must not exist.\nif grep --quiet '^_Z' \"$DM_OUTPUT\"; then\n    MANGLED=`grep '^_Z' \"$DM_OUTPUT\" | wc -l | awk '{ print \\$1 }'`\n    echo \"Mangled symbols ($MANGLED out of $NM_LINES) found in $DM_OUTPUT:\"\n    grep '^_Z' \"$DM_OUTPUT\"\n    die \"Mangled symbols ($MANGLED out of $NM_LINES) found in $DM_OUTPUT\"\nfi\n\n# All C++ symbols are demangled successfully.\necho \"PASS\"\nexit 0\n"
  },
  {
    "path": "src/demangle_unittest.txt",
    "content": "# Test caces for demangle_unittest.  Each line consists of a\n# tab-separated pair of mangled and demangled symbol names.\n\n# Constructors and destructors.\n_ZN3FooC1Ev\tFoo::Foo()\n_ZN3FooD1Ev\tFoo::~Foo()\n_ZNSoD0Ev\tstd::ostream::~ostream()\n\n# G++ extensions.\n_ZTCN10LogMessage9LogStreamE0_So\tLogMessage::LogStream\n_ZTv0_n12_N10LogMessage9LogStreamD0Ev\tLogMessage::LogStream::~LogStream()\n_ZThn4_N7icu_3_410UnicodeSetD0Ev\ticu_3_4::UnicodeSet::~UnicodeSet()\n\n# A bug in g++'s C++ ABI version 2 (-fabi-version=2).\n_ZN7NSSInfoI5groupjjXadL_Z10getgrgid_rEELZ19nss_getgrgid_r_nameEEC1Ei\tNSSInfo<>::NSSInfo()\n\n# C linkage symbol names.  Should keep them untouched.\nmain\tmain\nDemangle\tDemangle\n_ZERO\t_ZERO\n\n# Cast operator.\n_Zcviv\toperator int()\n_ZN3foocviEv\tfoo::operator int()\n\n# Versioned symbols.\n_Z3Foo@GLIBCXX_3.4\tFoo@GLIBCXX_3.4\n_Z3Foo@@GLIBCXX_3.4\tFoo@@GLIBCXX_3.4\n\n# Abbreviations.\n_ZNSaE\tstd::allocator\n_ZNSbE\tstd::basic_string\n_ZNSdE\tstd::iostream\n_ZNSiE\tstd::istream\n_ZNSoE\tstd::ostream\n_ZNSsE\tstd::string\n\n# Substitutions.  We just replace them with ?.\n_ZN3fooS_E\tfoo::?\n_ZN3foo3barS0_E\tfoo::bar::?\n_ZNcvT_IiEEv\toperator ?<>()\n\n# \"<< <\" case.\n_ZlsI3fooE\toperator<< <>\n\n# ABI tags.\n_Z1AB3barB3foo\tA\n_ZN3fooL3barB5cxx11E\tfoo::bar\n\n# Random things we found interesting.\n_ZN3FooISt6vectorISsSaISsEEEclEv\tFoo<>::operator()()\n_ZTI9Callback1IiE\tCallback1<>\n_ZN7icu_3_47UMemorynwEj\ticu_3_4::UMemory::operator new()\n_ZNSt6vectorIbE9push_backE\tstd::vector<>::push_back\n_ZNSt6vectorIbSaIbEE9push_backEb\tstd::vector<>::push_back()\n_ZlsRSoRK15PRIVATE_Counter\toperator<<()\n_ZSt6fill_nIPPN9__gnu_cxx15_Hashtable_nodeISt4pairIKPKcjEEEjS8_ET_SA_T0_RKT1_\tstd::fill_n<>()\n_ZZ3FoovE3Bar\tFoo()::Bar\n_ZGVZ7UpTimervE8up_timer\tUpTimer()::up_timer\n\n# Test cases from gcc-4.1.0/libstdc++-v3/testsuite/demangle.\n# Collected by:\n# % grep verify_demangle **/*.cc | perl -nle 'print $1 if /\"(_Z.*?)\"/' |\n#   sort | uniq\n#\n# Note that the following symbols are invalid.\n# That's why they are not demangled.\n# - _ZNZN1N1fEiE1X1gE\n# - _ZNZN1N1fEiE1X1gEv\n# - _Z1xINiEE\n_Z1fA37_iPS_\tf()\n_Z1fAszL_ZZNK1N1A1fEvE3foo_0E_i\tf()\n_Z1fI1APS0_PKS0_EvT_T0_T1_PA4_S3_M1CS8_\tf<>()\n_Z1fI1XENT_1tES2_\tf<>()\n_Z1fI1XEvPVN1AIT_E1TE\tf<>()\n_Z1fILi1ELc120EEv1AIXplT_cviLd4028ae147ae147aeEEE\tf<>()\n_Z1fILi1ELc120EEv1AIXplT_cviLf3f800000EEE\tf<>()\n_Z1fILi5E1AEvN1CIXqugtT_Li0ELi1ELi2EEE1qE\tf<>()\n_Z1fILi5E1AEvN1CIXstN1T1tEEXszsrS2_1tEE1qE\tf<>()\n_Z1fILi5EEvN1AIXcvimlT_Li22EEE1qE\tf<>()\n_Z1fIiEvi\tf<>()\n_Z1fKPFiiE\tf()\n_Z1fM1AFivEPS0_\tf()\n_Z1fM1AKFivE\tf()\n_Z1fM1AKFvvE\tf()\n_Z1fPFPA1_ivE\tf()\n_Z1fPFYPFiiEiE\tf()\n_Z1fPFvvEM1SFvvE\tf()\n_Z1fPKM1AFivE\tf()\n_Z1fi\tf()\n_Z1fv\tf()\n_Z1jM1AFivEPS1_\tj()\n_Z1rM1GFivEMS_KFivES_M1HFivES1_4whatIKS_E5what2IS8_ES3_\tr()\n_Z1sPA37_iPS0_\ts()\n_Z1xINiEE\t_Z1xINiEE\n_Z3absILi11EEvv\tabs<>()\n_Z3foo3bar\tfoo()\n_Z3foo5Hello5WorldS0_S_\tfoo()\n_Z3fooA30_A_i\tfoo()\n_Z3fooIA6_KiEvA9_KT_rVPrS4_\tfoo<>()\n_Z3fooILi2EEvRAplT_Li1E_i\tfoo<>()\n_Z3fooIiFvdEiEvv\tfoo<>()\n_Z3fooPM2ABi\tfoo()\n_Z3fooc\tfoo()\n_Z3fooiPiPS_PS0_PS1_PS2_PS3_PS4_PS5_PS6_PS7_PS8_PS9_PSA_PSB_PSC_\tfoo()\n_Z3kooPA28_A30_i\tkoo()\n_Z4makeI7FactoryiET_IT0_Ev\tmake<>()\n_Z5firstI3DuoEvS0_\tfirst<>()\n_Z5firstI3DuoEvT_\tfirst<>()\n_Z9hairyfuncM1YKFPVPFrPA2_PM1XKFKPA3_ilEPcEiE\thairyfunc()\n_ZGVN5libcw24_GLOBAL__N_cbll.cc0ZhUKa23compiler_bug_workaroundISt6vectorINS_13omanip_id_tctINS_5debug32memblk_types_manipulator_data_ctEEESaIS6_EEE3idsE\tlibcw::(anonymous namespace)::compiler_bug_workaround<>::ids\n_ZN12libcw_app_ct10add_optionIS_EEvMT_FvPKcES3_cS3_S3_\tlibcw_app_ct::add_option<>()\n_ZN1AIfEcvT_IiEEv\tA<>::operator ?<>()\n_ZN1N1TIiiE2mfES0_IddE\tN::T<>::mf()\n_ZN1N1fE\tN::f\n_ZN1f1fE\tf::f\n_ZN3FooIA4_iE3barE\tFoo<>::bar\n_ZN5Arena5levelE\tArena::level\n_ZN5StackIiiE5levelE\tStack<>::level\n_ZN5libcw5debug13cwprint_usingINS_9_private_12GlobalObjectEEENS0_17cwprint_using_tctIT_EERKS5_MS5_KFvRSt7ostreamE\tlibcw::debug::cwprint_using<>()\n_ZN6System5Sound4beepEv\tSystem::Sound::beep()\n_ZNKSt14priority_queueIP27timer_event_request_base_ctSt5dequeIS1_SaIS1_EE13timer_greaterE3topEv\tstd::priority_queue<>::top()\n_ZNKSt15_Deque_iteratorIP15memory_block_stRKS1_PS2_EeqERKS5_\tstd::_Deque_iterator<>::operator==()\n_ZNKSt17__normal_iteratorIPK6optionSt6vectorIS0_SaIS0_EEEmiERKS6_\tstd::__normal_iterator<>::operator-()\n_ZNSbIcSt11char_traitsIcEN5libcw5debug27no_alloc_checking_allocatorEE12_S_constructIPcEES6_T_S7_RKS3_\tstd::basic_string<>::_S_construct<>()\n_ZNSt13_Alloc_traitsISbIcSt18string_char_traitsIcEN5libcw5debug9_private_17allocator_adaptorIcSt24__default_alloc_templateILb0ELi327664EELb1EEEENS5_IS9_S7_Lb1EEEE15_S_instancelessE\tstd::_Alloc_traits<>::_S_instanceless\n_ZNSt3_In4wardE\tstd::_In::ward\n_ZNZN1N1fEiE1X1gE\t_ZNZN1N1fEiE1X1gE\n_ZNZN1N1fEiE1X1gEv\t_ZNZN1N1fEiE1X1gEv\n_ZSt1BISt1DIP1ARKS2_PS3_ES0_IS2_RS2_PS2_ES2_ET0_T_SB_SA_PT1_\tstd::B<>()\n_ZSt5state\tstd::state\n_ZTI7a_class\ta_class\n_ZZN1N1fEiE1p\tN::f()::p\n_ZZN1N1fEiEs\tN::f()\n_ZlsRK1XS1_\toperator<<()\n_ZlsRKU3fooU4bart1XS0_\toperator<<()\n_ZlsRKU3fooU4bart1XS2_\toperator<<()\n_ZlsRSoRKSs\toperator<<()\n_ZngILi42EEvN1AIXplT_Li2EEE1TE\toperator-<>()\n_ZplR1XS0_\toperator+()\n_Zrm1XS_\toperator%()\n\n# Template argument packs can start with I or J.\n_Z3addIIiEEvDpT_\tadd<>()\n_Z3addIJiEEvDpT_\tadd<>()\n\n# Nested templates with pack expansion\n_ZSt13__invoke_implIvPFvPiEJDnEET_St14__invoke_otherOT0_DpOT1_\tstd::__invoke_impl<>()\n_ZSt8__invokeIPFvPiEJDnEENSt15__invoke_resultIT_JDpT0_EE4typeEOS4_DpOS5_\tstd::__invoke<>()\n_ZNSt6thread8_InvokerISt5tupleIJPFvPiEDnEEE9_M_invokeIJLm0ELm1EEEEvSt12_Index_tupleIJXspT_EEE\tstd::thread::_Invoker<>::_M_invoke<>()\n_ZNSt6thread8_InvokerISt5tupleIJPFvPiEDnEEEclEv\tstd::thread::_Invoker<>::operator()()\n_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvPiEDnEEEEE6_M_runEv\tstd::thread::_State_impl<>::_M_run()\n"
  },
  {
    "path": "src/flags.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n\n#include \"glog/flags.h\"\n\n#include <cstdlib>\n#include <cstring>\n\n#include \"base/commandlineflags.h\"\n#include \"glog/log_severity.h\"\n\nnamespace {\n\n// Compute the default value for --log_dir\nstatic const char* DefaultLogDir() {\n  constexpr const char* const names[]{\"GOOGLE_LOG_DIR\", \"TEST_TMPDIR\"};\n  for (const char* const name : names) {\n    const char* const env = std::getenv(name);\n    if (env != nullptr && env[0] != '\\0') {\n      return env;\n    }\n  }\n  return \"\";\n}\n\nbool BoolFromEnv(const char* varname, bool defval) {\n  const char* const valstr = getenv(varname);\n  if (!valstr) {\n    return defval;\n  }\n  return std::memchr(\"tTyY1\\0\", valstr[0], 6) != nullptr;\n}\n\n}  // namespace\n\nGLOG_DEFINE_bool(timestamp_in_logfile_name,\n                 BoolFromEnv(\"GOOGLE_TIMESTAMP_IN_LOGFILE_NAME\", true),\n                 \"put a timestamp at the end of the log file name\");\nGLOG_DEFINE_bool(logtostderr, BoolFromEnv(\"GOOGLE_LOGTOSTDERR\", false),\n                 \"log messages go to stderr instead of logfiles\");\nGLOG_DEFINE_bool(alsologtostderr, BoolFromEnv(\"GOOGLE_ALSOLOGTOSTDERR\", false),\n                 \"log messages go to stderr in addition to logfiles\");\nGLOG_DEFINE_bool(colorlogtostderr, false,\n                 \"color messages logged to stderr (if supported by terminal)\");\nGLOG_DEFINE_bool(colorlogtostdout, false,\n                 \"color messages logged to stdout (if supported by terminal)\");\nGLOG_DEFINE_bool(logtostdout, BoolFromEnv(\"GOOGLE_LOGTOSTDOUT\", false),\n                 \"log messages go to stdout instead of logfiles\");\n#ifdef GLOG_OS_LINUX\nGLOG_DEFINE_bool(\n    drop_log_memory, true,\n    \"Drop in-memory buffers of log contents. \"\n    \"Logs can grow very quickly and they are rarely read before they \"\n    \"need to be evicted from memory. Instead, drop them from memory \"\n    \"as soon as they are flushed to disk.\");\n#endif\n\n// By default, errors (including fatal errors) get logged to stderr as\n// well as the file.\n//\n// The default is ERROR instead of FATAL so that users can see problems\n// when they run a program without having to look in another file.\nGLOG_DEFINE_int32(\n    stderrthreshold, google::GLOG_ERROR,\n    \"log messages at or above this level are copied to stderr in \"\n    \"addition to logfiles.  This flag obsoletes --alsologtostderr.\");\n\nGLOG_DEFINE_string(alsologtoemail, \"\",\n                   \"log messages go to these email addresses \"\n                   \"in addition to logfiles\");\nGLOG_DEFINE_bool(log_file_header, true,\n                 \"Write the file header at the start of each log file\");\nGLOG_DEFINE_bool(log_prefix, true,\n                 \"Prepend the log prefix to the start of each log line\");\nGLOG_DEFINE_bool(log_year_in_prefix, true,\n                 \"Include the year in the log prefix\");\nGLOG_DEFINE_int32(minloglevel, 0,\n                  \"Messages logged at a lower level than this don't \"\n                  \"actually get logged anywhere\");\nGLOG_DEFINE_int32(logbuflevel, 0,\n                  \"Buffer log messages logged at this level or lower\"\n                  \" (-1 means don't buffer; 0 means buffer INFO only;\"\n                  \" ...)\");\nGLOG_DEFINE_int32(logbufsecs, 30,\n                  \"Buffer log messages for at most this many seconds\");\n\nGLOG_DEFINE_int32(logcleansecs, 60 * 5,  // every 5 minutes\n                  \"Clean overdue logs every this many seconds\");\n\nGLOG_DEFINE_int32(logemaillevel, 999,\n                  \"Email log messages logged at this level or higher\"\n                  \" (0 means email all; 3 means email FATAL only;\"\n                  \" ...)\");\nGLOG_DEFINE_string(logmailer, \"\", \"Mailer used to send logging email\");\n\nGLOG_DEFINE_int32(logfile_mode, 0664, \"Log file mode/permissions.\");\n\nGLOG_DEFINE_string(\n    log_dir, DefaultLogDir(),\n    \"If specified, logfiles are written into this directory instead \"\n    \"of the default logging directory.\");\nGLOG_DEFINE_string(log_link, \"\",\n                   \"Put additional links to the log \"\n                   \"files in this directory\");\n\nGLOG_DEFINE_uint32(max_log_size, 1800,\n                   \"approx. maximum log file size (in MB). A value of 0 will \"\n                   \"be silently overridden to 1.\");\n\nGLOG_DEFINE_bool(stop_logging_if_full_disk, false,\n                 \"Stop attempting to log to disk if the disk is full.\");\n\nGLOG_DEFINE_string(log_backtrace_at, \"\",\n                   \"Emit a backtrace when logging at file:linenum.\");\n\nGLOG_DEFINE_bool(log_utc_time, false, \"Use UTC time for logging.\");\n\nGLOG_DEFINE_int32(v, 0,\n                  \"Show all VLOG(m) messages for m <= this.\"\n                  \" Overridable by --vmodule.\");\n\nGLOG_DEFINE_string(\n    vmodule, \"\",\n    \"per-module verbose level.\"\n    \" Argument is a comma-separated list of <module name>=<log level>.\"\n    \" <module name> is a glob pattern, matched against the filename base\"\n    \" (that is, name ignoring .cc/.h./-inl.h).\"\n    \" <log level> overrides any value given by --v.\");\n\nGLOG_DEFINE_bool(symbolize_stacktrace, true,\n                 \"Symbolize the stack trace in the tombstone\");\n"
  },
  {
    "path": "src/fuzz_demangle.cc",
    "content": "// Copyright 2023 Google LLC\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n////////////////////////////////////////////////////////////////////////////////\n\n#include <cstring>\n\n#include \"demangle.h\"\n\nextern \"C\" int LLVMFuzzerTestOneInput(const unsigned char* Data,\n                                      unsigned Size) {\n  if (Size >= 4095) {\n    return 0;\n  }\n  char Buffer[Size + 1];\n  std::memcpy(Buffer, Data, Size);\n  Buffer[Size] = 0;\n  char demangled[4096];\n  google::Demangle(Buffer, demangled, Size);\n  return 0;\n}\n"
  },
  {
    "path": "src/glog/flags.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n\n#ifndef GLOG_FLAGS_H\n#define GLOG_FLAGS_H\n\n#include <string>\n\n#if defined(GLOG_USE_GFLAGS)\n#  include <gflags/gflags.h>\n#endif\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_EXPORT)\n#  error <glog/flags.h> was not included correctly. See the documentation for how to consume the library.\n#endif\n\n#include \"glog/platform.h\"\n#include \"glog/types.h\"\n\n#pragma push_macro(\"DECLARE_VARIABLE\")\n#pragma push_macro(\"DECLARE_bool\")\n#pragma push_macro(\"DECLARE_string\")\n#pragma push_macro(\"DECLARE_int32\")\n#pragma push_macro(\"DECLARE_uint32\")\n\n#ifdef DECLARE_VARIABLE\n#  undef DECLARE_VARIABLE\n#endif\n\n#ifdef DECLARE_bool\n#  undef DECLARE_bool\n#endif\n\n#ifdef DECLARE_string\n#  undef DECLARE_string\n#endif\n\n#ifdef DECLARE_int32\n#  undef DECLARE_int32\n#endif\n\n#ifdef DECLARE_uint32\n#  undef DECLARE_uint32\n#endif\n\n#ifndef DECLARE_VARIABLE\n#  define DECLARE_VARIABLE(type, shorttype, name, tn) \\\n    namespace fL##shorttype {                         \\\n      extern GLOG_EXPORT type FLAGS_##name;           \\\n    }                                                 \\\n    using fL##shorttype::FLAGS_##name\n\n// bool specialization\n#  define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)\n\n// int32 specialization\n#  define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)\n\n#  if !defined(DECLARE_uint32)\n// uint32 specialization\n#    define DECLARE_uint32(name) \\\n      DECLARE_VARIABLE(google::uint32, U, name, uint32)\n#  endif  // !defined(DECLARE_uint32) && !defined(GLOG_USE_GFLAGS)\n\n// Special case for string, because we have to specify the namespace\n// std::string, which doesn't play nicely with our FLAG__namespace hackery.\n#  define DECLARE_string(name)                    \\\n    namespace fLS {                               \\\n    extern GLOG_EXPORT std::string& FLAGS_##name; \\\n    }                                             \\\n    using fLS::FLAGS_##name\n#endif\n\nDECLARE_int32(logemaillevel);\nDECLARE_int32(logcleansecs);\n\n#ifdef GLOG_OS_LINUX\nDECLARE_bool(drop_log_memory);\n#endif\nDECLARE_string(alsologtoemail);\nDECLARE_string(log_backtrace_at);\n\n// Set whether appending a timestamp to the log file name\nDECLARE_bool(timestamp_in_logfile_name);\n\n// Set whether log messages go to stdout instead of logfiles\nDECLARE_bool(logtostdout);\n\n// Set color messages logged to stdout (if supported by terminal).\nDECLARE_bool(colorlogtostdout);\n\n// Set whether log messages go to stderr instead of logfiles\nDECLARE_bool(logtostderr);\n\n// Set whether log messages go to stderr in addition to logfiles.\nDECLARE_bool(alsologtostderr);\n\n// Set color messages logged to stderr (if supported by terminal).\nDECLARE_bool(colorlogtostderr);\n\n// Log messages at a level >= this flag are automatically sent to\n// stderr in addition to log files.\nDECLARE_int32(stderrthreshold);\n\n// Set whether the log file header should be written upon creating a file.\nDECLARE_bool(log_file_header);\n\n// Set whether the log prefix should be prepended to each line of output.\nDECLARE_bool(log_prefix);\n\n// Set whether the year should be included in the log prefix.\nDECLARE_bool(log_year_in_prefix);\n\n// Log messages at a level <= this flag are buffered.\n// Log messages at a higher level are flushed immediately.\nDECLARE_int32(logbuflevel);\n\n// Sets the maximum number of seconds which logs may be buffered for.\nDECLARE_int32(logbufsecs);\n\n// Log suppression level: messages logged at a lower level than this\n// are suppressed.\nDECLARE_int32(minloglevel);\n\n// If specified, logfiles are written into this directory instead of the\n// default logging directory.\nDECLARE_string(log_dir);\n\n// Set the log file mode.\nDECLARE_int32(logfile_mode);\n\n// Sets the path of the directory into which to put additional links\n// to the log files.\nDECLARE_string(log_link);\n\nDECLARE_int32(v);  // in vlog_is_on.cc\n\nDECLARE_string(vmodule);  // also in vlog_is_on.cc\n\n// Sets the maximum log file size (in MB).\nDECLARE_uint32(max_log_size);\n\n// Sets whether to avoid logging to the disk if the disk is full.\nDECLARE_bool(stop_logging_if_full_disk);\n\n// Use UTC time for logging\nDECLARE_bool(log_utc_time);\n\n// Mailer used to send logging email\nDECLARE_string(logmailer);\n\nDECLARE_bool(symbolize_stacktrace);\n\n#pragma pop_macro(\"DECLARE_VARIABLE\")\n#pragma pop_macro(\"DECLARE_bool\")\n#pragma pop_macro(\"DECLARE_string\")\n#pragma pop_macro(\"DECLARE_int32\")\n#pragma pop_macro(\"DECLARE_uint32\")\n\n#endif  // GLOG_FLAGS_H\n"
  },
  {
    "path": "src/glog/log_severity.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#ifndef BASE_LOG_SEVERITY_H__\n#define BASE_LOG_SEVERITY_H__\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_EXPORT)\n#  error <glog/log_severity.h> was not included correctly. See the documentation for how to consume the library.\n#endif\n\nnamespace google {\n\n// The recommended semantics of the log levels are as follows:\n//\n// INFO:\n//   Use for state changes or other major events, or to aid debugging.\n// WARNING:\n//   Use for undesired but relatively expected events, which may indicate a\n//   problem\n// ERROR:\n//   Use for undesired and unexpected events that the program can recover from.\n//   All ERRORs should be actionable - it should be appropriate to file a bug\n//   whenever an ERROR occurs in production.\n// FATAL:\n//   Use for undesired and unexpected events that the program cannot recover\n//   from.\n\n// Variables of type LogSeverity are widely taken to lie in the range\n// [0, NUM_SEVERITIES-1].  Be careful to preserve this assumption if\n// you ever need to change their values or add a new severity.\n\nenum LogSeverity {\n  GLOG_INFO = 0,\n  GLOG_WARNING = 1,\n  GLOG_ERROR = 2,\n  GLOG_FATAL = 3,\n#ifndef GLOG_NO_ABBREVIATED_SEVERITIES\n#  ifdef ERROR\n#  error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.\n#  endif\n  INFO = GLOG_INFO,\n  WARNING = GLOG_WARNING,\n  ERROR = GLOG_ERROR,\n  FATAL = GLOG_FATAL\n#endif\n};\n\n#if defined(__cpp_inline_variables)\n#  if (__cpp_inline_variables >= 201606L)\n#    define GLOG_INLINE_VARIABLE inline\n#  endif  // (__cpp_inline_variables >= 201606L)\n#endif    // defined(__cpp_inline_variables)\n\n#if !defined(GLOG_INLINE_VARIABLE)\n#  define GLOG_INLINE_VARIABLE\n#endif  // !defined(GLOG_INLINE_VARIABLE)\n\nGLOG_INLINE_VARIABLE\nconstexpr int NUM_SEVERITIES = 4;\n\n// DFATAL is FATAL in debug mode, ERROR in normal mode\n#ifdef NDEBUG\n#  define DFATAL_LEVEL ERROR\n#else\n#  define DFATAL_LEVEL FATAL\n#endif\n\n// NDEBUG usage helpers related to (RAW_)DCHECK:\n//\n// DEBUG_MODE is for small !NDEBUG uses like\n//   if (DEBUG_MODE) foo.CheckThatFoo();\n// instead of substantially more verbose\n//   #ifndef NDEBUG\n//     foo.CheckThatFoo();\n//   #endif\n//\n// IF_DEBUG_MODE is for small !NDEBUG uses like\n//   IF_DEBUG_MODE( string error; )\n//   DCHECK(Foo(&error)) << error;\n// instead of substantially more verbose\n//   #ifndef NDEBUG\n//     string error;\n//     DCHECK(Foo(&error)) << error;\n//   #endif\n//\n#ifdef NDEBUG\nenum { DEBUG_MODE = 0 };\n#  define IF_DEBUG_MODE(x)\n#else\nenum { DEBUG_MODE = 1 };\n#  define IF_DEBUG_MODE(x) x\n#endif\n\n} // namespace google\n\n#endif  // BASE_LOG_SEVERITY_H__\n"
  },
  {
    "path": "src/glog/logging.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Ray Sidney\n//\n// This file contains #include information about logging-related stuff.\n// Pretty much everybody needs to #include this file so that they can\n// log various happenings.\n//\n#ifndef GLOG_LOGGING_H\n#define GLOG_LOGGING_H\n\n#include <atomic>\n#include <cerrno>\n#include <chrono>\n#include <cstddef>\n#include <cstdlib>\n#include <cstring>\n#include <ctime>\n#include <iosfwd>\n#include <memory>\n#include <ostream>\n#include <sstream>\n#include <string>\n#include <thread>\n#include <utility>\n#include <vector>\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_EXPORT) || !defined(GLOG_NO_EXPORT)\n#  error <glog/logging.h> was not included correctly. See the documentation for how to consume the library.\n#endif\n\n#include \"glog/flags.h\"\n#include \"glog/platform.h\"\n#include \"glog/types.h\"\n\n#if defined(__has_attribute)\n#  if __has_attribute(used)\n#    define GLOG_USED __attribute__((used))\n#  endif  // __has_attribute(used)\n#endif    // defined(__has_attribute)\n\n#if !defined(GLOG_USED)\n#  define GLOG_USED\n#endif  // !defined(GLOG_USED)\n\n#include \"glog/log_severity.h\"\n#include \"glog/vlog_is_on.h\"\n\nnamespace google {\n\nstruct GLOG_EXPORT LogMessageTime {\n  LogMessageTime();\n  explicit LogMessageTime(std::chrono::system_clock::time_point now);\n\n  const std::chrono::system_clock::time_point& when() const noexcept {\n    return timestamp_;\n  }\n  int sec() const noexcept { return tm_.tm_sec; }\n  long usec() const noexcept { return usecs_.count(); }\n  int(min)() const noexcept { return tm_.tm_min; }\n  int hour() const noexcept { return tm_.tm_hour; }\n  int day() const noexcept { return tm_.tm_mday; }\n  int month() const noexcept { return tm_.tm_mon; }\n  int year() const noexcept { return tm_.tm_year; }\n  int dayOfWeek() const noexcept { return tm_.tm_wday; }\n  int dayInYear() const noexcept { return tm_.tm_yday; }\n  int dst() const noexcept { return tm_.tm_isdst; }\n  std::chrono::seconds gmtoffset() const noexcept { return gmtoffset_; }\n  const std::tm& tm() const noexcept { return tm_; }\n\n private:\n  std::tm tm_{};  // Time of creation of LogMessage\n  std::chrono::system_clock::time_point\n      timestamp_;  // Time of creation of LogMessage in seconds\n  std::chrono::microseconds usecs_;\n  std::chrono::seconds gmtoffset_;\n};\n\n}  // namespace google\n\n// The global value of GOOGLE_STRIP_LOG. All the messages logged to\n// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed.\n// If it can be determined at compile time that the message will not be\n// printed, the statement will be compiled out.\n//\n// Example: to strip out all INFO and WARNING messages, use the value\n// of 2 below. To make an exception for WARNING messages from a single\n// file, add \"#define GOOGLE_STRIP_LOG 1\" to that file _before_ including\n// base/logging.h\n#ifndef GOOGLE_STRIP_LOG\n#  define GOOGLE_STRIP_LOG 0\n#endif\n\n// GCC can be told that a certain branch is not likely to be taken (for\n// instance, a CHECK failure), and use that information in static analysis.\n// Giving it this information can help it optimize for the common case in\n// the absence of better information (ie. -fprofile-arcs).\n//\n#if defined(__has_builtin)\n#  if __has_builtin(__builtin_expect)\n#    define GLOG_BUILTIN_EXPECT_PRESENT\n#  endif\n#endif\n\n#if !defined(GLOG_BUILTIN_EXPECT_PRESENT) && defined(__GNUG__)\n// __has_builtin is not available prior to GCC 10\n#  define GLOG_BUILTIN_EXPECT_PRESENT\n#endif\n\n#if defined(GLOG_BUILTIN_EXPECT_PRESENT)\n\n#  ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN\n#    define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))\n#  endif\n\n#  ifndef GOOGLE_PREDICT_FALSE\n#    define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))\n#  endif\n\n#  ifndef GOOGLE_PREDICT_TRUE\n#    define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))\n#  endif\n\n#else\n\n#  ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN\n#    define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x\n#  endif\n\n#  ifndef GOOGLE_PREDICT_TRUE\n#    define GOOGLE_PREDICT_FALSE(x) x\n#  endif\n\n#  ifndef GOOGLE_PREDICT_TRUE\n#    define GOOGLE_PREDICT_TRUE(x) x\n#  endif\n\n#endif\n\n#undef GLOG_BUILTIN_EXPECT_PRESENT\n\n// Make a bunch of macros for logging.  The way to log things is to stream\n// things to LOG(<a particular severity level>).  E.g.,\n//\n//   LOG(INFO) << \"Found \" << num_cookies << \" cookies\";\n//\n// You can capture log messages in a string, rather than reporting them\n// immediately:\n//\n//   vector<string> errors;\n//   LOG_STRING(ERROR, &errors) << \"Couldn't parse cookie #\" << cookie_num;\n//\n// This pushes back the new error onto 'errors'; if given a nullptr pointer,\n// it reports the error via LOG(ERROR).\n//\n// You can also do conditional logging:\n//\n//   LOG_IF(INFO, num_cookies > 10) << \"Got lots of cookies\";\n//\n// You can also do occasional logging (log every n'th occurrence of an\n// event):\n//\n//   LOG_EVERY_N(INFO, 10) << \"Got the \" << google::COUNTER << \"th cookie\";\n//\n// The above will cause log messages to be output on the 1st, 11th, 21st, ...\n// times it is executed.  Note that the special google::COUNTER value is used\n// to identify which repetition is happening.\n//\n// You can also do occasional conditional logging (log every n'th\n// occurrence of an event, when condition is satisfied):\n//\n//   LOG_IF_EVERY_N(INFO, (size > 1024), 10) << \"Got the \" << google::COUNTER\n//                                           << \"th big cookie\";\n//\n// You can log messages the first N times your code executes a line. E.g.\n//\n//   LOG_FIRST_N(INFO, 20) << \"Got the \" << google::COUNTER << \"th cookie\";\n//\n// Outputs log messages for the first 20 times it is executed.\n//\n// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available.\n// These log to syslog as well as to the normal logs.  If you use these at\n// all, you need to be aware that syslog can drastically reduce performance,\n// especially if it is configured for remote logging!  Don't use these\n// unless you fully understand this and have a concrete need to use them.\n// Even then, try to minimize your use of them.\n//\n// There are also \"debug mode\" logging macros like the ones above:\n//\n//   DLOG(INFO) << \"Found cookies\";\n//\n//   DLOG_IF(INFO, num_cookies > 10) << \"Got lots of cookies\";\n//\n//   DLOG_EVERY_N(INFO, 10) << \"Got the \" << google::COUNTER << \"th cookie\";\n//\n// All \"debug mode\" logging is compiled away to nothing for non-debug mode\n// compiles.\n//\n// We also have\n//\n//   LOG_ASSERT(assertion);\n//   DLOG_ASSERT(assertion);\n//\n// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;\n//\n// There are \"verbose level\" logging macros.  They look like\n//\n//   VLOG(1) << \"I'm printed when you run the program with --v=1 or more\";\n//   VLOG(2) << \"I'm printed when you run the program with --v=2 or more\";\n//\n// These always log at the INFO log level (when they log at all).\n// The verbose logging can also be turned on module-by-module.  For instance,\n//    --vmodule=mapreduce=2,file=1,gfs*=3 --v=0\n// will cause:\n//   a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc}\n//   b. VLOG(1) and lower messages to be printed from file.{h,cc}\n//   c. VLOG(3) and lower messages to be printed from files prefixed with \"gfs\"\n//   d. VLOG(0) and lower messages to be printed from elsewhere\n//\n// The wildcarding functionality shown by (c) supports both '*' (match\n// 0 or more characters) and '?' (match any single character) wildcards.\n//\n// There's also VLOG_IS_ON(n) \"verbose level\" condition macro. To be used as\n//\n//   if (VLOG_IS_ON(2)) {\n//     // do some logging preparation and logging\n//     // that can't be accomplished with just VLOG(2) << ...;\n//   }\n//\n// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N \"verbose level\"\n// condition macros for sample cases, when some extra computation and\n// preparation for logs is not needed.\n//   VLOG_IF(1, (size > 1024))\n//      << \"I'm printed when size is more than 1024 and when you run the \"\n//         \"program with --v=1 or more\";\n//   VLOG_EVERY_N(1, 10)\n//      << \"I'm printed every 10th occurrence, and when you run the program \"\n//         \"with --v=1 or more. Present occurrence is \" << google::COUNTER;\n//   VLOG_IF_EVERY_N(1, (size > 1024), 10)\n//      << \"I'm printed on every 10th occurrence of case when size is more \"\n//         \" than 1024, when you run the program with --v=1 or more. \";\n//         \"Present occurrence is \" << google::COUNTER;\n//\n// The supported severity levels for macros that allow you to specify one\n// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.\n// Note that messages of a given severity are logged not only in the\n// logfile for that severity, but also in all logfiles of lower severity.\n// E.g., a message of severity FATAL will be logged to the logfiles of\n// severity FATAL, ERROR, WARNING, and INFO.\n//\n// There is also the special severity of DFATAL, which logs FATAL in\n// debug mode, ERROR in normal mode.\n//\n// Very important: logging a message at the FATAL severity level causes\n// the program to terminate (after the message is logged).\n//\n// Unless otherwise specified, logs will be written to the filename\n// \"<program name>.<hostname>.<user name>.log.<severity level>.\", followed\n// by the date, time, and pid (you can't prevent the date, time, and pid\n// from being in the filename).\n//\n// The logging code takes two flags:\n//     --v=#           set the verbose level\n//     --logtostderr   log all the messages to stderr instead of to logfiles\n\n// LOG LINE PREFIX FORMAT\n//\n// Log lines have this form:\n//\n//     Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg...\n//\n// where the fields are defined as follows:\n//\n//   L                A single character, representing the log level\n//                    (eg 'I' for INFO)\n//   yyyy             The year\n//   mm               The month (zero padded; ie May is '05')\n//   dd               The day (zero padded)\n//   hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds\n//   threadid         The space-padded thread ID as returned by GetTID()\n//                    (this matches the PID on Linux)\n//   file             The file name\n//   line             The line number\n//   msg              The user-supplied message\n//\n// Example:\n//\n//   I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog\n//   I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395\n//\n// NOTE: although the microseconds are useful for comparing events on\n// a single machine, clocks on different machines may not be well\n// synchronized.  Hence, use caution when comparing the low bits of\n// timestamps from different machines.\n\n// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for\n// security reasons. See LOG(severity) below.\n\n// A few definitions of macros that don't generate much code.  Since\n// LOG(INFO) and its ilk are used all over our code, it's\n// better to have compact code for these operations.\n\n#if GOOGLE_STRIP_LOG == 0\n#  define COMPACT_GOOGLE_LOG_INFO google::LogMessage(__FILE__, __LINE__)\n#  define LOG_TO_STRING_INFO(message) \\\n    google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, message)\n#else\n#  define COMPACT_GOOGLE_LOG_INFO google::NullStream()\n#  define LOG_TO_STRING_INFO(message) google::NullStream()\n#endif\n\n#if GOOGLE_STRIP_LOG <= 1\n#  define COMPACT_GOOGLE_LOG_WARNING \\\n    google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING)\n#  define LOG_TO_STRING_WARNING(message) \\\n    google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, message)\n#else\n#  define COMPACT_GOOGLE_LOG_WARNING google::NullStream()\n#  define LOG_TO_STRING_WARNING(message) google::NullStream()\n#endif\n\n#if GOOGLE_STRIP_LOG <= 2\n#  define COMPACT_GOOGLE_LOG_ERROR \\\n    google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR)\n#  define LOG_TO_STRING_ERROR(message) \\\n    google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, message)\n#else\n#  define COMPACT_GOOGLE_LOG_ERROR google::NullStream()\n#  define LOG_TO_STRING_ERROR(message) google::NullStream()\n#endif\n\n#if GOOGLE_STRIP_LOG <= 3\n#  define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal(__FILE__, __LINE__)\n#  define LOG_TO_STRING_FATAL(message) \\\n    google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, message)\n#else\n#  define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()\n#  define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()\n#endif\n\n#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)\n#  define DCHECK_IS_ON() 0\n#else\n#  define DCHECK_IS_ON() 1\n#endif\n\n// For DFATAL, we want to use LogMessage (as opposed to\n// LogMessageFatal), to be consistent with the original behavior.\n#if !DCHECK_IS_ON()\n#  define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR\n#elif GOOGLE_STRIP_LOG <= 3\n#  define COMPACT_GOOGLE_LOG_DFATAL \\\n    google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL)\n#else\n#  define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()\n#endif\n\n#define GOOGLE_LOG_INFO(counter)                                     \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \\\n                     &google::LogMessage::SendToLog)\n#define SYSLOG_INFO(counter)                                         \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \\\n                     &google::LogMessage::SendToSyslogAndLog)\n#define GOOGLE_LOG_WARNING(counter)                                     \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \\\n                     &google::LogMessage::SendToLog)\n#define SYSLOG_WARNING(counter)                                         \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \\\n                     &google::LogMessage::SendToSyslogAndLog)\n#define GOOGLE_LOG_ERROR(counter)                                     \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \\\n                     &google::LogMessage::SendToLog)\n#define SYSLOG_ERROR(counter)                                         \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \\\n                     &google::LogMessage::SendToSyslogAndLog)\n#define GOOGLE_LOG_FATAL(counter)                                     \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \\\n                     &google::LogMessage::SendToLog)\n#define SYSLOG_FATAL(counter)                                         \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \\\n                     &google::LogMessage::SendToSyslogAndLog)\n#define GOOGLE_LOG_DFATAL(counter)                                      \\\n  google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \\\n                     &google::LogMessage::SendToLog)\n#define SYSLOG_DFATAL(counter)                                          \\\n  google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \\\n                     &google::LogMessage::SendToSyslogAndLog)\n\n#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \\\n    defined(__CYGWIN__) || defined(__CYGWIN32__)\n// A very useful logging macro to log windows errors:\n#  define LOG_SYSRESULT(result)                                                \\\n    if (FAILED(HRESULT_FROM_WIN32(result))) {                                  \\\n      LPSTR message = nullptr;                                                 \\\n      LPSTR msg = reinterpret_cast<LPSTR>(&message);                           \\\n      DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |   \\\n                                                FORMAT_MESSAGE_FROM_SYSTEM |   \\\n                                                FORMAT_MESSAGE_IGNORE_INSERTS, \\\n                                            0, result, 0, msg, 100, nullptr);  \\\n      std::unique_ptr<char, decltype(&LocalFree)> release{message,             \\\n                                                          &LocalFree};         \\\n      if (message_length > 0) {                                                \\\n        google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0,          \\\n                           &google::LogMessage::SendToLog)                     \\\n                .stream()                                                      \\\n            << reinterpret_cast<const char*>(message);                         \\\n      }                                                                        \\\n    }\n#endif\n\n// We use the preprocessor's merging operator, \"##\", so that, e.g.,\n// LOG(INFO) becomes the token GOOGLE_LOG_INFO.  There's some funny\n// subtle difference between ostream member streaming functions (e.g.,\n// ostream::operator<<(int) and ostream non-member streaming functions\n// (e.g., ::operator<<(ostream&, string&): it turns out that it's\n// impossible to stream something like a string directly to an unnamed\n// ostream. We employ a neat hack by calling the stream() member\n// function of LogMessage which seems to avoid the problem.\n#define LOG(severity) COMPACT_GOOGLE_LOG_##severity.stream()\n#define SYSLOG(severity) SYSLOG_##severity(0).stream()\n\nnamespace google {\n\n// Initialize google's logging library. You will see the program name\n// specified by argv0 in log outputs.\nGLOG_EXPORT void InitGoogleLogging(const char* argv0);\n\n// Check if google's logging library has been initialized.\nGLOG_EXPORT bool IsGoogleLoggingInitialized();\n\n// Shutdown google's logging library.\nGLOG_EXPORT void ShutdownGoogleLogging();\n\n#if defined(__GNUC__)\ntypedef void (*logging_fail_func_t)() __attribute__((noreturn));\n#else\ntypedef void (*logging_fail_func_t)();\n#endif\n\nclass LogMessage;\n\nusing PrefixFormatterCallback = void (*)(std::ostream&, const LogMessage&,\n                                         void*);\n\nGLOG_EXPORT void InstallPrefixFormatter(PrefixFormatterCallback callback,\n                                        void* data = nullptr);\n\n// Install a function which will be called after LOG(FATAL). Returns the\n// previously set function.\nGLOG_EXPORT logging_fail_func_t\nInstallFailureFunction(logging_fail_func_t fail_func);\n\n// Enable/Disable old log cleaner.\nGLOG_EXPORT void EnableLogCleaner(const std::chrono::minutes& overdue);\nGLOG_EXPORT void DisableLogCleaner();\nGLOG_EXPORT void SetApplicationFingerprint(const std::string& fingerprint);\n\nclass LogSink;  // defined below\n\n// If a non-nullptr sink pointer is given, we push this message to that sink.\n// For LOG_TO_SINK we then do normal LOG(severity) logging as well.\n// This is useful for capturing messages and passing/storing them\n// somewhere more specific than the global log of the process.\n// Argument types:\n//   LogSink* sink;\n//   LogSeverity severity;\n// The cast is to disambiguate nullptr arguments.\n#define LOG_TO_SINK(sink, severity)                               \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_##severity, \\\n                     static_cast<google::LogSink*>(sink), true)   \\\n      .stream()\n#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity)            \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_##severity, \\\n                     static_cast<google::LogSink*>(sink), false)  \\\n      .stream()\n\n// If a non-nullptr string pointer is given, we write this message to that\n// string. We then do normal LOG(severity) logging as well. This is useful for\n// capturing messages and storing them somewhere more specific than the global\n// log of the process. Argument types:\n//   string* message;\n//   LogSeverity severity;\n// The cast is to disambiguate nullptr arguments.\n// NOTE: LOG(severity) expands to LogMessage().stream() for the specified\n// severity.\n#define LOG_TO_STRING(severity, message) \\\n  LOG_TO_STRING_##severity(static_cast<std::string*>(message)).stream()\n\n// If a non-nullptr pointer is given, we push the message onto the end\n// of a vector of strings; otherwise, we report it with LOG(severity).\n// This is handy for capturing messages and perhaps passing them back\n// to the caller, rather than reporting them immediately.\n// Argument types:\n//   LogSeverity severity;\n//   vector<string> *outvec;\n// The cast is to disambiguate nullptr arguments.\n#define LOG_STRING(severity, outvec)                                       \\\n  LOG_TO_STRING_##severity(static_cast<std::vector<std::string>*>(outvec)) \\\n      .stream()\n\n#define LOG_IF(severity, condition) \\\n  static_cast<void>(0),             \\\n      !(condition)                  \\\n          ? (void)0                 \\\n          : google::logging::internal::LogMessageVoidify() & LOG(severity)\n#define SYSLOG_IF(severity, condition) \\\n  static_cast<void>(0),                \\\n      !(condition)                     \\\n          ? (void)0                    \\\n          : google::logging::internal::LogMessageVoidify() & SYSLOG(severity)\n\n#define LOG_ASSERT(condition) \\\n  LOG_IF(FATAL, !(condition)) << \"Assert failed: \" #condition\n#define SYSLOG_ASSERT(condition) \\\n  SYSLOG_IF(FATAL, !(condition)) << \"Assert failed: \" #condition\n\n// CHECK dies with a fatal error if condition is not true.  It is *not*\n// controlled by DCHECK_IS_ON(), so the check will be executed regardless of\n// compilation mode.  Therefore, it is safe to do things like:\n//    CHECK(fp->Write(x) == 4)\n#define CHECK(condition)                                       \\\n  LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \\\n      << \"Check failed: \" #condition \" \"\n\nnamespace logging {\nnamespace internal {\n\n// A container for a string pointer which can be evaluated to a bool -\n// true iff the pointer is nullptr.\nstruct CheckOpString {\n  CheckOpString(std::unique_ptr<std::string> str) : str_(std::move(str)) {}\n  explicit operator bool() const noexcept {\n    return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != nullptr);\n  }\n  std::unique_ptr<std::string> str_;\n};\n\n// Function is overloaded for integral types to allow static const\n// integrals declared in classes and not defined to be used as arguments to\n// CHECK* macros. It's not encouraged though.\ntemplate <class T>\ninline const T& GetReferenceableValue(const T& t) {\n  return t;\n}\ninline char GetReferenceableValue(char t) { return t; }\ninline unsigned char GetReferenceableValue(unsigned char t) { return t; }\ninline signed char GetReferenceableValue(signed char t) { return t; }\ninline short GetReferenceableValue(short t) { return t; }\ninline unsigned short GetReferenceableValue(unsigned short t) { return t; }\ninline int GetReferenceableValue(int t) { return t; }\ninline unsigned int GetReferenceableValue(unsigned int t) { return t; }\ninline long GetReferenceableValue(long t) { return t; }\ninline unsigned long GetReferenceableValue(unsigned long t) { return t; }\ninline long long GetReferenceableValue(long long t) { return t; }\ninline unsigned long long GetReferenceableValue(unsigned long long t) {\n  return t;\n}\n\n// This is a dummy class to define the following operator.\nstruct DummyClassToDefineOperator {};\n\n// Define global operator<< to declare using ::operator<<.\n// This declaration will allow use to use CHECK macros for user\n// defined classes which have operator<< (e.g., stl_logging.h).\ninline std::ostream& operator<<(std::ostream& out,\n                                const DummyClassToDefineOperator&) {\n  return out;\n}\n\n// This formats a value for a failing CHECK_XX statement.  Ordinarily,\n// it uses the definition for operator<<, with a few special cases below.\ntemplate <typename T>\ninline void MakeCheckOpValueString(std::ostream* os, const T& v) {\n  (*os) << v;\n}\n\n// Overrides for char types provide readable values for unprintable\n// characters.\ntemplate <>\nGLOG_EXPORT void MakeCheckOpValueString(std::ostream* os, const char& v);\ntemplate <>\nGLOG_EXPORT void MakeCheckOpValueString(std::ostream* os, const signed char& v);\ntemplate <>\nGLOG_EXPORT void MakeCheckOpValueString(std::ostream* os,\n                                        const unsigned char& v);\n\n// Provide printable value for nullptr_t\ntemplate <>\nGLOG_EXPORT void MakeCheckOpValueString(std::ostream* os,\n                                        const std::nullptr_t& v);\n\n// Build the error message string. Specify no inlining for code size.\ntemplate <typename T1, typename T2>\nstd::unique_ptr<std::string> MakeCheckOpString(const T1& v1, const T2& v2,\n                                               const char* exprtext)\n#if defined(__has_attribute)\n#  if __has_attribute(used)\n    __attribute__((noinline))\n#  endif\n#endif\n    ;\n\n// A helper class for formatting \"expr (V1 vs. V2)\" in a CHECK_XX\n// statement.  See MakeCheckOpString for sample usage.  Other\n// approaches were considered: use of a template method (e.g.,\n// base::BuildCheckOpString(exprtext, base::Print<T1>, &v1,\n// base::Print<T2>, &v2), however this approach has complications\n// related to volatile arguments and function-pointer arguments).\nclass GLOG_EXPORT CheckOpMessageBuilder {\n public:\n  // Inserts \"exprtext\" and \" (\" to the stream.\n  explicit CheckOpMessageBuilder(const char* exprtext);\n  // Deletes \"stream_\".\n  ~CheckOpMessageBuilder();\n  // For inserting the first variable.\n  std::ostream* ForVar1() { return stream_; }\n  // For inserting the second variable (adds an intermediate \" vs. \").\n  std::ostream* ForVar2();\n  // Get the result (inserts the closing \")\").\n  std::unique_ptr<std::string> NewString();\n\n private:\n  std::ostringstream* stream_;\n};\n\ntemplate <typename T1, typename T2>\nstd::unique_ptr<std::string> MakeCheckOpString(const T1& v1, const T2& v2,\n                                               const char* exprtext) {\n  CheckOpMessageBuilder comb(exprtext);\n  MakeCheckOpValueString(comb.ForVar1(), v1);\n  MakeCheckOpValueString(comb.ForVar2(), v2);\n  return comb.NewString();\n}\n\n// Helper functions for CHECK_OP macro.\n// The (int, int) specialization works around the issue that the compiler\n// will not instantiate the template version of the function on values of\n// unnamed enum type - see comment below.\n#define DEFINE_CHECK_OP_IMPL(name, op)                                       \\\n  template <typename T1, typename T2>                                        \\\n  inline std::unique_ptr<std::string> name##Impl(const T1& v1, const T2& v2, \\\n                                                 const char* exprtext) {     \\\n    if (GOOGLE_PREDICT_TRUE(v1 op v2)) {                                     \\\n      return nullptr;                                                        \\\n    }                                                                        \\\n    return MakeCheckOpString(v1, v2, exprtext);                              \\\n  }                                                                          \\\n  inline std::unique_ptr<std::string> name##Impl(int v1, int v2,             \\\n                                                 const char* exprtext) {     \\\n    return name##Impl<int, int>(v1, v2, exprtext);                           \\\n  }\n\n// We use the full name Check_EQ, Check_NE, etc. in case the file including\n// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.\n// This happens if, for example, those are used as token names in a\n// yacc grammar.\nDEFINE_CHECK_OP_IMPL(Check_EQ, ==)\nDEFINE_CHECK_OP_IMPL(Check_NE, !=)\nDEFINE_CHECK_OP_IMPL(Check_LE, <=)\nDEFINE_CHECK_OP_IMPL(Check_LT, <)\nDEFINE_CHECK_OP_IMPL(Check_GE, >=)\nDEFINE_CHECK_OP_IMPL(Check_GT, >)\n\n#undef DEFINE_CHECK_OP_IMPL\n\n// Helper macro for binary operators.\n// Don't use this macro directly in your code, use CHECK_EQ et al below.\n\n#if defined(STATIC_ANALYSIS)\n// Only for static analysis tool to know that it is equivalent to assert\n#  define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1)op(val2))\n#elif DCHECK_IS_ON()\n// In debug mode, avoid constructing CheckOpStrings if possible,\n// to reduce the overhead of CHECK statements by 2x.\n// Real DCHECK-heavy tests have seen 1.5x speedups.\n\n// The meaning of \"string\" might be different between now and\n// when this macro gets invoked (e.g., if someone is experimenting\n// with other string implementations that get defined after this\n// file is included).  Save the current meaning now and use it\n// in the macro.\nusing _Check_string = std::string;\n#  define CHECK_OP_LOG(name, op, val1, val2, log)                              \\\n    while (std::unique_ptr<google::logging::internal::_Check_string> _result = \\\n               google::logging::internal::Check##name##Impl(                   \\\n                   google::logging::internal::GetReferenceableValue(val1),     \\\n                   google::logging::internal::GetReferenceableValue(val2),     \\\n                   #val1 \" \" #op \" \" #val2))                                   \\\n    log(__FILE__, __LINE__,                                                    \\\n        google::logging::internal::CheckOpString(std::move(_result)))          \\\n        .stream()\n#else\n// In optimized mode, use CheckOpString to hint to compiler that\n// the while condition is unlikely.\n#  define CHECK_OP_LOG(name, op, val1, val2, log)                          \\\n    while (google::logging::internal::CheckOpString _result =              \\\n               google::logging::internal::Check##name##Impl(               \\\n                   google::logging::internal::GetReferenceableValue(val1), \\\n                   google::logging::internal::GetReferenceableValue(val2), \\\n                   #val1 \" \" #op \" \" #val2))                               \\\n    log(__FILE__, __LINE__, _result).stream()\n#endif  // STATIC_ANALYSIS, DCHECK_IS_ON()\n\n#if GOOGLE_STRIP_LOG <= 3\n#  define CHECK_OP(name, op, val1, val2) \\\n    CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)\n#else\n#  define CHECK_OP(name, op, val1, val2) \\\n    CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)\n#endif  // STRIP_LOG <= 3\n\n// Equality/Inequality checks - compare two values, and log a FATAL message\n// including the two values when the result is not as expected.  The values\n// must have operator<<(ostream, ...) defined.\n//\n// You may append to the error message like so:\n//   CHECK_NE(1, 2) << \": The world must be ending!\";\n//\n// We are very careful to ensure that each argument is evaluated exactly\n// once, and that anything which is legal to pass as a function argument is\n// legal here.  In particular, the arguments may be temporary expressions\n// which will end up being destroyed at the end of the apparent statement,\n// for example:\n//   CHECK_EQ(string(\"abc\")[1], 'b');\n//\n// WARNING: These don't compile correctly if one of the arguments is a pointer\n// and the other is nullptr. To work around this, simply static_cast nullptr to\n// the type of the desired pointer.\n\n#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)\n#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)\n#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)\n#define CHECK_LT(val1, val2) CHECK_OP(_LT, <, val1, val2)\n#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)\n#define CHECK_GT(val1, val2) CHECK_OP(_GT, >, val1, val2)\n\n// Check that the input is non nullptr.  This very useful in constructor\n// initializer lists.\n\n#define CHECK_NOTNULL(val)                 \\\n  google::logging::internal::CheckNotNull( \\\n      __FILE__, __LINE__, \"'\" #val \"' Must be non nullptr\", (val))\n\n// Helper functions for string comparisons.\n// To avoid bloat, the definitions are in logging.cc.\n#define DECLARE_CHECK_STROP_IMPL(func, expected)                        \\\n  GLOG_EXPORT std::unique_ptr<std::string> Check##func##expected##Impl( \\\n      const char* s1, const char* s2, const char* names);\n\nDECLARE_CHECK_STROP_IMPL(strcmp, true)\nDECLARE_CHECK_STROP_IMPL(strcmp, false)\nDECLARE_CHECK_STROP_IMPL(strcasecmp, true)\nDECLARE_CHECK_STROP_IMPL(strcasecmp, false)\n\n}  // namespace internal\n}  // namespace logging\n\n#undef DECLARE_CHECK_STROP_IMPL\n\n// Helper macro for string comparisons.\n// Don't use this macro directly in your code, use CHECK_STREQ et al below.\n#define CHECK_STROP(func, op, expected, s1, s2)                      \\\n  while (google::logging::internal::CheckOpString _result =          \\\n             google::logging::internal::Check##func##expected##Impl( \\\n                 (s1), (s2), #s1 \" \" #op \" \" #s2))                   \\\n  LOG(FATAL) << (*_result.str_)\n\n// String (char*) equality/inequality checks.\n// CASE versions are case-insensitive.\n//\n// Note that \"s1\" and \"s2\" may be temporary strings which are destroyed\n// by the compiler at the end of the current \"full expression\"\n// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())).\n\n#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2)\n#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2)\n#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2)\n#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2)\n\n#define CHECK_INDEX(I, A) CHECK(I < (sizeof(A) / sizeof(A[0])))\n#define CHECK_BOUND(B, A) CHECK(B <= (sizeof(A) / sizeof(A[0])))\n\n#define CHECK_DOUBLE_EQ(val1, val2)                \\\n  do {                                             \\\n    CHECK_LE((val1), (val2) + 0.000000000000001L); \\\n    CHECK_GE((val1), (val2)-0.000000000000001L);   \\\n  } while (0)\n\n#define CHECK_NEAR(val1, val2, margin)   \\\n  do {                                   \\\n    CHECK_LE((val1), (val2) + (margin)); \\\n    CHECK_GE((val1), (val2) - (margin)); \\\n  } while (0)\n\n// perror()..googly style!\n//\n// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and\n// CHECK equivalents with the addition that they postpend a description\n// of the current state of errno to their output lines.\n\n#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream()\n\n#define GOOGLE_PLOG(severity, counter)                                 \\\n  google::ErrnoLogMessage(__FILE__, __LINE__, google::GLOG_##severity, \\\n                          counter, &google::LogMessage::SendToLog)\n\n#define PLOG_IF(severity, condition) \\\n  static_cast<void>(0),              \\\n      !(condition)                   \\\n          ? (void)0                  \\\n          : google::logging::internal::LogMessageVoidify() & PLOG(severity)\n\n// A CHECK() macro that postpends errno if the condition is false. E.g.\n//\n// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... }\n#define PCHECK(condition)                                       \\\n  PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \\\n      << \"Check failed: \" #condition \" \"\n\n// A CHECK() macro that lets you assert the success of a function that\n// returns -1 and sets errno in case of an error. E.g.\n//\n// CHECK_ERR(mkdir(path, 0700));\n//\n// or\n//\n// int fd = open(filename, flags); CHECK_ERR(fd) << \": open \" << filename;\n#define CHECK_ERR(invocation)                                         \\\n  PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \\\n      << #invocation\n\n// Use macro expansion to create, for each use of LOG_EVERY_N(), static\n// variables with the __LINE__ expansion as part of the variable name.\n#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line)\n#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base##line\n\n#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__)\n#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__)\n\n#define LOG_TIME_PERIOD LOG_EVERY_N_VARNAME(timePeriod_, __LINE__)\n#define LOG_PREVIOUS_TIME_RAW LOG_EVERY_N_VARNAME(previousTimeRaw_, __LINE__)\n#define LOG_TIME_DELTA LOG_EVERY_N_VARNAME(deltaTime_, __LINE__)\n#define LOG_CURRENT_TIME LOG_EVERY_N_VARNAME(currentTime_, __LINE__)\n#define LOG_PREVIOUS_TIME LOG_EVERY_N_VARNAME(previousTime_, __LINE__)\n\n}  // namespace google\n\nnamespace google {\n\n#define SOME_KIND_OF_LOG_EVERY_T(severity, seconds)                            \\\n  constexpr std::chrono::nanoseconds LOG_TIME_PERIOD =                         \\\n      std::chrono::duration_cast<std::chrono::nanoseconds>(                    \\\n          std::chrono::duration<double>(seconds));                             \\\n  static std::atomic<google::int64> LOG_PREVIOUS_TIME_RAW;                     \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(                         \\\n      __FILE__, __LINE__, &LOG_TIME_PERIOD, sizeof(google::int64), \"\"));       \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(                         \\\n      __FILE__, __LINE__, &LOG_PREVIOUS_TIME_RAW, sizeof(google::int64), \"\")); \\\n  const auto LOG_CURRENT_TIME =                                                \\\n      std::chrono::duration_cast<std::chrono::nanoseconds>(                    \\\n          std::chrono::steady_clock::now().time_since_epoch());                \\\n  const auto LOG_PREVIOUS_TIME =                                               \\\n      LOG_PREVIOUS_TIME_RAW.load(std::memory_order_relaxed);                   \\\n  const auto LOG_TIME_DELTA =                                                  \\\n      LOG_CURRENT_TIME - std::chrono::nanoseconds(LOG_PREVIOUS_TIME);          \\\n  if (LOG_TIME_DELTA > LOG_TIME_PERIOD)                                        \\\n    LOG_PREVIOUS_TIME_RAW.store(                                               \\\n        std::chrono::duration_cast<std::chrono::nanoseconds>(LOG_CURRENT_TIME) \\\n            .count(),                                                          \\\n        std::memory_order_relaxed);                                            \\\n  if (LOG_TIME_DELTA > LOG_TIME_PERIOD)                                        \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_##severity).stream()\n\n#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do)               \\\n  static std::atomic<int> LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(                  \\\n      __FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), \"\"));          \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(                  \\\n      __FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), \"\"));    \\\n  ++LOG_OCCURRENCES;                                                    \\\n  if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n;          \\\n  if (LOG_OCCURRENCES_MOD_N == 1)                                       \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_##severity,       \\\n                     LOG_OCCURRENCES, &what_to_do)                      \\\n      .stream()\n\n#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do)       \\\n  static std::atomic<int> LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0);       \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(                        \\\n      __FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), \"\"));                \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(                        \\\n      __FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), \"\"));          \\\n  ++LOG_OCCURRENCES;                                                          \\\n  if ((condition) &&                                                          \\\n      ((LOG_OCCURRENCES_MOD_N = (LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_##severity,             \\\n                     LOG_OCCURRENCES, &what_to_do)                            \\\n      .stream()\n\n#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do)              \\\n  static std::atomic<int> LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(                  \\\n      __FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), \"\"));          \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(                  \\\n      __FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), \"\"));    \\\n  ++LOG_OCCURRENCES;                                                    \\\n  if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n;          \\\n  if (LOG_OCCURRENCES_MOD_N == 1)                                       \\\n  google::ErrnoLogMessage(__FILE__, __LINE__, google::GLOG_##severity,  \\\n                          LOG_OCCURRENCES, &what_to_do)                 \\\n      .stream()\n\n#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do)         \\\n  static std::atomic<int> LOG_OCCURRENCES(0);                     \\\n  GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(            \\\n      __FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), \"\"));    \\\n  if (LOG_OCCURRENCES <= n) ++LOG_OCCURRENCES;                    \\\n  if (LOG_OCCURRENCES <= n)                                       \\\n  google::LogMessage(__FILE__, __LINE__, google::GLOG_##severity, \\\n                     LOG_OCCURRENCES, &what_to_do)                \\\n      .stream()\n\nnamespace logging {\nnamespace internal {\ntemplate <bool>\nstruct CompileAssert {};\nstruct CrashReason;\n}  // namespace internal\n}  // namespace logging\n\n#define LOG_EVERY_N(severity, n) \\\n  SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)\n\n#define LOG_EVERY_T(severity, T) SOME_KIND_OF_LOG_EVERY_T(severity, (T))\n\n#define SYSLOG_EVERY_N(severity, n)       \\\n  SOME_KIND_OF_LOG_EVERY_N(severity, (n), \\\n                           google::LogMessage::SendToSyslogAndLog)\n\n#define PLOG_EVERY_N(severity, n) \\\n  SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)\n\n#define LOG_FIRST_N(severity, n) \\\n  SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog)\n\n#define LOG_IF_EVERY_N(severity, condition, n)            \\\n  SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), \\\n                              google::LogMessage::SendToLog)\n\n// We want the special COUNTER value available for LOG_EVERY_X()'ed messages\nstruct Counter_t {};\nGLOG_INLINE_VARIABLE constexpr Counter_t COUNTER{};\n\n#ifdef GLOG_NO_ABBREVIATED_SEVERITIES\n// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets\n// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us\n// to keep using this syntax, we define this macro to do the same thing\n// as COMPACT_GOOGLE_LOG_ERROR.\n#  define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR\n#  define SYSLOG_0 SYSLOG_ERROR\n#  define LOG_TO_STRING_0 LOG_TO_STRING_ERROR\n// Needed for LOG_IS_ON(ERROR).\nGLOG_INLINE_VARIABLE\nconstexpr LogSeverity GLOG_0 = GLOG_ERROR;\n#else\n// Users may include windows.h after logging.h without\n// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN.\n// For this case, we cannot detect if ERROR is defined before users\n// actually use ERROR. Let's make an undefined symbol to warn users.\n#  define GLOG_ERROR_MSG \\\n    ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail\n#  define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG\n#  define SYSLOG_0 GLOG_ERROR_MSG\n#  define LOG_TO_STRING_0 GLOG_ERROR_MSG\n#  define GLOG_0 GLOG_ERROR_MSG\n#endif\n\n// Plus some debug-logging macros that get compiled to nothing for production\n\n#if DCHECK_IS_ON()\n\n#  define DLOG(severity) LOG(severity)\n#  define DVLOG(verboselevel) VLOG(verboselevel)\n#  define DLOG_IF(severity, condition) LOG_IF(severity, condition)\n#  define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)\n#  define DLOG_IF_EVERY_N(severity, condition, n) \\\n    LOG_IF_EVERY_N(severity, condition, n)\n#  define DLOG_FIRST_N(severity, n) LOG_FIRST_N(severity, n)\n#  define DLOG_EVERY_T(severity, T) LOG_EVERY_T(severity, T)\n#  define DLOG_ASSERT(condition) LOG_ASSERT(condition)\n\n// debug-only checking.  executed if DCHECK_IS_ON().\n#  define DCHECK(condition) CHECK(condition)\n#  define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)\n#  define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)\n#  define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)\n#  define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)\n#  define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)\n#  define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)\n#  define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)\n#  define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)\n#  define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)\n#  define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)\n#  define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)\n\n#else  // !DCHECK_IS_ON()\n\n#  define DLOG(severity)  \\\n    static_cast<void>(0), \\\n        true ? (void)0    \\\n             : google::logging::internal::LogMessageVoidify() & LOG(severity)\n\n#  define DVLOG(verboselevel)               \\\n    static_cast<void>(0),                   \\\n        (true || !VLOG_IS_ON(verboselevel)) \\\n            ? (void)0                       \\\n            : google::logging::internal::LogMessageVoidify() & LOG(INFO)\n\n#  define DLOG_IF(severity, condition) \\\n    static_cast<void>(0),              \\\n        (true || !(condition))         \\\n            ? (void)0                  \\\n            : google::logging::internal::LogMessageVoidify() & LOG(severity)\n\n#  define DLOG_EVERY_N(severity, n) \\\n    static_cast<void>(0),           \\\n        true ? (void)0              \\\n             : google::logging::internal::LogMessageVoidify() & LOG(severity)\n\n#  define DLOG_IF_EVERY_N(severity, condition, n) \\\n    static_cast<void>(0),                         \\\n        (true || !(condition))                    \\\n            ? (void)0                             \\\n            : google::logging::internal::LogMessageVoidify() & LOG(severity)\n\n#  define DLOG_FIRST_N(severity, n) \\\n    static_cast<void>(0),           \\\n        true ? (void)0              \\\n             : google::logging::internal::LogMessageVoidify() & LOG(severity)\n\n#  define DLOG_EVERY_T(severity, T) \\\n    static_cast<void>(0),           \\\n        true ? (void)0              \\\n             : google::logging::internal::LogMessageVoidify() & LOG(severity)\n\n#  define DLOG_ASSERT(condition) \\\n    static_cast<void>(0), true ? (void)0 : (LOG_ASSERT(condition))\n\n// MSVC warning C4127: conditional expression is constant\n#  define DCHECK(condition)              \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK(condition)\n\n#  define DCHECK_EQ(val1, val2)          \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2)\n\n#  define DCHECK_NE(val1, val2)          \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2)\n\n#  define DCHECK_LE(val1, val2)          \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2)\n\n#  define DCHECK_LT(val1, val2)          \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2)\n\n#  define DCHECK_GE(val1, val2)          \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2)\n\n#  define DCHECK_GT(val1, val2)          \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2)\n\n// You may see warnings in release mode if you don't use the return\n// value of DCHECK_NOTNULL. Please just use DCHECK for such cases.\n#  define DCHECK_NOTNULL(val) (val)\n\n#  define DCHECK_STREQ(str1, str2)       \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2)\n\n#  define DCHECK_STRCASEEQ(str1, str2)   \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2)\n\n#  define DCHECK_STRNE(str1, str2)       \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2)\n\n#  define DCHECK_STRCASENE(str1, str2)   \\\n    GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \\\n    while (false) GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)\n\n#endif  // DCHECK_IS_ON()\n\n// Log only in verbose mode.\n\n#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))\n\n#define VLOG_IF(verboselevel, condition) \\\n  LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))\n\n#define VLOG_EVERY_N(verboselevel, n) \\\n  LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n)\n\n#define VLOG_IF_EVERY_N(verboselevel, condition, n) \\\n  LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)\n\nnamespace base_logging {\n\n// LogMessage::LogStream is a std::ostream backed by this streambuf.\n// This class ignores overflow and leaves two bytes at the end of the\n// buffer to allow for a '\\n' and '\\0'.\nclass GLOG_EXPORT LogStreamBuf : public std::streambuf {\n public:\n  // REQUIREMENTS: \"len\" must be >= 2 to account for the '\\n' and '\\0'.\n  LogStreamBuf(char* buf, int len) { setp(buf, buf + len - 2); }\n\n  // This effectively ignores overflow.\n  int_type overflow(int_type ch) { return ch; }\n\n  // Legacy public ostrstream method.\n  size_t pcount() const { return static_cast<size_t>(pptr() - pbase()); }\n  char* pbase() const { return std::streambuf::pbase(); }\n};\n\n}  // namespace base_logging\n\nnamespace logging {\nnamespace internal {\nstruct GLOG_NO_EXPORT LogMessageData;\n}  // namespace internal\n}  // namespace logging\n\n//\n// This class more or less represents a particular log message.  You\n// create an instance of LogMessage and then stream stuff to it.\n// When you finish streaming to it, ~LogMessage is called and the\n// full message gets streamed to the appropriate destination.\n//\n// You shouldn't actually use LogMessage's constructor to log things,\n// though.  You should use the LOG() macro (and variants thereof)\n// above.\nclass GLOG_EXPORT LogMessage {\n public:\n  enum {\n    // Passing kNoLogPrefix for the line number disables the\n    // log-message prefix. Useful for using the LogMessage\n    // infrastructure as a printing utility. See also the --log_prefix\n    // flag for controlling the log-message prefix on an\n    // application-wide basis.\n    kNoLogPrefix = -1\n  };\n\n  // LogStream inherit from non-DLL-exported class (std::ostrstream)\n  // and VC++ produces a warning for this situation.\n  // However, MSDN says \"C4275 can be ignored in Microsoft Visual C++\n  // 2005 if you are deriving from a type in the Standard C++ Library\"\n  // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx\n  // Let's just ignore the warning.\n  GLOG_MSVC_PUSH_DISABLE_WARNING(4275)\n  class GLOG_EXPORT LogStream : public std::ostream {\n    GLOG_MSVC_POP_WARNING()\n   public:\n    // In some cases, like when compiling glog as a static library with GCC and\n    // linking against a Clang-built executable, this constructor will be\n    // removed by the linker. We use this attribute to prevent the linker from\n    // discarding it.\n    GLOG_USED\n    LogStream(char* buf, int len, int64 ctr)\n        : std::ostream(nullptr), streambuf_(buf, len), ctr_(ctr), self_(this) {\n      rdbuf(&streambuf_);\n    }\n\n    LogStream(LogStream&& other) noexcept\n        : std::ostream(nullptr),\n          streambuf_(std::move(other.streambuf_)),\n          ctr_(std::exchange(other.ctr_, 0)),\n          self_(this) {\n      rdbuf(&streambuf_);\n    }\n\n    LogStream& operator=(LogStream&& other) noexcept {\n      streambuf_ = std::move(other.streambuf_);\n      ctr_ = std::exchange(other.ctr_, 0);\n      rdbuf(&streambuf_);\n      return *this;\n    }\n\n    int64 ctr() const { return ctr_; }\n    void set_ctr(int64 ctr) { ctr_ = ctr; }\n    LogStream* self() const { return self_; }\n\n    // Legacy std::streambuf methods.\n    size_t pcount() const { return streambuf_.pcount(); }\n    char* pbase() const { return streambuf_.pbase(); }\n    char* str() const { return pbase(); }\n\n    LogStream(const LogStream&) = delete;\n    LogStream& operator=(const LogStream&) = delete;\n\n   private:\n    base_logging::LogStreamBuf streambuf_;\n    int64 ctr_;        // Counter hack (for the LOG_EVERY_X() macro)\n    LogStream* self_;  // Consistency check hack\n  };\n\n public:\n  // icc 8 requires this typedef to avoid an internal compiler error.\n  typedef void (LogMessage::*SendMethod)();\n\n  LogMessage(const char* file, int line, LogSeverity severity, int64 ctr,\n             SendMethod send_method);\n\n  // Two special constructors that generate reduced amounts of code at\n  // LOG call sites for common cases.\n\n  // Used for LOG(INFO): Implied are:\n  // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog.\n  //\n  // Using this constructor instead of the more complex constructor above\n  // saves 19 bytes per call site.\n  LogMessage(const char* file, int line);\n\n  // Used for LOG(severity) where severity != INFO.  Implied\n  // are: ctr = 0, send_method = &LogMessage::SendToLog\n  //\n  // Using this constructor instead of the more complex constructor above\n  // saves 17 bytes per call site.\n  LogMessage(const char* file, int line, LogSeverity severity);\n\n  // Constructor to log this message to a specified sink (if not nullptr).\n  // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if\n  // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise.\n  LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink,\n             bool also_send_to_log);\n\n  // Constructor where we also give a vector<string> pointer\n  // for storing the messages (if the pointer is not nullptr).\n  // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog.\n  LogMessage(const char* file, int line, LogSeverity severity,\n             std::vector<std::string>* outvec);\n\n  // Constructor where we also give a string pointer for storing the\n  // message (if the pointer is not nullptr).  Implied are: ctr = 0,\n  // send_method = &LogMessage::WriteToStringAndLog.\n  LogMessage(const char* file, int line, LogSeverity severity,\n             std::string* message);\n\n  // A special constructor used for check failures\n  LogMessage(const char* file, int line,\n             const logging::internal::CheckOpString& result);\n\n  ~LogMessage() noexcept(false);\n\n  // Flush a buffered message to the sink set in the constructor.  Always\n  // called by the destructor, it may also be called from elsewhere if\n  // needed.  Only the first call is actioned; any later ones are ignored.\n  void Flush();\n\n  // An arbitrary limit on the length of a single log message.  This\n  // is so that streaming can be done more efficiently.\n  static const size_t kMaxLogMessageLen;\n\n  // These should not be called directly outside of logging.*,\n  // only passed as SendMethod arguments to other LogMessage methods:\n  void SendToLog();           // Actually dispatch to the logs\n  void SendToSyslogAndLog();  // Actually dispatch to syslog and the logs\n\n  // Call abort() or similar to perform LOG(FATAL) crash.\n  [[noreturn]] static void Fail();\n\n  std::ostream& stream();\n\n  int preserved_errno() const;\n\n  // Must be called without the log_mutex held.  (L < log_mutex)\n  static int64 num_messages(int severity);\n\n  LogSeverity severity() const noexcept;\n  int line() const noexcept;\n  const std::thread::id& thread_id() const noexcept;\n  const char* fullname() const noexcept;\n  const char* basename() const noexcept;\n  const LogMessageTime& time() const noexcept;\n\n  LogMessage(const LogMessage&) = delete;\n  LogMessage& operator=(const LogMessage&) = delete;\n\n private:\n  // Fully internal SendMethod cases:\n  void SendToSinkAndLog();  // Send to sink if provided and dispatch to the logs\n  void SendToSink();        // Send to sink if provided, do nothing otherwise.\n\n  // Write to string if provided and dispatch to the logs.\n  void WriteToStringAndLog();\n\n  void SaveOrSendToLog();  // Save to stringvec if provided, else to logs\n\n  void Init(const char* file, int line, LogSeverity severity,\n            void (LogMessage::*send_method)());\n\n  // Used to fill in crash information during LOG(FATAL) failures.\n  void RecordCrashReason(logging::internal::CrashReason* reason);\n\n  // Counts of messages sent at each priority:\n  static int64 num_messages_[NUM_SEVERITIES];  // under log_mutex\n\n  // We keep the data in a separate struct so that each instance of\n  // LogMessage uses less stack space.\n  logging::internal::LogMessageData* allocated_;\n  logging::internal::LogMessageData* data_;\n  LogMessageTime time_;\n\n  friend class LogDestination;\n};\n\n// This class happens to be thread-hostile because all instances share\n// a single data buffer, but since it can only be created just before\n// the process dies, we don't worry so much.\nclass GLOG_EXPORT LogMessageFatal : public LogMessage {\n public:\n  LogMessageFatal(const char* file, int line);\n  LogMessageFatal(const char* file, int line,\n                  const logging::internal::CheckOpString& result);\n  [[noreturn]] ~LogMessageFatal() noexcept(false);\n};\n\n// A non-macro interface to the log facility; (useful\n// when the logging level is not a compile-time constant).\ninline void LogAtLevel(LogSeverity severity, std::string const& msg) {\n  LogMessage(__FILE__, __LINE__, severity).stream() << msg;\n}\n\n// A macro alternative of LogAtLevel. New code may want to use this\n// version since there are two advantages: 1. this version outputs the\n// file name and the line number where this macro is put like other\n// LOG macros, 2. this macro can be used as C++ stream.\n#define LOG_AT_LEVEL(severity) \\\n  google::LogMessage(__FILE__, __LINE__, severity).stream()\n\n// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This\n// only works if ostream is a LogStream. If the ostream is not a\n// LogStream you'll get an assert saying as much at runtime.\nGLOG_EXPORT std::ostream& operator<<(std::ostream& os, const Counter_t&);\n\n// Derived class for PLOG*() above.\nclass GLOG_EXPORT ErrnoLogMessage : public LogMessage {\n public:\n  ErrnoLogMessage(const char* file, int line, LogSeverity severity, int64 ctr,\n                  void (LogMessage::*send_method)());\n\n  // Postpends \": strerror(errno) [errno]\".\n  ~ErrnoLogMessage();\n\n private:\n  ErrnoLogMessage(const ErrnoLogMessage&);\n  void operator=(const ErrnoLogMessage&);\n};\n\n// This class is used to explicitly ignore values in the conditional\n// logging macros.  This avoids compiler warnings like \"value computed\n// is not used\" and \"statement has no effect\".\n\nnamespace logging {\nnamespace internal {\n\n// Helper for CHECK_NOTNULL().\n//\n// In C++11, all cases can be handled by a single function. Since the value\n// category of the argument is preserved (also for rvalue references),\n// member initializer lists like the one below will compile correctly:\n//\n//   Foo()\n//     : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {}\ntemplate <typename T>\nT CheckNotNull(const char* file, int line, const char* names, T&& t) {\n  if (t == nullptr) {\n    LogMessageFatal(file, line, std::make_unique<std::string>(names));\n  }\n  return std::forward<T>(t);\n}\n\nstruct LogMessageVoidify {\n  // This has to be an operator with a precedence lower than << but\n  // higher than ?:\n  constexpr void operator&(std::ostream&) const noexcept {}\n};\n\n}  // namespace internal\n}  // namespace logging\n\n// Flushes all log files that contains messages that are at least of\n// the specified severity level.  Thread-safe.\nGLOG_EXPORT void FlushLogFiles(LogSeverity min_severity);\n\n// Flushes all log files that contains messages that are at least of\n// the specified severity level. Thread-hostile because it ignores\n// locking -- used for catastrophic failures.\nGLOG_EXPORT void FlushLogFilesUnsafe(LogSeverity min_severity);\n\n//\n// Set the destination to which a particular severity level of log\n// messages is sent.  If base_filename is \"\", it means \"don't log this\n// severity\".  Thread-safe.\n//\nGLOG_EXPORT void SetLogDestination(LogSeverity severity,\n                                   const char* base_filename);\n\n//\n// Set the basename of the symlink to the latest log file at a given\n// severity.  If symlink_basename is empty, do not make a symlink.  If\n// you don't call this function, the symlink basename is the\n// invocation name of the program.  Thread-safe.\n//\nGLOG_EXPORT void SetLogSymlink(LogSeverity severity,\n                               const char* symlink_basename);\n\n//\n// Used to send logs to some other kind of destination\n// Users should subclass LogSink and override send to do whatever they want.\n// Implementations must be thread-safe because a shared instance will\n// be called from whichever thread ran the LOG(XXX) line.\nclass GLOG_EXPORT LogSink {\n public:\n  virtual ~LogSink();\n\n  // Sink's logging logic (message_len is such as to exclude '\\n' at the end).\n  // This method can't use LOG() or CHECK() as logging system mutex(s) are held\n  // during this call.\n  virtual void send(LogSeverity severity, const char* full_filename,\n                    const char* base_filename, int line,\n                    const LogMessageTime& time, const char* message,\n                    size_t message_len) = 0;\n\n  // Redefine this to implement waiting for\n  // the sink's logging logic to complete.\n  // It will be called after each send() returns,\n  // but before that LogMessage exits or crashes.\n  // By default this function does nothing.\n  // Using this function one can implement complex logic for send()\n  // that itself involves logging; and do all this w/o causing deadlocks and\n  // inconsistent rearrangement of log messages.\n  // E.g. if a LogSink has thread-specific actions, the send() method\n  // can simply add the message to a queue and wake up another thread that\n  // handles real logging while itself making some LOG() calls;\n  // WaitTillSent() can be implemented to wait for that logic to complete.\n  // See our unittest for an example.\n  virtual void WaitTillSent();\n\n  // Returns the normal text output of the log message.\n  // Can be useful to implement send().\n  static std::string ToString(LogSeverity severity, const char* file, int line,\n                              const LogMessageTime& time, const char* message,\n                              size_t message_len);\n};\n\n// Add or remove a LogSink as a consumer of logging data.  Thread-safe.\nGLOG_EXPORT void AddLogSink(LogSink* destination);\nGLOG_EXPORT void RemoveLogSink(LogSink* destination);\n\n//\n// Specify an \"extension\" added to the filename specified via\n// SetLogDestination.  This applies to all severity levels.  It's\n// often used to append the port we're listening on to the logfile\n// name.  Thread-safe.\n//\nGLOG_EXPORT void SetLogFilenameExtension(const char* filename_extension);\n\n//\n// Make it so that all log messages of at least a particular severity\n// are logged to stderr (in addition to logging to the usual log\n// file(s)).  Thread-safe.\n//\nGLOG_EXPORT void SetStderrLogging(LogSeverity min_severity);\n\n//\n// Make it so that all log messages go only to stderr.  Thread-safe.\n//\nGLOG_EXPORT void LogToStderr();\n\n//\n// Make it so that all log messages of at least a particular severity are\n// logged via email to a list of addresses (in addition to logging to the\n// usual log file(s)).  The list of addresses is just a string containing\n// the email addresses to send to (separated by spaces, say).  Thread-safe.\n//\nGLOG_EXPORT void SetEmailLogging(LogSeverity min_severity,\n                                 const char* addresses);\n\n// A simple function that sends email. dest is a comma-separated\n// list of addresses.  Thread-safe.\nGLOG_EXPORT bool SendEmail(const char* dest, const char* subject,\n                           const char* body);\n\nGLOG_EXPORT const std::vector<std::string>& GetLoggingDirectories();\n\n// Print any fatal message again -- useful to call from signal handler\n// so that the last thing in the output is the fatal message.\n// Thread-hostile, but a race is unlikely.\nGLOG_EXPORT void ReprintFatalMessage();\n\n// Truncate a log file that may be the append-only output of multiple\n// processes and hence can't simply be renamed/reopened (typically a\n// stdout/stderr).  If the file \"path\" is > \"limit\" bytes, copy the\n// last \"keep\" bytes to offset 0 and truncate the rest. Since we could\n// be racing with other writers, this approach has the potential to\n// lose very small amounts of data. For security, only follow symlinks\n// if the path is /proc/self/fd/*\nGLOG_EXPORT void TruncateLogFile(const char* path, uint64 limit, uint64 keep);\n\n// Truncate stdout and stderr if they are over the value specified by\n// --max_log_size; keep the final 1MB.  This function has the same\n// race condition as TruncateLogFile.\nGLOG_EXPORT void TruncateStdoutStderr();\n\n// Return the string representation of the provided LogSeverity level.\n// Thread-safe.\nGLOG_EXPORT const char* GetLogSeverityName(LogSeverity severity);\n\n// ---------------------------------------------------------------------\n// Implementation details that are not useful to most clients\n// ---------------------------------------------------------------------\n\n// A Logger is the interface used by logging modules to emit entries\n// to a log.  A typical implementation will dump formatted data to a\n// sequence of files.  We also provide interfaces that will forward\n// the data to another thread so that the invoker never blocks.\n// Implementations should be thread-safe since the logging system\n// will write to them from multiple threads.\n\nnamespace base {\n\nclass GLOG_EXPORT Logger {\n public:\n  virtual ~Logger();\n\n  // Writes \"message[0,message_len-1]\" corresponding to an event that\n  // occurred at \"timestamp\".  If \"force_flush\" is true, the log file\n  // is flushed immediately.\n  //\n  // The input message has already been formatted as deemed\n  // appropriate by the higher level logging facility.  For example,\n  // textual log messages already contain timestamps, and the\n  // file:linenumber header.\n  virtual void Write(bool force_flush,\n                     const std::chrono::system_clock::time_point& timestamp,\n                     const char* message, size_t message_len) = 0;\n\n  // Flush any buffered messages\n  virtual void Flush() = 0;\n\n  // Get the current LOG file size.\n  // The returned value is approximate since some\n  // logged data may not have been flushed to disk yet.\n  virtual uint32 LogSize() = 0;\n};\n\n// Get the logger for the specified severity level.  The logger\n// remains the property of the logging module and should not be\n// deleted by the caller.  Thread-safe.\nextern GLOG_EXPORT Logger* GetLogger(LogSeverity level);\n\n// Set the logger for the specified severity level.  The logger\n// becomes the property of the logging module and should not\n// be deleted by the caller.  Thread-safe.\nextern GLOG_EXPORT void SetLogger(LogSeverity level, Logger* logger);\n\n}  // namespace base\n\n// A class for which we define operator<<, which does nothing.\nclass GLOG_EXPORT NullStream : public LogMessage::LogStream {\n public:\n  // Initialize the LogStream so the messages can be written somewhere\n  // (they'll never be actually displayed). This will be needed if a\n  // NullStream& is implicitly converted to LogStream&, in which case\n  // the overloaded NullStream::operator<< will not be invoked.\n  NullStream();\n  NullStream(const char* /*file*/, int /*line*/,\n             const logging::internal::CheckOpString& /*result*/);\n  NullStream& stream();\n\n private:\n  // A very short buffer for messages (which we discard anyway). This\n  // will be needed if NullStream& converted to LogStream& (e.g. as a\n  // result of a conditional expression).\n  char message_buffer_[3];\n};\n\n// Do nothing. This operator is inline, allowing the message to be\n// compiled away. The message will not be compiled away if we do\n// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when\n// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly\n// converted to LogStream and the message will be computed and then\n// quietly discarded.\ntemplate <class T>\ninline NullStream& operator<<(NullStream& str, const T&) {\n  return str;\n}\n\n// Similar to NullStream, but aborts the program (without stack\n// trace), like LogMessageFatal.\nclass GLOG_EXPORT NullStreamFatal : public NullStream {\n public:\n  using NullStream::NullStream;\n  [[noreturn]]\n  // Prevent the linker from discarding the destructor.\n  GLOG_USED ~NullStreamFatal();\n};\n\n// Install a signal handler that will dump signal information and a stack\n// trace when the program crashes on certain signals.  We'll install the\n// signal handler for the following signals.\n//\n// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM.\n//\n// By default, the signal handler will write the failure dump to the\n// standard error.  You can customize the destination by installing your\n// own writer function by InstallFailureWriter() below.\n//\n// Note on threading:\n//\n// The function should be called before threads are created, if you want\n// to use the failure signal handler for all threads.  The stack trace\n// will be shown only for the thread that receives the signal.  In other\n// words, stack traces of other threads won't be shown.\nGLOG_EXPORT void InstallFailureSignalHandler();\n\n// Returns true if FailureSignalHandler is installed.\nGLOG_EXPORT bool IsFailureSignalHandlerInstalled();\n\n// Installs a function that is used for writing the failure dump.  \"data\"\n// is the pointer to the beginning of a message to be written, and \"size\"\n// is the size of the message.  You should not expect the data is\n// terminated with '\\0'.\nGLOG_EXPORT void InstallFailureWriter(void (*writer)(const char* data,\n                                                     size_t size));\n\n// Dump stack trace as a string.\nGLOG_EXPORT std::string GetStackTrace();\n\n}  // namespace google\n\n#endif  // GLOG_LOGGING_H\n"
  },
  {
    "path": "src/glog/platform.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Shinichiro Hamaji\n//\n// Detect supported platforms.\n\n#ifndef GLOG_PLATFORM_H\n#define GLOG_PLATFORM_H\n\n#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)\n#  define GLOG_OS_WINDOWS\n#elif defined(__CYGWIN__) || defined(__CYGWIN32__)\n#  define GLOG_OS_CYGWIN\n#elif defined(linux) || defined(__linux) || defined(__linux__)\n#  define GLOG_OS_LINUX\n#  if defined(__ANDROID__)\n#    define GLOG_OS_ANDROID\n#  endif\n#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)\n#  define GLOG_OS_MACOSX\n#elif defined(__FreeBSD__)\n#  define GLOG_OS_FREEBSD\n#elif defined(__NetBSD__)\n#  define GLOG_OS_NETBSD\n#elif defined(__OpenBSD__)\n#  define GLOG_OS_OPENBSD\n#elif defined(__EMSCRIPTEN__)\n#  define GLOG_OS_EMSCRIPTEN\n#else\n// TODO(hamaji): Add other platforms.\n#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.\n#endif\n\n#endif  // GLOG_PLATFORM_H\n"
  },
  {
    "path": "src/glog/raw_logging.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Maxim Lifantsev\n//\n// Thread-safe logging routines that do not allocate any memory or\n// acquire any locks, and can therefore be used by low-level memory\n// allocation and synchronization code.\n\n#ifndef GLOG_RAW_LOGGING_H\n#define GLOG_RAW_LOGGING_H\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_EXPORT)\n#  error <glog/raw_logging.h> was not included correctly. See the documentation for how to consume the library.\n#endif\n\n#include \"glog/log_severity.h\"\n#include \"glog/vlog_is_on.h\"\n\nnamespace google {\n\n// This is similar to LOG(severity) << format... and VLOG(level) << format..,\n// but\n// * it is to be used ONLY by low-level modules that can't use normal LOG()\n// * it is desiged to be a low-level logger that does not allocate any\n//   memory and does not need any locks, hence:\n// * it logs straight and ONLY to STDERR w/o buffering\n// * it uses an explicit format and arguments list\n// * it will silently chop off really long message strings\n// Usage example:\n//   RAW_LOG(ERROR, \"Failed foo with %i: %s\", status, error);\n//   RAW_VLOG(3, \"status is %i\", status);\n// These will print an almost standard log lines like this to stderr only:\n//   E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file\n//   I20200821 211317 file.cc:142] RAW: status is 20\n#define RAW_LOG(severity, ...)         \\\n  do {                                 \\\n    switch (google::GLOG_##severity) { \\\n      case 0:                          \\\n        RAW_LOG_INFO(__VA_ARGS__);     \\\n        break;                         \\\n      case 1:                          \\\n        RAW_LOG_WARNING(__VA_ARGS__);  \\\n        break;                         \\\n      case 2:                          \\\n        RAW_LOG_ERROR(__VA_ARGS__);    \\\n        break;                         \\\n      case 3:                          \\\n        RAW_LOG_FATAL(__VA_ARGS__);    \\\n        break;                         \\\n      default:                         \\\n        break;                         \\\n    }                                  \\\n  } while (0)\n\n// The following STRIP_LOG testing is performed in the header file so that it's\n// possible to completely compile out the logging code and the log messages.\n#if !defined(STRIP_LOG) || STRIP_LOG == 0\n#  define RAW_VLOG(verboselevel, ...) \\\n    do {                              \\\n      if (VLOG_IS_ON(verboselevel)) { \\\n        RAW_LOG_INFO(__VA_ARGS__);    \\\n      }                               \\\n    } while (0)\n#else\n#  define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)\n#endif  // STRIP_LOG == 0\n\n#if !defined(STRIP_LOG) || STRIP_LOG == 0\n#  define RAW_LOG_INFO(...) \\\n    google::RawLog__(google::GLOG_INFO, __FILE__, __LINE__, __VA_ARGS__)\n#else\n#  define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)\n#endif  // STRIP_LOG == 0\n\n#if !defined(STRIP_LOG) || STRIP_LOG <= 1\n#  define RAW_LOG_WARNING(...) \\\n    google::RawLog__(google::GLOG_WARNING, __FILE__, __LINE__, __VA_ARGS__)\n#else\n#  define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)\n#endif  // STRIP_LOG <= 1\n\n#if !defined(STRIP_LOG) || STRIP_LOG <= 2\n#  define RAW_LOG_ERROR(...) \\\n    google::RawLog__(google::GLOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)\n#else\n#  define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)\n#endif  // STRIP_LOG <= 2\n\n#if !defined(STRIP_LOG) || STRIP_LOG <= 3\n#  define RAW_LOG_FATAL(...) \\\n    google::RawLog__(google::GLOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)\n#else\n#  define RAW_LOG_FATAL(...)                \\\n    do {                                    \\\n      google::RawLogStub__(0, __VA_ARGS__); \\\n      exit(EXIT_FAILURE);                   \\\n    } while (0)\n#endif  // STRIP_LOG <= 3\n\n// Similar to CHECK(condition) << message,\n// but for low-level modules: we use only RAW_LOG that does not allocate memory.\n// We do not want to provide args list here to encourage this usage:\n//   if (!cond)  RAW_LOG(FATAL, \"foo ...\", hard_to_compute_args);\n// so that the args are not computed when not needed.\n#define RAW_CHECK(condition, message)                             \\\n  do {                                                            \\\n    if (!(condition)) {                                           \\\n      RAW_LOG(FATAL, \"Check %s failed: %s\", #condition, message); \\\n    }                                                             \\\n  } while (0)\n\n// Debug versions of RAW_LOG and RAW_CHECK\n#ifndef NDEBUG\n\n#  define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)\n#  define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)\n\n#else  // NDEBUG\n\n#  define RAW_DLOG(severity, ...) \\\n    while (false) RAW_LOG(severity, __VA_ARGS__)\n#  define RAW_DCHECK(condition, message) \\\n    while (false) RAW_CHECK(condition, message)\n\n#endif  // NDEBUG\n\n// Stub log function used to work around for unused variable warnings when\n// building with STRIP_LOG > 0.\nstatic inline void RawLogStub__(int /* ignored */, ...) {}\n\n// Helper function to implement RAW_LOG and RAW_VLOG\n// Logs format... at \"severity\" level, reporting it\n// as called from file:line.\n// This does not allocate memory or acquire locks.\nGLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,\n                          const char* format, ...)\n#if defined(__has_attribute)\n#  if __has_attribute(used)\n    __attribute__((__format__(__printf__, 4, 5)))\n#  endif\n#endif\n    ;\n}  // namespace google\n\n#endif  // GLOG_RAW_LOGGING_H\n"
  },
  {
    "path": "src/glog/stl_logging.h",
    "content": "// Copyright (c) 2023, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Stream output operators for STL containers; to be used for logging *only*.\n// Inclusion of this file lets you do:\n//\n// list<string> x;\n// LOG(INFO) << \"data: \" << x;\n// vector<int> v1, v2;\n// CHECK_EQ(v1, v2);\n//\n\n#ifndef GLOG_STL_LOGGING_H\n#define GLOG_STL_LOGGING_H\n\n#include <deque>\n#include <list>\n#include <map>\n#include <ostream>\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n#include <utility>\n#include <vector>\n\n// Forward declare these two, and define them after all the container streams\n// operators so that we can recurse from pair -> container -> container -> pair\n// properly.\ntemplate <class First, class Second>\nstd::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);\n\nnamespace google {\n\ntemplate <class Iter>\nvoid PrintSequence(std::ostream& out, Iter begin, Iter end);\n\n}\n#define OUTPUT_TWO_ARG_CONTAINER(Sequence)                       \\\n  template <class T1, class T2>                                  \\\n  inline std::ostream& operator<<(std::ostream& out,             \\\n                                  const Sequence<T1, T2>& seq) { \\\n    google::PrintSequence(out, seq.begin(), seq.end());          \\\n    return out;                                                  \\\n  }\n\nOUTPUT_TWO_ARG_CONTAINER(std::vector)\nOUTPUT_TWO_ARG_CONTAINER(std::deque)\nOUTPUT_TWO_ARG_CONTAINER(std::list)\n#undef OUTPUT_TWO_ARG_CONTAINER\n\n#define OUTPUT_THREE_ARG_CONTAINER(Sequence)                         \\\n  template <class T1, class T2, class T3>                            \\\n  inline std::ostream& operator<<(std::ostream& out,                 \\\n                                  const Sequence<T1, T2, T3>& seq) { \\\n    google::PrintSequence(out, seq.begin(), seq.end());              \\\n    return out;                                                      \\\n  }\n\nOUTPUT_THREE_ARG_CONTAINER(std::set)\nOUTPUT_THREE_ARG_CONTAINER(std::multiset)\n\n#undef OUTPUT_THREE_ARG_CONTAINER\n\n#define OUTPUT_FOUR_ARG_CONTAINER(Sequence)                              \\\n  template <class T1, class T2, class T3, class T4>                      \\\n  inline std::ostream& operator<<(std::ostream& out,                     \\\n                                  const Sequence<T1, T2, T3, T4>& seq) { \\\n    google::PrintSequence(out, seq.begin(), seq.end());                  \\\n    return out;                                                          \\\n  }\n\nOUTPUT_FOUR_ARG_CONTAINER(std::map)\nOUTPUT_FOUR_ARG_CONTAINER(std::multimap)\nOUTPUT_FOUR_ARG_CONTAINER(std::unordered_set)\nOUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset)\n#undef OUTPUT_FOUR_ARG_CONTAINER\n\n#define OUTPUT_FIVE_ARG_CONTAINER(Sequence)                                  \\\n  template <class T1, class T2, class T3, class T4, class T5>                \\\n  inline std::ostream& operator<<(std::ostream& out,                         \\\n                                  const Sequence<T1, T2, T3, T4, T5>& seq) { \\\n    google::PrintSequence(out, seq.begin(), seq.end());                      \\\n    return out;                                                              \\\n  }\n\nOUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)\nOUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap)\n\n#undef OUTPUT_FIVE_ARG_CONTAINER\n\ntemplate <class First, class Second>\ninline std::ostream& operator<<(std::ostream& out,\n                                const std::pair<First, Second>& p) {\n  out << '(' << p.first << \", \" << p.second << ')';\n  return out;\n}\n\nnamespace google {\n\ntemplate <class Iter>\ninline void PrintSequence(std::ostream& out, Iter begin, Iter end) {\n  // Output at most 100 elements -- appropriate if used for logging.\n  for (int i = 0; begin != end && i < 100; ++i, ++begin) {\n    if (i > 0) out << ' ';\n    out << *begin;\n  }\n  if (begin != end) {\n    out << \" ...\";\n  }\n}\n\n}  // namespace google\n\n// Note that this is technically undefined behavior! We are adding things into\n// the std namespace for a reason though -- we are providing new operations on\n// types which are themselves defined with this namespace. Without this, these\n// operator overloads cannot be found via ADL. If these definitions are not\n// found via ADL, they must be #included before they're used, which requires\n// this header to be included before apparently independent other headers.\n//\n// For example, base/logging.h defines various template functions to implement\n// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails.\n// It does so via the function template MakeCheckOpValueString:\n//   template<class T>\n//   void MakeCheckOpValueString(strstream* ss, const T& v) {\n//     (*ss) << v;\n//   }\n// Because 'glog/logging.h' is included before 'glog/stl_logging.h',\n// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only\n// find these operator definitions via ADL.\n//\n// Even this solution has problems -- it may pull unintended operators into the\n// namespace as well, allowing them to also be found via ADL, and creating code\n// that only works with a particular order of includes. Long term, we need to\n// move all of the *definitions* into namespace std, bet we need to ensure no\n// one references them first. This lets us take that step. We cannot define them\n// in both because that would create ambiguous overloads when both are found.\nnamespace std {\nusing ::operator<<;\n}\n\n#endif  // GLOG_STL_LOGGING_H\n"
  },
  {
    "path": "src/glog/types.h",
    "content": "\n// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n\n#ifndef GLOG_TYPES_H\n#define GLOG_TYPES_H\n\n#include <cstddef>\n#include <cstdint>\n\nnamespace google {\n\nusing int32 = std::int32_t;\nusing uint32 = std::uint32_t;\nusing int64 = std::int64_t;\nusing uint64 = std::uint64_t;\n\n}  // namespace google\n\n#if defined(__has_feature)\n#  if __has_feature(thread_sanitizer)\n#    define GLOG_SANITIZE_THREAD 1\n#  endif\n#endif\n\n#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && \\\n    __SANITIZE_THREAD__\n#  define GLOG_SANITIZE_THREAD 1\n#endif\n\n#if defined(GLOG_SANITIZE_THREAD)\n#  define GLOG_IFDEF_THREAD_SANITIZER(X) X\n#else\n#  define GLOG_IFDEF_THREAD_SANITIZER(X)\n#endif\n\n#if defined(_MSC_VER)\n#  define GLOG_MSVC_PUSH_DISABLE_WARNING(n) \\\n    __pragma(warning(push)) __pragma(warning(disable : n))\n#  define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))\n#else\n#  define GLOG_MSVC_PUSH_DISABLE_WARNING(n)\n#  define GLOG_MSVC_POP_WARNING()\n#endif\n\n#if defined(GLOG_SANITIZE_THREAD)\n// We need to identify the static variables as \"benign\" races\n// to avoid noisy reports from TSAN.\nextern \"C\" void AnnotateBenignRaceSized(const char* file, int line,\n                                        const volatile void* mem, size_t size,\n                                        const char* description);\n#endif  // defined(GLOG_SANITIZE_THREAD)\n\n#endif  // GLOG_TYPES_H\n"
  },
  {
    "path": "src/glog/vlog_is_on.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Ray Sidney and many others\n//\n// Defines the VLOG_IS_ON macro that controls the variable-verbosity\n// conditional logging.\n//\n// It's used by VLOG and VLOG_IF in logging.h\n// and by RAW_VLOG in raw_logging.h to trigger the logging.\n//\n// It can also be used directly e.g. like this:\n//   if (VLOG_IS_ON(2)) {\n//     // do some logging preparation and logging\n//     // that can't be accomplished e.g. via just VLOG(2) << ...;\n//   }\n//\n// The truth value that VLOG_IS_ON(level) returns is determined by\n// the three verbosity level flags:\n//   --v=<n>  Gives the default maximal active V-logging level;\n//            0 is the default.\n//            Normally positive values are used for V-logging levels.\n//   --vmodule=<str>  Gives the per-module maximal V-logging levels to override\n//                    the value given by --v.\n//                    E.g. \"my_module=2,foo*=3\" would change the logging level\n//                    for all code in source files \"my_module.*\" and \"foo*.*\"\n//                    (\"-inl\" suffixes are also disregarded for this matching).\n//\n// SetVLOGLevel helper function is provided to do limited dynamic control over\n// V-logging by overriding the per-module settings given via --vmodule flag.\n//\n// CAVEAT: --vmodule functionality is not available in non gcc compilers.\n//\n\n#ifndef GLOG_VLOG_IS_ON_H\n#define GLOG_VLOG_IS_ON_H\n\n#include <cstddef>\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_EXPORT)\n#  error <glog/vlog_is_on.h> was not included correctly. See the documentation for how to consume the library.\n#endif\n\n#include \"glog/flags.h\"\n#include \"glog/types.h\"\n\n#if defined(__GNUC__)\n// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.\n// (Normally) the first time every VLOG_IS_ON(n) site is hit,\n// we determine what variable will dynamically control logging at this site:\n// it's either FLAGS_v or an appropriate internal variable\n// matching the current source file that represents results of\n// parsing of --vmodule flag and/or SetVLOGLevel calls.\n#  define VLOG_IS_ON(verboselevel)                                       \\\n    __extension__({                                                      \\\n      static google::SiteFlag vlocal__ = {nullptr, nullptr, 0, nullptr}; \\\n      GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(               \\\n          __FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), \"\")); \\\n      google::int32 verbose_level__ = (verboselevel);                    \\\n      (vlocal__.level == nullptr                                         \\\n           ? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__,          \\\n                                 verbose_level__)                        \\\n           : *vlocal__.level >= verbose_level__);                        \\\n    })\n#else\n// GNU extensions not available, so we do not support --vmodule.\n// Dynamic value of FLAGS_v always controls the logging level.\n#  define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))\n#endif\n\nnamespace google {\n\n// Set VLOG(_IS_ON) level for module_pattern to log_level.\n// This lets us dynamically control what is normally set by the --vmodule flag.\n// Returns the level that previously applied to module_pattern.\n// NOTE: To change the log level for VLOG(_IS_ON) sites\n//\t that have already executed after/during InitGoogleLogging,\n//\t one needs to supply the exact --vmodule pattern that applied to them.\n//       (If no --vmodule pattern applied to them\n//       the value of FLAGS_v will continue to control them.)\nextern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level);\n\n// Various declarations needed for VLOG_IS_ON above: =========================\n\nstruct SiteFlag {\n  int32* level;\n  const char* base_name;\n  std::size_t base_len;\n  SiteFlag* next;\n};\n\n// Helper routine which determines the logging info for a particular VLOG site.\n//   site_flag     is the address of the site-local pointer to the controlling\n//                 verbosity level\n//   site_default  is the default to use for *site_flag\n//   fname         is the current source file name\n//   verbose_level is the argument to VLOG_IS_ON\n// We will return the return value for VLOG_IS_ON\n// and if possible set *site_flag appropriately.\nextern GLOG_EXPORT bool InitVLOG3__(SiteFlag* site_flag,\n                                    int32* site_default,\n                                    const char* fname,\n                                    int32 verbose_level);\n} // namespace google\n\n#endif  // GLOG_VLOG_IS_ON_H\n"
  },
  {
    "path": "src/googletest.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Shinichiro Hamaji\n//   (based on googletest: http://code.google.com/p/googletest/)\n\n#ifdef GOOGLETEST_H__\n#  error You must not include this file twice.\n#endif\n#define GOOGLETEST_H__\n\n#include <fcntl.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n\n#include <cctype>\n#include <csetjmp>\n#include <cstdio>\n#include <cstdlib>\n#include <ctime>\n#include <map>\n#include <new>\n#include <sstream>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include \"config.h\"\n#ifdef HAVE_UNISTD_H\n#  include <unistd.h>\n#endif\n\n#if defined(GLOG_USE_WINDOWS_PORT)\n#  include \"port.h\"\n#endif  // defined(GLOG_USE_WINDOWS_PORT)\n#include \"base/commandlineflags.h\"\n#include \"utilities.h\"\n\n#if __cplusplus < 201103L && !defined(_MSC_VER)\n#  define GOOGLE_GLOG_THROW_BAD_ALLOC throw(std::bad_alloc)\n#else\n#  define GOOGLE_GLOG_THROW_BAD_ALLOC\n#endif\n\nusing std::map;\nusing std::string;\nusing std::vector;\n\nnamespace google {\nextern void (*g_logging_fail_func)();\nextern void GetExistingTempDirectories(std::vector<std::string>& list);\nextern int posix_strerror_r(int err, char* buf, size_t len);\nextern std::string StrError(int err);\n}  // namespace google\n\n#undef GLOG_EXPORT\n#define GLOG_EXPORT\n\nstatic inline string GetTempDir() {\n  vector<string> temp_directories_list;\n  google::GetExistingTempDirectories(temp_directories_list);\n\n  if (temp_directories_list.empty()) {\n    fprintf(stderr, \"No temporary directory found\\n\");\n    exit(EXIT_FAILURE);\n  }\n\n  // Use first directory from list of existing temporary directories.\n  return temp_directories_list.front();\n}\n\n#if defined(GLOG_OS_WINDOWS) && defined(_MSC_VER) && !defined(TEST_SRC_DIR)\n// The test will run in glog/vsproject/<project name>\n// (e.g., glog/vsproject/logging_unittest).\nstatic const char TEST_SRC_DIR[] = \"../..\";\n#elif !defined(TEST_SRC_DIR)\n#  warning TEST_SRC_DIR should be defined in config.h\nstatic const char TEST_SRC_DIR[] = \".\";\n#endif\n\nstatic const uint32_t PTR_TEST_VALUE = 0x12345678;\n\nDEFINE_string(test_tmpdir, GetTempDir(), \"Dir we use for temp files\");\nDEFINE_string(test_srcdir, TEST_SRC_DIR,\n              \"Source-dir root, needed to find glog_unittest_flagfile\");\nDEFINE_bool(run_benchmark, false, \"If true, run benchmarks\");\n#ifdef NDEBUG\nDEFINE_int32(benchmark_iters, 100000000, \"Number of iterations per benchmark\");\n#else\nDEFINE_int32(benchmark_iters, 100000, \"Number of iterations per benchmark\");\n#endif\n\n#ifdef HAVE_LIB_GTEST\n#  include <gtest/gtest.h>\n// Use our ASSERT_DEATH implementation.\n#  undef ASSERT_DEATH\n#  undef ASSERT_DEBUG_DEATH\nusing testing::InitGoogleTest;\n#else\n\nnamespace google {\n\nvoid InitGoogleTest(int*, char**);\n\nvoid InitGoogleTest(int*, char**) {}\n\n// The following is some bare-bones testing infrastructure\n\n#  define EXPECT_NEAR(val1, val2, abs_error)                         \\\n    do {                                                             \\\n      if (abs(val1 - val2) > abs_error) {                            \\\n        fprintf(stderr, \"Check failed: %s within %s of %s\\n\", #val1, \\\n                #abs_error, #val2);                                  \\\n        exit(EXIT_FAILURE);                                          \\\n      }                                                              \\\n    } while (0)\n\n#  define EXPECT_TRUE(cond)                           \\\n    do {                                              \\\n      if (!(cond)) {                                  \\\n        fprintf(stderr, \"Check failed: %s\\n\", #cond); \\\n        exit(EXIT_FAILURE);                           \\\n      }                                               \\\n    } while (0)\n\n#  define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))\n\n#  define EXPECT_OP(op, val1, val2)                                     \\\n    do {                                                                \\\n      if (!((val1)op(val2))) {                                          \\\n        fprintf(stderr, \"Check failed: %s %s %s\\n\", #val1, #op, #val2); \\\n        exit(EXIT_FAILURE);                                             \\\n      }                                                                 \\\n    } while (0)\n\n#  define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)\n#  define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)\n#  define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)\n#  define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)\n\n#  define EXPECT_NAN(arg)                                   \\\n    do {                                                    \\\n      if (!isnan(arg)) {                                    \\\n        fprintf(stderr, \"Check failed: isnan(%s)\\n\", #arg); \\\n        exit(EXIT_FAILURE);                                 \\\n      }                                                     \\\n    } while (0)\n\n#  define EXPECT_INF(arg)                                   \\\n    do {                                                    \\\n      if (!isinf(arg)) {                                    \\\n        fprintf(stderr, \"Check failed: isinf(%s)\\n\", #arg); \\\n        exit(EXIT_FAILURE);                                 \\\n      }                                                     \\\n    } while (0)\n\n#  define EXPECT_DOUBLE_EQ(val1, val2)                             \\\n    do {                                                           \\\n      if (((val1) < (val2)-0.001 || (val1) > (val2) + 0.001)) {    \\\n        fprintf(stderr, \"Check failed: %s == %s\\n\", #val1, #val2); \\\n        exit(EXIT_FAILURE);                                        \\\n      }                                                            \\\n    } while (0)\n\n#  define EXPECT_STREQ(val1, val2)                                      \\\n    do {                                                                \\\n      if (strcmp((val1), (val2)) != 0) {                                \\\n        fprintf(stderr, \"Check failed: streq(%s, %s)\\n\", #val1, #val2); \\\n        exit(EXIT_FAILURE);                                             \\\n      }                                                                 \\\n    } while (0)\n\n#  define EXPECT_THROW(statement, exception)                    \\\n    do {                                                        \\\n      try {                                                     \\\n        statement;                                              \\\n      } catch (const exception&) {                              \\\n        printf(\"ok\\n\");                                         \\\n      } catch (...) {                                           \\\n        fprintf(stderr, \"%s\\n\", \"Unexpected exception thrown\"); \\\n        exit(EXIT_FAILURE);                                     \\\n      }                                                         \\\n    } while (0)\n\nvector<void (*)()> g_testlist;  // the tests to run\n#  define TEST(a, b)                                   \\\n    struct Test_##a##_##b {                            \\\n      Test_##a##_##b() { g_testlist.push_back(&Run); } \\\n      static void Run() {                              \\\n        FlagSaver fs;                                  \\\n        RunTest();                                     \\\n      }                                                \\\n      static void RunTest();                           \\\n    };                                                 \\\n    static Test_##a##_##b g_test_##a##_##b;            \\\n    void Test_##a##_##b::RunTest()\n\nstatic inline int RUN_ALL_TESTS() {\n  vector<void (*)()>::const_iterator it;\n  for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {\n    (*it)();\n  }\n  fprintf(stderr, \"Passed %d tests\\n\\nPASS\\n\",\n          static_cast<int>(g_testlist.size()));\n  return 0;\n}\n\n}  // namespace google\n\n#endif  // ! HAVE_LIB_GTEST\n\nnamespace google {\n\nstatic bool g_called_abort;\nstatic jmp_buf g_jmp_buf;\nstatic inline void CalledAbort() {\n  g_called_abort = true;\n  longjmp(g_jmp_buf, 1);\n}\n\n#ifdef GLOG_OS_WINDOWS\n// TODO(hamaji): Death test somehow doesn't work in Windows.\n#  define ASSERT_DEATH(fn, msg)\n#else\n#  define ASSERT_DEATH(fn, msg)                                      \\\n    do {                                                             \\\n      g_called_abort = false;                                        \\\n      /* in logging.cc */                                            \\\n      void (*original_logging_fail_func)() = g_logging_fail_func;    \\\n      g_logging_fail_func = &CalledAbort;                            \\\n      if (!setjmp(g_jmp_buf)) fn;                                    \\\n      /* set back to their default */                                \\\n      g_logging_fail_func = original_logging_fail_func;              \\\n      if (!g_called_abort) {                                         \\\n        fprintf(stderr, \"Function didn't die (%s): %s\\n\", msg, #fn); \\\n        exit(EXIT_FAILURE);                                          \\\n      }                                                              \\\n    } while (0)\n#endif\n\n#ifdef NDEBUG\n#  define ASSERT_DEBUG_DEATH(fn, msg)\n#else\n#  define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)\n#endif  // NDEBUG\n\n// Benchmark tools.\n\n#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_##n(#n, &n);\n\nmap<string, void (*)(int)> g_benchlist;  // the benchmarks to run\n\nclass BenchmarkRegisterer {\n public:\n  BenchmarkRegisterer(const char* name, void (*function)(int iters)) {\n    EXPECT_TRUE(g_benchlist.insert(std::make_pair(name, function)).second);\n  }\n};\n\nstatic inline void RunSpecifiedBenchmarks() {\n  if (!FLAGS_run_benchmark) {\n    return;\n  }\n\n  int iter_cnt = FLAGS_benchmark_iters;\n  puts(\"Benchmark\\tTime(ns)\\tIterations\");\n  for (auto& iter : g_benchlist) {\n    clock_t start = clock();\n    iter.second(iter_cnt);\n    double elapsed_ns = (static_cast<double>(clock()) - start) /\n                        CLOCKS_PER_SEC * 1000 * 1000 * 1000;\n#if defined(__GNUC__) && !defined(__clang__)\n#  pragma GCC diagnostic push\n#  pragma GCC diagnostic ignored \"-Wformat=\"\n#endif\n    printf(\"%s\\t%8.2lf\\t%10d\\n\", iter.first.c_str(), elapsed_ns / iter_cnt,\n           iter_cnt);\n#if defined(__GNUC__) && !defined(__clang__)\n#  pragma GCC diagnostic pop\n#endif\n  }\n  puts(\"\");\n}\n\n// ----------------------------------------------------------------------\n// Golden file functions\n// ----------------------------------------------------------------------\n\nclass CapturedStream {\n public:\n  CapturedStream(int fd, string filename)\n      : fd_(fd), filename_(std::move(filename)) {\n    Capture();\n  }\n\n  // Start redirecting output to a file\n  void Capture() {\n    // Keep original stream for later\n    CHECK(!uncaptured_fd_) << \", Stream \" << fd_ << \" already captured!\";\n    uncaptured_fd_.reset(dup(fd_));\n    CHECK(uncaptured_fd_);\n\n    // Open file to save stream to\n    FileDescriptor cap_fd{open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY,\n                               S_IRUSR | S_IWUSR)};\n    CHECK(cap_fd);\n\n    // Send stdout/stderr to this file\n    fflush(nullptr);\n    CHECK(dup2(cap_fd.get(), fd_) != -1);\n    CHECK(cap_fd.close() != -1);\n  }\n\n  // Remove output redirection\n  void StopCapture() {\n    // Restore original stream\n    if (uncaptured_fd_) {\n      fflush(nullptr);\n      CHECK(dup2(uncaptured_fd_.get(), fd_) != -1);\n    }\n  }\n\n  const string& filename() const { return filename_; }\n\n private:\n  int fd_;  // file descriptor being captured\n  FileDescriptor\n      uncaptured_fd_;  // where the stream was originally being sent to\n  string filename_;    // file where stream is being saved\n};\nstatic std::map<int, std::unique_ptr<CapturedStream>> s_captured_streams;\n// Redirect a file descriptor to a file.\n//   fd       - Should be stdout or stderr\n//   filename - File where output should be stored\nstatic inline void CaptureTestOutput(int fd, const string& filename) {\n  CHECK((fd == fileno(stdout)) || (fd == fileno(stderr)));\n  CHECK(s_captured_streams.find(fd) == s_captured_streams.end());\n  s_captured_streams[fd] = std::make_unique<CapturedStream>(fd, filename);\n}\nstatic inline void CaptureTestStdout() {\n  CaptureTestOutput(fileno(stdout), FLAGS_test_tmpdir + \"/captured.out\");\n}\nstatic inline void CaptureTestStderr() {\n  CaptureTestOutput(fileno(stderr), FLAGS_test_tmpdir + \"/captured.err\");\n}\n// Return the size (in bytes) of a file\nstatic inline size_t GetFileSize(FILE* file) {\n  fseek(file, 0, SEEK_END);\n  return static_cast<size_t>(ftell(file));\n}\n// Read the entire content of a file as a string\nstatic inline string ReadEntireFile(FILE* file) {\n  const size_t file_size = GetFileSize(file);\n  std::vector<char> content(file_size);\n\n  size_t bytes_last_read = 0;  // # of bytes read in the last fread()\n  size_t bytes_read = 0;       // # of bytes read so far\n\n  fseek(file, 0, SEEK_SET);\n\n  // Keep reading the file until we cannot read further or the\n  // pre-determined file size is reached.\n  do {\n    bytes_last_read =\n        fread(content.data() + bytes_read, 1, file_size - bytes_read, file);\n    bytes_read += bytes_last_read;\n  } while (bytes_last_read > 0 && bytes_read < file_size);\n\n  return std::string(content.data(), bytes_read);\n}\n// Get the captured stdout  or stderr as a string\nstatic inline string GetCapturedTestOutput(int fd) {\n  CHECK((fd == fileno(stdout)) || (fd == fileno(stderr)));\n  std::unique_ptr<CapturedStream> cap = std::move(s_captured_streams.at(fd));\n  s_captured_streams.erase(fd);\n  CHECK(cap) << \": did you forget CaptureTestStdout() or CaptureTestStderr()?\";\n\n  // Make sure everything is flushed.\n  cap->StopCapture();\n\n  // Read the captured file.\n  std::unique_ptr<FILE> file{fopen(cap->filename().c_str(), \"r\")};\n  const string content = ReadEntireFile(file.get());\n  file.reset();\n\n  return content;\n}\n// Get the captured stderr of a test as a string.\nstatic inline string GetCapturedTestStderr() {\n  return GetCapturedTestOutput(fileno(stderr));\n}\n\nstatic const std::size_t kLoggingPrefixLength = 9;\n\n// Check if the string is [IWEF](\\d{8}|YEARDATE)\nstatic inline bool IsLoggingPrefix(const string& s) {\n  if (s.size() != kLoggingPrefixLength) {\n    return false;\n  }\n  if (!strchr(\"IWEF\", s[0])) return false;\n  for (size_t i = 1; i <= 8; ++i) {\n    if (!isdigit(s[i]) && s[i] != \"YEARDATE\"[i - 1]) return false;\n  }\n  return true;\n}\n\n// Convert log output into normalized form.\n//\n// Example:\n//     I20200102 030405 logging_unittest.cc:345] RAW: vlog -1\n//  => IYEARDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1\nstatic inline string MungeLine(const string& line) {\n  string before, logcode_date, time, thread_lineinfo;\n  std::size_t begin_of_logging_prefix = 0;\n  for (; begin_of_logging_prefix + kLoggingPrefixLength < line.size();\n       ++begin_of_logging_prefix) {\n    if (IsLoggingPrefix(\n            line.substr(begin_of_logging_prefix, kLoggingPrefixLength))) {\n      break;\n    }\n  }\n  if (begin_of_logging_prefix + kLoggingPrefixLength >= line.size()) {\n    return line;\n  } else if (begin_of_logging_prefix > 0) {\n    before = line.substr(0, begin_of_logging_prefix - 1);\n  }\n  std::istringstream iss(line.substr(begin_of_logging_prefix));\n  iss >> logcode_date;\n  iss >> time;\n  iss >> thread_lineinfo;\n  CHECK(!thread_lineinfo.empty());\n  if (thread_lineinfo[thread_lineinfo.size() - 1] != ']') {\n    // We found thread ID.\n    string tmp;\n    iss >> tmp;\n    CHECK(!tmp.empty());\n    CHECK_EQ(']', tmp[tmp.size() - 1]);\n    thread_lineinfo = \"THREADID \" + tmp;\n  }\n  size_t index = thread_lineinfo.find(':');\n  CHECK_NE(string::npos, index);\n  thread_lineinfo = thread_lineinfo.substr(0, index + 1) + \"LINE]\";\n  string rest;\n  std::getline(iss, rest);\n  return (before + logcode_date[0] + \"YEARDATE TIME__ \" + thread_lineinfo +\n          MungeLine(rest));\n}\n\nstatic inline void StringReplace(string* str, const string& oldsub,\n                                 const string& newsub) {\n  size_t pos = str->find(oldsub);\n  if (pos != string::npos) {\n    str->replace(pos, oldsub.size(), newsub);\n  }\n}\n\nstatic inline string Munge(const string& filename) {\n  std::unique_ptr<FILE> fp{fopen(filename.c_str(), \"rb\")};\n  CHECK(fp != nullptr) << filename << \": couldn't open\";\n  char buf[4096];\n  string result;\n  while (fgets(buf, 4095, fp.get())) {\n    string line = MungeLine(buf);\n    const size_t str_size = 256;\n    char null_str[str_size];\n    char ptr_str[str_size];\n    std::snprintf(null_str, str_size, \"%p\", static_cast<void*>(nullptr));\n    std::snprintf(ptr_str, str_size, \"%p\",\n                  reinterpret_cast<void*>(PTR_TEST_VALUE));\n\n    StringReplace(&line, \"__NULLP__\", null_str);\n    StringReplace(&line, \"__PTRTEST__\", ptr_str);\n\n    StringReplace(&line, \"__SUCCESS__\", StrError(0));\n    StringReplace(&line, \"__ENOENT__\", StrError(ENOENT));\n    StringReplace(&line, \"__EINTR__\", StrError(EINTR));\n    StringReplace(&line, \"__ENXIO__\", StrError(ENXIO));\n    StringReplace(&line, \"__ENOEXEC__\", StrError(ENOEXEC));\n    result += line + \"\\n\";\n  }\n  return result;\n}\n\nstatic inline void WriteToFile(const string& body, const string& file) {\n  std::unique_ptr<FILE> fp{fopen(file.c_str(), \"wb\")};\n  fwrite(body.data(), 1, body.size(), fp.get());\n}\n\nstatic inline bool MungeAndDiffTest(const string& golden_filename,\n                                    CapturedStream* cap) {\n  auto pos = s_captured_streams.find(fileno(stdout));\n\n  if (pos != s_captured_streams.end() && cap == pos->second.get()) {\n    CHECK(cap) << \": did you forget CaptureTestStdout()?\";\n  } else {\n    CHECK(cap) << \": did you forget CaptureTestStderr()?\";\n  }\n\n  cap->StopCapture();\n\n  // Run munge\n  const string captured = Munge(cap->filename());\n  const string golden = Munge(golden_filename);\n  if (captured != golden) {\n    fprintf(stderr,\n            \"Test with golden file failed. We'll try to show the diff:\\n\");\n    string munged_golden = golden_filename + \".munged\";\n    WriteToFile(golden, munged_golden);\n    string munged_captured = cap->filename() + \".munged\";\n    WriteToFile(captured, munged_captured);\n#ifdef GLOG_OS_WINDOWS\n    string diffcmd(\"fc \" + munged_golden + \" \" + munged_captured);\n#else\n    string diffcmd(\"diff -u \" + munged_golden + \" \" + munged_captured);\n#endif\n    if (system(diffcmd.c_str()) != 0) {\n      fprintf(stderr, \"diff command was failed.\\n\");\n    }\n    unlink(munged_golden.c_str());\n    unlink(munged_captured.c_str());\n    return false;\n  }\n  LOG(INFO) << \"Diff was successful\";\n  return true;\n}\n\nstatic inline bool MungeAndDiffTestStderr(const string& golden_filename) {\n  return MungeAndDiffTest(golden_filename,\n                          s_captured_streams.at(fileno(stderr)).get());\n}\n\nstatic inline bool MungeAndDiffTestStdout(const string& golden_filename) {\n  return MungeAndDiffTest(golden_filename,\n                          s_captured_streams.at(fileno(stdout)).get());\n}\n\n// Save flags used from logging_unittest.cc.\n#ifndef GLOG_USE_GFLAGS\nstruct FlagSaver {\n  FlagSaver()\n      : v_(FLAGS_v),\n        stderrthreshold_(FLAGS_stderrthreshold),\n        logtostderr_(FLAGS_logtostderr),\n        alsologtostderr_(FLAGS_alsologtostderr),\n        logmailer_(FLAGS_logmailer) {}\n  ~FlagSaver() {\n    FLAGS_v = v_;\n    FLAGS_stderrthreshold = stderrthreshold_;\n    FLAGS_logtostderr = logtostderr_;\n    FLAGS_alsologtostderr = alsologtostderr_;\n    FLAGS_logmailer = logmailer_;\n  }\n  int v_;\n  int stderrthreshold_;\n  bool logtostderr_;\n  bool alsologtostderr_;\n  std::string logmailer_;\n};\n#endif\n\n// Add hook for operator new to ensure there are no memory allocation.\n\nvoid (*g_new_hook)() = nullptr;\n\n}  // namespace google\n\nvoid* operator new(size_t size, const std::nothrow_t&) noexcept {\n  if (google::g_new_hook) {\n    google::g_new_hook();\n  }\n  return malloc(size);\n}\n\nvoid* operator new(size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC {\n  void* p = ::operator new(size, std::nothrow);\n  if (p == nullptr) {\n    throw std::bad_alloc{};\n  }\n  return p;\n}\n\nvoid* operator new[](size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC {\n  return ::operator new(size);\n}\n\nvoid operator delete(void* p) noexcept { free(p); }\n\nvoid operator delete(void* p, size_t) noexcept { ::operator delete(p); }\n\nvoid operator delete[](void* p) noexcept { ::operator delete(p); }\n\nvoid operator delete[](void* p, size_t) noexcept { ::operator delete(p); }\n"
  },
  {
    "path": "src/includes_unittest/CMakeLists.txt",
    "content": "cmake_minimum_required (VERSION 3.16)\nproject (glog_includes LANGUAGES CXX)\n\nfind_package (glog REQUIRED NO_MODULE)\n\nadd_executable (glog_includes_logging glog_includes_logging.cc)\ntarget_link_libraries (glog_includes_logging PRIVATE glog::glog)\n\nadd_executable (glog_includes_vlog_is_on glog_includes_vlog_is_on.cc)\ntarget_link_libraries (glog_includes_vlog_is_on PRIVATE glog::glog)\n\nadd_executable (glog_includes_raw_logging glog_includes_raw_logging.cc)\ntarget_link_libraries (glog_includes_raw_logging PRIVATE glog::glog)\n\nadd_executable (glog_includes_stl_logging glog_includes_stl_logging.cc)\ntarget_link_libraries (glog_includes_stl_logging PRIVATE glog::glog)\n"
  },
  {
    "path": "src/includes_unittest/glog_includes_logging.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergiu Deitsch\n\n#include <glog/logging.h>\n\nint main() {\n  LOG(INFO) << \"info\";\n  LOG(WARNING) << \"warning\";\n  LOG(ERROR) << \"error\";\n  LOG(FATAL) << \"fatal\";\n}\n"
  },
  {
    "path": "src/includes_unittest/glog_includes_raw_logging.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergiu Deitsch\n\n#include <glog/raw_logging.h>\n\nint main() {\n  RAW_LOG(INFO, \"info\");\n  RAW_LOG(WARNING, \"warning\");\n  RAW_LOG(ERROR, \"error\");\n  RAW_LOG(FATAL, \"fatal\");\n}\n"
  },
  {
    "path": "src/includes_unittest/glog_includes_stl_logging.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergiu Deitsch\n\n#include <glog/stl_logging.h>\n\nint main() {}\n"
  },
  {
    "path": "src/includes_unittest/glog_includes_vlog_is_on.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergiu Deitsch\n\n#include <glog/vlog_is_on.h>\n\nint main() { VLOG_IS_ON(0); }\n"
  },
  {
    "path": "src/log_severity_unittest/CMakeLists.txt",
    "content": "cmake_minimum_required (VERSION 3.16)\nproject (glog_log_severity LANGUAGES CXX)\n\nfind_package (glog REQUIRED NO_MODULE)\n\nadd_executable (glog_log_severity_constants glog_log_severity_constants.cc)\ntarget_link_libraries (glog_log_severity_constants PRIVATE glog::glog)\n\nadd_executable (glog_log_severity_conversion glog_log_severity_conversion.cc)\ntarget_link_libraries (glog_log_severity_conversion PRIVATE glog::glog)\n"
  },
  {
    "path": "src/log_severity_unittest/glog_log_severity_constants.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergiu Deitsch\n\n#include <glog/logging.h>\n\nint main() {\n  // Must not compile\n  LOG(0) << \"type unsafe info\";\n  LOG(1) << \"type unsafe info\";\n  LOG(2) << \"type unsafe info\";\n  LOG(3) << \"type unsafe info\";\n}\n"
  },
  {
    "path": "src/log_severity_unittest/glog_log_severity_conversion.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergiu Deitsch\n\n#include <glog/logging.h>\n\nint main() {\n  // Must not compile\n  google::LogMessage{__FILE__, __LINE__, -1};\n  // Cast to int to avoid implicit conversoin to nullptr\n  google::LogMessage{__FILE__, __LINE__, static_cast<int>(0)};\n  google::LogMessage{__FILE__, __LINE__, 1};\n  google::LogMessage{__FILE__, __LINE__, 2};\n  google::LogMessage{__FILE__, __LINE__, 3};\n}\n"
  },
  {
    "path": "src/logging.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#define _GNU_SOURCE 1  // needed for O_NOFOLLOW and pread()/pwrite()\n\n#include \"glog/logging.h\"\n\n#include <algorithm>\n#include <cassert>\n#include <chrono>\n#include <cstddef>\n#include <cstdint>\n#include <iomanip>\n#include <iterator>\n#include <memory>\n#include <mutex>\n#include <shared_mutex>\n#include <string>\n#include <thread>\n#include <tuple>\n#include <type_traits>\n#include <utility>\n\n#include \"config.h\"\n#include \"glog/platform.h\"\n#include \"glog/raw_logging.h\"\n#include \"stacktrace.h\"\n#include \"utilities.h\"\n\n#ifdef GLOG_OS_WINDOWS\n#  include \"windows/dirent.h\"\n#else\n#  include <dirent.h>  // for automatic removal of old logs\n#endif\n\n#include <fcntl.h>\n#include <sys/stat.h>\n\n#include <cctype>  // for std::isspace\n#include <cerrno>  // for errno\n#include <climits>\n#include <cstdarg>\n#include <cstdio>\n#include <cstdlib>\n#include <ctime>\n#include <regex>\n#include <sstream>\n#include <vector>\n\n#ifdef HAVE__CHSIZE_S\n#  include <io.h>  // for truncate log file\n#endif\n#ifdef HAVE_PWD_H\n#  include <pwd.h>\n#endif\n#ifdef HAVE_SYS_UTSNAME_H\n#  include <sys/utsname.h>  // For uname.\n#endif\n#ifdef HAVE_SYSLOG_H\n#  include <syslog.h>\n#endif\n\n#ifdef HAVE_SYS_TYPES_H\n#  include <sys/types.h>\n#endif\n\n#ifdef HAVE_UNISTD_H\n#  include <unistd.h>\n#endif\n\n#ifndef HAVE_MODE_T\ntypedef int mode_t;\n#endif\n\nusing std::dec;\nusing std::hex;\nusing std::min;\nusing std::ostream;\nusing std::ostringstream;\nusing std::setfill;\nusing std::setw;\nusing std::string;\nusing std::vector;\n\nusing std::fclose;\nusing std::fflush;\nusing std::FILE;\nusing std::fprintf;\nusing std::fwrite;\nusing std::perror;\n\n#ifdef __QNX__\nusing std::fdopen;\n#endif\n\n// There is no thread annotation support.\n#define EXCLUSIVE_LOCKS_REQUIRED(mu)\n\n// TODO(hamaji): consider windows\nenum { PATH_SEPARATOR = '/' };\n\n#ifndef HAVE_PREAD\nstatic ssize_t pread(int fd, void* buf, size_t count, off_t offset) {\n  off_t orig_offset = lseek(fd, 0, SEEK_CUR);\n  if (orig_offset == (off_t)-1) return -1;\n  if (lseek(fd, offset, SEEK_CUR) == (off_t)-1) return -1;\n  ssize_t len = read(fd, buf, count);\n  if (len < 0) return len;\n  if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1) return -1;\n  return len;\n}\n#endif  // !HAVE_PREAD\n\n#ifndef HAVE_PWRITE\nstatic ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {\n  off_t orig_offset = lseek(fd, 0, SEEK_CUR);\n  if (orig_offset == (off_t)-1) return -1;\n  if (lseek(fd, offset, SEEK_CUR) == (off_t)-1) return -1;\n  ssize_t len = write(fd, buf, count);\n  if (len < 0) return len;\n  if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1) return -1;\n  return len;\n}\n#endif  // !HAVE_PWRITE\n\nstatic void GetHostName(string* hostname) {\n#if defined(HAVE_SYS_UTSNAME_H)\n  struct utsname buf;\n  if (uname(&buf) < 0) {\n    // ensure null termination on failure\n    *buf.nodename = '\\0';\n  }\n  *hostname = buf.nodename;\n#elif defined(GLOG_OS_WINDOWS)\n  char buf[MAX_COMPUTERNAME_LENGTH + 1];\n  DWORD len = MAX_COMPUTERNAME_LENGTH + 1;\n  if (GetComputerNameA(buf, &len)) {\n    *hostname = buf;\n  } else {\n    hostname->clear();\n  }\n#else\n#  warning There is no way to retrieve the host name.\n  *hostname = \"(unknown)\";\n#endif\n}\n\n// Returns true iff terminal supports using colors in output.\nstatic bool TerminalSupportsColor() {\n  bool term_supports_color = false;\n#ifdef GLOG_OS_WINDOWS\n  // on Windows TERM variable is usually not set, but the console does\n  // support colors.\n  term_supports_color = true;\n#else\n  // On non-Windows platforms, we rely on the TERM variable.\n  const char* const term = getenv(\"TERM\");\n  if (term != nullptr && term[0] != '\\0') {\n    term_supports_color =\n        !strcmp(term, \"xterm\") || !strcmp(term, \"xterm-color\") ||\n        !strcmp(term, \"xterm-256color\") || !strcmp(term, \"screen-256color\") ||\n        !strcmp(term, \"konsole\") || !strcmp(term, \"konsole-16color\") ||\n        !strcmp(term, \"konsole-256color\") || !strcmp(term, \"screen\") ||\n        !strcmp(term, \"linux\") || !strcmp(term, \"cygwin\");\n  }\n#endif\n  return term_supports_color;\n}\n\n#if defined(__cpp_lib_unreachable) && (__cpp_lib_unreachable >= 202202L)\n#  define GLOG_UNREACHABLE std::unreachable()\n#elif !defined(NDEBUG)\n#  define GLOG_UNREACHABLE assert(false)\n#else\n#  if defined(_MSC_VER)\n#    define GLOG_UNREACHABLE __assume(false)\n#  elif defined(__has_builtin)\n#    if __has_builtin(unreachable)\n#      define GLOG_UNREACHABLE __builtin_unreachable()\n#    endif\n#  endif\n#  if !defined(GLOG_UNREACHABLE) && defined(__GNUG__)\n#    define GLOG_UNREACHABLE __builtin_unreachable()\n#  endif\n#  if !defined(GLOG_UNREACHABLE)\n#    define GLOG_UNREACHABLE\n#  endif\n#endif\n\nnamespace google {\n\nGLOG_NO_EXPORT\nstd::string StrError(int err);\n\nenum GLogColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW };\n\nstatic GLogColor SeverityToColor(LogSeverity severity) {\n  switch (severity) {\n    case GLOG_INFO:\n      return COLOR_DEFAULT;\n    case GLOG_WARNING:\n      return COLOR_YELLOW;\n    case GLOG_ERROR:\n    case GLOG_FATAL:\n      return COLOR_RED;\n  }\n\n  // should never get here.\n  GLOG_UNREACHABLE;\n}\n\n#ifdef GLOG_OS_WINDOWS\n\n// Returns the character attribute for the given color.\nstatic WORD GetColorAttribute(GLogColor color) {\n  switch (color) {\n    case COLOR_RED:\n      return FOREGROUND_RED;\n    case COLOR_GREEN:\n      return FOREGROUND_GREEN;\n    case COLOR_YELLOW:\n      return FOREGROUND_RED | FOREGROUND_GREEN;\n    case COLOR_DEFAULT:\n      break;\n  }\n  return 0;\n}\n\n#else\n\n// Returns the ANSI color code for the given color.\nstatic const char* GetAnsiColorCode(GLogColor color) {\n  switch (color) {\n    case COLOR_RED:\n      return \"1\";\n    case COLOR_GREEN:\n      return \"2\";\n    case COLOR_YELLOW:\n      return \"3\";\n    case COLOR_DEFAULT:\n      return \"\";\n  };\n  return nullptr;  // stop warning about return type.\n}\n\n#endif  // GLOG_OS_WINDOWS\n\n// Safely get max_log_size, overriding to 1 if it somehow gets defined as 0\nstatic uint32 MaxLogSize() {\n  return (FLAGS_max_log_size > 0 && FLAGS_max_log_size < 4096\n              ? FLAGS_max_log_size\n              : 1);\n}\n\n// An arbitrary limit on the length of a single log message.  This\n// is so that streaming can be done more efficiently.\nconst size_t LogMessage::kMaxLogMessageLen = 30000;\n\nnamespace logging {\nnamespace internal {\nstruct LogMessageData {\n  LogMessageData();\n\n  int preserved_errno_;  // preserved errno\n  // Buffer space; contains complete message text.\n  char message_text_[LogMessage::kMaxLogMessageLen + 1];\n  LogMessage::LogStream stream_;\n  LogSeverity severity_;  // What level is this LogMessage logged at?\n  int line_;              // line number where logging call is.\n  void (LogMessage::*send_method_)();  // Call this in destructor to send\n  union {  // At most one of these is used: union to keep the size low.\n    LogSink* sink_;  // nullptr or sink to send message to\n    std::vector<std::string>*\n        outvec_;            // nullptr or vector to push message onto\n    std::string* message_;  // nullptr or string to write message into\n  };\n  size_t num_prefix_chars_;     // # of chars of prefix in this message\n  size_t num_chars_to_log_;     // # of chars of msg to send to log\n  size_t num_chars_to_syslog_;  // # of chars of msg to send to syslog\n  const char* basename_;        // basename of file that called LOG\n  const char* fullname_;        // fullname of file that called LOG\n  bool has_been_flushed_;       // false => data has not been flushed\n  bool first_fatal_;            // true => this was first fatal msg\n  std::thread::id thread_id_;\n\n  LogMessageData(const LogMessageData&) = delete;\n  LogMessageData& operator=(const LogMessageData&) = delete;\n};\n}  // namespace internal\n}  // namespace logging\n\n// A mutex that allows only one thread to log at a time, to keep things from\n// getting jumbled.  Some other very uncommon logging operations (like\n// changing the destination file for log messages of a given severity) also\n// lock this mutex.  Please be sure that anybody who might possibly need to\n// lock it does so.\nstatic std::mutex log_mutex;\n\n// Number of messages sent at each severity.  Under log_mutex.\nint64 LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};\n\n// Globally disable log writing (if disk is full)\nstatic bool stop_writing = false;\n\nconst char* const LogSeverityNames[] = {\"INFO\", \"WARNING\", \"ERROR\", \"FATAL\"};\n\n// Has the user called SetExitOnDFatal(true)?\nstatic bool exit_on_dfatal = true;\n\nconst char* GetLogSeverityName(LogSeverity severity) {\n  return LogSeverityNames[severity];\n}\n\nstatic bool SendEmailInternal(const char* dest, const char* subject,\n                              const char* body, bool use_logging);\n\nbase::Logger::~Logger() = default;\n\nnamespace {\n\nconstexpr std::intmax_t kSecondsInDay = 60 * 60 * 24;\nconstexpr std::intmax_t kSecondsInWeek = kSecondsInDay * 7;\n\n// Optional user-configured callback to print custom prefixes.\nclass PrefixFormatter {\n public:\n  PrefixFormatter(PrefixFormatterCallback callback, void* data) noexcept\n      : version{V2}, callback_v2{callback}, data{data} {}\n\n  void operator()(std::ostream& s, const LogMessage& message) const {\n    switch (version) {\n      case V2:\n        callback_v2(s, message, data);\n        break;\n    }\n  }\n\n  PrefixFormatter(const PrefixFormatter& other) = delete;\n  PrefixFormatter& operator=(const PrefixFormatter& other) = delete;\n\n private:\n  enum Version { V2 } version;\n  union {\n    PrefixFormatterCallback callback_v2;\n  };\n  // User-provided data to pass to the callback:\n  void* data;\n};\n\nstd::unique_ptr<PrefixFormatter> g_prefix_formatter;\n\n// Encapsulates all file-system related state\nclass LogFileObject : public base::Logger {\n public:\n  LogFileObject(LogSeverity severity, const char* base_filename);\n  ~LogFileObject() override;\n\n  void Write(bool force_flush,  // Should we force a flush here?\n             const std::chrono::system_clock::time_point&\n                 timestamp,  // Timestamp for this entry\n             const char* message, size_t message_len) override;\n\n  // Configuration options\n  void SetBasename(const char* basename);\n  void SetExtension(const char* ext);\n  void SetSymlinkBasename(const char* symlink_basename);\n\n  // Normal flushing routine\n  void Flush() override;\n\n  // It is the actual file length for the system loggers,\n  // i.e., INFO, ERROR, etc.\n  uint32 LogSize() override {\n    std::lock_guard<std::mutex> l{mutex_};\n    return file_length_;\n  }\n\n  // Internal flush routine.  Exposed so that FlushLogFilesUnsafe()\n  // can avoid grabbing a lock.  Usually Flush() calls it after\n  // acquiring lock_.\n  void FlushUnlocked(const std::chrono::system_clock::time_point& now);\n\n private:\n  static const uint32 kRolloverAttemptFrequency = 0x20;\n\n  std::mutex mutex_;\n  bool base_filename_selected_;\n  string base_filename_;\n  string symlink_basename_;\n  string filename_extension_;  // option users can specify (eg to add port#)\n  std::unique_ptr<FILE> file_;\n  LogSeverity severity_;\n  uint32 bytes_since_flush_{0};\n  uint32 dropped_mem_length_{0};\n  uint32 file_length_{0};\n  unsigned int rollover_attempt_;\n  std::chrono::system_clock::time_point\n      next_flush_time_;  // cycle count at which to flush log\n  std::chrono::system_clock::time_point start_time_;\n\n  // Actually create a logfile using the value of base_filename_ and the\n  // optional argument time_pid_string\n  // REQUIRES: lock_ is held\n  bool CreateLogfile(const string& time_pid_string);\n};\n\n// Encapsulate all log cleaner related states\nclass LogCleaner {\n public:\n  LogCleaner();\n\n  // Setting overdue to 0 days will delete all logs.\n  void Enable(const std::chrono::minutes& overdue);\n  void Disable();\n\n  void Run(const std::chrono::system_clock::time_point& current_time,\n           bool base_filename_selected, const string& base_filename,\n           const string& filename_extension);\n\n  bool enabled() const { return enabled_; }\n\n private:\n  vector<string> GetOverdueLogNames(\n      string log_directory,\n      const std::chrono::system_clock::time_point& current_time,\n      const string& base_filename, const string& filename_extension) const;\n\n  bool IsLogFromCurrentProject(const string& filepath,\n                               const string& base_filename,\n                               const string& filename_extension) const;\n\n  bool IsLogLastModifiedOver(\n      const string& filepath,\n      const std::chrono::system_clock::time_point& current_time) const;\n\n  bool enabled_{false};\n  std::chrono::minutes overdue_{\n      std::chrono::duration<int, std::ratio<kSecondsInWeek>>{1}};\n  std::chrono::system_clock::time_point\n      next_cleanup_time_;  // cycle count at which to clean overdue log\n};\n\nLogCleaner log_cleaner;\n\n}  // namespace\n\nclass LogDestination {\n public:\n  friend class LogMessage;\n  friend void ReprintFatalMessage();\n  friend base::Logger* base::GetLogger(LogSeverity);\n  friend void base::SetLogger(LogSeverity, base::Logger*);\n\n  // These methods are just forwarded to by their global versions.\n  static void SetLogDestination(LogSeverity severity,\n                                const char* base_filename);\n  static void SetLogSymlink(LogSeverity severity, const char* symlink_basename);\n  static void AddLogSink(LogSink* destination);\n  static void RemoveLogSink(LogSink* destination);\n  static void SetLogFilenameExtension(const char* filename_extension);\n  static void SetStderrLogging(LogSeverity min_severity);\n  static void SetEmailLogging(LogSeverity min_severity, const char* addresses);\n  static void LogToStderr();\n  // Flush all log files that are at least at the given severity level\n  static void FlushLogFiles(int min_severity);\n  static void FlushLogFilesUnsafe(int min_severity);\n\n  // we set the maximum size of our packet to be 1400, the logic being\n  // to prevent fragmentation.\n  // Really this number is arbitrary.\n  static const int kNetworkBytes = 1400;\n\n  static const string& hostname();\n  static const bool& terminal_supports_color() {\n    return terminal_supports_color_;\n  }\n\n  static void DeleteLogDestinations();\n  LogDestination(LogSeverity severity, const char* base_filename);\n\n private:\n#if defined(__cpp_lib_shared_mutex) && (__cpp_lib_shared_mutex >= 201505L)\n  // Use untimed shared mutex\n  using SinkMutex = std::shared_mutex;\n  using SinkLock = std::lock_guard<SinkMutex>;\n#else  // !(defined(__cpp_lib_shared_mutex) && (__cpp_lib_shared_mutex >=\n       // 201505L)) Fallback to timed shared mutex\n  using SinkMutex = std::shared_timed_mutex;\n  using SinkLock = std::unique_lock<SinkMutex>;\n#endif  // defined(__cpp_lib_shared_mutex) && (__cpp_lib_shared_mutex >=\n        // 201505L)\n\n  friend std::default_delete<LogDestination>;\n  ~LogDestination();\n\n  // Take a log message of a particular severity and log it to stderr\n  // iff it's of a high enough severity to deserve it.\n  static void MaybeLogToStderr(LogSeverity severity, const char* message,\n                               size_t message_len, size_t prefix_len);\n\n  // Take a log message of a particular severity and log it to email\n  // iff it's of a high enough severity to deserve it.\n  static void MaybeLogToEmail(LogSeverity severity, const char* message,\n                              size_t len);\n  // Take a log message of a particular severity and log it to a file\n  // iff the base filename is not \"\" (which means \"don't log to me\")\n  static void MaybeLogToLogfile(\n      LogSeverity severity,\n      const std::chrono::system_clock::time_point& timestamp,\n      const char* message, size_t len);\n  // Take a log message of a particular severity and log it to the file\n  // for that severity and also for all files with severity less than\n  // this severity.\n  static void LogToAllLogfiles(\n      LogSeverity severity,\n      const std::chrono::system_clock::time_point& timestamp,\n      const char* message, size_t len);\n\n  // Send logging info to all registered sinks.\n  static void LogToSinks(LogSeverity severity, const char* full_filename,\n                         const char* base_filename, int line,\n                         const LogMessageTime& time, const char* message,\n                         size_t message_len);\n\n  // Wait for all registered sinks via WaitTillSent\n  // including the optional one in \"data\".\n  static void WaitForSinks(logging::internal::LogMessageData* data);\n\n  static LogDestination* log_destination(LogSeverity severity);\n\n  base::Logger* GetLoggerImpl() const { return logger_; }\n  void SetLoggerImpl(base::Logger* logger);\n  void ResetLoggerImpl() { SetLoggerImpl(&fileobject_); }\n\n  LogFileObject fileobject_;\n  base::Logger* logger_;  // Either &fileobject_, or wrapper around it\n\n  static std::unique_ptr<LogDestination> log_destinations_[NUM_SEVERITIES];\n  static std::underlying_type_t<LogSeverity> email_logging_severity_;\n  static string addresses_;\n  static string hostname_;\n  static bool terminal_supports_color_;\n\n  // arbitrary global logging destinations.\n  static std::unique_ptr<vector<LogSink*>> sinks_;\n\n  // Protects the vector sinks_,\n  // but not the LogSink objects its elements reference.\n  static SinkMutex sink_mutex_;\n\n  // Disallow\n  LogDestination(const LogDestination&) = delete;\n  LogDestination& operator=(const LogDestination&) = delete;\n};\n\n// Errors do not get logged to email by default.\nstd::underlying_type_t<LogSeverity> LogDestination::email_logging_severity_ =\n    99999;\n\nstring LogDestination::addresses_;\nstring LogDestination::hostname_;\n\nstd::unique_ptr<vector<LogSink*>> LogDestination::sinks_;\nLogDestination::SinkMutex LogDestination::sink_mutex_;\nbool LogDestination::terminal_supports_color_ = TerminalSupportsColor();\n\n/* static */\nconst string& LogDestination::hostname() {\n  if (hostname_.empty()) {\n    GetHostName(&hostname_);\n    if (hostname_.empty()) {\n      hostname_ = \"(unknown)\";\n    }\n  }\n  return hostname_;\n}\n\nLogDestination::LogDestination(LogSeverity severity, const char* base_filename)\n    : fileobject_(severity, base_filename), logger_(&fileobject_) {}\n\nLogDestination::~LogDestination() { ResetLoggerImpl(); }\n\nvoid LogDestination::SetLoggerImpl(base::Logger* logger) {\n  if (logger_ == logger) {\n    // Prevent releasing currently held sink on reset\n    return;\n  }\n\n  if (logger_ && logger_ != &fileobject_) {\n    // Delete user-specified logger set via SetLogger().\n    delete logger_;\n  }\n  logger_ = logger;\n}\n\ninline void LogDestination::FlushLogFilesUnsafe(int min_severity) {\n  // assume we have the log_mutex or we simply don't care\n  // about it\n  std::for_each(std::next(std::begin(log_destinations_), min_severity),\n                std::end(log_destinations_),\n                [now = std::chrono::system_clock::now()](\n                    std::unique_ptr<LogDestination>& log) {\n                  if (log != nullptr) {\n                    // Flush the base fileobject_ logger directly instead of\n                    // going through any wrappers to reduce chance of deadlock.\n                    log->fileobject_.FlushUnlocked(now);\n                  }\n                });\n}\n\ninline void LogDestination::FlushLogFiles(int min_severity) {\n  // Prevent any subtle race conditions by wrapping a mutex lock around\n  // all this stuff.\n  std::lock_guard<std::mutex> l{log_mutex};\n  for (int i = min_severity; i < NUM_SEVERITIES; i++) {\n    LogDestination* log = log_destination(static_cast<LogSeverity>(i));\n    if (log != nullptr) {\n      log->logger_->Flush();\n    }\n  }\n}\n\ninline void LogDestination::SetLogDestination(LogSeverity severity,\n                                              const char* base_filename) {\n  // Prevent any subtle race conditions by wrapping a mutex lock around\n  // all this stuff.\n  std::lock_guard<std::mutex> l{log_mutex};\n  log_destination(severity)->fileobject_.SetBasename(base_filename);\n}\n\ninline void LogDestination::SetLogSymlink(LogSeverity severity,\n                                          const char* symlink_basename) {\n  CHECK_GE(severity, 0);\n  CHECK_LT(severity, NUM_SEVERITIES);\n  std::lock_guard<std::mutex> l{log_mutex};\n  log_destination(severity)->fileobject_.SetSymlinkBasename(symlink_basename);\n}\n\ninline void LogDestination::AddLogSink(LogSink* destination) {\n  // Prevent any subtle race conditions by wrapping a mutex lock around\n  // all this stuff.\n  SinkLock l{sink_mutex_};\n  if (sinks_ == nullptr) sinks_ = std::make_unique<std::vector<LogSink*>>();\n  sinks_->push_back(destination);\n}\n\ninline void LogDestination::RemoveLogSink(LogSink* destination) {\n  // Prevent any subtle race conditions by wrapping a mutex lock around\n  // all this stuff.\n  SinkLock l{sink_mutex_};\n  // This doesn't keep the sinks in order, but who cares?\n  if (sinks_) {\n    sinks_->erase(std::remove(sinks_->begin(), sinks_->end(), destination),\n                  sinks_->end());\n  }\n}\n\ninline void LogDestination::SetLogFilenameExtension(const char* ext) {\n  // Prevent any subtle race conditions by wrapping a mutex lock around\n  // all this stuff.\n  std::lock_guard<std::mutex> l{log_mutex};\n  for (int severity = 0; severity < NUM_SEVERITIES; ++severity) {\n    log_destination(static_cast<LogSeverity>(severity))\n        ->fileobject_.SetExtension(ext);\n  }\n}\n\ninline void LogDestination::SetStderrLogging(LogSeverity min_severity) {\n  // Prevent any subtle race conditions by wrapping a mutex lock around\n  // all this stuff.\n  std::lock_guard<std::mutex> l{log_mutex};\n  FLAGS_stderrthreshold = min_severity;\n}\n\ninline void LogDestination::LogToStderr() {\n  // *Don't* put this stuff in a mutex lock, since SetStderrLogging &\n  // SetLogDestination already do the locking!\n  SetStderrLogging(GLOG_INFO);  // thus everything is \"also\" logged to stderr\n  for (int i = 0; i < NUM_SEVERITIES; ++i) {\n    SetLogDestination(static_cast<LogSeverity>(i),\n                      \"\");  // \"\" turns off logging to a logfile\n  }\n}\n\ninline void LogDestination::SetEmailLogging(LogSeverity min_severity,\n                                            const char* addresses) {\n  // Prevent any subtle race conditions by wrapping a mutex lock around\n  // all this stuff.\n  std::lock_guard<std::mutex> l{log_mutex};\n  LogDestination::email_logging_severity_ = min_severity;\n  LogDestination::addresses_ = addresses;\n}\n\nstatic void ColoredWriteToStderrOrStdout(FILE* output, LogSeverity severity,\n                                         const char* message, size_t len) {\n  bool is_stdout = (output == stdout);\n  const GLogColor color = (LogDestination::terminal_supports_color() &&\n                           ((!is_stdout && FLAGS_colorlogtostderr) ||\n                            (is_stdout && FLAGS_colorlogtostdout)))\n                              ? SeverityToColor(severity)\n                              : COLOR_DEFAULT;\n\n  // Avoid using cerr from this module since we may get called during\n  // exit code, and cerr may be partially or fully destroyed by then.\n  if (COLOR_DEFAULT == color) {\n    fwrite(message, len, 1, output);\n    return;\n  }\n#ifdef GLOG_OS_WINDOWS\n  const HANDLE output_handle =\n      GetStdHandle(is_stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);\n\n  // Gets the current text color.\n  CONSOLE_SCREEN_BUFFER_INFO buffer_info;\n  GetConsoleScreenBufferInfo(output_handle, &buffer_info);\n  const WORD old_color_attrs = buffer_info.wAttributes;\n\n  // We need to flush the stream buffers into the console before each\n  // SetConsoleTextAttribute call lest it affect the text that is already\n  // printed but has not yet reached the console.\n  fflush(output);\n  SetConsoleTextAttribute(output_handle,\n                          GetColorAttribute(color) | FOREGROUND_INTENSITY);\n  fwrite(message, len, 1, output);\n  fflush(output);\n  // Restores the text color.\n  SetConsoleTextAttribute(output_handle, old_color_attrs);\n#else\n  fprintf(output, \"\\033[0;3%sm\", GetAnsiColorCode(color));\n  fwrite(message, len, 1, output);\n  fprintf(output, \"\\033[m\");  // Resets the terminal to default.\n#endif  // GLOG_OS_WINDOWS\n}\n\nstatic void ColoredWriteToStdout(LogSeverity severity, const char* message,\n                                 size_t len) {\n  FILE* output = stdout;\n  // We also need to send logs to the stderr when the severity is\n  // higher or equal to the stderr threshold.\n  if (severity >= FLAGS_stderrthreshold) {\n    output = stderr;\n  }\n  ColoredWriteToStderrOrStdout(output, severity, message, len);\n}\n\nstatic void ColoredWriteToStderr(LogSeverity severity, const char* message,\n                                 size_t len) {\n  ColoredWriteToStderrOrStdout(stderr, severity, message, len);\n}\n\nstatic void WriteToStderr(const char* message, size_t len) {\n  // Avoid using cerr from this module since we may get called during\n  // exit code, and cerr may be partially or fully destroyed by then.\n  fwrite(message, len, 1, stderr);\n}\n\ninline void LogDestination::MaybeLogToStderr(LogSeverity severity,\n                                             const char* message,\n                                             size_t message_len,\n                                             size_t prefix_len) {\n  if ((severity >= FLAGS_stderrthreshold) || FLAGS_alsologtostderr) {\n    ColoredWriteToStderr(severity, message, message_len);\n    AlsoErrorWrite(severity,\n                   glog_internal_namespace_::ProgramInvocationShortName(),\n                   message + prefix_len);\n  }\n}\n\ninline void LogDestination::MaybeLogToEmail(LogSeverity severity,\n                                            const char* message, size_t len) {\n  if (severity >= email_logging_severity_ || severity >= FLAGS_logemaillevel) {\n    string to(FLAGS_alsologtoemail);\n    if (!addresses_.empty()) {\n      if (!to.empty()) {\n        to += \",\";\n      }\n      to += addresses_;\n    }\n    const string subject(\n        string(\"[LOG] \") + LogSeverityNames[severity] + \": \" +\n        glog_internal_namespace_::ProgramInvocationShortName());\n    string body(hostname());\n    body += \"\\n\\n\";\n    body.append(message, len);\n\n    // should NOT use SendEmail().  The caller of this function holds the\n    // log_mutex and SendEmail() calls LOG/VLOG which will block trying to\n    // acquire the log_mutex object.  Use SendEmailInternal() and set\n    // use_logging to false.\n    SendEmailInternal(to.c_str(), subject.c_str(), body.c_str(), false);\n  }\n}\n\ninline void LogDestination::MaybeLogToLogfile(\n    LogSeverity severity,\n    const std::chrono::system_clock::time_point& timestamp, const char* message,\n    size_t len) {\n  const bool should_flush = severity > FLAGS_logbuflevel;\n  LogDestination* destination = log_destination(severity);\n  destination->logger_->Write(should_flush, timestamp, message, len);\n}\n\ninline void LogDestination::LogToAllLogfiles(\n    LogSeverity severity,\n    const std::chrono::system_clock::time_point& timestamp, const char* message,\n    size_t len) {\n  if (FLAGS_logtostdout) {  // global flag: never log to file\n    ColoredWriteToStdout(severity, message, len);\n  } else if (FLAGS_logtostderr) {  // global flag: never log to file\n    ColoredWriteToStderr(severity, message, len);\n  } else {\n    for (int i = severity; i >= 0; --i) {\n      LogDestination::MaybeLogToLogfile(static_cast<LogSeverity>(i), timestamp,\n                                        message, len);\n    }\n  }\n}\n\ninline void LogDestination::LogToSinks(LogSeverity severity,\n                                       const char* full_filename,\n                                       const char* base_filename, int line,\n                                       const LogMessageTime& time,\n                                       const char* message,\n                                       size_t message_len) {\n  std::shared_lock<SinkMutex> l{sink_mutex_};\n  if (sinks_) {\n    for (size_t i = sinks_->size(); i-- > 0;) {\n      (*sinks_)[i]->send(severity, full_filename, base_filename, line, time,\n                         message, message_len);\n    }\n  }\n}\n\ninline void LogDestination::WaitForSinks(\n    logging::internal::LogMessageData* data) {\n  std::shared_lock<SinkMutex> l{sink_mutex_};\n  if (sinks_) {\n    for (size_t i = sinks_->size(); i-- > 0;) {\n      (*sinks_)[i]->WaitTillSent();\n    }\n  }\n  const bool send_to_sink =\n      (data->send_method_ == &LogMessage::SendToSink) ||\n      (data->send_method_ == &LogMessage::SendToSinkAndLog);\n  if (send_to_sink && data->sink_ != nullptr) {\n    data->sink_->WaitTillSent();\n  }\n}\n\nstd::unique_ptr<LogDestination>\n    LogDestination::log_destinations_[NUM_SEVERITIES];\n\ninline LogDestination* LogDestination::log_destination(LogSeverity severity) {\n  if (log_destinations_[severity] == nullptr) {\n    log_destinations_[severity] =\n        std::make_unique<LogDestination>(severity, nullptr);\n  }\n  return log_destinations_[severity].get();\n}\n\nvoid LogDestination::DeleteLogDestinations() {\n  for (auto& log_destination : log_destinations_) {\n    log_destination.reset();\n  }\n  SinkLock l{sink_mutex_};\n  sinks_.reset();\n}\n\nnamespace {\n\nstd::string g_application_fingerprint;\n\n}  // namespace\n\nvoid SetApplicationFingerprint(const std::string& fingerprint) {\n  g_application_fingerprint = fingerprint;\n}\n\nnamespace {\n\n// Directory delimiter; Windows supports both forward slashes and backslashes\n#ifdef GLOG_OS_WINDOWS\nconst char possible_dir_delim[] = {'\\\\', '/'};\n#else\nconst char possible_dir_delim[] = {'/'};\n#endif\n\nstring PrettyDuration(const std::chrono::duration<int>& secs) {\n  std::stringstream result;\n  int mins = secs.count() / 60;\n  int hours = mins / 60;\n  mins = mins % 60;\n  int s = secs.count() % 60;\n  result.fill('0');\n  result << hours << ':' << setw(2) << mins << ':' << setw(2) << s;\n  return result.str();\n}\n\nLogFileObject::LogFileObject(LogSeverity severity, const char* base_filename)\n    : base_filename_selected_(base_filename != nullptr),\n      base_filename_((base_filename != nullptr) ? base_filename : \"\"),\n      symlink_basename_(glog_internal_namespace_::ProgramInvocationShortName()),\n      filename_extension_(),\n      severity_(severity),\n      rollover_attempt_(kRolloverAttemptFrequency - 1),\n      start_time_(std::chrono::system_clock::now()) {}\n\nLogFileObject::~LogFileObject() {\n  std::lock_guard<std::mutex> l{mutex_};\n  file_ = nullptr;\n}\n\nvoid LogFileObject::SetBasename(const char* basename) {\n  std::lock_guard<std::mutex> l{mutex_};\n  base_filename_selected_ = true;\n  if (base_filename_ != basename) {\n    // Get rid of old log file since we are changing names\n    if (file_ != nullptr) {\n      file_ = nullptr;\n      rollover_attempt_ = kRolloverAttemptFrequency - 1;\n    }\n    base_filename_ = basename;\n  }\n}\n\nvoid LogFileObject::SetExtension(const char* ext) {\n  std::lock_guard<std::mutex> l{mutex_};\n  if (filename_extension_ != ext) {\n    // Get rid of old log file since we are changing names\n    if (file_ != nullptr) {\n      file_ = nullptr;\n      rollover_attempt_ = kRolloverAttemptFrequency - 1;\n    }\n    filename_extension_ = ext;\n  }\n}\n\nvoid LogFileObject::SetSymlinkBasename(const char* symlink_basename) {\n  std::lock_guard<std::mutex> l{mutex_};\n  symlink_basename_ = symlink_basename;\n}\n\nvoid LogFileObject::Flush() {\n  std::lock_guard<std::mutex> l{mutex_};\n  FlushUnlocked(std::chrono::system_clock::now());\n}\n\nvoid LogFileObject::FlushUnlocked(\n    const std::chrono::system_clock::time_point& now) {\n  if (file_ != nullptr) {\n    fflush(file_.get());\n    bytes_since_flush_ = 0;\n  }\n  // Figure out when we are due for another flush.\n  next_flush_time_ =\n      now + std::chrono::duration_cast<std::chrono::system_clock::duration>(\n                std::chrono::duration<int32>{FLAGS_logbufsecs});\n}\n\nbool LogFileObject::CreateLogfile(const string& time_pid_string) {\n  string string_filename = base_filename_;\n  if (FLAGS_timestamp_in_logfile_name) {\n    string_filename += time_pid_string;\n  }\n  string_filename += filename_extension_;\n  const char* filename = string_filename.c_str();\n  // only write to files, create if non-existant.\n  int flags = O_WRONLY | O_CREAT;\n  if (FLAGS_timestamp_in_logfile_name) {\n    // demand that the file is unique for our timestamp (fail if it exists).\n    flags = flags | O_EXCL;\n  } else {\n    // logs are written to a single file, where: a log file is created for the\n    // the first time or a file is being recreated due to exceeding max size\n\n    struct stat statbuf;\n    if (stat(filename, &statbuf) == 0) {\n      // truncate the file if it exceeds the max size\n      if ((static_cast<uint32>(statbuf.st_size) >> 20U) >= MaxLogSize()) {\n        flags |= O_TRUNC;\n      }\n\n      // update file length to sync file size\n      file_length_ = static_cast<uint32>(statbuf.st_size);\n    }\n  }\n\n  FileDescriptor fd{\n      open(filename, flags, static_cast<mode_t>(FLAGS_logfile_mode))};\n  if (!fd) return false;\n#ifdef HAVE_FCNTL\n  // Mark the file close-on-exec. We don't really care if this fails\n  fcntl(fd.get(), F_SETFD, FD_CLOEXEC);\n\n  // Mark the file as exclusive write access to avoid two clients logging to the\n  // same file. This applies particularly when !FLAGS_timestamp_in_logfile_name\n  // (otherwise open would fail because the O_EXCL flag on similar filename).\n  // locks are released on unlock or close() automatically, only after log is\n  // released.\n  // This will work after a fork as it is not inherited (not stored in the fd).\n  // Lock will not be lost because the file is opened with exclusive lock\n  // (write) and we will never read from it inside the process.\n  // TODO: windows implementation of this (as flock is not available on\n  // mingw).\n  static struct flock w_lock;\n\n  w_lock.l_type = F_WRLCK;\n  w_lock.l_start = 0;\n  w_lock.l_whence = SEEK_SET;\n  w_lock.l_len = 0;\n\n  int wlock_ret = fcntl(fd.get(), F_SETLK, &w_lock);\n  if (wlock_ret == -1) {\n    return false;\n  }\n#endif\n\n  // fdopen in append mode so if the file exists it will fseek to the end\n  file_.reset(fdopen(fd.release(), \"a\"));  // Make a FILE*.\n  if (file_ == nullptr) {                  // Man, we're screwed!\n    if (FLAGS_timestamp_in_logfile_name) {\n      unlink(filename);  // Erase the half-baked evidence: an unusable log file,\n                         // only if we just created it.\n    }\n    return false;\n  }\n#ifdef GLOG_OS_WINDOWS\n  // https://github.com/golang/go/issues/27638 - make sure we seek to the end to\n  // append empirically replicated with wine over mingw build\n  if (!FLAGS_timestamp_in_logfile_name) {\n    if (fseek(file_.get(), 0, SEEK_END) != 0) {\n      return false;\n    }\n  }\n#endif\n  // We try to create a symlink called <program_name>.<severity>,\n  // which is easier to use.  (Every time we create a new logfile,\n  // we destroy the old symlink and create a new one, so it always\n  // points to the latest logfile.)  If it fails, we're sad but it's\n  // no error.\n  if (!symlink_basename_.empty()) {\n    // take directory from filename\n    const char* slash = strrchr(filename, PATH_SEPARATOR);\n    const string linkname =\n        symlink_basename_ + '.' + LogSeverityNames[severity_];\n    string linkpath;\n    if (slash)\n      linkpath = string(\n          filename, static_cast<size_t>(slash - filename + 1));  // get dirname\n    linkpath += linkname;\n    unlink(linkpath.c_str());  // delete old one if it exists\n\n#if defined(GLOG_OS_WINDOWS)\n    // TODO(hamaji): Create lnk file on Windows?\n#elif defined(HAVE_UNISTD_H)\n    // We must have unistd.h.\n    // Make the symlink be relative (in the same dir) so that if the\n    // entire log directory gets relocated the link is still valid.\n    const char* linkdest = slash ? (slash + 1) : filename;\n    if (symlink(linkdest, linkpath.c_str()) != 0) {\n      // silently ignore failures\n    }\n\n    // Make an additional link to the log file in a place specified by\n    // FLAGS_log_link, if indicated\n    if (!FLAGS_log_link.empty()) {\n      linkpath = FLAGS_log_link + \"/\" + linkname;\n      unlink(linkpath.c_str());  // delete old one if it exists\n      if (symlink(filename, linkpath.c_str()) != 0) {\n        // silently ignore failures\n      }\n    }\n#endif\n  }\n\n  return true;  // Everything worked\n}\n\nvoid LogFileObject::Write(\n    bool force_flush, const std::chrono::system_clock::time_point& timestamp,\n    const char* message, size_t message_len) {\n  std::lock_guard<std::mutex> l{mutex_};\n\n  // We don't log if the base_name_ is \"\" (which means \"don't write\")\n  if (base_filename_selected_ && base_filename_.empty()) {\n    return;\n  }\n\n  auto cleanupLogs = [this, current_time = timestamp] {\n    if (log_cleaner.enabled()) {\n      log_cleaner.Run(current_time, base_filename_selected_, base_filename_,\n                      filename_extension_);\n    }\n  };\n\n  // Remove old logs\n  ScopedExit<decltype(cleanupLogs)> cleanupAtEnd{cleanupLogs};\n\n  if (file_length_ >> 20U >= MaxLogSize() || PidHasChanged()) {\n    file_ = nullptr;\n    file_length_ = bytes_since_flush_ = dropped_mem_length_ = 0;\n    rollover_attempt_ = kRolloverAttemptFrequency - 1;\n  }\n\n  // If there's no destination file, make one before outputting\n  if (file_ == nullptr) {\n    // Try to rollover the log file every 32 log messages.  The only time\n    // this could matter would be when we have trouble creating the log\n    // file.  If that happens, we'll lose lots of log messages, of course!\n    if (++rollover_attempt_ != kRolloverAttemptFrequency) return;\n    rollover_attempt_ = 0;\n\n    struct ::tm tm_time;\n    std::time_t t = std::chrono::system_clock::to_time_t(timestamp);\n\n    if (FLAGS_log_utc_time) {\n      gmtime_r(&t, &tm_time);\n    } else {\n      localtime_r(&t, &tm_time);\n    }\n\n    // The logfile's filename will have the date/time & pid in it\n    ostringstream time_pid_stream;\n    time_pid_stream.fill('0');\n    time_pid_stream << 1900 + tm_time.tm_year << setw(2) << 1 + tm_time.tm_mon\n                    << setw(2) << tm_time.tm_mday << '-' << setw(2)\n                    << tm_time.tm_hour << setw(2) << tm_time.tm_min << setw(2)\n                    << tm_time.tm_sec << '.' << GetMainThreadPid();\n    const string& time_pid_string = time_pid_stream.str();\n\n    if (base_filename_selected_) {\n      if (!CreateLogfile(time_pid_string)) {\n        perror(\"Could not create log file\");\n        fprintf(stderr, \"COULD NOT CREATE LOGFILE '%s'!\\n\",\n                time_pid_string.c_str());\n        return;\n      }\n    } else {\n      // If no base filename for logs of this severity has been set, use a\n      // default base filename of\n      // \"<program name>.<hostname>.<user name>.log.<severity level>.\".  So\n      // logfiles will have names like\n      // webserver.examplehost.root.log.INFO.19990817-150000.4354, where\n      // 19990817 is a date (1999 August 17), 150000 is a time (15:00:00),\n      // and 4354 is the pid of the logging process.  The date & time reflect\n      // when the file was created for output.\n      //\n      // Where does the file get put?  Successively try the directories\n      // \"/tmp\", and \".\"\n      string stripped_filename(\n          glog_internal_namespace_::ProgramInvocationShortName());\n      string hostname;\n      GetHostName(&hostname);\n\n      string uidname = MyUserName();\n      // We should not call CHECK() here because this function can be\n      // called after holding on to log_mutex. We don't want to\n      // attempt to hold on to the same mutex, and get into a\n      // deadlock. Simply use a name like invalid-user.\n      if (uidname.empty()) uidname = \"invalid-user\";\n\n      stripped_filename = stripped_filename + '.' + hostname + '.' + uidname +\n                          \".log.\" + LogSeverityNames[severity_] + '.';\n      // We're going to (potentially) try to put logs in several different dirs\n      const vector<string>& log_dirs = GetLoggingDirectories();\n\n      // Go through the list of dirs, and try to create the log file in each\n      // until we succeed or run out of options\n      bool success = false;\n      for (const auto& log_dir : log_dirs) {\n        base_filename_ = log_dir + \"/\" + stripped_filename;\n        if (CreateLogfile(time_pid_string)) {\n          success = true;\n          break;\n        }\n      }\n      // If we never succeeded, we have to give up\n      if (success == false) {\n        perror(\"Could not create logging file\");\n        fprintf(stderr, \"COULD NOT CREATE A LOGGINGFILE %s!\",\n                time_pid_string.c_str());\n        return;\n      }\n    }\n\n    // Write a header message into the log file\n    if (FLAGS_log_file_header) {\n      ostringstream file_header_stream;\n      file_header_stream.fill('0');\n      file_header_stream << \"Log file created at: \" << 1900 + tm_time.tm_year\n                         << '/' << setw(2) << 1 + tm_time.tm_mon << '/'\n                         << setw(2) << tm_time.tm_mday << ' ' << setw(2)\n                         << tm_time.tm_hour << ':' << setw(2) << tm_time.tm_min\n                         << ':' << setw(2) << tm_time.tm_sec\n                         << (FLAGS_log_utc_time ? \" UTC\\n\" : \"\\n\")\n                         << \"Running on machine: \" << LogDestination::hostname()\n                         << '\\n';\n\n      if (!g_application_fingerprint.empty()) {\n        file_header_stream << \"Application fingerprint: \"\n                           << g_application_fingerprint << '\\n';\n      }\n      const char* const date_time_format = FLAGS_log_year_in_prefix\n                                               ? \"yyyymmdd hh:mm:ss.uuuuuu\"\n                                               : \"mmdd hh:mm:ss.uuuuuu\";\n      file_header_stream\n          << \"Running duration (h:mm:ss): \"\n          << PrettyDuration(\n                 std::chrono::duration_cast<std::chrono::duration<int>>(\n                     timestamp - start_time_))\n          << '\\n'\n          << \"Log line format: [IWEF]\" << date_time_format << \" \"\n          << \"threadid file:line] msg\" << '\\n';\n      const string& file_header_string = file_header_stream.str();\n\n      const size_t header_len = file_header_string.size();\n      fwrite(file_header_string.data(), 1, header_len, file_.get());\n      file_length_ += header_len;\n      bytes_since_flush_ += header_len;\n    }\n  }\n\n  // Write to LOG file\n  if (!stop_writing) {\n    // fwrite() doesn't return an error when the disk is full, for\n    // messages that are less than 4096 bytes. When the disk is full,\n    // it returns the message length for messages that are less than\n    // 4096 bytes. fwrite() returns 4096 for message lengths that are\n    // greater than 4096, thereby indicating an error.\n    errno = 0;\n    fwrite(message, 1, message_len, file_.get());\n    if (FLAGS_stop_logging_if_full_disk &&\n        errno == ENOSPC) {  // disk full, stop writing to disk\n      stop_writing = true;  // until the disk is\n      return;\n    } else {\n      file_length_ += message_len;\n      bytes_since_flush_ += message_len;\n    }\n  } else {\n    if (timestamp >= next_flush_time_) {\n      stop_writing = false;  // check to see if disk has free space.\n    }\n    return;  // no need to flush\n  }\n\n  // See important msgs *now*.  Also, flush logs at least every 10^6 chars,\n  // or every \"FLAGS_logbufsecs\" seconds.\n  if (force_flush || (bytes_since_flush_ >= 1000000) ||\n      (timestamp >= next_flush_time_)) {\n    FlushUnlocked(timestamp);\n#ifdef GLOG_OS_LINUX\n    // Only consider files >= 3MiB\n    if (FLAGS_drop_log_memory && file_length_ >= (3U << 20U)) {\n      // Don't evict the most recent 1-2MiB so as not to impact a tailer\n      // of the log file and to avoid page rounding issue on linux < 4.7\n      uint32 total_drop_length =\n          (file_length_ & ~((1U << 20U) - 1U)) - (1U << 20U);\n      uint32 this_drop_length = total_drop_length - dropped_mem_length_;\n      if (this_drop_length >= (2U << 20U)) {\n        // Only advise when >= 2MiB to drop\n#  if defined(HAVE_POSIX_FADVISE)\n        posix_fadvise(\n            fileno(file_.get()), static_cast<off_t>(dropped_mem_length_),\n            static_cast<off_t>(this_drop_length), POSIX_FADV_DONTNEED);\n#  endif\n        dropped_mem_length_ = total_drop_length;\n      }\n    }\n#endif\n  }\n}\n\nLogCleaner::LogCleaner() = default;\n\nvoid LogCleaner::Enable(const std::chrono::minutes& overdue) {\n  enabled_ = true;\n  overdue_ = overdue;\n}\n\nvoid LogCleaner::Disable() { enabled_ = false; }\n\nvoid LogCleaner::Run(const std::chrono::system_clock::time_point& current_time,\n                     bool base_filename_selected, const string& base_filename,\n                     const string& filename_extension) {\n  assert(enabled_);\n  assert(!base_filename_selected || !base_filename.empty());\n\n  // avoid scanning logs too frequently\n  if (current_time < next_cleanup_time_) {\n    return;\n  }\n\n  next_cleanup_time_ =\n      current_time +\n      std::chrono::duration_cast<std::chrono::system_clock::duration>(\n          std::chrono::duration<int32>{FLAGS_logcleansecs});\n\n  vector<string> dirs;\n\n  if (!base_filename_selected) {\n    dirs = GetLoggingDirectories();\n  } else {\n    size_t pos = base_filename.find_last_of(possible_dir_delim, string::npos,\n                                            sizeof(possible_dir_delim));\n    if (pos != string::npos) {\n      string dir = base_filename.substr(0, pos + 1);\n      dirs.push_back(dir);\n    } else {\n      dirs.emplace_back(\".\");\n    }\n  }\n\n  for (const std::string& dir : dirs) {\n    vector<string> logs = GetOverdueLogNames(dir, current_time, base_filename,\n                                             filename_extension);\n    for (const std::string& log : logs) {\n      // NOTE May fail on Windows if the file is still open\n      int result = unlink(log.c_str());\n      if (result != 0) {\n        perror((\"Could not remove overdue log \" + log).c_str());\n      }\n    }\n  }\n}\n\nvector<string> LogCleaner::GetOverdueLogNames(\n    string log_directory,\n    const std::chrono::system_clock::time_point& current_time,\n    const string& base_filename, const string& filename_extension) const {\n  // The names of overdue logs.\n  vector<string> overdue_log_names;\n\n  // Try to get all files within log_directory.\n  DIR* dir;\n  struct dirent* ent;\n\n  if ((dir = opendir(log_directory.c_str()))) {\n    while ((ent = readdir(dir))) {\n      if (strcmp(ent->d_name, \".\") == 0 || strcmp(ent->d_name, \"..\") == 0) {\n        continue;\n      }\n\n      string filepath = ent->d_name;\n      const char* const dir_delim_end =\n          possible_dir_delim + sizeof(possible_dir_delim);\n\n      if (!log_directory.empty() &&\n          std::find(possible_dir_delim, dir_delim_end,\n                    log_directory[log_directory.size() - 1]) != dir_delim_end) {\n        filepath = log_directory + filepath;\n      }\n\n      if (IsLogFromCurrentProject(filepath, base_filename,\n                                  filename_extension) &&\n          IsLogLastModifiedOver(filepath, current_time)) {\n        overdue_log_names.push_back(filepath);\n      }\n    }\n    closedir(dir);\n  }\n\n  return overdue_log_names;\n}\n\nbool LogCleaner::IsLogFromCurrentProject(\n    const string& filepath, const string& base_filename,\n    const string& filename_extension) const {\n  // We should remove duplicated delimiters from `base_filename`, e.g.,\n  // before: \"/tmp//<base_filename>.<create_time>.<pid>\"\n  // after:  \"/tmp/<base_filename>.<create_time>.<pid>\"\n  string cleaned_base_filename;\n\n  const char* const dir_delim_end =\n      possible_dir_delim + sizeof(possible_dir_delim);\n\n  size_t real_filepath_size = filepath.size();\n  for (char c : base_filename) {\n    if (cleaned_base_filename.empty()) {\n      cleaned_base_filename += c;\n    } else if (std::find(possible_dir_delim, dir_delim_end, c) ==\n                   dir_delim_end ||\n               (!cleaned_base_filename.empty() &&\n                c != cleaned_base_filename[cleaned_base_filename.size() - 1])) {\n      cleaned_base_filename += c;\n    }\n  }\n\n  // Return early if the filename doesn't start with `cleaned_base_filename`.\n  if (filepath.find(cleaned_base_filename) != 0) {\n    return false;\n  }\n\n  // Check if in the string `filename_extension` is right next to\n  // `cleaned_base_filename` in `filepath` if the user\n  // has set a custom filename extension.\n  if (!filename_extension.empty()) {\n    if (cleaned_base_filename.size() >= real_filepath_size) {\n      return false;\n    }\n    // for origin version, `filename_extension` is middle of the `filepath`.\n    string ext = filepath.substr(cleaned_base_filename.size(),\n                                 filename_extension.size());\n    if (ext == filename_extension) {\n      cleaned_base_filename += filename_extension;\n    } else {\n      // for new version, `filename_extension` is right of the `filepath`.\n      if (filename_extension.size() >= real_filepath_size) {\n        return false;\n      }\n      real_filepath_size = filepath.size() - filename_extension.size();\n      if (filepath.substr(real_filepath_size) != filename_extension) {\n        return false;\n      }\n    }\n  }\n\n  // The characters after `cleaned_base_filename` should match the format:\n  // YYYYMMDD-HHMMSS.pid\n  for (size_t i = cleaned_base_filename.size(); i < real_filepath_size; i++) {\n    const char& c = filepath[i];\n\n    if (i <= cleaned_base_filename.size() + 7) {  // 0 ~ 7 : YYYYMMDD\n      if (c < '0' || c > '9') {\n        return false;\n      }\n\n    } else if (i == cleaned_base_filename.size() + 8) {  // 8: -\n      if (c != '-') {\n        return false;\n      }\n\n    } else if (i <= cleaned_base_filename.size() + 14) {  // 9 ~ 14: HHMMSS\n      if (c < '0' || c > '9') {\n        return false;\n      }\n\n    } else if (i == cleaned_base_filename.size() + 15) {  // 15: .\n      if (c != '.') {\n        return false;\n      }\n\n    } else if (i >= cleaned_base_filename.size() + 16) {  // 16+: pid\n      if (c < '0' || c > '9') {\n        return false;\n      }\n    }\n  }\n\n  return true;\n}\n\nbool LogCleaner::IsLogLastModifiedOver(\n    const string& filepath,\n    const std::chrono::system_clock::time_point& current_time) const {\n  // Try to get the last modified time of this file.\n  struct stat file_stat;\n\n  if (stat(filepath.c_str(), &file_stat) == 0) {\n    const auto last_modified_time =\n        std::chrono::system_clock::from_time_t(file_stat.st_mtime);\n    const auto diff = current_time - last_modified_time;\n    return diff >= overdue_;\n  }\n\n  // If failed to get file stat, don't return true!\n  return false;\n}\n\n}  // namespace\n\n// Static log data space to avoid alloc failures in a LOG(FATAL)\n//\n// Since multiple threads may call LOG(FATAL), and we want to preserve\n// the data from the first call, we allocate two sets of space.  One\n// for exclusive use by the first thread, and one for shared use by\n// all other threads.\nstatic std::mutex fatal_msg_lock;\nstatic logging::internal::CrashReason crash_reason;\nstatic bool fatal_msg_exclusive = true;\nstatic logging::internal::LogMessageData fatal_msg_data_exclusive;\nstatic logging::internal::LogMessageData fatal_msg_data_shared;\n\n#ifdef GLOG_THREAD_LOCAL_STORAGE\n// Static thread-local log data space to use, because typically at most one\n// LogMessageData object exists (in this case glog makes zero heap memory\n// allocations).\nstatic thread_local bool thread_data_available = true;\n\n#  if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L\n// std::aligned_storage is deprecated in C++23\nalignas(logging::internal::LogMessageData) static thread_local std::byte\n    thread_msg_data[sizeof(logging::internal::LogMessageData)];\n#  else   // !(defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L)\nstatic thread_local std::aligned_storage<\n    sizeof(logging::internal::LogMessageData),\n    alignof(logging::internal::LogMessageData)>::type thread_msg_data;\n#  endif  // defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603L\n#endif    // defined(GLOG_THREAD_LOCAL_STORAGE)\n\nlogging::internal::LogMessageData::LogMessageData()\n    : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {}\n\nLogMessage::LogMessage(const char* file, int line, LogSeverity severity,\n                       int64 ctr, void (LogMessage::*send_method)())\n    : allocated_(nullptr) {\n  Init(file, line, severity, send_method);\n  data_->stream_.set_ctr(ctr);\n}\n\nLogMessage::LogMessage(const char* file, int line,\n                       const logging::internal::CheckOpString& result)\n    : allocated_(nullptr) {\n  Init(file, line, GLOG_FATAL, &LogMessage::SendToLog);\n  stream() << \"Check failed: \" << (*result.str_) << \" \";\n}\n\nLogMessage::LogMessage(const char* file, int line) : allocated_(nullptr) {\n  Init(file, line, GLOG_INFO, &LogMessage::SendToLog);\n}\n\nLogMessage::LogMessage(const char* file, int line, LogSeverity severity)\n    : allocated_(nullptr) {\n  Init(file, line, severity, &LogMessage::SendToLog);\n}\n\nLogMessage::LogMessage(const char* file, int line, LogSeverity severity,\n                       LogSink* sink, bool also_send_to_log)\n    : allocated_(nullptr) {\n  Init(file, line, severity,\n       also_send_to_log ? &LogMessage::SendToSinkAndLog\n                        : &LogMessage::SendToSink);\n  data_->sink_ = sink;  // override Init()'s setting to nullptr\n}\n\nLogMessage::LogMessage(const char* file, int line, LogSeverity severity,\n                       vector<string>* outvec)\n    : allocated_(nullptr) {\n  Init(file, line, severity, &LogMessage::SaveOrSendToLog);\n  data_->outvec_ = outvec;  // override Init()'s setting to nullptr\n}\n\nLogMessage::LogMessage(const char* file, int line, LogSeverity severity,\n                       string* message)\n    : allocated_(nullptr) {\n  Init(file, line, severity, &LogMessage::WriteToStringAndLog);\n  data_->message_ = message;  // override Init()'s setting to nullptr\n}\n\nvoid LogMessage::Init(const char* file, int line, LogSeverity severity,\n                      void (LogMessage::*send_method)()) {\n  allocated_ = nullptr;\n  if (severity != GLOG_FATAL || !exit_on_dfatal) {\n#ifdef GLOG_THREAD_LOCAL_STORAGE\n    // No need for locking, because this is thread local.\n    if (thread_data_available) {\n      thread_data_available = false;\n      data_ = new (&thread_msg_data) logging::internal::LogMessageData;\n    } else {\n      allocated_ = new logging::internal::LogMessageData();\n      data_ = allocated_;\n    }\n#else   // !defined(GLOG_THREAD_LOCAL_STORAGE)\n    allocated_ = new logging::internal::LogMessageData();\n    data_ = allocated_;\n#endif  // defined(GLOG_THREAD_LOCAL_STORAGE)\n    data_->first_fatal_ = false;\n  } else {\n    std::lock_guard<std::mutex> l{fatal_msg_lock};\n    if (fatal_msg_exclusive) {\n      fatal_msg_exclusive = false;\n      data_ = &fatal_msg_data_exclusive;\n      data_->first_fatal_ = true;\n    } else {\n      data_ = &fatal_msg_data_shared;\n      data_->first_fatal_ = false;\n    }\n  }\n\n  data_->preserved_errno_ = errno;\n  data_->severity_ = severity;\n  data_->line_ = line;\n  data_->send_method_ = send_method;\n  data_->sink_ = nullptr;\n  data_->outvec_ = nullptr;\n\n  const auto now = std::chrono::system_clock::now();\n  time_ = LogMessageTime(now);\n\n  data_->num_chars_to_log_ = 0;\n  data_->num_chars_to_syslog_ = 0;\n  data_->basename_ = const_basename(file);\n  data_->fullname_ = file;\n  data_->has_been_flushed_ = false;\n  data_->thread_id_ = std::this_thread::get_id();\n\n  // If specified, prepend a prefix to each line.  For example:\n  //    I20201018 160715 f5d4fbb0 logging.cc:1153]\n  //    (log level, GMT year, month, date, time, thread_id, file basename, line)\n  // We exclude the thread_id for the default thread.\n  if (FLAGS_log_prefix && (line != kNoLogPrefix)) {\n    std::ios saved_fmt(nullptr);\n    saved_fmt.copyfmt(stream());\n    stream().fill('0');\n    if (g_prefix_formatter == nullptr) {\n      stream() << LogSeverityNames[severity][0];\n      if (FLAGS_log_year_in_prefix) {\n        stream() << setw(4) << 1900 + time_.year();\n      }\n      stream() << setw(2) << 1 + time_.month() << setw(2) << time_.day() << ' '\n               << setw(2) << time_.hour() << ':' << setw(2) << time_.min()\n               << ':' << setw(2) << time_.sec() << \".\" << setw(6)\n               << time_.usec() << ' ' << setfill(' ') << setw(5)\n               << data_->thread_id_ << setfill('0') << ' ' << data_->basename_\n               << ':' << data_->line_ << \"] \";\n    } else {\n      (*g_prefix_formatter)(stream(), *this);\n      stream() << \" \";\n    }\n    stream().copyfmt(saved_fmt);\n  }\n  data_->num_prefix_chars_ = data_->stream_.pcount();\n\n  if (!FLAGS_log_backtrace_at.empty()) {\n    char fileline[128];\n    std::snprintf(fileline, sizeof(fileline), \"%s:%d\", data_->basename_, line);\n#ifdef HAVE_STACKTRACE\n    if (FLAGS_log_backtrace_at == fileline) {\n      string stacktrace = GetStackTrace();\n      stream() << \" (stacktrace:\\n\" << stacktrace << \") \";\n    }\n#endif\n  }\n}\n\nLogSeverity LogMessage::severity() const noexcept { return data_->severity_; }\n\nint LogMessage::line() const noexcept { return data_->line_; }\nconst std::thread::id& LogMessage::thread_id() const noexcept {\n  return data_->thread_id_;\n}\nconst char* LogMessage::fullname() const noexcept { return data_->fullname_; }\nconst char* LogMessage::basename() const noexcept { return data_->basename_; }\nconst LogMessageTime& LogMessage::time() const noexcept { return time_; }\n\nLogMessage::~LogMessage() noexcept(false) {\n  Flush();\n  bool fail = data_->severity_ == GLOG_FATAL && exit_on_dfatal;\n#ifdef GLOG_THREAD_LOCAL_STORAGE\n  if (data_ == static_cast<void*>(&thread_msg_data)) {\n    data_->~LogMessageData();\n    thread_data_available = true;\n  } else {\n    delete allocated_;\n  }\n#else   // !defined(GLOG_THREAD_LOCAL_STORAGE)\n  delete allocated_;\n#endif  // defined(GLOG_THREAD_LOCAL_STORAGE)\n        //\n\n  if (fail) {\n    const char* message = \"*** Check failure stack trace: ***\\n\";\n    if (write(fileno(stderr), message, strlen(message)) < 0) {\n      // Ignore errors.\n    }\n    AlsoErrorWrite(GLOG_FATAL,\n                   glog_internal_namespace_::ProgramInvocationShortName(),\n                   message);\n#if defined(__cpp_lib_uncaught_exceptions) && \\\n    (__cpp_lib_uncaught_exceptions >= 201411L)\n    if (std::uncaught_exceptions() == 0)\n#else\n    if (!std::uncaught_exception())\n#endif\n    {\n      Fail();\n    }\n  }\n}\n\nint LogMessage::preserved_errno() const { return data_->preserved_errno_; }\n\nostream& LogMessage::stream() { return data_->stream_; }\n\n// Flush buffered message, called by the destructor, or any other function\n// that needs to synchronize the log.\nvoid LogMessage::Flush() {\n  if (data_->has_been_flushed_ || data_->severity_ < FLAGS_minloglevel) {\n    return;\n  }\n\n  data_->num_chars_to_log_ = data_->stream_.pcount();\n  data_->num_chars_to_syslog_ =\n      data_->num_chars_to_log_ - data_->num_prefix_chars_;\n\n  // Do we need to add a \\n to the end of this message?\n  bool append_newline =\n      (data_->message_text_[data_->num_chars_to_log_ - 1] != '\\n');\n  char original_final_char = '\\0';\n\n  // If we do need to add a \\n, we'll do it by violating the memory of the\n  // ostrstream buffer.  This is quick, and we'll make sure to undo our\n  // modification before anything else is done with the ostrstream.  It\n  // would be preferable not to do things this way, but it seems to be\n  // the best way to deal with this.\n  if (append_newline) {\n    original_final_char = data_->message_text_[data_->num_chars_to_log_];\n    data_->message_text_[data_->num_chars_to_log_++] = '\\n';\n  }\n  data_->message_text_[data_->num_chars_to_log_] = '\\0';\n\n  // Prevent any subtle race conditions by wrapping a mutex lock around\n  // the actual logging action per se.\n  {\n    std::lock_guard<std::mutex> l{log_mutex};\n    (this->*(data_->send_method_))();\n    ++num_messages_[static_cast<int>(data_->severity_)];\n  }\n  LogDestination::WaitForSinks(data_);\n\n  if (append_newline) {\n    // Fix the ostrstream back how it was before we screwed with it.\n    // It's 99.44% certain that we don't need to worry about doing this.\n    data_->message_text_[data_->num_chars_to_log_ - 1] = original_final_char;\n  }\n\n  // If errno was already set before we enter the logging call, we'll\n  // set it back to that value when we return from the logging call.\n  // It happens often that we log an error message after a syscall\n  // failure, which can potentially set the errno to some other\n  // values.  We would like to preserve the original errno.\n  if (data_->preserved_errno_ != 0) {\n    errno = data_->preserved_errno_;\n  }\n\n  // Note that this message is now safely logged.  If we're asked to flush\n  // again, as a result of destruction, say, we'll do nothing on future calls.\n  data_->has_been_flushed_ = true;\n}\n\n// Copy of first FATAL log message so that we can print it out again\n// after all the stack traces.  To preserve legacy behavior, we don't\n// use fatal_msg_data_exclusive.\nstatic std::chrono::system_clock::time_point fatal_time;\nstatic char fatal_message[256];\n\nvoid ReprintFatalMessage() {\n  if (fatal_message[0]) {\n    const size_t n = strlen(fatal_message);\n    if (!FLAGS_logtostderr) {\n      // Also write to stderr (don't color to avoid terminal checks)\n      WriteToStderr(fatal_message, n);\n    }\n    LogDestination::LogToAllLogfiles(GLOG_ERROR, fatal_time, fatal_message, n);\n  }\n}\n\n// L >= log_mutex (callers must hold the log_mutex).\nvoid LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {\n  static bool already_warned_before_initgoogle = false;\n\n  RAW_DCHECK(data_->num_chars_to_log_ > 0 &&\n                 data_->message_text_[data_->num_chars_to_log_ - 1] == '\\n',\n             \"\");\n\n  // Messages of a given severity get logged to lower severity logs, too\n\n  if (!already_warned_before_initgoogle && !IsGoogleLoggingInitialized()) {\n    const char w[] =\n        \"WARNING: Logging before InitGoogleLogging() is \"\n        \"written to STDERR\\n\";\n    WriteToStderr(w, strlen(w));\n    already_warned_before_initgoogle = true;\n  }\n\n  // global flag: never log to file if set.  Also -- don't log to a\n  // file if we haven't parsed the command line flags to get the\n  // program name.\n  if (FLAGS_logtostderr || FLAGS_logtostdout || !IsGoogleLoggingInitialized()) {\n    if (FLAGS_logtostdout) {\n      ColoredWriteToStdout(data_->severity_, data_->message_text_,\n                           data_->num_chars_to_log_);\n    } else {\n      ColoredWriteToStderr(data_->severity_, data_->message_text_,\n                           data_->num_chars_to_log_);\n    }\n\n    // this could be protected by a flag if necessary.\n    LogDestination::LogToSinks(\n        data_->severity_, data_->fullname_, data_->basename_, data_->line_,\n        time_, data_->message_text_ + data_->num_prefix_chars_,\n        (data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));\n  } else {\n    // log this message to all log files of severity <= severity_\n    LogDestination::LogToAllLogfiles(data_->severity_, time_.when(),\n                                     data_->message_text_,\n                                     data_->num_chars_to_log_);\n\n    LogDestination::MaybeLogToStderr(data_->severity_, data_->message_text_,\n                                     data_->num_chars_to_log_,\n                                     data_->num_prefix_chars_);\n    LogDestination::MaybeLogToEmail(data_->severity_, data_->message_text_,\n                                    data_->num_chars_to_log_);\n    LogDestination::LogToSinks(\n        data_->severity_, data_->fullname_, data_->basename_, data_->line_,\n        time_, data_->message_text_ + data_->num_prefix_chars_,\n        (data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));\n    // NOTE: -1 removes trailing \\n\n  }\n\n  // If we log a FATAL message, flush all the log destinations, then toss\n  // a signal for others to catch. We leave the logs in a state that\n  // someone else can use them (as long as they flush afterwards)\n  if (data_->severity_ == GLOG_FATAL && exit_on_dfatal) {\n    if (data_->first_fatal_) {\n      // Store crash information so that it is accessible from within signal\n      // handlers that may be invoked later.\n      RecordCrashReason(&crash_reason);\n      SetCrashReason(&crash_reason);\n\n      // Store shortened fatal message for other logs and GWQ status\n      const size_t copy =\n          min(data_->num_chars_to_log_, sizeof(fatal_message) - 1);\n      memcpy(fatal_message, data_->message_text_, copy);\n      fatal_message[copy] = '\\0';\n      fatal_time = time_.when();\n    }\n\n    if (!FLAGS_logtostderr && !FLAGS_logtostdout) {\n      for (auto& log_destination : LogDestination::log_destinations_) {\n        if (log_destination) {\n          log_destination->logger_->Write(\n              true, std::chrono::system_clock::time_point{}, \"\", 0);\n        }\n      }\n    }\n\n    LogDestination::WaitForSinks(data_);\n  }\n}\n\nvoid LogMessage::RecordCrashReason(logging::internal::CrashReason* reason) {\n  reason->filename = fatal_msg_data_exclusive.fullname_;\n  reason->line_number = fatal_msg_data_exclusive.line_;\n  reason->message = fatal_msg_data_exclusive.message_text_ +\n                    fatal_msg_data_exclusive.num_prefix_chars_;\n#ifdef HAVE_STACKTRACE\n  // Retrieve the stack trace, omitting the logging frames that got us here.\n  reason->depth = GetStackTrace(reason->stack, ARRAYSIZE(reason->stack), 4);\n#else\n  reason->depth = 0;\n#endif\n}\n\nGLOG_NO_EXPORT logging_fail_func_t g_logging_fail_func =\n    reinterpret_cast<logging_fail_func_t>(&abort);\n\nNullStream::NullStream() : LogMessage::LogStream(message_buffer_, 2, 0) {}\nNullStream::NullStream(const char* /*file*/, int /*line*/,\n                       const logging::internal::CheckOpString& /*result*/)\n    : LogMessage::LogStream(message_buffer_, 2, 0) {}\nNullStream& NullStream::stream() { return *this; }\n\nNullStreamFatal::~NullStreamFatal() {\n  // Cannot use g_logging_fail_func here as it may output the backtrace which\n  // would be inconsistent with NullStream behavior.\n  std::abort();\n}\n\nlogging_fail_func_t InstallFailureFunction(logging_fail_func_t fail_func) {\n  return std::exchange(g_logging_fail_func, fail_func);\n}\n\nvoid LogMessage::Fail() { g_logging_fail_func(); }\n\n// L >= log_mutex (callers must hold the log_mutex).\nvoid LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {\n  if (data_->sink_ != nullptr) {\n    RAW_DCHECK(data_->num_chars_to_log_ > 0 &&\n                   data_->message_text_[data_->num_chars_to_log_ - 1] == '\\n',\n               \"\");\n    data_->sink_->send(\n        data_->severity_, data_->fullname_, data_->basename_, data_->line_,\n        time_, data_->message_text_ + data_->num_prefix_chars_,\n        (data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));\n  }\n}\n\n// L >= log_mutex (callers must hold the log_mutex).\nvoid LogMessage::SendToSinkAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {\n  SendToSink();\n  SendToLog();\n}\n\n// L >= log_mutex (callers must hold the log_mutex).\nvoid LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {\n  if (data_->outvec_ != nullptr) {\n    RAW_DCHECK(data_->num_chars_to_log_ > 0 &&\n                   data_->message_text_[data_->num_chars_to_log_ - 1] == '\\n',\n               \"\");\n    // Omit prefix of message and trailing newline when recording in outvec_.\n    const char* start = data_->message_text_ + data_->num_prefix_chars_;\n    size_t len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;\n    data_->outvec_->push_back(string(start, len));\n  } else {\n    SendToLog();\n  }\n}\n\nvoid LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {\n  if (data_->message_ != nullptr) {\n    RAW_DCHECK(data_->num_chars_to_log_ > 0 &&\n                   data_->message_text_[data_->num_chars_to_log_ - 1] == '\\n',\n               \"\");\n    // Omit prefix of message and trailing newline when writing to message_.\n    const char* start = data_->message_text_ + data_->num_prefix_chars_;\n    size_t len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;\n    data_->message_->assign(start, len);\n  }\n  SendToLog();\n}\n\n// L >= log_mutex (callers must hold the log_mutex).\nvoid LogMessage::SendToSyslogAndLog() {\n#ifdef HAVE_SYSLOG_H\n  // Before any calls to syslog(), make a single call to openlog()\n  static bool openlog_already_called = false;\n  if (!openlog_already_called) {\n    openlog(glog_internal_namespace_::ProgramInvocationShortName(),\n            LOG_CONS | LOG_NDELAY | LOG_PID, LOG_USER);\n    openlog_already_called = true;\n  }\n\n  // This array maps Google severity levels to syslog levels\n  const int SEVERITY_TO_LEVEL[] = {LOG_INFO, LOG_WARNING, LOG_ERR, LOG_EMERG};\n  syslog(LOG_USER | SEVERITY_TO_LEVEL[static_cast<int>(data_->severity_)],\n         \"%.*s\", static_cast<int>(data_->num_chars_to_syslog_),\n         data_->message_text_ + data_->num_prefix_chars_);\n  SendToLog();\n#else\n  LOG(ERROR) << \"No syslog support: message=\" << data_->message_text_;\n#endif\n}\n\nbase::Logger* base::GetLogger(LogSeverity severity) {\n  std::lock_guard<std::mutex> l{log_mutex};\n  return LogDestination::log_destination(severity)->GetLoggerImpl();\n}\n\nvoid base::SetLogger(LogSeverity severity, base::Logger* logger) {\n  std::lock_guard<std::mutex> l{log_mutex};\n  LogDestination::log_destination(severity)->SetLoggerImpl(logger);\n}\n\n// L < log_mutex.  Acquires and releases mutex_.\nint64 LogMessage::num_messages(int severity) {\n  std::lock_guard<std::mutex> l{log_mutex};\n  return num_messages_[severity];\n}\n\n// Output the COUNTER value. This is only valid if ostream is a\n// LogStream.\nostream& operator<<(ostream& os, const Counter_t&) {\n#ifdef DISABLE_RTTI\n  LogMessage::LogStream* log = static_cast<LogMessage::LogStream*>(&os);\n#else\n  auto* log = dynamic_cast<LogMessage::LogStream*>(&os);\n#endif\n  CHECK(log && log == log->self())\n      << \"You must not use COUNTER with non-glog ostream\";\n  os << log->ctr();\n  return os;\n}\n\nErrnoLogMessage::ErrnoLogMessage(const char* file, int line,\n                                 LogSeverity severity, int64 ctr,\n                                 void (LogMessage::*send_method)())\n    : LogMessage(file, line, severity, ctr, send_method) {}\n\nErrnoLogMessage::~ErrnoLogMessage() {\n  // Don't access errno directly because it may have been altered\n  // while streaming the message.\n  stream() << \": \" << StrError(preserved_errno()) << \" [\" << preserved_errno()\n           << \"]\";\n}\n\nvoid FlushLogFiles(LogSeverity min_severity) {\n  LogDestination::FlushLogFiles(min_severity);\n}\n\nvoid FlushLogFilesUnsafe(LogSeverity min_severity) {\n  LogDestination::FlushLogFilesUnsafe(min_severity);\n}\n\nvoid SetLogDestination(LogSeverity severity, const char* base_filename) {\n  LogDestination::SetLogDestination(severity, base_filename);\n}\n\nvoid SetLogSymlink(LogSeverity severity, const char* symlink_basename) {\n  LogDestination::SetLogSymlink(severity, symlink_basename);\n}\n\nLogSink::~LogSink() = default;\n\nvoid LogSink::WaitTillSent() {\n  // noop default\n}\n\nstring LogSink::ToString(LogSeverity severity, const char* file, int line,\n                         const LogMessageTime& time, const char* message,\n                         size_t message_len) {\n  ostringstream stream;\n  stream.fill('0');\n\n  stream << LogSeverityNames[severity][0];\n  if (FLAGS_log_year_in_prefix) {\n    stream << setw(4) << 1900 + time.year();\n  }\n  stream << setw(2) << 1 + time.month() << setw(2) << time.day() << ' '\n         << setw(2) << time.hour() << ':' << setw(2) << time.min() << ':'\n         << setw(2) << time.sec() << '.' << setw(6) << time.usec() << ' '\n         << setfill(' ') << setw(5) << std::this_thread::get_id()\n         << setfill('0') << ' ' << file << ':' << line << \"] \";\n\n  // A call to `write' is enclosed in parenthneses to prevent possible macro\n  // expansion.  On Windows, `write' could be a macro defined for portability.\n  (stream.write)(message, static_cast<std::streamsize>(message_len));\n  return stream.str();\n}\n\nvoid AddLogSink(LogSink* destination) {\n  LogDestination::AddLogSink(destination);\n}\n\nvoid RemoveLogSink(LogSink* destination) {\n  LogDestination::RemoveLogSink(destination);\n}\n\nvoid SetLogFilenameExtension(const char* ext) {\n  LogDestination::SetLogFilenameExtension(ext);\n}\n\nvoid SetStderrLogging(LogSeverity min_severity) {\n  LogDestination::SetStderrLogging(min_severity);\n}\n\nvoid SetEmailLogging(LogSeverity min_severity, const char* addresses) {\n  LogDestination::SetEmailLogging(min_severity, addresses);\n}\n\nvoid LogToStderr() { LogDestination::LogToStderr(); }\n\nnamespace base {\nnamespace internal {\n\nbool GetExitOnDFatal();\nbool GetExitOnDFatal() {\n  std::lock_guard<std::mutex> l{log_mutex};\n  return exit_on_dfatal;\n}\n\n// Determines whether we exit the program for a LOG(DFATAL) message in\n// debug mode.  It does this by skipping the call to Fail/FailQuietly.\n// This is intended for testing only.\n//\n// This can have some effects on LOG(FATAL) as well.  Failure messages\n// are always allocated (rather than sharing a buffer), the crash\n// reason is not recorded, the \"gwq\" status message is not updated,\n// and the stack trace is not recorded.  The LOG(FATAL) *will* still\n// exit the program.  Since this function is used only in testing,\n// these differences are acceptable.\nvoid SetExitOnDFatal(bool value);\nvoid SetExitOnDFatal(bool value) {\n  std::lock_guard<std::mutex> l{log_mutex};\n  exit_on_dfatal = value;\n}\n\n}  // namespace internal\n}  // namespace base\n\n#ifndef GLOG_OS_EMSCRIPTEN\n// Shell-escaping as we need to shell out ot /bin/mail.\nstatic const char kDontNeedShellEscapeChars[] =\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n    \"abcdefghijklmnopqrstuvwxyz\"\n    \"0123456789+-_.=/:,@\";\n\nstatic string ShellEscape(const string& src) {\n  string result;\n  if (!src.empty() &&  // empty string needs quotes\n      src.find_first_not_of(kDontNeedShellEscapeChars) == string::npos) {\n    // only contains chars that don't need quotes; it's fine\n    result.assign(src);\n  } else if (src.find_first_of('\\'') == string::npos) {\n    // no single quotes; just wrap it in single quotes\n    result.assign(\"'\");\n    result.append(src);\n    result.append(\"'\");\n  } else {\n    // needs double quote escaping\n    result.assign(\"\\\"\");\n    for (size_t i = 0; i < src.size(); ++i) {\n      switch (src[i]) {\n        case '\\\\':\n        case '$':\n        case '\"':\n        case '`':\n          result.append(\"\\\\\");\n      }\n      result.append(src, i, 1);\n    }\n    result.append(\"\\\"\");\n  }\n  return result;\n}\n\n// Trim whitespace from both ends of the provided string.\nstatic inline void trim(std::string& s) {\n  const auto toRemove = [](char ch) { return std::isspace(ch) == 0; };\n  s.erase(s.begin(), std::find_if(s.begin(), s.end(), toRemove));\n  s.erase(std::find_if(s.rbegin(), s.rend(), toRemove).base(), s.end());\n}\n#endif\n\n// use_logging controls whether the logging functions LOG/VLOG are used\n// to log errors.  It should be set to false when the caller holds the\n// log_mutex.\nstatic bool SendEmailInternal(const char* dest, const char* subject,\n                              const char* body, bool use_logging) {\n#ifndef GLOG_OS_EMSCRIPTEN\n  if (dest && *dest) {\n    // Split the comma-separated list of email addresses, validate each one and\n    // build a sanitized new comma-separated string without whitespace.\n    std::istringstream ss(dest);\n    std::ostringstream sanitized_dests;\n    std::string s;\n    while (std::getline(ss, s, ',')) {\n      trim(s);\n      if (s.empty()) {\n        continue;\n      }\n      // We validate the provided email addresses using the same regular\n      // expression that HTML5 uses[1], except that we require the address to\n      // start with an alpha-numeric character. This is because we don't want to\n      // allow email addresses that start with a special character, such as a\n      // pipe or dash, which could be misunderstood as a command-line flag by\n      // certain versions of `mail` that are vulnerable to command injection.[2]\n      // [1]\n      // https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address\n      // [2] e.g. https://nvd.nist.gov/vuln/detail/CVE-2004-2771\n      if (!std::regex_match(\n              s,\n              std::regex(\"^[a-zA-Z0-9]\"\n                         \"[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]*@[a-zA-Z0-9]\"\n                         \"(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\\\.[a-zA-Z0-9]\"\n                         \"(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$\"))) {\n        if (use_logging) {\n          VLOG(1) << \"Invalid destination email address:\" << s;\n        } else {\n          fprintf(stderr, \"Invalid destination email address: %s\\n\", s.c_str());\n        }\n        return false;\n      }\n      if (!sanitized_dests.str().empty()) {\n        sanitized_dests << \",\";\n      }\n      sanitized_dests << s;\n    }\n    // Avoid dangling reference\n    const std::string& tmp = sanitized_dests.str();\n    dest = tmp.c_str();\n\n    if (use_logging) {\n      VLOG(1) << \"Trying to send TITLE:\" << subject << \" BODY:\" << body\n              << \" to \" << dest;\n    } else {\n      fprintf(stderr, \"Trying to send TITLE: %s BODY: %s to %s\\n\", subject,\n              body, dest);\n    }\n\n    string logmailer;\n\n    if (FLAGS_logmailer.empty()) {\n      // Don't need to shell escape the literal string\n      logmailer = \"/bin/mail\";\n    } else {\n      logmailer = ShellEscape(FLAGS_logmailer);\n    }\n\n    string cmd =\n        logmailer + \" -s\" + ShellEscape(subject) + \" \" + ShellEscape(dest);\n    if (use_logging) {\n      VLOG(4) << \"Mailing command: \" << cmd;\n    }\n\n    FILE* pipe = popen(cmd.c_str(), \"w\");\n    if (pipe != nullptr) {\n      // Add the body if we have one\n      if (body) {\n        fwrite(body, sizeof(char), strlen(body), pipe);\n      }\n      bool ok = pclose(pipe) != -1;\n      if (!ok) {\n        if (use_logging) {\n          LOG(ERROR) << \"Problems sending mail to \" << dest << \": \"\n                     << StrError(errno);\n        } else {\n          fprintf(stderr, \"Problems sending mail to %s: %s\\n\", dest,\n                  StrError(errno).c_str());\n        }\n      }\n      return ok;\n    } else {\n      if (use_logging) {\n        LOG(ERROR) << \"Unable to send mail to \" << dest;\n      } else {\n        fprintf(stderr, \"Unable to send mail to %s\\n\", dest);\n      }\n    }\n  }\n#else\n  (void)dest;\n  (void)subject;\n  (void)body;\n  (void)use_logging;\n  LOG(WARNING) << \"Email support not available; not sending message\";\n#endif\n  return false;\n}\n\nbool SendEmail(const char* dest, const char* subject, const char* body) {\n  return SendEmailInternal(dest, subject, body, true);\n}\n\nstatic void GetTempDirectories(vector<string>& list) {\n  list.clear();\n#ifdef GLOG_OS_WINDOWS\n  // On windows we'll try to find a directory in this order:\n  //   C:/Documents & Settings/whomever/TEMP (or whatever GetTempPath() is)\n  //   C:/TMP/\n  //   C:/TEMP/\n  char tmp[MAX_PATH];\n  if (GetTempPathA(MAX_PATH, tmp)) list.push_back(tmp);\n  list.push_back(\"C:\\\\TMP\\\\\");\n  list.push_back(\"C:\\\\TEMP\\\\\");\n#else\n  // Directories, in order of preference. If we find a dir that\n  // exists, we stop adding other less-preferred dirs\n  const char* candidates[] = {\n      // Non-null only during unittest/regtest\n      getenv(\"TEST_TMPDIR\"),\n\n      // Explicitly-supplied temp dirs\n      getenv(\"TMPDIR\"),\n      getenv(\"TMP\"),\n\n      // If all else fails\n      \"/tmp\",\n  };\n\n  for (auto d : candidates) {\n    if (!d) continue;  // Empty env var\n\n    // Make sure we don't surprise anyone who's expecting a '/'\n    string dstr = d;\n    if (dstr[dstr.size() - 1] != '/') {\n      dstr += \"/\";\n    }\n    list.push_back(dstr);\n\n    struct stat statbuf;\n    if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode)) {\n      // We found a dir that exists - we're done.\n      return;\n    }\n  }\n#endif\n}\n\nstatic std::unique_ptr<std::vector<std::string>> logging_directories_list;\n\nconst vector<string>& GetLoggingDirectories() {\n  // Not strictly thread-safe but we're called early in InitGoogle().\n  if (logging_directories_list == nullptr) {\n    logging_directories_list = std::make_unique<std::vector<std::string>>();\n\n    if (!FLAGS_log_dir.empty()) {\n      // Ensure the specified path ends with a directory delimiter.\n      if (std::find(std::begin(possible_dir_delim),\n                    std::end(possible_dir_delim),\n                    FLAGS_log_dir.back()) == std::end(possible_dir_delim)) {\n        logging_directories_list->push_back(FLAGS_log_dir + \"/\");\n      } else {\n        logging_directories_list->push_back(FLAGS_log_dir);\n      }\n    } else {\n      GetTempDirectories(*logging_directories_list);\n#ifdef GLOG_OS_WINDOWS\n      char tmp[MAX_PATH];\n      if (GetWindowsDirectoryA(tmp, MAX_PATH))\n        logging_directories_list->push_back(tmp);\n      logging_directories_list->push_back(\".\\\\\");\n#else\n      logging_directories_list->push_back(\"./\");\n#endif\n    }\n  }\n  return *logging_directories_list;\n}\n\n// Returns a set of existing temporary directories, which will be a\n// subset of the directories returned by GetLoggingDirectories().\n// Thread-safe.\nGLOG_NO_EXPORT\nvoid GetExistingTempDirectories(vector<string>& list) {\n  GetTempDirectories(list);\n  auto i_dir = list.begin();\n  while (i_dir != list.end()) {\n    // zero arg to access means test for existence; no constant\n    // defined on windows\n    if (access(i_dir->c_str(), 0)) {\n      i_dir = list.erase(i_dir);\n    } else {\n      ++i_dir;\n    }\n  }\n}\n\nvoid TruncateLogFile(const char* path, uint64 limit, uint64 keep) {\n#if defined(HAVE_UNISTD_H) || defined(HAVE__CHSIZE_S)\n  struct stat statbuf;\n  const int kCopyBlockSize = 8 << 10;\n  char copybuf[kCopyBlockSize];\n  off_t read_offset, write_offset;\n  // Don't follow symlinks unless they're our own fd symlinks in /proc\n  int flags = O_RDWR;\n  // TODO(hamaji): Support other environments.\n#  ifdef GLOG_OS_LINUX\n  const char* procfd_prefix = \"/proc/self/fd/\";\n  if (strncmp(procfd_prefix, path, strlen(procfd_prefix))) flags |= O_NOFOLLOW;\n#  endif\n\n  FileDescriptor fd{open(path, flags)};\n  if (!fd) {\n    if (errno == EFBIG) {\n      // The log file in question has got too big for us to open. The\n      // real fix for this would be to compile logging.cc (or probably\n      // all of base/...) with -D_FILE_OFFSET_BITS=64 but that's\n      // rather scary.\n      // Instead just truncate the file to something we can manage\n#  ifdef HAVE__CHSIZE_S\n      if (_chsize_s(fd.get(), 0) != 0) {\n#  else\n      if (truncate(path, 0) == -1) {\n#  endif\n        PLOG(ERROR) << \"Unable to truncate \" << path;\n      } else {\n        LOG(ERROR) << \"Truncated \" << path << \" due to EFBIG error\";\n      }\n    } else {\n      PLOG(ERROR) << \"Unable to open \" << path;\n    }\n    return;\n  }\n\n  if (fstat(fd.get(), &statbuf) == -1) {\n    PLOG(ERROR) << \"Unable to fstat()\";\n    return;\n  }\n\n  // See if the path refers to a regular file bigger than the\n  // specified limit\n  if (!S_ISREG(statbuf.st_mode)) return;\n  if (statbuf.st_size <= static_cast<off_t>(limit)) return;\n  if (statbuf.st_size <= static_cast<off_t>(keep)) return;\n\n  // This log file is too large - we need to truncate it\n  LOG(INFO) << \"Truncating \" << path << \" to \" << keep << \" bytes\";\n\n  // Copy the last \"keep\" bytes of the file to the beginning of the file\n  read_offset = statbuf.st_size - static_cast<off_t>(keep);\n  write_offset = 0;\n  ssize_t bytesin, bytesout;\n  while ((bytesin = pread(fd.get(), copybuf, sizeof(copybuf), read_offset)) >\n         0) {\n    bytesout =\n        pwrite(fd.get(), copybuf, static_cast<size_t>(bytesin), write_offset);\n    if (bytesout == -1) {\n      PLOG(ERROR) << \"Unable to write to \" << path;\n      break;\n    } else if (bytesout != bytesin) {\n      LOG(ERROR) << \"Expected to write \" << bytesin << \", wrote \" << bytesout;\n    }\n    read_offset += bytesin;\n    write_offset += bytesout;\n  }\n  if (bytesin == -1) PLOG(ERROR) << \"Unable to read from \" << path;\n\n    // Truncate the remainder of the file. If someone else writes to the\n    // end of the file after our last read() above, we lose their latest\n    // data. Too bad ...\n#  ifdef HAVE__CHSIZE_S\n  if (_chsize_s(fd.get(), write_offset) != 0) {\n#  else\n  if (ftruncate(fd.get(), write_offset) == -1) {\n#  endif\n    PLOG(ERROR) << \"Unable to truncate \" << path;\n  }\n\n#else\n  LOG(ERROR) << \"No log truncation support.\";\n#endif\n}\n\nvoid TruncateStdoutStderr() {\n#ifdef HAVE_UNISTD_H\n  uint64 limit = MaxLogSize() << 20U;\n  uint64 keep = 1U << 20U;\n  TruncateLogFile(\"/proc/self/fd/1\", limit, keep);\n  TruncateLogFile(\"/proc/self/fd/2\", limit, keep);\n#else\n  LOG(ERROR) << \"No log truncation support.\";\n#endif\n}\n\nnamespace logging {\nnamespace internal {\n// Helper functions for string comparisons.\n#define DEFINE_CHECK_STROP_IMPL(name, func, expected)                         \\\n  std::unique_ptr<string> Check##func##expected##Impl(                        \\\n      const char* s1, const char* s2, const char* names) {                    \\\n    bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2));                     \\\n    if (equal == (expected))                                                  \\\n      return nullptr;                                                         \\\n    else {                                                                    \\\n      ostringstream ss;                                                       \\\n      if (!s1) s1 = \"\";                                                       \\\n      if (!s2) s2 = \"\";                                                       \\\n      ss << #name \" failed: \" << names << \" (\" << s1 << \" vs. \" << s2 << \")\"; \\\n      return std::make_unique<std::string>(ss.str());                         \\\n    }                                                                         \\\n  }\nDEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)\nDEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)\nDEFINE_CHECK_STROP_IMPL(CHECK_STRCASEEQ, strcasecmp, true)\nDEFINE_CHECK_STROP_IMPL(CHECK_STRCASENE, strcasecmp, false)\n#undef DEFINE_CHECK_STROP_IMPL\n}  // namespace internal\n}  // namespace logging\n\n// glibc has traditionally implemented two incompatible versions of\n// strerror_r(). There is a poorly defined convention for picking the\n// version that we want, but it is not clear whether it even works with\n// all versions of glibc.\n// So, instead, we provide this wrapper that automatically detects the\n// version that is in use, and then implements POSIX semantics.\n// N.B. In addition to what POSIX says, we also guarantee that \"buf\" will\n// be set to an empty string, if this function failed. This means, in most\n// cases, you do not need to check the error code and you can directly\n// use the value of \"buf\". It will never have an undefined value.\n// DEPRECATED: Use StrError(int) instead.\nGLOG_NO_EXPORT\nint posix_strerror_r(int err, char* buf, size_t len) {\n  // Sanity check input parameters\n  if (buf == nullptr || len <= 0) {\n    errno = EINVAL;\n    return -1;\n  }\n\n  // Reset buf and errno, and try calling whatever version of strerror_r()\n  // is implemented by glibc\n  buf[0] = '\\000';\n  int old_errno = errno;\n  errno = 0;\n  char* rc = reinterpret_cast<char*>(strerror_r(err, buf, len));\n\n  // Both versions set errno on failure\n  if (errno) {\n    // Should already be there, but better safe than sorry\n    buf[0] = '\\000';\n    return -1;\n  }\n  errno = old_errno;\n\n  // POSIX is vague about whether the string will be terminated, although\n  // is indirectly implies that typically ERANGE will be returned, instead\n  // of truncating the string. This is different from the GNU implementation.\n  // We play it safe by always terminating the string explicitly.\n  buf[len - 1] = '\\000';\n\n  // If the function succeeded, we can use its exit code to determine the\n  // semantics implemented by glibc\n  if (!rc) {\n    return 0;\n  } else {\n    // GNU semantics detected\n    if (rc == buf) {\n      return 0;\n    } else {\n      buf[0] = '\\000';\n#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || \\\n    defined(GLOG_OS_OPENBSD)\n      if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {\n        // This means an error on MacOSX or FreeBSD.\n        return -1;\n      }\n#endif\n      strncat(buf, rc, len - 1);\n      return 0;\n    }\n  }\n}\n\n// A thread-safe replacement for strerror(). Returns a string describing the\n// given POSIX error code.\nstring StrError(int err) {\n  char buf[100];\n  int rc = posix_strerror_r(err, buf, sizeof(buf));\n  if ((rc < 0) || (buf[0] == '\\000')) {\n    std::snprintf(buf, sizeof(buf), \"Error number %d\", err);\n  }\n  return buf;\n}\n\nLogMessageFatal::LogMessageFatal(const char* file, int line)\n    : LogMessage(file, line, GLOG_FATAL) {}\n\nLogMessageFatal::LogMessageFatal(const char* file, int line,\n                                 const logging::internal::CheckOpString& result)\n    : LogMessage(file, line, result) {}\n\nLogMessageFatal::~LogMessageFatal() noexcept(false) {\n  Flush();\n  LogMessage::Fail();\n}\n\nnamespace logging {\nnamespace internal {\n\nCheckOpMessageBuilder::CheckOpMessageBuilder(const char* exprtext)\n    : stream_(new ostringstream) {\n  *stream_ << exprtext << \" (\";\n}\n\nCheckOpMessageBuilder::~CheckOpMessageBuilder() { delete stream_; }\n\nostream* CheckOpMessageBuilder::ForVar2() {\n  *stream_ << \" vs. \";\n  return stream_;\n}\n\nstd::unique_ptr<string> CheckOpMessageBuilder::NewString() {\n  *stream_ << \")\";\n  return std::make_unique<std::string>(stream_->str());\n}\n\ntemplate <>\nvoid MakeCheckOpValueString(std::ostream* os, const char& v) {\n  if (v >= 32 && v <= 126) {\n    (*os) << \"'\" << v << \"'\";\n  } else {\n    (*os) << \"char value \" << static_cast<short>(v);\n  }\n}\n\ntemplate <>\nvoid MakeCheckOpValueString(std::ostream* os, const signed char& v) {\n  if (v >= 32 && v <= 126) {\n    (*os) << \"'\" << v << \"'\";\n  } else {\n    (*os) << \"signed char value \" << static_cast<short>(v);\n  }\n}\n\ntemplate <>\nvoid MakeCheckOpValueString(std::ostream* os, const unsigned char& v) {\n  if (v >= 32 && v <= 126) {\n    (*os) << \"'\" << v << \"'\";\n  } else {\n    (*os) << \"unsigned char value \" << static_cast<unsigned short>(v);\n  }\n}\n\ntemplate <>\nvoid MakeCheckOpValueString(std::ostream* os, const std::nullptr_t& /*v*/) {\n  (*os) << \"nullptr\";\n}\n\n}  // namespace internal\n}  // namespace logging\n\nvoid InitGoogleLogging(const char* argv0) { InitGoogleLoggingUtilities(argv0); }\n\nvoid InstallPrefixFormatter(PrefixFormatterCallback callback, void* data) {\n  if (callback != nullptr) {\n    g_prefix_formatter = std::make_unique<PrefixFormatter>(callback, data);\n  } else {\n    g_prefix_formatter = nullptr;\n  }\n}\n\nvoid ShutdownGoogleLogging() {\n  ShutdownGoogleLoggingUtilities();\n  LogDestination::DeleteLogDestinations();\n  logging_directories_list = nullptr;\n  g_prefix_formatter = nullptr;\n}\n\nvoid EnableLogCleaner(unsigned int overdue_days) {\n  log_cleaner.Enable(std::chrono::duration_cast<std::chrono::minutes>(\n      std::chrono::duration<unsigned, std::ratio<kSecondsInDay>>{\n          overdue_days}));\n}\n\nvoid EnableLogCleaner(const std::chrono::minutes& overdue) {\n  log_cleaner.Enable(overdue);\n}\n\nvoid DisableLogCleaner() { log_cleaner.Disable(); }\n\nLogMessageTime::LogMessageTime() = default;\n\nnamespace {\n\ntemplate <class... Args>\nstruct void_impl {\n  using type = void;\n};\n\ntemplate <class... Args>\nusing void_t = typename void_impl<Args...>::type;\n\ntemplate <class T, class E = void>\nstruct has_member_tm_gmtoff : std::false_type {};\n\ntemplate <class T>\nstruct has_member_tm_gmtoff<T, void_t<decltype(&T::tm_gmtoff)>>\n    : std::true_type {};\n\ntemplate <class T = std::tm>\nauto Breakdown(const std::chrono::system_clock::time_point& now)\n    -> std::enable_if_t<!has_member_tm_gmtoff<T>::value,\n                        std::tuple<std::tm, std::time_t, std::chrono::hours>> {\n  std::time_t timestamp = std::chrono::system_clock::to_time_t(now);\n  std::tm tm_local;\n  std::tm tm_utc;\n  int isdst = 0;\n\n  if (FLAGS_log_utc_time) {\n    gmtime_r(&timestamp, &tm_local);\n    localtime_r(&timestamp, &tm_utc);\n    isdst = tm_utc.tm_isdst;\n    tm_utc = tm_local;\n  } else {\n    localtime_r(&timestamp, &tm_local);\n    isdst = tm_local.tm_isdst;\n    gmtime_r(&timestamp, &tm_utc);\n  }\n\n  std::time_t gmt_sec = std::mktime(&tm_utc);\n\n  // If the Daylight Saving Time(isDst) is active subtract an hour from the\n  // current timestamp.\n  using namespace std::chrono_literals;\n  const auto gmtoffset = std::chrono::duration_cast<std::chrono::hours>(\n      now - std::chrono::system_clock::from_time_t(gmt_sec) +\n      (isdst ? 1h : 0h));\n\n  return std::make_tuple(tm_local, timestamp, gmtoffset);\n}\n\ntemplate <class T = std::tm>\nauto Breakdown(const std::chrono::system_clock::time_point& now)\n    -> std::enable_if_t<has_member_tm_gmtoff<T>::value,\n                        std::tuple<std::tm, std::time_t, std::chrono::hours>> {\n  std::time_t timestamp = std::chrono::system_clock::to_time_t(now);\n  T tm;\n\n  if (FLAGS_log_utc_time) {\n    gmtime_r(&timestamp, &tm);\n  } else {\n    localtime_r(&timestamp, &tm);\n  }\n\n  const auto gmtoffset = std::chrono::duration_cast<std::chrono::hours>(\n      std::chrono::seconds{tm.tm_gmtoff});\n\n  return std::make_tuple(tm, timestamp, gmtoffset);\n}\n\n}  // namespace\n\nLogMessageTime::LogMessageTime(std::chrono::system_clock::time_point now)\n    : timestamp_{now} {\n  std::time_t timestamp;\n  std::tie(tm_, timestamp, gmtoffset_) = Breakdown(now);\n  usecs_ = std::chrono::duration_cast<std::chrono::microseconds>(\n      now - std::chrono::system_clock::from_time_t(timestamp));\n}\n\n}  // namespace google\n"
  },
  {
    "path": "src/logging_striplog_test.sh",
    "content": "#! /bin/sh\n#\n# Copyright (c) 2023, Google Inc.\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are\n# met:\n#\n#     * Redistributions of source code must retain the above copyright\n# notice, this list of conditions and the following disclaimer.\n#     * Redistributions in binary form must reproduce the above\n# copyright notice, this list of conditions and the following disclaimer\n# in the documentation and/or other materials provided with the\n# distribution.\n#     * Neither the name of Google Inc. nor the names of its\n# contributors may be used to endorse or promote products derived from\n# this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#\n# Author: Sergey Ioffe\n\nget_strings () {\n    if test -e \"$1\"; then\n        binary=\"$1\"\n    elif test -e \"$1.exe\"; then\n        binary=\"$1.exe\"\n    else\n        echo \"We coundn't find $1 binary.\"\n        exit 1\n    fi\n\n    strings -n 10 $binary | sort | awk '/TESTMESSAGE/ {printf \"%s \", $2}'\n}\n\n# Die if \"$1\" != \"$2\", print $3 as death reason\ncheck_eq () {\n    if [ \"$1\" != \"$2\" ]; then\n        echo \"Check failed: '$1' == '$2' ${3:+ ($3)}\"\n        exit 1\n    fi\n}\n\ndie () {\n    echo $1\n    exit 1\n}\n\n# Check that the string literals are appropriately stripped. This will\n# not be the case in debug mode.\n\nmode=`GLOG_check_mode=1 ./striplog0_unittest 2> /dev/null`\necho $mode\nif [ \"$mode\" = \"opt\" ];\nthen\n    echo \"In OPT mode\"\n    check_eq \"`get_strings striplog0_unittest`\" \"COND ERROR FATAL INFO WARNING \"\n    check_eq \"`get_strings striplog2_unittest`\" \"COND ERROR FATAL \"\n    check_eq \"`get_strings striplog10_unittest`\" \"\"\nelse\n    echo \"In DBG mode; not checking strings\"\nfi\n\n# Check that LOG(FATAL) aborts even for large STRIP_LOG\n\n./striplog2_unittest 2>/dev/null && die \"Did not abort for STRIP_LOG=2\"\n./striplog10_unittest 2>/dev/null && die \"Did not abort for STRIP_LOG=10\"\n\necho \"PASS\"\n"
  },
  {
    "path": "src/logging_unittest.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Ray Sidney\n\n#include <fcntl.h>\n\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n#include <memory>\n#include <mutex>\n#include <queue>\n#include <sstream>\n#include <stdexcept>\n#include <string>\n#include <thread>\n#include <vector>\n\n#include \"config.h\"\n#ifdef HAVE_GLOB_H\n#  include <glob.h>\n#endif\n#include <sys/stat.h>\n#ifdef HAVE_UNISTD_H\n#  include <unistd.h>\n#endif\n#ifdef HAVE_SYS_WAIT_H\n#  include <sys/wait.h>\n#endif\n\n#include \"base/commandlineflags.h\"\n#include \"glog/logging.h\"\n#include \"glog/raw_logging.h\"\n#include \"googletest.h\"\n#include \"stacktrace.h\"\n#include \"utilities.h\"\n\n#ifdef GLOG_USE_GFLAGS\n#  include <gflags/gflags.h>\nusing namespace GFLAGS_NAMESPACE;\n#endif\n\n#ifdef HAVE_LIB_GMOCK\n#  include <gmock/gmock.h>\n\n#  include \"mock-log.h\"\n// Introduce several symbols from gmock.\nusing google::glog_testing::ScopedMockLog;\nusing testing::_;\nusing testing::AllOf;\nusing testing::AnyNumber;\nusing testing::HasSubstr;\nusing testing::InitGoogleMock;\nusing testing::StrictMock;\nusing testing::StrNe;\n#endif\n\nusing namespace std;\nusing namespace google;\n\n// Some non-advertised functions that we want to test or use.\nnamespace google {\nnamespace base {\nnamespace internal {\nbool GetExitOnDFatal();\nvoid SetExitOnDFatal(bool value);\n}  // namespace internal\n}  // namespace base\n}  // namespace google\n\nstatic void TestLogging(bool check_counts);\nstatic void TestRawLogging();\nstatic void LogWithLevels(int v, int severity, bool err, bool alsoerr);\nstatic void TestLoggingLevels();\nstatic void TestVLogModule();\nstatic void TestLogString();\nstatic void TestLogSink();\nstatic void TestLogToString();\nstatic void TestLogSinkWaitTillSent();\nstatic void TestCHECK();\nstatic void TestDCHECK();\nstatic void TestSTREQ();\nstatic void TestMaxLogSizeWhenNoTimestamp();\nstatic void TestBasename();\nstatic void TestBasenameAppendWhenNoTimestamp();\nstatic void TestTwoProcessesWrite();\nstatic void TestSymlink();\nstatic void TestExtension();\nstatic void TestWrapper();\nstatic void TestErrno();\nstatic void TestTruncate();\nstatic void TestCustomLoggerDeletionOnShutdown();\nstatic void TestLogPeriodically();\n\nstatic int x = -1;\nstatic void BM_Check1(int n) {\n  while (n-- > 0) {\n    CHECK_GE(n, x);\n    CHECK_GE(n, x);\n    CHECK_GE(n, x);\n    CHECK_GE(n, x);\n    CHECK_GE(n, x);\n    CHECK_GE(n, x);\n    CHECK_GE(n, x);\n    CHECK_GE(n, x);\n  }\n}\nBENCHMARK(BM_Check1)\n\nstatic void CheckFailure(int a, int b, const char* file, int line,\n                         const char* msg);\nstatic void BM_Check3(int n) {\n  while (n-- > 0) {\n    if (n < x) CheckFailure(n, x, __FILE__, __LINE__, \"n < x\");\n    if (n < x) CheckFailure(n, x, __FILE__, __LINE__, \"n < x\");\n    if (n < x) CheckFailure(n, x, __FILE__, __LINE__, \"n < x\");\n    if (n < x) CheckFailure(n, x, __FILE__, __LINE__, \"n < x\");\n    if (n < x) CheckFailure(n, x, __FILE__, __LINE__, \"n < x\");\n    if (n < x) CheckFailure(n, x, __FILE__, __LINE__, \"n < x\");\n    if (n < x) CheckFailure(n, x, __FILE__, __LINE__, \"n < x\");\n    if (n < x) CheckFailure(n, x, __FILE__, __LINE__, \"n < x\");\n  }\n}\nBENCHMARK(BM_Check3)\n\nstatic void BM_Check2(int n) {\n  if (n == 17) {\n    x = 5;\n  }\n  while (n-- > 0) {\n    CHECK(n >= x);\n    CHECK(n >= x);\n    CHECK(n >= x);\n    CHECK(n >= x);\n    CHECK(n >= x);\n    CHECK(n >= x);\n    CHECK(n >= x);\n    CHECK(n >= x);\n  }\n}\nBENCHMARK(BM_Check2)\n\nstatic void CheckFailure(int, int, const char* /* file */, int /* line */,\n                         const char* /* msg */) {}\n\nstatic void BM_logspeed(int n) {\n  while (n-- > 0) {\n    LOG(INFO) << \"test message\";\n  }\n}\nBENCHMARK(BM_logspeed)\n\nstatic void BM_vlog(int n) {\n  while (n-- > 0) {\n    VLOG(1) << \"test message\";\n  }\n}\nBENCHMARK(BM_vlog)\n\nnamespace {\n\n// Dynamically generate a prefix using the default format and write it to the\n// stream.\nvoid PrefixAttacher(std::ostream& s, const LogMessage& m, void* data) {\n  // Assert that `data` contains the expected contents before producing the\n  // prefix (otherwise causing the tests to fail):\n  if (data == nullptr || *static_cast<string*>(data) != \"good data\") {\n    return;\n  }\n\n  s << GetLogSeverityName(m.severity())[0] << setw(4) << 1900 + m.time().year()\n    << setw(2) << 1 + m.time().month() << setw(2) << m.time().day() << ' '\n    << setw(2) << m.time().hour() << ':' << setw(2) << m.time().min() << ':'\n    << setw(2) << m.time().sec() << \".\" << setw(6) << m.time().usec() << ' '\n    << setfill(' ') << setw(5) << m.thread_id() << setfill('0') << ' '\n    << m.basename() << ':' << m.line() << \"]\";\n}\n\n}  // namespace\n\nint main(int argc, char** argv) {\n  FLAGS_colorlogtostderr = false;\n  FLAGS_timestamp_in_logfile_name = true;\n\n  // Make sure stderr is not buffered as stderr seems to be buffered\n  // on recent windows.\n  setbuf(stderr, nullptr);\n\n  // Test some basics before InitGoogleLogging:\n  CaptureTestStderr();\n  LogWithLevels(FLAGS_v, FLAGS_stderrthreshold, FLAGS_logtostderr,\n                FLAGS_alsologtostderr);\n  LogWithLevels(0, 0, false, false);  // simulate \"before global c-tors\"\n  const string early_stderr = GetCapturedTestStderr();\n\n  EXPECT_FALSE(IsGoogleLoggingInitialized());\n\n  // Setting a custom prefix generator (it will use the default format so that\n  // the golden outputs can be reused):\n  string prefix_attacher_data = \"good data\";\n  InitGoogleLogging(argv[0]);\n  InstallPrefixFormatter(&PrefixAttacher, &prefix_attacher_data);\n\n  EXPECT_TRUE(IsGoogleLoggingInitialized());\n\n  RunSpecifiedBenchmarks();\n\n  FLAGS_logtostderr = true;\n\n  InitGoogleTest(&argc, argv);\n#ifdef HAVE_LIB_GMOCK\n  InitGoogleMock(&argc, argv);\n#endif\n\n#ifdef GLOG_USE_GFLAGS\n  ParseCommandLineFlags(&argc, &argv, true);\n#endif\n\n  // so that death tests run before we use threads\n  CHECK_EQ(RUN_ALL_TESTS(), 0);\n\n  CaptureTestStderr();\n\n  // re-emit early_stderr\n  LogMessage(\"dummy\", LogMessage::kNoLogPrefix, GLOG_INFO).stream()\n      << early_stderr;\n\n  TestLogging(true);\n  TestRawLogging();\n  TestLoggingLevels();\n  TestVLogModule();\n  TestLogString();\n  TestLogSink();\n  TestLogToString();\n  TestLogSinkWaitTillSent();\n  TestCHECK();\n  TestDCHECK();\n  TestSTREQ();\n\n  // TODO: The golden test portion of this test is very flakey.\n  EXPECT_TRUE(\n      MungeAndDiffTestStderr(FLAGS_test_srcdir + \"/src/logging_unittest.err\"));\n\n  FLAGS_logtostderr = false;\n\n  FLAGS_logtostdout = true;\n  FLAGS_stderrthreshold = NUM_SEVERITIES;\n  CaptureTestStdout();\n  TestRawLogging();\n  TestLoggingLevels();\n  TestLogString();\n  TestLogSink();\n  TestLogToString();\n  TestLogSinkWaitTillSent();\n  TestCHECK();\n  TestDCHECK();\n  TestSTREQ();\n  EXPECT_TRUE(\n      MungeAndDiffTestStdout(FLAGS_test_srcdir + \"/src/logging_unittest.out\"));\n  FLAGS_logtostdout = false;\n\n  TestMaxLogSizeWhenNoTimestamp();\n  TestBasename();\n  TestBasenameAppendWhenNoTimestamp();\n  TestTwoProcessesWrite();\n  TestSymlink();\n  TestExtension();\n  TestWrapper();\n  TestErrno();\n  TestTruncate();\n  TestCustomLoggerDeletionOnShutdown();\n  TestLogPeriodically();\n\n  fprintf(stdout, \"PASS\\n\");\n  return 0;\n}\n\nvoid TestLogging(bool check_counts) {\n  int64 base_num_infos = LogMessage::num_messages(GLOG_INFO);\n  int64 base_num_warning = LogMessage::num_messages(GLOG_WARNING);\n  int64 base_num_errors = LogMessage::num_messages(GLOG_ERROR);\n\n  LOG(INFO) << string(\"foo \") << \"bar \" << 10 << ' ' << 3.4;\n  for (int i = 0; i < 10; ++i) {\n    int old_errno = errno;\n    errno = i;\n    PLOG_EVERY_N(ERROR, 2) << \"Plog every 2, iteration \" << COUNTER;\n    errno = old_errno;\n\n    LOG_EVERY_N(ERROR, 3) << \"Log every 3, iteration \" << COUNTER << endl;\n    LOG_EVERY_N(ERROR, 4) << \"Log every 4, iteration \" << COUNTER << endl;\n\n    LOG_IF_EVERY_N(WARNING, true, 5) << \"Log if every 5, iteration \" << COUNTER;\n    LOG_IF_EVERY_N(WARNING, false, 3)\n        << \"Log if every 3, iteration \" << COUNTER;\n    LOG_IF_EVERY_N(INFO, true, 1) << \"Log if every 1, iteration \" << COUNTER;\n    LOG_IF_EVERY_N(ERROR, (i < 3), 2)\n        << \"Log if less than 3 every 2, iteration \" << COUNTER;\n  }\n  LOG_IF(WARNING, true) << \"log_if this\";\n  LOG_IF(WARNING, false) << \"don't log_if this\";\n\n  char s[] = \"array\";\n  LOG(INFO) << s;\n  const char const_s[] = \"const array\";\n  LOG(INFO) << const_s;\n  int j = 1000;\n  LOG(ERROR) << string(\"foo\") << ' ' << j << ' ' << setw(10) << j << \" \"\n             << setw(1) << hex << j;\n  LOG(INFO) << \"foo \" << std::setw(10) << 1.0;\n\n  {\n    google::LogMessage outer(__FILE__, __LINE__, GLOG_ERROR);\n    outer.stream() << \"outer\";\n\n    LOG(ERROR) << \"inner\";\n  }\n\n  LogMessage(\"foo\", LogMessage::kNoLogPrefix, GLOG_INFO).stream()\n      << \"no prefix\";\n\n  if (check_counts) {\n    CHECK_EQ(base_num_infos + 15, LogMessage::num_messages(GLOG_INFO));\n    CHECK_EQ(base_num_warning + 3, LogMessage::num_messages(GLOG_WARNING));\n    CHECK_EQ(base_num_errors + 17, LogMessage::num_messages(GLOG_ERROR));\n  }\n}\n\nstatic void NoAllocNewHook() { LOG(FATAL) << \"unexpected new\"; }\n\nstruct NewHook {\n  NewHook() { g_new_hook = &NoAllocNewHook; }\n  ~NewHook() { g_new_hook = nullptr; }\n};\n\nnamespace {\nint* allocInt() { return new int; }\n}  // namespace\n\nTEST(DeathNoAllocNewHook, logging) {\n  // tests that NewHook used below works\n  NewHook new_hook;\n  // Avoid unused warnings under MinGW\n  //\n  // NOTE MSVC produces warning C4551 here if we do not take the address of the\n  // function explicitly.\n  (void)&allocInt;\n  ASSERT_DEATH({ allocInt(); }, \"unexpected new\");\n}\n\nvoid TestRawLogging() {\n  auto* foo = new string(\"foo \");\n  string huge_str(50000, 'a');\n\n  FlagSaver saver;\n\n  // Check that RAW logging does not use mallocs.\n  NewHook new_hook;\n\n  RAW_LOG(INFO, \"%s%s%d%c%f\", foo->c_str(), \"bar \", 10, ' ', 3.4);\n  char s[] = \"array\";\n  RAW_LOG(WARNING, \"%s\", s);\n  const char const_s[] = \"const array\";\n  RAW_LOG(INFO, \"%s\", const_s);\n  void* p = reinterpret_cast<void*>(PTR_TEST_VALUE);\n  RAW_LOG(INFO, \"ptr %p\", p);\n  p = nullptr;\n  RAW_LOG(INFO, \"ptr %p\", p);\n  int j = 1000;\n  RAW_LOG(ERROR, \"%s%d%c%010d%s%1x\", foo->c_str(), j, ' ', j, \" \", j);\n  RAW_VLOG(0, \"foo %d\", j);\n\n#if defined(NDEBUG)\n  RAW_LOG(INFO, \"foo %d\", j);  // so that have same stderr to compare\n#else\n  RAW_DLOG(INFO, \"foo %d\", j);  // test RAW_DLOG in debug mode\n#endif\n\n  // test how long messages are chopped:\n  RAW_LOG(WARNING, \"Huge string: %s\", huge_str.c_str());\n  RAW_VLOG(0, \"Huge string: %s\", huge_str.c_str());\n\n  FLAGS_v = 0;\n  RAW_LOG(INFO, \"log\");\n  RAW_VLOG(0, \"vlog 0 on\");\n  RAW_VLOG(1, \"vlog 1 off\");\n  RAW_VLOG(2, \"vlog 2 off\");\n  RAW_VLOG(3, \"vlog 3 off\");\n  FLAGS_v = 2;\n  RAW_LOG(INFO, \"log\");\n  RAW_VLOG(1, \"vlog 1 on\");\n  RAW_VLOG(2, \"vlog 2 on\");\n  RAW_VLOG(3, \"vlog 3 off\");\n\n#if defined(NDEBUG)\n  RAW_DCHECK(1 == 2, \" RAW_DCHECK's shouldn't be compiled in normal mode\");\n#endif\n\n  RAW_CHECK(1 == 1, \"should be ok\");\n  RAW_DCHECK(true, \"should be ok\");\n\n  delete foo;\n}\n\nvoid LogWithLevels(int v, int severity, bool err, bool alsoerr) {\n  RAW_LOG(INFO,\n          \"Test: v=%d stderrthreshold=%d logtostderr=%d alsologtostderr=%d\", v,\n          severity, err, alsoerr);\n\n  FlagSaver saver;\n\n  FLAGS_v = v;\n  FLAGS_stderrthreshold = severity;\n  FLAGS_logtostderr = err;\n  FLAGS_alsologtostderr = alsoerr;\n\n  RAW_VLOG(-1, \"vlog -1\");\n  RAW_VLOG(0, \"vlog 0\");\n  RAW_VLOG(1, \"vlog 1\");\n  RAW_LOG(INFO, \"log info\");\n  RAW_LOG(WARNING, \"log warning\");\n  RAW_LOG(ERROR, \"log error\");\n\n  VLOG(-1) << \"vlog -1\";\n  VLOG(0) << \"vlog 0\";\n  VLOG(1) << \"vlog 1\";\n  LOG(INFO) << \"log info\";\n  LOG(WARNING) << \"log warning\";\n  LOG(ERROR) << \"log error\";\n\n  VLOG_IF(-1, true) << \"vlog_if -1\";\n  VLOG_IF(-1, false) << \"don't vlog_if -1\";\n  VLOG_IF(0, true) << \"vlog_if 0\";\n  VLOG_IF(0, false) << \"don't vlog_if 0\";\n  VLOG_IF(1, true) << \"vlog_if 1\";\n  VLOG_IF(1, false) << \"don't vlog_if 1\";\n  LOG_IF(INFO, true) << \"log_if info\";\n  LOG_IF(INFO, false) << \"don't log_if info\";\n  LOG_IF(WARNING, true) << \"log_if warning\";\n  LOG_IF(WARNING, false) << \"don't log_if warning\";\n  LOG_IF(ERROR, true) << \"log_if error\";\n  LOG_IF(ERROR, false) << \"don't log_if error\";\n\n  int c;\n  c = 1;\n  VLOG_IF(100, c -= 2) << \"vlog_if 100 expr\";\n  EXPECT_EQ(c, -1);\n  c = 1;\n  VLOG_IF(0, c -= 2) << \"vlog_if 0 expr\";\n  EXPECT_EQ(c, -1);\n  c = 1;\n  LOG_IF(INFO, c -= 2) << \"log_if info expr\";\n  EXPECT_EQ(c, -1);\n  c = 1;\n  LOG_IF(ERROR, c -= 2) << \"log_if error expr\";\n  EXPECT_EQ(c, -1);\n  c = 2;\n  VLOG_IF(0, c -= 2) << \"don't vlog_if 0 expr\";\n  EXPECT_EQ(c, 0);\n  c = 2;\n  LOG_IF(ERROR, c -= 2) << \"don't log_if error expr\";\n  EXPECT_EQ(c, 0);\n\n  c = 3;\n  LOG_IF_EVERY_N(INFO, c -= 4, 1) << \"log_if info every 1 expr\";\n  EXPECT_EQ(c, -1);\n  c = 3;\n  LOG_IF_EVERY_N(ERROR, c -= 4, 1) << \"log_if error every 1 expr\";\n  EXPECT_EQ(c, -1);\n  c = 4;\n  LOG_IF_EVERY_N(ERROR, c -= 4, 3) << \"don't log_if info every 3 expr\";\n  EXPECT_EQ(c, 0);\n  c = 4;\n  LOG_IF_EVERY_N(ERROR, c -= 4, 3) << \"don't log_if error every 3 expr\";\n  EXPECT_EQ(c, 0);\n  c = 5;\n  VLOG_IF_EVERY_N(0, c -= 4, 1) << \"vlog_if 0 every 1 expr\";\n  EXPECT_EQ(c, 1);\n  c = 5;\n  VLOG_IF_EVERY_N(100, c -= 4, 3) << \"vlog_if 100 every 3 expr\";\n  EXPECT_EQ(c, 1);\n  c = 6;\n  VLOG_IF_EVERY_N(0, c -= 6, 1) << \"don't vlog_if 0 every 1 expr\";\n  EXPECT_EQ(c, 0);\n  c = 6;\n  VLOG_IF_EVERY_N(100, c -= 6, 3) << \"don't vlog_if 100 every 1 expr\";\n  EXPECT_EQ(c, 0);\n}\n\nvoid TestLoggingLevels() {\n  LogWithLevels(0, GLOG_INFO, false, false);\n  LogWithLevels(1, GLOG_INFO, false, false);\n  LogWithLevels(-1, GLOG_INFO, false, false);\n  LogWithLevels(0, GLOG_WARNING, false, false);\n  LogWithLevels(0, GLOG_ERROR, false, false);\n  LogWithLevels(0, GLOG_FATAL, false, false);\n  LogWithLevels(0, GLOG_FATAL, true, false);\n  LogWithLevels(0, GLOG_FATAL, false, true);\n  LogWithLevels(1, GLOG_WARNING, false, false);\n  LogWithLevels(1, GLOG_FATAL, false, true);\n}\n\nint TestVlogHelper() {\n  if (VLOG_IS_ON(1)) {\n    return 1;\n  }\n  return 0;\n}\n\nvoid TestVLogModule() {\n  int c = TestVlogHelper();\n  EXPECT_EQ(0, c);\n\n#if defined(__GNUC__)\n  EXPECT_EQ(0, SetVLOGLevel(\"logging_unittest\", 1));\n  c = TestVlogHelper();\n  EXPECT_EQ(1, c);\n#endif\n}\n\nTEST(DeathRawCHECK, logging) {\n  ASSERT_DEATH(RAW_CHECK(false, \"failure 1\"),\n               \"RAW: Check false failed: failure 1\");\n  ASSERT_DEBUG_DEATH(RAW_DCHECK(1 == 2, \"failure 2\"),\n                     \"RAW: Check 1 == 2 failed: failure 2\");\n}\n\nvoid TestLogString() {\n  vector<string> errors;\n  vector<string>* no_errors = nullptr;\n\n  LOG_STRING(INFO, &errors) << \"LOG_STRING: \"\n                            << \"collected info\";\n  LOG_STRING(WARNING, &errors) << \"LOG_STRING: \"\n                               << \"collected warning\";\n  LOG_STRING(ERROR, &errors) << \"LOG_STRING: \"\n                             << \"collected error\";\n\n  LOG_STRING(INFO, no_errors) << \"LOG_STRING: \"\n                              << \"reported info\";\n  LOG_STRING(WARNING, no_errors) << \"LOG_STRING: \"\n                                 << \"reported warning\";\n  LOG_STRING(ERROR, nullptr) << \"LOG_STRING: \"\n                             << \"reported error\";\n\n  for (auto& error : errors) {\n    LOG(INFO) << \"Captured by LOG_STRING:  \" << error;\n  }\n}\n\nvoid TestLogToString() {\n  string error;\n  string* no_error = nullptr;\n\n  LOG_TO_STRING(INFO, &error) << \"LOG_TO_STRING: \"\n                              << \"collected info\";\n  LOG(INFO) << \"Captured by LOG_TO_STRING:  \" << error;\n  LOG_TO_STRING(WARNING, &error) << \"LOG_TO_STRING: \"\n                                 << \"collected warning\";\n  LOG(INFO) << \"Captured by LOG_TO_STRING:  \" << error;\n  LOG_TO_STRING(ERROR, &error) << \"LOG_TO_STRING: \"\n                               << \"collected error\";\n  LOG(INFO) << \"Captured by LOG_TO_STRING:  \" << error;\n\n  LOG_TO_STRING(INFO, no_error) << \"LOG_TO_STRING: \"\n                                << \"reported info\";\n  LOG_TO_STRING(WARNING, no_error) << \"LOG_TO_STRING: \"\n                                   << \"reported warning\";\n  LOG_TO_STRING(ERROR, nullptr) << \"LOG_TO_STRING: \"\n                                << \"reported error\";\n}\n\nclass TestLogSinkImpl : public LogSink {\n public:\n  vector<string> errors;\n  void send(LogSeverity severity, const char* /* full_filename */,\n            const char* base_filename, int line,\n            const LogMessageTime& logmsgtime, const char* message,\n            size_t message_len) override {\n    errors.push_back(ToString(severity, base_filename, line, logmsgtime,\n                              message, message_len));\n  }\n};\n\nvoid TestLogSink() {\n  TestLogSinkImpl sink;\n  LogSink* no_sink = nullptr;\n\n  LOG_TO_SINK(&sink, INFO) << \"LOG_TO_SINK: \"\n                           << \"collected info\";\n  LOG_TO_SINK(&sink, WARNING) << \"LOG_TO_SINK: \"\n                              << \"collected warning\";\n  LOG_TO_SINK(&sink, ERROR) << \"LOG_TO_SINK: \"\n                            << \"collected error\";\n\n  LOG_TO_SINK(no_sink, INFO) << \"LOG_TO_SINK: \"\n                             << \"reported info\";\n  LOG_TO_SINK(no_sink, WARNING) << \"LOG_TO_SINK: \"\n                                << \"reported warning\";\n  LOG_TO_SINK(nullptr, ERROR) << \"LOG_TO_SINK: \"\n                              << \"reported error\";\n\n  LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)\n      << \"LOG_TO_SINK_BUT_NOT_TO_LOGFILE: \"\n      << \"collected info\";\n  LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, WARNING)\n      << \"LOG_TO_SINK_BUT_NOT_TO_LOGFILE: \"\n      << \"collected warning\";\n  LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, ERROR)\n      << \"LOG_TO_SINK_BUT_NOT_TO_LOGFILE: \"\n      << \"collected error\";\n\n  LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, INFO)\n      << \"LOG_TO_SINK_BUT_NOT_TO_LOGFILE: \"\n      << \"thrashed info\";\n  LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, WARNING)\n      << \"LOG_TO_SINK_BUT_NOT_TO_LOGFILE: \"\n      << \"thrashed warning\";\n  LOG_TO_SINK_BUT_NOT_TO_LOGFILE(nullptr, ERROR)\n      << \"LOG_TO_SINK_BUT_NOT_TO_LOGFILE: \"\n      << \"thrashed error\";\n\n  LOG(INFO) << \"Captured by LOG_TO_SINK:\";\n  for (auto& error : sink.errors) {\n    LogMessage(\"foo\", LogMessage::kNoLogPrefix, GLOG_INFO).stream() << error;\n  }\n}\n\n// For testing using CHECK*() on anonymous enums.\nenum { CASE_A, CASE_B };\n\nvoid TestCHECK() {\n  // Tests using CHECK*() on int values.\n  CHECK(1 == 1);\n  CHECK_EQ(1, 1);\n  CHECK_NE(1, 2);\n  CHECK_GE(1, 1);\n  CHECK_GE(2, 1);\n  CHECK_LE(1, 1);\n  CHECK_LE(1, 2);\n  CHECK_GT(2, 1);\n  CHECK_LT(1, 2);\n\n  // Tests using CHECK*() on anonymous enums.\n  // Apple's GCC doesn't like this.\n#if !defined(GLOG_OS_MACOSX)\n  CHECK_EQ(CASE_A, CASE_A);\n  CHECK_NE(CASE_A, CASE_B);\n  CHECK_GE(CASE_A, CASE_A);\n  CHECK_GE(CASE_B, CASE_A);\n  CHECK_LE(CASE_A, CASE_A);\n  CHECK_LE(CASE_A, CASE_B);\n  CHECK_GT(CASE_B, CASE_A);\n  CHECK_LT(CASE_A, CASE_B);\n#endif\n}\n\nvoid TestDCHECK() {\n#if defined(NDEBUG)\n  DCHECK(1 == 2) << \" DCHECK's shouldn't be compiled in normal mode\";\n#endif\n  DCHECK(1 == 1);\n  DCHECK_EQ(1, 1);\n  DCHECK_NE(1, 2);\n  DCHECK_GE(1, 1);\n  DCHECK_GE(2, 1);\n  DCHECK_LE(1, 1);\n  DCHECK_LE(1, 2);\n  DCHECK_GT(2, 1);\n  DCHECK_LT(1, 2);\n\n  auto* orig_ptr = new int64;\n  int64* ptr = DCHECK_NOTNULL(orig_ptr);\n  CHECK_EQ(ptr, orig_ptr);\n  delete orig_ptr;\n}\n\nvoid TestSTREQ() {\n  CHECK_STREQ(\"this\", \"this\");\n  CHECK_STREQ(nullptr, nullptr);\n  CHECK_STRCASEEQ(\"this\", \"tHiS\");\n  CHECK_STRCASEEQ(nullptr, nullptr);\n  CHECK_STRNE(\"this\", \"tHiS\");\n  CHECK_STRNE(\"this\", nullptr);\n  CHECK_STRCASENE(\"this\", \"that\");\n  CHECK_STRCASENE(nullptr, \"that\");\n  CHECK_STREQ((string(\"a\") + \"b\").c_str(), \"ab\");\n  CHECK_STREQ(string(\"test\").c_str(), (string(\"te\") + string(\"st\")).c_str());\n}\n\nTEST(DeathSTREQ, logging) {\n  ASSERT_DEATH(CHECK_STREQ(nullptr, \"this\"), \"\");\n  ASSERT_DEATH(CHECK_STREQ(\"this\", \"siht\"), \"\");\n  ASSERT_DEATH(CHECK_STRCASEEQ(nullptr, \"siht\"), \"\");\n  ASSERT_DEATH(CHECK_STRCASEEQ(\"this\", \"siht\"), \"\");\n  ASSERT_DEATH(CHECK_STRNE(nullptr, nullptr), \"\");\n  ASSERT_DEATH(CHECK_STRNE(\"this\", \"this\"), \"\");\n  ASSERT_DEATH(CHECK_STREQ((string(\"a\") + \"b\").c_str(), \"abc\"), \"\");\n}\n\nTEST(CheckNOTNULL, Simple) {\n  int64 t;\n  void* ptr = static_cast<void*>(&t);\n  void* ref = CHECK_NOTNULL(ptr);\n  EXPECT_EQ(ptr, ref);\n  CHECK_NOTNULL(reinterpret_cast<char*>(ptr));\n  CHECK_NOTNULL(reinterpret_cast<unsigned char*>(ptr));\n  CHECK_NOTNULL(reinterpret_cast<int*>(ptr));\n  CHECK_NOTNULL(reinterpret_cast<int64*>(ptr));\n}\n\nTEST(DeathCheckNN, Simple) {\n  ASSERT_DEATH(CHECK_NOTNULL(static_cast<void*>(nullptr)), \"\");\n}\n\n// Get list of file names that match pattern\nstatic void GetFiles(const string& pattern, vector<string>* files) {\n  files->clear();\n#if defined(HAVE_GLOB_H)\n  glob_t g;\n  const int r = glob(pattern.c_str(), 0, nullptr, &g);\n  CHECK((r == 0) || (r == GLOB_NOMATCH)) << \": error matching \" << pattern;\n  for (size_t i = 0; i < g.gl_pathc; i++) {\n    files->push_back(string(g.gl_pathv[i]));\n  }\n  globfree(&g);\n#elif defined(GLOG_OS_WINDOWS)\n  WIN32_FIND_DATAA data;\n  HANDLE handle = FindFirstFileA(pattern.c_str(), &data);\n  size_t index = pattern.rfind('\\\\');\n  if (index == string::npos) {\n    LOG(FATAL) << \"No directory separator.\";\n  }\n  const string dirname = pattern.substr(0, index + 1);\n  if (handle == INVALID_HANDLE_VALUE) {\n    // Finding no files is OK.\n    return;\n  }\n  do {\n    files->push_back(dirname + data.cFileName);\n  } while (FindNextFileA(handle, &data));\n  if (!FindClose(handle)) {\n    LOG_SYSRESULT(GetLastError());\n  }\n#else\n#  error There is no way to do glob.\n#endif\n}\n\n// Delete files patching pattern\nstatic void DeleteFiles(const string& pattern) {\n  vector<string> files;\n  GetFiles(pattern, &files);\n  for (auto& file : files) {\n    CHECK(unlink(file.c_str()) == 0) << \": \" << strerror(errno);\n  }\n}\n\n// check string is in file (or is *NOT*, depending on optional checkInFileOrNot)\nstatic void CheckFile(const string& name, const string& expected_string,\n                      const bool checkInFileOrNot = true) {\n  vector<string> files;\n  GetFiles(name + \"*\", &files);\n  CHECK_EQ(files.size(), 1UL);\n\n  std::unique_ptr<std::FILE> file{fopen(files[0].c_str(), \"r\")};\n  CHECK(file != nullptr) << \": could not open \" << files[0];\n  char buf[1000];\n  while (fgets(buf, sizeof(buf), file.get()) != nullptr) {\n    char* first = strstr(buf, expected_string.c_str());\n    // if first == nullptr, not found.\n    // Terser than if (checkInFileOrNot && first != nullptr || !check...\n    if (checkInFileOrNot != (first == nullptr)) {\n      return;\n    }\n  }\n  LOG(FATAL) << \"Did \" << (checkInFileOrNot ? \"not \" : \"\") << \"find \"\n             << expected_string << \" in \" << files[0];\n}\n\nstatic void TestMaxLogSizeWhenNoTimestamp() {\n  fprintf(stderr, \"==== Test setting max log size without timestamp\\n\");\n  const string dest = FLAGS_test_tmpdir + \"/logging_test_max_log_size\";\n  DeleteFiles(dest + \"*\");\n\n  auto original_max_log_size = FLAGS_max_log_size;\n  auto original_timestamp_in_logfile_name = FLAGS_timestamp_in_logfile_name;\n\n  FLAGS_max_log_size = 1;  // Set max log size to 1MB\n  FLAGS_timestamp_in_logfile_name = false;\n\n  // Set log destination\n  SetLogDestination(GLOG_INFO, dest.c_str());\n\n  // 1e4 info logs -> is about 772 KB in size\n  // 2e4 info logs -> is around 1500 KB in size -> 1.5MB\n  // If our max_log_size constraint is respected, it will truncate earlier logs\n  // and the file size will be lesser than 1MB (around 0.5MB)\n  const int num_logs = 2e4;\n  for (int i = 0; i < num_logs; i++) {\n    LOG(INFO) << \"Hello world\";\n  }\n  FlushLogFiles(GLOG_INFO);\n\n  // Check log file size\n  struct stat statbuf;\n  stat(dest.c_str(), &statbuf);\n\n  // Verify file size is less than the max log size limit\n  CHECK_LT(static_cast<unsigned int>(statbuf.st_size),\n           FLAGS_max_log_size << 20U);\n\n  // Reset flag values to their original values\n  FLAGS_max_log_size = original_max_log_size;\n  FLAGS_timestamp_in_logfile_name = original_timestamp_in_logfile_name;\n\n  // Release file handle for the destination file to unlock the file in Windows.\n  LogToStderr();\n  DeleteFiles(dest + \"*\");\n}\n\nstatic void TestBasename() {\n  fprintf(stderr, \"==== Test setting log file basename\\n\");\n  const string dest = FLAGS_test_tmpdir + \"/logging_test_basename\";\n  DeleteFiles(dest + \"*\");\n\n  SetLogDestination(GLOG_INFO, dest.c_str());\n  LOG(INFO) << \"message to new base\";\n  FlushLogFiles(GLOG_INFO);\n\n  CheckFile(dest, \"message to new base\");\n\n  // Release file handle for the destination file to unlock the file in Windows.\n  LogToStderr();\n  DeleteFiles(dest + \"*\");\n}\n\nstatic void TestBasenameAppendWhenNoTimestamp() {\n  fprintf(stderr,\n          \"==== Test setting log file basename without timestamp and appending \"\n          \"properly\\n\");\n  const string dest =\n      FLAGS_test_tmpdir + \"/logging_test_basename_append_when_no_timestamp\";\n  DeleteFiles(dest + \"*\");\n\n  ofstream out(dest.c_str());\n  out << \"test preexisting content\" << endl;\n  out.close();\n\n  CheckFile(dest, \"test preexisting content\");\n\n  FLAGS_timestamp_in_logfile_name = false;\n  SetLogDestination(GLOG_INFO, dest.c_str());\n  LOG(INFO) << \"message to new base, appending to preexisting file\";\n  FlushLogFiles(GLOG_INFO);\n  FLAGS_timestamp_in_logfile_name = true;\n\n  // if the logging overwrites the file instead of appending it will fail.\n  CheckFile(dest, \"test preexisting content\");\n  CheckFile(dest, \"message to new base, appending to preexisting file\");\n\n  // Release file handle for the destination file to unlock the file in Windows.\n  LogToStderr();\n  DeleteFiles(dest + \"*\");\n}\n\nstatic void TestTwoProcessesWrite() {\n// test only implemented for platforms with fork & wait; the actual\n// implementation relies on flock\n#if defined(HAVE_SYS_WAIT_H) && defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL)\n  fprintf(stderr,\n          \"==== Test setting log file basename and two processes writing - \"\n          \"second should fail\\n\");\n  const string dest =\n      FLAGS_test_tmpdir + \"/logging_test_basename_two_processes_writing\";\n  DeleteFiles(dest + \"*\");\n\n  // make both processes write into the same file (easier test)\n  FLAGS_timestamp_in_logfile_name = false;\n  SetLogDestination(GLOG_INFO, dest.c_str());\n  LOG(INFO) << \"message to new base, parent\";\n  FlushLogFiles(GLOG_INFO);\n\n  pid_t pid = fork();\n  CHECK_ERR(pid);\n  if (pid == 0) {\n    LOG(INFO) << \"message to new base, child - should only appear on STDERR \"\n                 \"not on the file\";\n    ShutdownGoogleLogging();  // for children proc\n    exit(EXIT_SUCCESS);\n  } else if (pid > 0) {\n    wait(nullptr);\n  }\n  FLAGS_timestamp_in_logfile_name = true;\n\n  CheckFile(dest, \"message to new base, parent\");\n  CheckFile(dest,\n            \"message to new base, child - should only appear on STDERR not on \"\n            \"the file\",\n            false);\n\n  // Release\n  LogToStderr();\n  DeleteFiles(dest + \"*\");\n#endif\n}\n\nstatic void TestSymlink() {\n#ifndef GLOG_OS_WINDOWS\n  fprintf(stderr, \"==== Test setting log file symlink\\n\");\n  string dest = FLAGS_test_tmpdir + \"/logging_test_symlink\";\n  string sym = FLAGS_test_tmpdir + \"/symlinkbase\";\n  DeleteFiles(dest + \"*\");\n  DeleteFiles(sym + \"*\");\n\n  SetLogSymlink(GLOG_INFO, \"symlinkbase\");\n  SetLogDestination(GLOG_INFO, dest.c_str());\n  LOG(INFO) << \"message to new symlink\";\n  FlushLogFiles(GLOG_INFO);\n  CheckFile(sym, \"message to new symlink\");\n\n  DeleteFiles(dest + \"*\");\n  DeleteFiles(sym + \"*\");\n#endif\n}\n\nstatic void TestExtension() {\n  fprintf(stderr, \"==== Test setting log file extension\\n\");\n  string dest = FLAGS_test_tmpdir + \"/logging_test_extension\";\n  DeleteFiles(dest + \"*\");\n\n  SetLogDestination(GLOG_INFO, dest.c_str());\n  SetLogFilenameExtension(\"specialextension\");\n  LOG(INFO) << \"message to new extension\";\n  FlushLogFiles(GLOG_INFO);\n  CheckFile(dest, \"message to new extension\");\n\n  // Check that file name ends with extension\n  vector<string> filenames;\n  GetFiles(dest + \"*\", &filenames);\n  CHECK_EQ(filenames.size(), 1UL);\n  CHECK(strstr(filenames[0].c_str(), \"specialextension\") != nullptr);\n\n  // Release file handle for the destination file to unlock the file in Windows.\n  LogToStderr();\n  DeleteFiles(dest + \"*\");\n}\n\nstruct MyLogger : public base::Logger {\n  string data;\n\n  explicit MyLogger(bool* set_on_destruction)\n      : set_on_destruction_(set_on_destruction) {}\n\n  ~MyLogger() override { *set_on_destruction_ = true; }\n\n  void Write(bool /* should_flush */,\n             const std::chrono::system_clock::time_point& /* timestamp */,\n             const char* message, size_t length) override {\n    data.append(message, length);\n  }\n\n  void Flush() override {}\n\n  uint32 LogSize() override { return static_cast<uint32>(data.length()); }\n\n private:\n  bool* set_on_destruction_;\n};\n\nstatic void TestWrapper() {\n  fprintf(stderr, \"==== Test log wrapper\\n\");\n\n  bool custom_logger_deleted = false;\n  auto* my_logger = new MyLogger(&custom_logger_deleted);\n  base::Logger* old_logger = base::GetLogger(GLOG_INFO);\n  base::SetLogger(GLOG_INFO, my_logger);\n  LOG(INFO) << \"Send to wrapped logger\";\n  CHECK(strstr(my_logger->data.c_str(), \"Send to wrapped logger\") != nullptr);\n  FlushLogFiles(GLOG_INFO);\n\n  EXPECT_FALSE(custom_logger_deleted);\n  base::SetLogger(GLOG_INFO, old_logger);\n  EXPECT_TRUE(custom_logger_deleted);\n}\n\nstatic void TestErrno() {\n  fprintf(stderr, \"==== Test errno preservation\\n\");\n\n  errno = ENOENT;\n  TestLogging(false);\n  CHECK_EQ(errno, ENOENT);\n}\n\nstatic void TestOneTruncate(const char* path, uint64 limit, uint64 keep,\n                            size_t dsize, size_t ksize, size_t expect) {\n  FileDescriptor fd{open(path, O_RDWR | O_CREAT | O_TRUNC, 0600)};\n  CHECK_ERR(fd);\n\n  const char *discardstr = \"DISCARDME!\", *keepstr = \"KEEPME!\";\n  const size_t discard_size = strlen(discardstr), keep_size = strlen(keepstr);\n\n  // Fill the file with the requested data; first discard data, then kept data\n  size_t written = 0;\n  while (written < dsize) {\n    size_t bytes = min(dsize - written, discard_size);\n    CHECK_ERR(write(fd.get(), discardstr, bytes));\n    written += bytes;\n  }\n  written = 0;\n  while (written < ksize) {\n    size_t bytes = min(ksize - written, keep_size);\n    CHECK_ERR(write(fd.get(), keepstr, bytes));\n    written += bytes;\n  }\n\n  TruncateLogFile(path, limit, keep);\n\n  // File should now be shorter\n  struct stat statbuf;\n  CHECK_ERR(fstat(fd.get(), &statbuf));\n  CHECK_EQ(static_cast<size_t>(statbuf.st_size), expect);\n  CHECK_ERR(lseek(fd.get(), 0, SEEK_SET));\n\n  // File should contain the suffix of the original file\n  const size_t buf_size = static_cast<size_t>(statbuf.st_size) + 1;\n  std::vector<char> buf(buf_size);\n  CHECK_ERR(read(fd.get(), buf.data(), buf_size));\n\n  const char* p = buf.data();\n  size_t checked = 0;\n  while (checked < expect) {\n    size_t bytes = min(expect - checked, keep_size);\n    CHECK(!memcmp(p, keepstr, bytes));\n    checked += bytes;\n  }\n}\n\nstatic void TestTruncate() {\n#ifdef HAVE_UNISTD_H\n  fprintf(stderr, \"==== Test log truncation\\n\");\n  string path = FLAGS_test_tmpdir + \"/truncatefile\";\n\n  // Test on a small file\n  TestOneTruncate(path.c_str(), 10, 10, 10, 10, 10);\n\n  // And a big file (multiple blocks to copy)\n  TestOneTruncate(path.c_str(), 2U << 20U, 4U << 10U, 3U << 20U, 4U << 10U,\n                  4U << 10U);\n\n  // Check edge-case limits\n  TestOneTruncate(path.c_str(), 10, 20, 0, 20, 20);\n  TestOneTruncate(path.c_str(), 10, 0, 0, 0, 0);\n  TestOneTruncate(path.c_str(), 10, 50, 0, 10, 10);\n  TestOneTruncate(path.c_str(), 50, 100, 0, 30, 30);\n\n  // MacOSX 10.4 doesn't fail in this case.\n  // Windows doesn't have symlink.\n  // Let's just ignore this test for these cases.\n#  if !defined(GLOG_OS_MACOSX) && !defined(GLOG_OS_WINDOWS)\n  // Through a symlink should fail to truncate\n  string linkname = path + \".link\";\n  unlink(linkname.c_str());\n  CHECK_ERR(symlink(path.c_str(), linkname.c_str()));\n  TestOneTruncate(linkname.c_str(), 10, 10, 0, 30, 30);\n#  endif\n\n  // The /proc/self path makes sense only for linux.\n#  if defined(GLOG_OS_LINUX)\n  // Through an open fd symlink should work\n  int fd;\n  CHECK_ERR(fd = open(path.c_str(), O_APPEND | O_WRONLY));\n  char fdpath[64];\n  std::snprintf(fdpath, sizeof(fdpath), \"/proc/self/fd/%d\", fd);\n  TestOneTruncate(fdpath, 10, 10, 10, 10, 10);\n#  endif\n\n#endif\n}\n\nstruct RecordDeletionLogger : public base::Logger {\n  RecordDeletionLogger(bool* set_on_destruction, base::Logger* wrapped_logger)\n      : set_on_destruction_(set_on_destruction),\n        wrapped_logger_(wrapped_logger) {\n    *set_on_destruction_ = false;\n  }\n  ~RecordDeletionLogger() override { *set_on_destruction_ = true; }\n  void Write(bool force_flush,\n             const std::chrono::system_clock::time_point& timestamp,\n             const char* message, size_t length) override {\n    wrapped_logger_->Write(force_flush, timestamp, message, length);\n  }\n  void Flush() override { wrapped_logger_->Flush(); }\n  uint32 LogSize() override { return wrapped_logger_->LogSize(); }\n\n private:\n  bool* set_on_destruction_;\n  base::Logger* wrapped_logger_;\n};\n\nstatic void TestCustomLoggerDeletionOnShutdown() {\n  bool custom_logger_deleted = false;\n  base::SetLogger(GLOG_INFO,\n                  new RecordDeletionLogger(&custom_logger_deleted,\n                                           base::GetLogger(GLOG_INFO)));\n  EXPECT_TRUE(IsGoogleLoggingInitialized());\n  ShutdownGoogleLogging();\n  EXPECT_TRUE(custom_logger_deleted);\n  EXPECT_FALSE(IsGoogleLoggingInitialized());\n}\n\nnamespace LogTimes {\n// Log a \"message\" every 10ms, 10 times. These numbers are nice compromise\n// between total running time of 100ms and the period of 10ms. The period is\n// large enough such that any CPU and OS scheduling variation shouldn't affect\n// the results from the ideal case by more than 5% (500us or 0.5ms)\nconstexpr int64_t LOG_PERIOD_NS = 10000000;    // 10ms\nconstexpr int64_t LOG_PERIOD_TOL_NS = 500000;  // 500us\n\n// Set an upper limit for the number of times the stream operator can be\n// called. Make sure not to exceed this number of times the stream operator is\n// called, since it is also the array size and will be indexed by the stream\n// operator.\nconstexpr size_t MAX_CALLS = 10;\n}  // namespace LogTimes\n\nstruct LogTimeRecorder {\n  LogTimeRecorder() = default;\n  size_t m_streamTimes{0};\n  std::chrono::steady_clock::time_point m_callTimes[LogTimes::MAX_CALLS];\n};\n// The stream operator is called by LOG_EVERY_T every time a logging event\n// occurs. Make sure to save the times for each call as they will be used later\n// to verify the time delta between each call.\nstd::ostream& operator<<(std::ostream& stream, LogTimeRecorder& t) {\n  t.m_callTimes[t.m_streamTimes++] = std::chrono::steady_clock::now();\n  return stream;\n}\n// get elapsed time in nanoseconds\nint64 elapsedTime_ns(const std::chrono::steady_clock::time_point& begin,\n                     const std::chrono::steady_clock::time_point& end) {\n  return std::chrono::duration_cast<std::chrono::nanoseconds>((end - begin))\n      .count();\n}\n\nstatic void TestLogPeriodically() {\n  fprintf(stderr, \"==== Test log periodically\\n\");\n\n  LogTimeRecorder timeLogger;\n\n  constexpr double LOG_PERIOD_SEC = LogTimes::LOG_PERIOD_NS * 1e-9;\n\n  while (timeLogger.m_streamTimes < LogTimes::MAX_CALLS) {\n    LOG_EVERY_T(INFO, LOG_PERIOD_SEC)\n        << timeLogger << \"Timed Message #\" << timeLogger.m_streamTimes;\n  }\n\n  // Calculate time between each call in nanoseconds for higher resolution to\n  // minimize error.\n  int64 nsBetweenCalls[LogTimes::MAX_CALLS - 1];\n  for (size_t i = 1; i < LogTimes::MAX_CALLS; ++i) {\n    nsBetweenCalls[i - 1] = elapsedTime_ns(timeLogger.m_callTimes[i - 1],\n                                           timeLogger.m_callTimes[i]);\n  }\n\n  for (long time_ns : nsBetweenCalls) {\n    EXPECT_NEAR(time_ns, LogTimes::LOG_PERIOD_NS, LogTimes::LOG_PERIOD_TOL_NS);\n  }\n}\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n// in logging.cc\nextern bool SafeFNMatch_(const char* pattern, size_t patt_len, const char* str,\n                         size_t str_len);\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\nstatic bool WrapSafeFNMatch(string pattern, string str) {\n  pattern += \"abc\";\n  str += \"defgh\";\n  return SafeFNMatch_(pattern.data(), pattern.size() - 3, str.data(),\n                      str.size() - 5);\n}\n\nTEST(SafeFNMatch, logging) {\n  CHECK(WrapSafeFNMatch(\"foo\", \"foo\"));\n  CHECK(!WrapSafeFNMatch(\"foo\", \"bar\"));\n  CHECK(!WrapSafeFNMatch(\"foo\", \"fo\"));\n  CHECK(!WrapSafeFNMatch(\"foo\", \"foo2\"));\n  CHECK(WrapSafeFNMatch(\"bar/foo.ext\", \"bar/foo.ext\"));\n  CHECK(WrapSafeFNMatch(\"*ba*r/fo*o.ext*\", \"bar/foo.ext\"));\n  CHECK(!WrapSafeFNMatch(\"bar/foo.ext\", \"bar/baz.ext\"));\n  CHECK(!WrapSafeFNMatch(\"bar/foo.ext\", \"bar/foo\"));\n  CHECK(!WrapSafeFNMatch(\"bar/foo.ext\", \"bar/foo.ext.zip\"));\n  CHECK(WrapSafeFNMatch(\"ba?/*.ext\", \"bar/foo.ext\"));\n  CHECK(WrapSafeFNMatch(\"ba?/*.ext\", \"baZ/FOO.ext\"));\n  CHECK(!WrapSafeFNMatch(\"ba?/*.ext\", \"barr/foo.ext\"));\n  CHECK(!WrapSafeFNMatch(\"ba?/*.ext\", \"bar/foo.ext2\"));\n  CHECK(WrapSafeFNMatch(\"ba?/*\", \"bar/foo.ext2\"));\n  CHECK(WrapSafeFNMatch(\"ba?/*\", \"bar/\"));\n  CHECK(!WrapSafeFNMatch(\"ba?/?\", \"bar/\"));\n  CHECK(!WrapSafeFNMatch(\"ba?/*\", \"bar\"));\n}\n\n// TestWaitingLogSink will save messages here\n// No lock: Accessed only by TestLogSinkWriter thread\n// and after its demise by its creator.\nstatic vector<string> global_messages;\n\n// helper for TestWaitingLogSink below.\n// Thread that does the logic of TestWaitingLogSink\n// It's free to use LOG() itself.\nclass TestLogSinkWriter {\n public:\n  TestLogSinkWriter() : t_{&TestLogSinkWriter::Run, this} {}\n\n  // Just buffer it (can't use LOG() here).\n  void Buffer(const string& message) {\n    mutex_.lock();\n    RAW_LOG(INFO, \"Buffering\");\n    messages_.push(message);\n    mutex_.unlock();\n    RAW_LOG(INFO, \"Buffered\");\n  }\n\n  // Wait for the buffer to clear (can't use LOG() here).\n  void Wait() {\n    using namespace std::chrono_literals;\n    RAW_LOG(INFO, \"Waiting\");\n    mutex_.lock();\n    while (!NoWork()) {\n      mutex_.unlock();\n      std::this_thread::sleep_for(1ms);\n      mutex_.lock();\n    }\n    RAW_LOG(INFO, \"Waited\");\n    mutex_.unlock();\n  }\n\n  // Trigger thread exit.\n  void Stop() {\n    std::lock_guard<std::mutex> l(mutex_);\n    should_exit_ = true;\n  }\n\n  void Join() { t_.join(); }\n\n private:\n  // helpers ---------------\n\n  // For creating a \"Condition\".\n  bool NoWork() { return messages_.empty(); }\n  bool HaveWork() { return !messages_.empty() || should_exit_; }\n\n  // Thread body; CAN use LOG() here!\n  void Run() {\n    using namespace std::chrono_literals;\n    while (true) {\n      mutex_.lock();\n      while (!HaveWork()) {\n        mutex_.unlock();\n        std::this_thread::sleep_for(1ms);\n        mutex_.lock();\n      }\n      if (should_exit_ && messages_.empty()) {\n        mutex_.unlock();\n        break;\n      }\n      // Give the main thread time to log its message,\n      // so that we get a reliable log capture to compare to golden file.\n      // Same for the other sleep below.\n      std::this_thread::sleep_for(20ms);\n      RAW_LOG(INFO, \"Sink got a messages\");  // only RAW_LOG under mutex_ here\n      string message = messages_.front();\n      messages_.pop();\n      // Normally this would be some more real/involved logging logic\n      // where LOG() usage can't be eliminated,\n      // e.g. pushing the message over with an RPC:\n      size_t messages_left = messages_.size();\n      mutex_.unlock();\n      std::this_thread::sleep_for(20ms);\n      // May not use LOG while holding mutex_, because Buffer()\n      // acquires mutex_, and Buffer is called from LOG(),\n      // which has its own internal mutex:\n      // LOG()->LogToSinks()->TestWaitingLogSink::send()->Buffer()\n      LOG(INFO) << \"Sink is sending out a message: \" << message;\n      LOG(INFO) << \"Have \" << messages_left << \" left\";\n      global_messages.push_back(message);\n    }\n  }\n\n  // data ---------------\n\n  std::thread t_;\n  std::mutex mutex_;\n  bool should_exit_{false};\n  queue<string> messages_;  // messages to be logged\n};\n\n// A log sink that exercises WaitTillSent:\n// it pushes data to a buffer and wakes up another thread to do the logging\n// (that other thread can than use LOG() itself),\nclass TestWaitingLogSink : public LogSink {\n public:\n  TestWaitingLogSink() {\n    tid_ = std::this_thread::get_id();  // for thread-specific behavior\n    AddLogSink(this);\n  }\n  ~TestWaitingLogSink() override {\n    RemoveLogSink(this);\n    writer_.Stop();\n    writer_.Join();\n  }\n\n  // (re)define LogSink interface\n\n  void send(LogSeverity severity, const char* /* full_filename */,\n            const char* base_filename, int line,\n            const LogMessageTime& logmsgtime, const char* message,\n            size_t message_len) override {\n    // Push it to Writer thread if we are the original logging thread.\n    // Note: Something like ThreadLocalLogSink is a better choice\n    //       to do thread-specific LogSink logic for real.\n    if (tid_ == std::this_thread::get_id()) {\n      writer_.Buffer(ToString(severity, base_filename, line, logmsgtime,\n                              message, message_len));\n    }\n  }\n\n  void WaitTillSent() override {\n    // Wait for Writer thread if we are the original logging thread.\n    if (tid_ == std::this_thread::get_id()) writer_.Wait();\n  }\n\n private:\n  std::thread::id tid_;\n  TestLogSinkWriter writer_;\n};\n\n// Check that LogSink::WaitTillSent can be used in the advertised way.\n// We also do golden-stderr comparison.\nstatic void TestLogSinkWaitTillSent() {\n  // Clear global_messages here to make sure that this test case can be\n  // reentered\n  global_messages.clear();\n  {\n    using namespace std::chrono_literals;\n    TestWaitingLogSink sink;\n    // Sleeps give the sink threads time to do all their work,\n    // so that we get a reliable log capture to compare to the golden file.\n    LOG(INFO) << \"Message 1\";\n    std::this_thread::sleep_for(60ms);\n    LOG(ERROR) << \"Message 2\";\n    std::this_thread::sleep_for(60ms);\n    LOG(WARNING) << \"Message 3\";\n    std::this_thread::sleep_for(60ms);\n  }\n  for (auto& global_message : global_messages) {\n    LOG(INFO) << \"Sink capture: \" << global_message;\n  }\n  CHECK_EQ(global_messages.size(), 3UL);\n}\n\nTEST(Strerror, logging) {\n  int errcode = EINTR;\n  std::string msg = strerror(errcode);\n  const size_t buf_size = msg.size() + 1;\n  std::vector<char> buf(buf_size);\n  CHECK_EQ(posix_strerror_r(errcode, nullptr, 0), -1);\n  buf[0] = 'A';\n  CHECK_EQ(posix_strerror_r(errcode, buf.data(), 0), -1);\n  CHECK_EQ(buf[0], 'A');\n  CHECK_EQ(posix_strerror_r(errcode, nullptr, buf_size), -1);\n#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || \\\n    defined(GLOG_OS_OPENBSD)\n  // MacOSX or FreeBSD considers this case is an error since there is\n  // no enough space.\n  CHECK_EQ(posix_strerror_r(errcode, buf.data(), 1), -1);\n#else\n  CHECK_EQ(posix_strerror_r(errcode, buf.data(), 1), 0);\n#endif\n  CHECK_STREQ(buf.data(), \"\");\n  CHECK_EQ(posix_strerror_r(errcode, buf.data(), buf_size), 0);\n  CHECK_STREQ(buf.data(), msg.c_str());\n  CHECK_EQ(msg, StrError(errcode));\n}\n\n// Simple routines to look at the sizes of generated code for LOG(FATAL) and\n// CHECK(..) via objdump\n/*\nstatic void MyFatal() {\n  LOG(FATAL) << \"Failed\";\n}\nstatic void MyCheck(bool a, bool b) {\n  CHECK_EQ(a, b);\n}\n*/\n#ifdef HAVE_LIB_GMOCK\n\nTEST(DVLog, Basic) {\n  ScopedMockLog log;\n\n#  if defined(NDEBUG)\n  // We are expecting that nothing is logged.\n  EXPECT_CALL(log, Log(_, _, _)).Times(0);\n#  else\n  EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, \"debug log\"));\n#  endif\n\n  FLAGS_v = 1;\n  DVLOG(1) << \"debug log\";\n}\n\nTEST(DVLog, V0) {\n  ScopedMockLog log;\n\n  // We are expecting that nothing is logged.\n  EXPECT_CALL(log, Log(_, _, _)).Times(0);\n\n  FLAGS_v = 0;\n  DVLOG(1) << \"debug log\";\n}\n\nTEST(LogAtLevel, Basic) {\n  ScopedMockLog log;\n\n  // The function version outputs \"logging.h\" as a file name.\n  EXPECT_CALL(log, Log(GLOG_WARNING, StrNe(__FILE__), \"function version\"));\n  EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, \"macro version\"));\n\n  LogSeverity severity = GLOG_WARNING;\n  LogAtLevel(severity, \"function version\");\n\n  severity = GLOG_INFO;\n  // We can use the macro version as a C++ stream.\n  LOG_AT_LEVEL(severity) << \"macro\" << ' ' << \"version\";\n}\n\nTEST(TestExitOnDFatal, ToBeOrNotToBe) {\n  // Check the default setting...\n  EXPECT_TRUE(base::internal::GetExitOnDFatal());\n\n  // Turn off...\n  base::internal::SetExitOnDFatal(false);\n  EXPECT_FALSE(base::internal::GetExitOnDFatal());\n\n  // We don't die.\n  {\n    ScopedMockLog log;\n    // EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());\n    //  LOG(DFATAL) has severity FATAL if debugging, but is\n    //  downgraded to ERROR if not debugging.\n    const LogSeverity severity =\n#  if defined(NDEBUG)\n        GLOG_ERROR;\n#  else\n        GLOG_FATAL;\n#  endif\n    EXPECT_CALL(log, Log(severity, __FILE__, \"This should not be fatal\"));\n    LOG(DFATAL) << \"This should not be fatal\";\n  }\n\n  // Turn back on...\n  base::internal::SetExitOnDFatal(true);\n  EXPECT_TRUE(base::internal::GetExitOnDFatal());\n\n#  ifdef GTEST_HAS_DEATH_TEST\n  // Death comes on little cats' feet.\n  EXPECT_DEBUG_DEATH({ LOG(DFATAL) << \"This should be fatal in debug mode\"; },\n                     \"This should be fatal in debug mode\");\n#  endif\n}\n\n#  ifdef HAVE_STACKTRACE\n\nstatic void BacktraceAtHelper() {\n  LOG(INFO) << \"Not me\";\n\n  // The vertical spacing of the next 3 lines is significant.\n  LOG(INFO) << \"Backtrace me\";\n}\nstatic int kBacktraceAtLine = __LINE__ - 2;  // The line of the LOG(INFO) above\n\nTEST(LogBacktraceAt, DoesNotBacktraceWhenDisabled) {\n  StrictMock<ScopedMockLog> log;\n\n  FLAGS_log_backtrace_at = \"\";\n\n  EXPECT_CALL(log, Log(_, _, \"Backtrace me\"));\n  EXPECT_CALL(log, Log(_, _, \"Not me\"));\n\n  BacktraceAtHelper();\n}\n\nTEST(LogBacktraceAt, DoesBacktraceAtRightLineWhenEnabled) {\n  StrictMock<ScopedMockLog> log;\n\n  char where[100];\n  std::snprintf(where, 100, \"%s:%d\", const_basename(__FILE__),\n                kBacktraceAtLine);\n  FLAGS_log_backtrace_at = where;\n\n  // The LOG at the specified line should include a stacktrace which includes\n  // the name of the containing function, followed by the log message.\n  // We use HasSubstr()s instead of ContainsRegex() for environments\n  // which don't have regexp.\n  EXPECT_CALL(\n      log, Log(_, _,\n               AllOf(HasSubstr(\"stacktrace:\"), HasSubstr(\"BacktraceAtHelper\"),\n                     HasSubstr(\"main\"), HasSubstr(\"Backtrace me\"))));\n  // Other LOGs should not include a backtrace.\n  EXPECT_CALL(log, Log(_, _, \"Not me\"));\n\n  BacktraceAtHelper();\n}\n\n#  endif  // HAVE_STACKTRACE\n\n#endif  // HAVE_LIB_GMOCK\n\nstruct UserDefinedClass {\n  bool operator==(const UserDefinedClass&) const { return true; }\n};\n\ninline ostream& operator<<(ostream& out, const UserDefinedClass&) {\n  out << \"OK\";\n  return out;\n}\n\nTEST(UserDefinedClass, logging) {\n  UserDefinedClass u;\n  vector<string> buf;\n  LOG_STRING(INFO, &buf) << u;\n  CHECK_EQ(1UL, buf.size());\n  CHECK(buf[0].find(\"OK\") != string::npos);\n\n  // We must be able to compile this.\n  CHECK_EQ(u, u);\n}\n\nTEST(LogMsgTime, gmtoff) {\n  /*\n   * Unit test for GMT offset API\n   * TODO: To properly test this API, we need a platform independent way to set\n   * time-zone.\n   * */\n  google::LogMessage log_obj(__FILE__, __LINE__);\n\n  std::chrono::seconds gmtoff = log_obj.time().gmtoffset();\n  // GMT offset ranges from UTC-12:00 to UTC+14:00\n  using namespace std::chrono_literals;\n  constexpr std::chrono::hours utc_min_offset = -12h;\n  constexpr std::chrono::hours utc_max_offset = +14h;\n  EXPECT_TRUE((gmtoff >= utc_min_offset) && (gmtoff <= utc_max_offset));\n}\n\nTEST(EmailLogging, ValidAddress) {\n  FlagSaver saver;\n  FLAGS_logmailer = \"/usr/bin/true\";\n\n  EXPECT_TRUE(\n      SendEmail(\"example@example.com\", \"Example subject\", \"Example body\"));\n}\n\nTEST(EmailLogging, MultipleAddresses) {\n  FlagSaver saver;\n  FLAGS_logmailer = \"/usr/bin/true\";\n\n  EXPECT_TRUE(SendEmail(\"example@example.com,foo@bar.com\", \"Example subject\",\n                        \"Example body\"));\n}\n\nTEST(EmailLogging, InvalidAddress) {\n  FlagSaver saver;\n  FLAGS_logmailer = \"/usr/bin/true\";\n\n  EXPECT_FALSE(SendEmail(\"hello world@foo\", \"Example subject\", \"Example body\"));\n}\n\nTEST(EmailLogging, MaliciousAddress) {\n  FlagSaver saver;\n  FLAGS_logmailer = \"/usr/bin/true\";\n\n  EXPECT_FALSE(\n      SendEmail(\"!/bin/true@example.com\", \"Example subject\", \"Example body\"));\n}\n\nTEST(Logging, FatalThrow) {\n  auto const fail_func =\n      InstallFailureFunction(+[]()\n#if defined(__has_attribute)\n#  if __has_attribute(noreturn)\n                                  __attribute__((noreturn))\n#  endif  // __has_attribute(noreturn)\n#endif    // defined(__has_attribute)\n                             { throw std::logic_error{\"fail\"}; });\n  auto restore_fail = [fail_func] { InstallFailureFunction(fail_func); };\n  ScopedExit<decltype(restore_fail)> restore{restore_fail};\n  EXPECT_THROW({ LOG(FATAL) << \"must throw to fail\"; }, std::logic_error);\n}\n"
  },
  {
    "path": "src/logging_unittest.err",
    "content": "IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=2 logtostderr=0 alsologtostderr=0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nWARNING: Logging before InitGoogleLogging() is written to STDERR\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=0 logtostderr=0 alsologtostderr=0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] foo bar 10 3.4\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Plog every 2, iteration 1: __SUCCESS__ [0]\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log every 3, iteration 1\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log every 4, iteration 1\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 5, iteration 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 1\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if less than 3 every 2, iteration 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 2\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Plog every 2, iteration 3: __ENOENT__ [2]\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 3\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if less than 3 every 2, iteration 3\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log every 3, iteration 4\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 4\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Plog every 2, iteration 5: __EINTR__ [4]\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log every 4, iteration 5\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 5\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 5, iteration 6\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 6\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Plog every 2, iteration 7: __ENXIO__ [6]\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log every 3, iteration 7\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 7\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 8\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Plog every 2, iteration 9: __ENOEXEC__ [8]\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log every 4, iteration 9\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 9\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log every 3, iteration 10\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Log if every 1, iteration 10\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if this\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] array\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] const array\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] foo 1000       1000 3e8\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] foo          1\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] inner\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] outer\nno prefix\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: foo bar 10 3.400000\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: array\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: const array\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: ptr __PTRTEST__\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: ptr __NULLP__\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: foo 1000 0000001000 3e8\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: foo 1000\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: foo 1000\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: RAW_LOG ERROR: The Message was too long!\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: RAW_LOG ERROR: The Message was too long!\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 0 on\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 1 on\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 2 on\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=0 logtostderr=0 alsologtostderr=0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=0 logtostderr=0 alsologtostderr=0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=-1 stderrthreshold=0 logtostderr=0 alsologtostderr=0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=1 logtostderr=0 alsologtostderr=0\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=2 logtostderr=0 alsologtostderr=0\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=0 alsologtostderr=0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=1 alsologtostderr=0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=0 alsologtostderr=1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=1 logtostderr=0 alsologtostderr=0\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=3 logtostderr=0 alsologtostderr=1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING:  LOG_STRING: collected info\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING:  LOG_STRING: collected warning\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING:  LOG_STRING: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_SINK:\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected info\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING:  LOG_TO_STRING: collected info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected warning\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING:  LOG_TO_STRING: collected warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING:  LOG_TO_STRING: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Buffering\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Buffered\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Waiting\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Sink got a messages\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Waited\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Buffering\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Buffered\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Waiting\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Sink got a messages\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Waited\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Buffering\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Buffered\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Waiting\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Sink got a messages\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] RAW: Waited\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3\n"
  },
  {
    "path": "src/logging_unittest.out",
    "content": "IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING:  LOG_STRING: collected info\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING:  LOG_STRING: collected warning\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING:  LOG_STRING: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_SINK:\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected info\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING:  LOG_TO_STRING: collected info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected warning\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING:  LOG_TO_STRING: collected warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING:  LOG_TO_STRING: collected error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported info\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported warning\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported error\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left\nEYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left\nWYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2\nIYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3\n"
  },
  {
    "path": "src/mock-log.h",
    "content": "// Copyright (c) 2007, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Zhanyong Wan\n//\n// Defines the ScopedMockLog class (using Google C++ Mocking\n// Framework), which is convenient for testing code that uses LOG().\n\n#ifndef GLOG_SRC_MOCK_LOG_H_\n#define GLOG_SRC_MOCK_LOG_H_\n\n// For google. This must go first so we get _XOPEN_SOURCE.\n#include <gmock/gmock.h>\n\n#include <string>\n\n#include \"glog/logging.h\"\n#include \"utilities.h\"\n\nnamespace google {\nnamespace glog_testing {\n\n// A ScopedMockLog object intercepts LOG() messages issued during its\n// lifespan.  Using this together with Google C++ Mocking Framework,\n// it's very easy to test how a piece of code calls LOG().  The\n// typical usage:\n//\n//   TEST(FooTest, LogsCorrectly) {\n//     ScopedMockLog log;\n//\n//     // We expect the WARNING \"Something bad!\" exactly twice.\n//     EXPECT_CALL(log, Log(WARNING, _, \"Something bad!\"))\n//         .Times(2);\n//\n//     // We allow foo.cc to call LOG(INFO) any number of times.\n//     EXPECT_CALL(log, Log(INFO, HasSubstr(\"/foo.cc\"), _))\n//         .Times(AnyNumber());\n//\n//     Foo();  // Exercises the code under test.\n//   }\nclass ScopedMockLog : public google::LogSink {\n public:\n  // When a ScopedMockLog object is constructed, it starts to\n  // intercept logs.\n  ScopedMockLog() { AddLogSink(this); }\n\n  // When the object is destructed, it stops intercepting logs.\n  ~ScopedMockLog() override { RemoveLogSink(this); }\n\n  // Implements the mock method:\n  //\n  //   void Log(LogSeverity severity, const string& file_path,\n  //            const string& message);\n  //\n  // The second argument to Send() is the full path of the source file\n  // in which the LOG() was issued.\n  //\n  // Note, that in a multi-threaded environment, all LOG() messages from a\n  // single thread will be handled in sequence, but that cannot be guaranteed\n  // for messages from different threads. In fact, if the same or multiple\n  // expectations are matched on two threads concurrently, their actions will\n  // be executed concurrently as well and may interleave.\n  MOCK_METHOD3(Log,\n               void(google::LogSeverity severity, const std::string& file_path,\n                    const std::string& message));\n\n private:\n  // Implements the send() virtual function in class LogSink.\n  // Whenever a LOG() statement is executed, this function will be\n  // invoked with information presented in the LOG().\n  //\n  // The method argument list is long and carries much information a\n  // test usually doesn't care about, so we trim the list before\n  // forwarding the call to Log(), which is much easier to use in\n  // tests.\n  //\n  // We still cannot call Log() directly, as it may invoke other LOG()\n  // messages, either due to Invoke, or due to an error logged in\n  // Google C++ Mocking Framework code, which would trigger a deadlock\n  // since a lock is held during send().\n  //\n  // Hence, we save the message for WaitTillSent() which will be called after\n  // the lock on send() is released, and we'll call Log() inside\n  // WaitTillSent(). Since while a single send() call may be running at a\n  // time, multiple WaitTillSent() calls (along with the one send() call) may\n  // be running simultaneously, we ensure thread-safety of the exchange between\n  // send() and WaitTillSent(), and that for each message, LOG(), send(),\n  // WaitTillSent() and Log() are executed in the same thread.\n  void send(google::LogSeverity severity, const char* full_filename,\n            const char* /*base_filename*/, int /*line*/,\n            const LogMessageTime& /*logmsgtime*/, const char* message,\n            size_t message_len) override {\n    // We are only interested in the log severity, full file name, and\n    // log message.\n    message_info_.severity = severity;\n    message_info_.file_path = full_filename;\n    message_info_.message = std::string(message, message_len);\n  }\n\n  // Implements the WaitTillSent() virtual function in class LogSink.\n  // It will be executed after send() and after the global logging lock is\n  // released, so calls within it (or rather within the Log() method called\n  // within) may also issue LOG() statements.\n  //\n  // LOG(), send(), WaitTillSent() and Log() will occur in the same thread for\n  // a given log message.\n  void WaitTillSent() override {\n    // First, and very importantly, we save a copy of the message being\n    // processed before calling Log(), since Log() may indirectly call send()\n    // and WaitTillSent() in the same thread again.\n    MessageInfo message_info = message_info_;\n    Log(message_info.severity, message_info.file_path, message_info.message);\n  }\n\n  // All relevant information about a logged message that needs to be passed\n  // from send() to WaitTillSent().\n  struct MessageInfo {\n    google::LogSeverity severity;\n    std::string file_path;\n    std::string message;\n  };\n  MessageInfo message_info_;\n};\n\n}  // namespace glog_testing\n}  // namespace google\n\n#endif  // GLOG_SRC_MOCK_LOG_H_\n"
  },
  {
    "path": "src/mock-log_unittest.cc",
    "content": "// Copyright (c) 2022, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Zhanyong Wan\n\n// Tests the ScopedMockLog class.\n\n#include \"mock-log.h\"\n\n#include <gmock/gmock.h>\n#include <gtest/gtest.h>\n\n#include <string>\n\nnamespace {\n\nusing google::GLOG_ERROR;\nusing google::GLOG_INFO;\nusing google::GLOG_WARNING;\nusing google::glog_testing::ScopedMockLog;\nusing std::string;\nusing testing::_;\nusing testing::EndsWith;\nusing testing::InSequence;\nusing testing::InvokeWithoutArgs;\n\n// Tests that ScopedMockLog intercepts LOG()s when it's alive.\nTEST(ScopedMockLogTest, InterceptsLog) {\n  ScopedMockLog log;\n\n  InSequence s;\n  EXPECT_CALL(log,\n              Log(GLOG_WARNING, EndsWith(\"mock-log_unittest.cc\"), \"Fishy.\"));\n  EXPECT_CALL(log, Log(GLOG_INFO, _, \"Working...\")).Times(2);\n  EXPECT_CALL(log, Log(GLOG_ERROR, _, \"Bad!!\"));\n\n  LOG(WARNING) << \"Fishy.\";\n  LOG(INFO) << \"Working...\";\n  LOG(INFO) << \"Working...\";\n  LOG(ERROR) << \"Bad!!\";\n}\n\nvoid LogBranch() { LOG(INFO) << \"Logging a branch...\"; }\n\nvoid LogTree() { LOG(INFO) << \"Logging the whole tree...\"; }\n\nvoid LogForest() {\n  LOG(INFO) << \"Logging the entire forest.\";\n  LOG(INFO) << \"Logging the entire forest..\";\n  LOG(INFO) << \"Logging the entire forest...\";\n}\n\n// The purpose of the following test is to verify that intercepting logging\n// continues to work properly if a LOG statement is executed within the scope\n// of a mocked call.\nTEST(ScopedMockLogTest, LogDuringIntercept) {\n  ScopedMockLog log;\n  InSequence s;\n  EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, \"Logging a branch...\"))\n      .WillOnce(InvokeWithoutArgs(LogTree));\n  EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, \"Logging the whole tree...\"))\n      .WillOnce(InvokeWithoutArgs(LogForest));\n  EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, \"Logging the entire forest.\"));\n  EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, \"Logging the entire forest..\"));\n  EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, \"Logging the entire forest...\"));\n  LogBranch();\n}\n\n}  // namespace\n\nint main(int argc, char** argv) {\n  google::InitGoogleLogging(argv[0]);\n  testing::InitGoogleTest(&argc, argv);\n  testing::InitGoogleMock(&argc, argv);\n\n  return RUN_ALL_TESTS();\n}\n"
  },
  {
    "path": "src/package_config_unittest/working_config/CMakeLists.txt",
    "content": "cmake_minimum_required (VERSION 3.16)\nproject (glog_package_config LANGUAGES CXX)\n\nfind_package (glog REQUIRED NO_MODULE)\n\nadd_executable (glog_package_config glog_package_config.cc)\n\ntarget_link_libraries (glog_package_config PRIVATE glog::glog)\n"
  },
  {
    "path": "src/package_config_unittest/working_config/glog_package_config.cc",
    "content": "#include \"glog/logging.h\"\n\nint main(int /*argc*/, char** argv) { google::InitGoogleLogging(argv[0]); }\n"
  },
  {
    "path": "src/raw_logging.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Maxim Lifantsev\n//\n// logging_unittest.cc covers the functionality herein\n\n#include <cstdarg>\n#include <cstdio>\n#include <cstring>\n#include <iomanip>\n#include <mutex>\n#include <ostream>\n#include <streambuf>\n#include <thread>\n\n#include \"config.h\"\n\n#ifdef HAVE_UNISTD_H\n#  include <unistd.h>  // for close() and write()\n#endif\n#if defined(HAVE_SYSCALL_H)\n#  include <syscall.h>  // for syscall()\n#elif defined(HAVE_SYS_SYSCALL_H)\n#  include <sys/syscall.h>  // for syscall()\n#endif\n#ifdef HAVE_UNISTD_H\n#  include <unistd.h>\n#endif\n#include <fcntl.h>  // for open()\n\n#include \"glog/logging.h\"\n#include \"glog/raw_logging.h\"\n#include \"stacktrace.h\"\n#include \"utilities.h\"\n\n#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) &&    \\\n    (!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \\\n    !defined(GLOG_OS_EMSCRIPTEN)\n#  define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)\n#else\n// Not so safe, but what can you do?\n#  define safe_write(fd, s, len) write(fd, s, len)\n#endif\n\nnamespace google {\n\n#if defined(__GNUC__)\n#  define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \\\n    __attribute__((format(archetype, stringIndex, firstToCheck)))\n#  define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \\\n    __attribute__((format_arg(stringIndex)))\n#else\n#  define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)\n#  define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)\n#endif\n\n// CAVEAT: std::vsnprintf called from *DoRawLog below has some (exotic) code\n// paths that invoke malloc() and getenv() that might acquire some locks. If\n// this becomes a problem we should reimplement a subset of std::vsnprintf that\n// does not need locks and malloc.\n\n// Helper for RawLog__ below.\n// *DoRawLog writes to *buf of *size and move them past the written portion.\n// It returns true iff there was no overflow or error.\nGLOG_ATTRIBUTE_FORMAT(printf, 3, 4)\nstatic bool DoRawLog(char** buf, size_t* size, const char* format, ...) {\n  va_list ap;\n  va_start(ap, format);\n  int n = std::vsnprintf(*buf, *size, format, ap);\n  va_end(ap);\n  if (n < 0 || static_cast<size_t>(n) > *size) return false;\n  *size -= static_cast<size_t>(n);\n  *buf += n;\n  return true;\n}\n\n// Helper for RawLog__ below.\ninline static bool VADoRawLog(char** buf, size_t* size, const char* format,\n                              va_list ap) {\n#if defined(__GNUC__)\n#  pragma GCC diagnostic push\n#  pragma GCC diagnostic ignored \"-Wformat-nonliteral\"\n#endif\n  int n = std::vsnprintf(*buf, *size, format, ap);\n#if defined(__GNUC__)\n#  pragma GCC diagnostic pop\n#endif\n  if (n < 0 || static_cast<size_t>(n) > *size) return false;\n  *size -= static_cast<size_t>(n);\n  *buf += n;\n  return true;\n}\n\nstatic const int kLogBufSize = 3000;\nstatic std::once_flag crashed;\nstatic logging::internal::CrashReason crash_reason;\nstatic char crash_buf[kLogBufSize + 1] = {0};  // Will end in '\\0'\n\nnamespace {\ntemplate <std::size_t N>\nclass StaticStringBuf : public std::streambuf {\n public:\n  StaticStringBuf() {\n    setp(std::begin(data_), std::end(data_));\n    setg(std::begin(data_), std::begin(data_), std::end(data_));\n  }\n  const char* data() noexcept {\n    if (pptr() != pbase() && pptr() != epptr() && *(pptr() - 1) != '\\0') {\n      sputc('\\0');\n    }\n    return data_;\n  }\n\n private:\n  char data_[N];\n};\n}  // namespace\n\nGLOG_ATTRIBUTE_FORMAT(printf, 4, 5)\nvoid RawLog__(LogSeverity severity, const char* file, int line,\n              const char* format, ...) {\n  if (!(FLAGS_logtostdout || FLAGS_logtostderr ||\n        severity >= FLAGS_stderrthreshold || FLAGS_alsologtostderr ||\n        !IsGoogleLoggingInitialized())) {\n    return;  // this stderr log message is suppressed\n  }\n\n  // We do not have any any option other that string streams to obtain the\n  // thread identifier as the corresponding value is not convertible to an\n  // integer. Use a statically allocated buffer to avoid dynamic memory\n  // allocations.\n  StaticStringBuf<kLogBufSize> sbuf;\n  std::ostream oss(&sbuf);\n\n  oss << std::setw(5) << std::this_thread::get_id();\n\n  // can't call localtime_r here: it can allocate\n  char buffer[kLogBufSize];\n  char* buf = buffer;\n  size_t size = sizeof(buffer);\n\n  // NOTE: this format should match the specification in base/logging.h\n  DoRawLog(&buf, &size, \"%c00000000 00:00:00.000000 %s %s:%d] RAW: \",\n           GetLogSeverityName(severity)[0], sbuf.data(),\n           const_basename(const_cast<char*>(file)), line);\n\n  // Record the position and size of the buffer after the prefix\n  const char* msg_start = buf;\n  const size_t msg_size = size;\n\n  va_list ap;\n  va_start(ap, format);\n  bool no_chop = VADoRawLog(&buf, &size, format, ap);\n  va_end(ap);\n  if (no_chop) {\n    DoRawLog(&buf, &size, \"\\n\");\n  } else {\n    DoRawLog(&buf, &size, \"RAW_LOG ERROR: The Message was too long!\\n\");\n  }\n  // We make a raw syscall to write directly to the stderr file descriptor,\n  // avoiding FILE buffering (to avoid invoking malloc()), and bypassing\n  // libc (to side-step any libc interception).\n  // We write just once to avoid races with other invocations of RawLog__.\n  safe_write(fileno(stderr), buffer, strlen(buffer));\n  if (severity == GLOG_FATAL) {\n    std::call_once(crashed, [file, line, msg_start, msg_size] {\n      crash_reason.filename = file;\n      crash_reason.line_number = line;\n      memcpy(crash_buf, msg_start, msg_size);  // Don't include prefix\n      crash_reason.message = crash_buf;\n#ifdef HAVE_STACKTRACE\n      crash_reason.depth =\n          GetStackTrace(crash_reason.stack, ARRAYSIZE(crash_reason.stack), 1);\n#else\n      crash_reason.depth = 0;\n#endif\n      SetCrashReason(&crash_reason);\n    });\n    LogMessage::Fail();  // abort()\n  }\n}\n\n}  // namespace google\n"
  },
  {
    "path": "src/signalhandler.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Satoru Takabayashi\n//\n// Implementation of InstallFailureSignalHandler().\n\n#include <algorithm>\n#include <csignal>\n#include <cstring>\n#include <ctime>\n#include <mutex>\n#include <sstream>\n#include <thread>\n\n#include \"config.h\"\n#include \"glog/logging.h\"\n#include \"glog/platform.h\"\n#include \"stacktrace.h\"\n#include \"symbolize.h\"\n#include \"utilities.h\"\n\n#ifdef HAVE_UCONTEXT_H\n#  include <ucontext.h>\n#endif\n#ifdef HAVE_SYS_UCONTEXT_H\n#  include <sys/ucontext.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#  include <unistd.h>\n#endif\n#if defined(HAVE_SYS_SYSCALL_H) && defined(HAVE_SYS_TYPES_H)\n#  include <sys/syscall.h>\n#  include <sys/types.h>\n#endif\n\nnamespace google {\n\nnamespace {\n\n// We'll install the failure signal handler for these signals.  We could\n// use strsignal() to get signal names, but we don't use it to avoid\n// introducing yet another #ifdef complication.\n//\n// The list should be synced with the comment in signalhandler.h.\nconst struct {\n  int number;\n  const char* name;\n} kFailureSignals[] = {\n    {SIGSEGV, \"SIGSEGV\"}, {SIGILL, \"SIGILL\"},\n    {SIGFPE, \"SIGFPE\"},   {SIGABRT, \"SIGABRT\"},\n#if !defined(GLOG_OS_WINDOWS)\n    {SIGBUS, \"SIGBUS\"},\n#endif\n    {SIGTERM, \"SIGTERM\"},\n};\n\nstatic bool kFailureSignalHandlerInstalled = false;\n\n#if !defined(GLOG_OS_WINDOWS)\n// Returns the program counter from signal context, nullptr if unknown.\nvoid* GetPC(void* ucontext_in_void) {\n#  if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && \\\n      defined(PC_FROM_UCONTEXT)\n  if (ucontext_in_void != nullptr) {\n    ucontext_t* context = reinterpret_cast<ucontext_t*>(ucontext_in_void);\n    return (void*)context->PC_FROM_UCONTEXT;\n  }\n#  else\n  (void)ucontext_in_void;\n#  endif\n  return nullptr;\n}\n#endif\n\n// The class is used for formatting error messages.  We don't use printf()\n// as it's not async signal safe.\nclass MinimalFormatter {\n public:\n  MinimalFormatter(char* buffer, size_t size)\n      : buffer_(buffer), cursor_(buffer), end_(buffer + size) {}\n\n  // Returns the number of bytes written in the buffer.\n  std::size_t num_bytes_written() const {\n    return static_cast<std::size_t>(cursor_ - buffer_);\n  }\n\n  // Appends string from \"str\" and updates the internal cursor.\n  void AppendString(const char* str) {\n    ptrdiff_t i = 0;\n    while (str[i] != '\\0' && cursor_ + i < end_) {\n      cursor_[i] = str[i];\n      ++i;\n    }\n    cursor_ += i;\n  }\n\n  // Formats \"number\" in \"radix\" and updates the internal cursor.\n  // Lowercase letters are used for 'a' - 'z'.\n  void AppendUint64(uint64 number, unsigned radix) {\n    unsigned i = 0;\n    while (cursor_ + i < end_) {\n      const uint64 tmp = number % radix;\n      number /= radix;\n      cursor_[i] = static_cast<char>(tmp < 10 ? '0' + tmp : 'a' + tmp - 10);\n      ++i;\n      if (number == 0) {\n        break;\n      }\n    }\n    // Reverse the bytes written.\n    std::reverse(cursor_, cursor_ + i);\n    cursor_ += i;\n  }\n\n  // Formats \"number\" as hexadecimal number, and updates the internal\n  // cursor.  Padding will be added in front if needed.\n  void AppendHexWithPadding(uint64 number, int width) {\n    char* start = cursor_;\n    AppendString(\"0x\");\n    AppendUint64(number, 16);\n    // Move to right and add padding in front if needed.\n    if (cursor_ < start + width) {\n      const int64 delta = start + width - cursor_;\n      std::copy(start, cursor_, start + delta);\n      std::fill(start, start + delta, ' ');\n      cursor_ = start + width;\n    }\n  }\n\n private:\n  char* buffer_;\n  char* cursor_;\n  const char* const end_;\n};\n\n// Writes the given data with the size to the standard error.\nvoid WriteToStderr(const char* data, size_t size) {\n  if (write(fileno(stderr), data, size) < 0) {\n    // Ignore errors.\n  }\n}\n\n// The writer function can be changed by InstallFailureWriter().\nvoid (*g_failure_writer)(const char* data, size_t size) = WriteToStderr;\n\n// Dumps time information.  We don't dump human-readable time information\n// as localtime() is not guaranteed to be async signal safe.\nvoid DumpTimeInfo() {\n  time_t time_in_sec = time(nullptr);\n  char buf[256];  // Big enough for time info.\n  MinimalFormatter formatter(buf, sizeof(buf));\n  formatter.AppendString(\"*** Aborted at \");\n  formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);\n  formatter.AppendString(\" (unix time)\");\n  formatter.AppendString(\" try \\\"date -d @\");\n  formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);\n  formatter.AppendString(\"\\\" if you are using GNU date ***\\n\");\n  g_failure_writer(buf, formatter.num_bytes_written());\n}\n\n// TODO(hamaji): Use signal instead of sigaction?\n#if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)\n\n// Dumps information about the signal to STDERR.\nvoid DumpSignalInfo(int signal_number, siginfo_t* siginfo) {\n  // Get the signal name.\n  const char* signal_name = nullptr;\n  for (auto kFailureSignal : kFailureSignals) {\n    if (signal_number == kFailureSignal.number) {\n      signal_name = kFailureSignal.name;\n    }\n  }\n\n  char buf[256];  // Big enough for signal info.\n  MinimalFormatter formatter(buf, sizeof(buf));\n\n  formatter.AppendString(\"*** \");\n  if (signal_name) {\n    formatter.AppendString(signal_name);\n  } else {\n    // Use the signal number if the name is unknown.  The signal name\n    // should be known, but just in case.\n    formatter.AppendString(\"Signal \");\n    formatter.AppendUint64(static_cast<uint64>(signal_number), 10);\n  }\n  formatter.AppendString(\" (@0x\");\n  formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);\n  formatter.AppendString(\")\");\n  formatter.AppendString(\" received by PID \");\n  formatter.AppendUint64(static_cast<uint64>(getpid()), 10);\n  formatter.AppendString(\" (TID \");\n\n  std::ostringstream oss;\n  oss << std::showbase << std::hex << std::this_thread::get_id();\n  formatter.AppendString(oss.str().c_str());\n#  if defined(GLOG_OS_LINUX) && defined(HAVE_SYS_SYSCALL_H) && \\\n      defined(HAVE_SYS_TYPES_H)\n  pid_t tid = syscall(SYS_gettid);\n  formatter.AppendString(\" LWP \");\n  formatter.AppendUint64(static_cast<uint64>(tid), 10);\n#  endif\n  formatter.AppendString(\") \");\n\n  // Only linux has the PID of the signal sender in si_pid.\n#  ifdef GLOG_OS_LINUX\n  formatter.AppendString(\"from PID \");\n  formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);\n  formatter.AppendString(\"; \");\n#  endif\n  formatter.AppendString(\"stack trace: ***\\n\");\n  g_failure_writer(buf, formatter.num_bytes_written());\n}\n\n#endif  // HAVE_SIGACTION\n\n// Dumps information about the stack frame to STDERR.\nvoid DumpStackFrameInfo(const char* prefix, void* pc) {\n  // Get the symbol name.\n  const char* symbol = \"(unknown)\";\n#if defined(HAVE_SYMBOLIZE)\n  char symbolized[1024];  // Big enough for a sane symbol.\n  // Symbolizes the previous address of pc because pc may be in the\n  // next function.\n  if (Symbolize(reinterpret_cast<char*>(pc) - 1, symbolized,\n                sizeof(symbolized))) {\n    symbol = symbolized;\n  }\n#else\n#  pragma message( \\\n          \"Symbolize functionality is not available for target platform: stack dump will contain empty frames.\")\n#endif  // defined(HAVE_SYMBOLIZE)\n\n  char buf[1024];  // Big enough for stack frame info.\n  MinimalFormatter formatter(buf, sizeof(buf));\n\n  formatter.AppendString(prefix);\n  formatter.AppendString(\"@ \");\n  const int width = 2 * sizeof(void*) + 2;  // + 2  for \"0x\".\n  formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);\n  formatter.AppendString(\" \");\n  formatter.AppendString(symbol);\n  formatter.AppendString(\"\\n\");\n  g_failure_writer(buf, formatter.num_bytes_written());\n}\n\n// Invoke the default signal handler.\nvoid InvokeDefaultSignalHandler(int signal_number) {\n#ifdef HAVE_SIGACTION\n  struct sigaction sig_action;\n  memset(&sig_action, 0, sizeof(sig_action));\n  sigemptyset(&sig_action.sa_mask);\n  sig_action.sa_handler = SIG_DFL;\n  sigaction(signal_number, &sig_action, nullptr);\n  kill(getpid(), signal_number);\n#elif defined(GLOG_OS_WINDOWS)\n  signal(signal_number, SIG_DFL);\n  raise(signal_number);\n#endif\n}\n\n// This variable is used for protecting FailureSignalHandler() from dumping\n// stuff while another thread is doing it.  Our policy is to let the first\n// thread dump stuff and let other threads do nothing.\n// See also comments in FailureSignalHandler().\nstatic std::once_flag signaled;\n\nstatic void HandleSignal(int signal_number\n#if !defined(GLOG_OS_WINDOWS)\n                         ,\n                         siginfo_t* signal_info, void* ucontext\n#endif\n) {\n\n  // This is the first time we enter the signal handler.  We are going to\n  // do some interesting stuff from here.\n  // TODO(satorux): We might want to set timeout here using alarm(), but\n  // mixing alarm() and sleep() can be a bad idea.\n\n  // First dump time info.\n  DumpTimeInfo();\n\n#if !defined(GLOG_OS_WINDOWS)\n  // Get the program counter from ucontext.\n  void* pc = GetPC(ucontext);\n  DumpStackFrameInfo(\"PC: \", pc);\n#endif\n\n#ifdef HAVE_STACKTRACE\n  // Get the stack traces.\n  void* stack[32];\n  // +1 to exclude this function.\n  const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);\n#  ifdef HAVE_SIGACTION\n  DumpSignalInfo(signal_number, signal_info);\n#  elif !defined(GLOG_OS_WINDOWS)\n  (void)signal_info;\n#  endif\n  // Dump the stack traces.\n  for (int i = 0; i < depth; ++i) {\n    DumpStackFrameInfo(\"    \", stack[i]);\n  }\n#elif !defined(GLOG_OS_WINDOWS)\n  (void)signal_info;\n#endif\n\n  // *** TRANSITION ***\n  //\n  // BEFORE this point, all code must be async-termination-safe!\n  // (See WARNING above.)\n  //\n  // AFTER this point, we do unsafe things, like using LOG()!\n  // The process could be terminated or hung at any time.  We try to\n  // do more useful things first and riskier things later.\n\n  // Flush the logs before we do anything in case 'anything'\n  // causes problems.\n  FlushLogFilesUnsafe(GLOG_INFO);\n\n  // Kill ourself by the default signal handler.\n  InvokeDefaultSignalHandler(signal_number);\n}\n\n// Dumps signal and stack frame information, and invokes the default\n// signal handler once our job is done.\n#if defined(GLOG_OS_WINDOWS)\nvoid FailureSignalHandler(int signal_number)\n#else\nvoid FailureSignalHandler(int signal_number, siginfo_t* signal_info,\n                          void* ucontext)\n#endif\n{\n  std::call_once(signaled, &HandleSignal, signal_number\n#if !defined(GLOG_OS_WINDOWS)\n                 ,\n                 signal_info, ucontext\n#endif\n  );\n}\n\n}  // namespace\n\nbool IsFailureSignalHandlerInstalled() {\n#ifdef HAVE_SIGACTION\n  // TODO(andschwa): Return kFailureSignalHandlerInstalled?\n  struct sigaction sig_action;\n  memset(&sig_action, 0, sizeof(sig_action));\n  sigemptyset(&sig_action.sa_mask);\n  sigaction(SIGABRT, nullptr, &sig_action);\n  if (sig_action.sa_sigaction == &FailureSignalHandler) {\n    return true;\n  }\n#elif defined(GLOG_OS_WINDOWS)\n  return kFailureSignalHandlerInstalled;\n#endif  // HAVE_SIGACTION\n  return false;\n}\n\nvoid InstallFailureSignalHandler() {\n#ifdef HAVE_SIGACTION\n  // Build the sigaction struct.\n  struct sigaction sig_action;\n  memset(&sig_action, 0, sizeof(sig_action));\n  sigemptyset(&sig_action.sa_mask);\n  sig_action.sa_flags |= SA_SIGINFO;\n  sig_action.sa_sigaction = &FailureSignalHandler;\n\n  for (auto kFailureSignal : kFailureSignals) {\n    CHECK_ERR(sigaction(kFailureSignal.number, &sig_action, nullptr));\n  }\n  kFailureSignalHandlerInstalled = true;\n#elif defined(GLOG_OS_WINDOWS)\n  for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {\n    CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), SIG_ERR);\n  }\n  kFailureSignalHandlerInstalled = true;\n#endif  // HAVE_SIGACTION\n}\n\nvoid InstallFailureWriter(void (*writer)(const char* data, size_t size)) {\n#if defined(HAVE_SIGACTION) || defined(GLOG_OS_WINDOWS)\n  g_failure_writer = writer;\n#endif  // HAVE_SIGACTION\n}\n\n}  // namespace google\n"
  },
  {
    "path": "src/signalhandler_unittest.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Satoru Takabayashi\n//\n// This is a helper binary for testing signalhandler.cc.  The actual test\n// is done in signalhandler_unittest.sh.\n\n#include <csignal>\n#include <cstdio>\n#include <cstdlib>\n#include <sstream>\n#include <string>\n#include <thread>\n\n#include \"config.h\"\n#include \"glog/logging.h\"\n#include \"stacktrace.h\"\n#include \"symbolize.h\"\n\n#if defined(HAVE_UNISTD_H)\n#  include <unistd.h>\n#endif\n#ifdef GLOG_USE_GFLAGS\n#  include <gflags/gflags.h>\nusing namespace GFLAGS_NAMESPACE;\n#endif\n#if defined(_MSC_VER)\n#  include <io.h>  // write\n#endif\n\nusing namespace google;\n\nstatic void DieInThread(int* a) {\n  std::ostringstream oss;\n  oss << std::showbase << std::hex << std::this_thread::get_id();\n\n  fprintf(stderr, \"%s is dying\\n\", oss.str().c_str());\n  int b = 1 / *a;\n  fprintf(stderr, \"We should have died: b=%d\\n\", b);\n}\n\nstatic void WriteToStdout(const char* data, size_t size) {\n  if (write(fileno(stdout), data, size) < 0) {\n    // Ignore errors.\n  }\n}\n\nint main(int argc, char** argv) {\n#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)\n  InitGoogleLogging(argv[0]);\n#  ifdef GLOG_USE_GFLAGS\n  ParseCommandLineFlags(&argc, &argv, true);\n#  endif\n  InstallFailureSignalHandler();\n  const std::string command = argc > 1 ? argv[1] : \"none\";\n  if (command == \"segv\") {\n    // We'll check if this is outputted.\n    LOG(INFO) << \"create the log file\";\n    LOG(INFO) << \"a message before segv\";\n    // We assume 0xDEAD is not writable.\n    int* a = (int*)0xDEAD;\n    *a = 0;\n  } else if (command == \"loop\") {\n    fprintf(stderr, \"looping\\n\");\n    while (true)\n      ;\n  } else if (command == \"die_in_thread\") {\n    std::thread t{&DieInThread, nullptr};\n    t.join();\n  } else if (command == \"dump_to_stdout\") {\n    InstallFailureWriter(WriteToStdout);\n    abort();\n  } else if (command == \"installed\") {\n    fprintf(stderr, \"signal handler installed: %s\\n\",\n            IsFailureSignalHandlerInstalled() ? \"true\" : \"false\");\n  } else {\n    // Tell the shell script\n    puts(\"OK\");\n  }\n#endif\n  return 0;\n}\n"
  },
  {
    "path": "src/signalhandler_unittest.sh",
    "content": "#! /bin/sh\n#\n# Copyright (c) 2008, Google Inc.\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are\n# met:\n#\n#     * Redistributions of source code must retain the above copyright\n# notice, this list of conditions and the following disclaimer.\n#     * Redistributions in binary form must reproduce the above\n# copyright notice, this list of conditions and the following disclaimer\n# in the documentation and/or other materials provided with the\n# distribution.\n#     * Neither the name of Google Inc. nor the names of its\n# contributors may be used to endorse or promote products derived from\n# this software without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#\n# Author: Satoru Takabayashi\n#\n# Unit tests for signalhandler.cc.\n\ndie () {\n    echo $1\n    exit 1\n}\n\nBINDIR=\".libs\"\nLIBGLOG=\"$BINDIR/libglog.so\"\n\nBINARY=\"$BINDIR/signalhandler_unittest\"\nLOG_INFO=\"./signalhandler_unittest.INFO\"\n\n# Remove temporary files.\nrm -f signalhandler.out*\n\nif test -e \"$BINARY\"; then\n  # We need shared object.\n  export LD_LIBRARY_PATH=$BINDIR\n  export DYLD_LIBRARY_PATH=$BINDIR\nelse\n  # For windows\n  BINARY=\"./signalhandler_unittest.exe\"\n  if ! test -e \"$BINARY\"; then\n    echo \"We coundn't find demangle_unittest binary.\"\n    exit 1\n  fi\nfi\n\nif [ x`$BINARY` != 'xOK' ]; then\n  echo \"PASS (No stacktrace support. We don't run this test.)\"\n  exit 0\nfi\n\n# The PC cannot be obtained in signal handlers on PowerPC correctly.\n# We just skip the test for PowerPC.\nif [ x`uname -p` = x\"powerpc\" ]; then\n  echo \"PASS (We don't test the signal handler on PowerPC.)\"\n  exit 0\nfi\n\n# Test for a case the program kills itself by SIGSEGV.\nGOOGLE_LOG_DIR=. $BINARY segv 2> signalhandler.out1\nfor pattern in SIGSEGV 0xdead main \"Aborted at [0-9]\"; do\n  if ! grep --quiet \"$pattern\" signalhandler.out1; then\n    die \"'$pattern' should appear in the output\"\n  fi\ndone\nif ! grep --quiet \"a message before segv\" $LOG_INFO; then\n  die \"'a message before segv' should appear in the INFO log\"\nfi\nrm -f $LOG_INFO\n\n# Test for a case the program is killed by this shell script.\n# $! = the process id of the last command run in the background.\n# $$ = the process id of this shell.\n$BINARY loop 2> signalhandler.out2 &\n# Wait until \"looping\" is written in the file.  This indicates the program\n# is ready to accept signals.\nwhile true; do\n  if grep --quiet looping signalhandler.out2; then\n    break\n  fi\ndone\nkill -TERM $!\nwait $!\n\nfrom_pid=''\n# Only linux has the process ID of the signal sender.\nif [ x`uname` = \"xLinux\" ]; then\n  from_pid=\"from PID $$\"\nfi\nfor pattern in SIGTERM \"by PID $!\" \"$from_pid\" main \"Aborted at [0-9]\"; do\n  if ! grep --quiet \"$pattern\" signalhandler.out2; then\n    die \"'$pattern' should appear in the output\"\n  fi\ndone\n\n# Test for a case the program dies in a non-main thread.\n$BINARY die_in_thread 2> signalhandler.out3\nEXPECTED_TID=\"`sed 's/ .*//; q' signalhandler.out3`\"\n\nfor pattern in SIGFPE DieInThread \"TID $EXPECTED_TID\" \"Aborted at [0-9]\"; do\n  if ! grep --quiet \"$pattern\" signalhandler.out3; then\n    die \"'$pattern' should appear in the output\"\n  fi\ndone\n\n# Test for a case the program installs a custom failure writer that writes\n# stuff to stdout instead of stderr.\n$BINARY dump_to_stdout 1> signalhandler.out4\nfor pattern in SIGABRT main \"Aborted at [0-9]\"; do\n  if ! grep --quiet \"$pattern\" signalhandler.out4; then\n    die \"'$pattern' should appear in the output\"\n  fi\ndone\n\necho PASS\n"
  },
  {
    "path": "src/stacktrace.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Routines to extract the current stack trace.  These functions are\n// thread-safe.\n\n#include \"stacktrace.h\"\n\n// Make an implementation of stacktrace compiled.\n#if defined(STACKTRACE_H)\n#  include STACKTRACE_H\n#endif\n"
  },
  {
    "path": "src/stacktrace.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Routines to extract the current stack trace.  These functions are\n// thread-safe.\n\n#ifndef GLOG_INTERNAL_STACKTRACE_H\n#define GLOG_INTERNAL_STACKTRACE_H\n\n#include \"glog/platform.h\"\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_NO_EXPORT)\n#  error \"stacktrace.h\" was not included correctly.\n#endif\n\n#include \"config.h\"\n#if defined(HAVE_LIBUNWIND)\n#  define STACKTRACE_H \"stacktrace_libunwind-inl.h\"\n#elif defined(HAVE_UNWIND)\n#  define STACKTRACE_H \"stacktrace_unwind-inl.h\"\n#elif !defined(NO_FRAME_POINTER)\n#  if defined(__i386__) && __GNUC__ >= 2\n#    define STACKTRACE_H \"stacktrace_x86-inl.h\"\n#  elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2\n#    define STACKTRACE_H \"stacktrace_powerpc-inl.h\"\n#  elif defined(GLOG_OS_WINDOWS)\n#    define STACKTRACE_H \"stacktrace_windows-inl.h\"\n#  endif\n#endif\n\n#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_BACKTRACE)\n#  define STACKTRACE_H \"stacktrace_generic-inl.h\"\n#endif\n\n#if defined(STACKTRACE_H)\n#  define HAVE_STACKTRACE\n#endif\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n#if defined(HAVE_STACKTRACE)\n\n// This is similar to the GetStackFrames routine, except that it returns\n// the stack trace only, and not the stack frame sizes as well.\n// Example:\n//      main() { foo(); }\n//      foo() { bar(); }\n//      bar() {\n//        void* result[10];\n//        int depth = GetStackFrames(result, 10, 1);\n//      }\n//\n// This produces:\n//      result[0]       foo\n//      result[1]       main\n//           ....       ...\n//\n// \"result\" must not be nullptr.\nGLOG_NO_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count);\n\n#endif  // defined(HAVE_STACKTRACE)\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#endif  // GLOG_INTERNAL_STACKTRACE_H\n"
  },
  {
    "path": "src/stacktrace_generic-inl.h",
    "content": "// Copyright (c) 2000 - 2007, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Portable implementation - just use glibc\n//\n// Note:  The glibc implementation may cause a call to malloc.\n// This can cause a deadlock in HeapProfiler.\n#include <execinfo.h>\n\n#include <cstring>\n\n#include \"stacktrace.h\"\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n// If you change this function, also change GetStackFrames below.\nint GetStackTrace(void** result, int max_depth, int skip_count) {\n  static const int kStackLength = 64;\n  void* stack[kStackLength];\n  int size;\n\n  size = backtrace(stack, kStackLength);\n  skip_count++;  // we want to skip the current frame as well\n  int result_count = size - skip_count;\n  if (result_count < 0) {\n    result_count = 0;\n  }\n  if (result_count > max_depth) {\n    result_count = max_depth;\n  }\n  for (int i = 0; i < result_count; i++) {\n    result[i] = stack[i + skip_count];\n  }\n\n  return result_count;\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n"
  },
  {
    "path": "src/stacktrace_libunwind-inl.h",
    "content": "// Copyright (c) 2005 - 2007, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Arun Sharma\n//\n// Produce stack trace using libunwind\n\n#include \"utilities.h\"\n\nextern \"C\" {\n#define UNW_LOCAL_ONLY\n#include <libunwind.h>\n}\n#include \"glog/raw_logging.h\"\n#include \"stacktrace.h\"\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n// Sometimes, we can try to get a stack trace from within a stack\n// trace, because libunwind can call mmap (maybe indirectly via an\n// internal mmap based memory allocator), and that mmap gets trapped\n// and causes a stack-trace request.  If were to try to honor that\n// recursive request, we'd end up with infinite recursion or deadlock.\n// Luckily, it's safe to ignore those subsequent traces.  In such\n// cases, we return 0 to indicate the situation.\n// We can use the GCC __thread syntax here since libunwind is not supported on\n// Windows.\nstatic __thread bool g_tl_entered;  // Initialized to false.\n\n// If you change this function, also change GetStackFrames below.\nint GetStackTrace(void** result, int max_depth, int skip_count) {\n  void* ip;\n  int n = 0;\n  unw_cursor_t cursor;\n  unw_context_t uc;\n\n  if (g_tl_entered) {\n    return 0;\n  }\n  g_tl_entered = true;\n\n  unw_getcontext(&uc);\n  RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, \"unw_init_local failed\");\n  skip_count++;  // Do not include the \"GetStackTrace\" frame\n\n  while (n < max_depth) {\n    int ret =\n        unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t*>(&ip));\n    if (ret < 0) {\n      break;\n    }\n    if (skip_count > 0) {\n      skip_count--;\n    } else {\n      result[n++] = ip;\n    }\n    ret = unw_step(&cursor);\n    if (ret <= 0) {\n      break;\n    }\n  }\n\n  g_tl_entered = false;\n  return n;\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n"
  },
  {
    "path": "src/stacktrace_powerpc-inl.h",
    "content": "// Copyright (c) 2007, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Craig Silverstein\n//\n// Produce stack trace.  I'm guessing (hoping!) the code is much like\n// for x86.  For apple machines, at least, it seems to be; see\n//    http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html\n//    http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK\n// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882\n\n#include <cstdint>  // for uintptr_t\n#include <cstdio>\n\n#include \"stacktrace.h\"\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n// Given a pointer to a stack frame, locate and return the calling\n// stackframe, or return nullptr if no stackframe can be found. Perform sanity\n// checks (the strictness of which is controlled by the boolean parameter\n// \"STRICT_UNWINDING\") to reduce the chance that a bad pointer is returned.\ntemplate <bool STRICT_UNWINDING>\nstatic void** NextStackFrame(void** old_sp) {\n  void** new_sp = static_cast<void**>(*old_sp);\n\n  // Check that the transition from frame pointer old_sp to frame\n  // pointer new_sp isn't clearly bogus\n  if (STRICT_UNWINDING) {\n    // With the stack growing downwards, older stack frame must be\n    // at a greater address that the current one.\n    if (new_sp <= old_sp) return nullptr;\n    // Assume stack frames larger than 100,000 bytes are bogus.\n    if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;\n  } else {\n    // In the non-strict mode, allow discontiguous stack frames.\n    // (alternate-signal-stacks for example).\n    if (new_sp == old_sp) return nullptr;\n    // And allow frames upto about 1MB.\n    if ((new_sp > old_sp) &&\n        ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) {\n      return nullptr;\n    }\n  }\n  if ((uintptr_t)new_sp & (sizeof(void*) - 1)) return nullptr;\n  return new_sp;\n}\n\n// This ensures that GetStackTrace stes up the Link Register properly.\nvoid StacktracePowerPCDummyFunction() __attribute__((noinline));\nvoid StacktracePowerPCDummyFunction() { __asm__ volatile(\"\"); }\n\n// If you change this function, also change GetStackFrames below.\nint GetStackTrace(void** result, int max_depth, int skip_count) {\n  void** sp;\n  // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)\n  // and Darwin 8.8.1 (Tiger) use as 1.38.  This means we have to use a\n  // different asm syntax.  I don't know quite the best way to discriminate\n  // systems using the old as from the new one; I've gone with __APPLE__.\n#ifdef __APPLE__\n  __asm__ volatile(\"mr %0,r1\" : \"=r\"(sp));\n#else\n  __asm__ volatile(\"mr %0,1\" : \"=r\"(sp));\n#endif\n\n  // On PowerPC, the \"Link Register\" or \"Link Record\" (LR), is a stack\n  // entry that holds the return address of the subroutine call (what\n  // instruction we run after our function finishes).  This is the\n  // same as the stack-pointer of our parent routine, which is what we\n  // want here.  While the compiler will always(?) set up LR for\n  // subroutine calls, it may not for leaf functions (such as this one).\n  // This routine forces the compiler (at least gcc) to push it anyway.\n  StacktracePowerPCDummyFunction();\n\n  // The LR save area is used by the callee, so the top entry is bogus.\n  skip_count++;\n\n  int n = 0;\n  while (sp && n < max_depth) {\n    if (skip_count > 0) {\n      skip_count--;\n    } else {\n      // PowerPC has 3 main ABIs, which say where in the stack the\n      // Link Register is.  For DARWIN and AIX (used by apple and\n      // linux ppc64), it's in sp[2].  For SYSV (used by linux ppc),\n      // it's in sp[1].\n#if defined(_CALL_AIX) || defined(_CALL_DARWIN)\n      result[n++] = *(sp + 2);\n#elif defined(_CALL_SYSV)\n      result[n++] = *(sp + 1);\n#elif defined(__APPLE__) || \\\n    ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))\n      // This check is in case the compiler doesn't define _CALL_AIX/etc.\n      result[n++] = *(sp + 2);\n#elif defined(__linux) || defined(__OpenBSD__)\n      // This check is in case the compiler doesn't define _CALL_SYSV.\n      result[n++] = *(sp + 1);\n#else\n#  error Need to specify the PPC ABI for your architecture.\n#endif\n    }\n    // Use strict unwinding rules.\n    sp = NextStackFrame<true>(sp);\n  }\n  return n;\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n"
  },
  {
    "path": "src/stacktrace_unittest.cc",
    "content": "// Copyright (c) 2004, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#include \"stacktrace.h\"\n\n#include <cstdio>\n#include <cstdlib>\n\n#include \"base/commandlineflags.h\"\n#include \"config.h\"\n#include \"glog/logging.h\"\n#include \"utilities.h\"\n\n#ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS\n#  include <execinfo.h>\n#endif\n\n#ifdef HAVE_STACKTRACE\n\n// Obtain a backtrace, verify that the expected callers are present in the\n// backtrace, and maybe print the backtrace to stdout.\n\n// The sequence of functions whose return addresses we expect to see in the\n// backtrace.\nconst int BACKTRACE_STEPS = 6;\n\nstruct AddressRange {\n  const void *start, *end;\n};\n\n// Expected function [start,end] range.\nAddressRange expected_range[BACKTRACE_STEPS];\n\n#  if __GNUC__\n// Using GCC extension: address of a label can be taken with '&&label'.\n// Start should be a label somewhere before recursive call, end somewhere\n// after it.\n#    define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \\\n      do {                                                         \\\n        (prange)->start = &&start_label;                           \\\n        (prange)->end = &&end_label;                               \\\n        CHECK_LT((prange)->start, (prange)->end);                  \\\n      } while (0)\n// This macro expands into \"unmovable\" code (opaque to GCC), and that\n// prevents GCC from moving a_label up or down in the code.\n// Without it, there is no code following the 'end' label, and GCC\n// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before\n// the recursive call.\n#    define DECLARE_ADDRESS_LABEL(a_label) \\\n    a_label:                               \\\n      do {                                 \\\n        __asm__ __volatile__(\"\");          \\\n      } while (0)\n// Gcc 4.4.0 may split function into multiple chunks, and the chunk\n// performing recursive call may end up later in the code then the return\n// instruction (this actually happens with FDO).\n// Adjust function range from __builtin_return_address.\n#    define ADJUST_ADDRESS_RANGE_FROM_RA(prange)                             \\\n      do {                                                                   \\\n        void* ra = __builtin_return_address(0);                              \\\n        CHECK_LT((prange)->start, ra);                                       \\\n        if (ra > (prange)->end) {                                            \\\n          printf(\"Adjusting range from %p..%p to %p..%p\\n\", (prange)->start, \\\n                 (prange)->end, (prange)->start, ra);                        \\\n          (prange)->end = ra;                                                \\\n        }                                                                    \\\n      } while (0)\n#  else\n// Assume the Check* functions below are not longer than 256 bytes.\n#    define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \\\n      do {                                                         \\\n        (prange)->start = reinterpret_cast<const void*>(&fn);      \\\n        (prange)->end = reinterpret_cast<const char*>(&fn) + 256;  \\\n      } while (0)\n#    define DECLARE_ADDRESS_LABEL(a_label) \\\n      do {                                 \\\n      } while (0)\n#    define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \\\n      do {                                       \\\n      } while (0)\n#  endif  // __GNUC__\n\n//-----------------------------------------------------------------------//\n\nstatic void CheckRetAddrIsInFunction(void* ret_addr,\n                                     const AddressRange& range) {\n  CHECK_GE(ret_addr, range.start);\n  CHECK_LE(ret_addr, range.end);\n}\n\n//-----------------------------------------------------------------------//\n\n#  if defined(__clang__)\n#    pragma clang diagnostic push\n#    pragma clang diagnostic ignored \"-Wgnu-label-as-value\"\n#  endif\n\nvoid ATTRIBUTE_NOINLINE CheckStackTrace(int);\nstatic void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {\n  const int STACK_LEN = 10;\n  void* stack[STACK_LEN];\n  int size;\n\n  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);\n  INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);\n  DECLARE_ADDRESS_LABEL(start);\n  size = google::GetStackTrace(stack, STACK_LEN, 0);\n  printf(\"Obtained %d stack frames.\\n\", size);\n  CHECK_GE(size, 1);\n  CHECK_LE(size, STACK_LEN);\n\n  if (true) {\n#  ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS\n    char** strings = backtrace_symbols(stack, size);\n    printf(\"Obtained %d stack frames.\\n\", size);\n    for (int i = 0; i < size; i++) {\n      printf(\"%s %p\\n\", strings[i], stack[i]);\n    }\n\n    union {\n      void (*p1)(int);\n      void* p2;\n    } p = {&CheckStackTrace};\n\n    printf(\"CheckStackTrace() addr: %p\\n\", p.p2);\n    free(strings);\n#  endif\n  }\n  for (int i = 0; i < BACKTRACE_STEPS; i++) {\n    printf(\"Backtrace %d: expected: %p..%p  actual: %p ... \", i,\n           expected_range[i].start, expected_range[i].end, stack[i]);\n    fflush(stdout);\n    CheckRetAddrIsInFunction(stack[i], expected_range[i]);\n    printf(\"OK\\n\");\n  }\n  DECLARE_ADDRESS_LABEL(end);\n}\n\n//-----------------------------------------------------------------------//\n\n/* Dummy functions to make the backtrace more interesting. */\nstatic void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {\n  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);\n  INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);\n  DECLARE_ADDRESS_LABEL(start);\n  for (int j = i; j >= 0; j--) {\n    CheckStackTraceLeaf();\n  }\n  DECLARE_ADDRESS_LABEL(end);\n}\nstatic void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {\n  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);\n  INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);\n  DECLARE_ADDRESS_LABEL(start);\n  for (int j = i; j >= 0; j--) {\n    CheckStackTrace4(j);\n  }\n  DECLARE_ADDRESS_LABEL(end);\n}\nstatic void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {\n  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);\n  INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);\n  DECLARE_ADDRESS_LABEL(start);\n  for (int j = i; j >= 0; j--) {\n    CheckStackTrace3(j);\n  }\n  DECLARE_ADDRESS_LABEL(end);\n}\nstatic void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {\n  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);\n  INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);\n  DECLARE_ADDRESS_LABEL(start);\n  for (int j = i; j >= 0; j--) {\n    CheckStackTrace2(j);\n  }\n  DECLARE_ADDRESS_LABEL(end);\n}\n\n#  ifndef __GNUC__\n// On non-GNU environment, we use the address of `CheckStackTrace` to\n// guess the address range of this function. This guess is wrong for\n// non-static function on Windows. This is probably because\n// `&CheckStackTrace` returns the address of a trampoline like PLT,\n// not the actual address of `CheckStackTrace`.\n// See https://github.com/google/glog/issues/421 for the detail.\nstatic\n#  endif\n    void ATTRIBUTE_NOINLINE\n    CheckStackTrace(int i) {\n  INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);\n  DECLARE_ADDRESS_LABEL(start);\n  for (int j = i; j >= 0; j--) {\n    CheckStackTrace1(j);\n  }\n  DECLARE_ADDRESS_LABEL(end);\n}\n\n#  if defined(__clang__)\n#    pragma clang diagnostic pop\n#  endif\n\n//-----------------------------------------------------------------------//\n\nint main(int, char** argv) {\n  FLAGS_logtostderr = true;\n  google::InitGoogleLogging(argv[0]);\n\n  CheckStackTrace(0);\n\n  printf(\"PASS\\n\");\n  return 0;\n}\n\n#else\nint main() {\n\n#  ifdef GLOG_BAZEL_BUILD\n  printf(\"HAVE_STACKTRACE is expected to be defined in Bazel tests\\n\");\n  exit(EXIT_FAILURE);\n#  endif  // GLOG_BAZEL_BUILD\n\n  printf(\"PASS (no stacktrace support)\\n\");\n  return 0;\n}\n#endif    // HAVE_STACKTRACE\n"
  },
  {
    "path": "src/stacktrace_unwind-inl.h",
    "content": "// Copyright (c) 2023, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Arun Sharma\n//\n// Produce stack trace using libgcc\n\n#include <unwind.h>  // ABI defined unwinder\n\n#include \"stacktrace.h\"\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\nstruct trace_arg_t {\n  void** result;\n  int max_depth;\n  int skip_count;\n  int count;\n};\n\n// Workaround for the malloc() in _Unwind_Backtrace() issue.\nstatic _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context* /*uc*/,\n                                         void* /*opq*/) {\n  return _URC_NO_REASON;\n}\n\n// This code is not considered ready to run until\n// static initializers run so that we are guaranteed\n// that any malloc-related initialization is done.\nstatic bool ready_to_run = false;\nclass StackTraceInit {\n public:\n  StackTraceInit() {\n    // Extra call to force initialization\n    _Unwind_Backtrace(nop_backtrace, nullptr);\n    ready_to_run = true;\n  }\n};\n\nstatic StackTraceInit module_initializer;  // Force initialization\n\nstatic _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context* uc, void* opq) {\n  auto* targ = static_cast<trace_arg_t*>(opq);\n\n  if (targ->skip_count > 0) {\n    targ->skip_count--;\n  } else {\n    targ->result[targ->count++] = reinterpret_cast<void*>(_Unwind_GetIP(uc));\n  }\n\n  if (targ->count == targ->max_depth) {\n    return _URC_END_OF_STACK;\n  }\n\n  return _URC_NO_REASON;\n}\n\n// If you change this function, also change GetStackFrames below.\nint GetStackTrace(void** result, int max_depth, int skip_count) {\n  if (!ready_to_run) {\n    return 0;\n  }\n\n  trace_arg_t targ;\n\n  skip_count += 1;  // Do not include the \"GetStackTrace\" frame\n\n  targ.result = result;\n  targ.max_depth = max_depth;\n  targ.skip_count = skip_count;\n  targ.count = 0;\n\n  _Unwind_Backtrace(GetOneFrame, &targ);\n\n  return targ.count;\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n"
  },
  {
    "path": "src/stacktrace_windows-inl.h",
    "content": "// Copyright (c) 2000 - 2007, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Andrew Schwartzmeyer\n//\n// Windows implementation - just use CaptureStackBackTrace\n\n// clang-format off\n#include <windows.h> // Must come before <dbghelp.h>\n#include <dbghelp.h>\n// clang-format on\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\nint GetStackTrace(void** result, int max_depth, int skip_count) {\n  if (max_depth > 64) {\n    max_depth = 64;\n  }\n  skip_count++;  // we want to skip the current frame as well\n  // This API is thread-safe (moreover it walks only the current thread).\n  return CaptureStackBackTrace(static_cast<DWORD>(skip_count),\n                               static_cast<DWORD>(max_depth), result, nullptr);\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n"
  },
  {
    "path": "src/stacktrace_x86-inl.h",
    "content": "// Copyright (c) 2000 - 2007, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Produce stack trace\n\n#include <cstdint>  // for uintptr_t\n\n#include \"utilities.h\"  // for OS_* macros\n\n#if !defined(GLOG_OS_WINDOWS)\n#  include <sys/mman.h>\n#  include <unistd.h>\n#endif\n\n#include <cstdio>  // for nullptr\n\n#include \"stacktrace.h\"\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n// Given a pointer to a stack frame, locate and return the calling\n// stackframe, or return nullptr if no stackframe can be found. Perform sanity\n// checks (the strictness of which is controlled by the boolean parameter\n// \"STRICT_UNWINDING\") to reduce the chance that a bad pointer is returned.\ntemplate <bool STRICT_UNWINDING>\nstatic void** NextStackFrame(void** old_sp) {\n  void** new_sp = static_cast<void**>(*old_sp);\n\n  // Check that the transition from frame pointer old_sp to frame\n  // pointer new_sp isn't clearly bogus\n  if (STRICT_UNWINDING) {\n    // With the stack growing downwards, older stack frame must be\n    // at a greater address that the current one.\n    if (new_sp <= old_sp) return nullptr;\n    // Assume stack frames larger than 100,000 bytes are bogus.\n    if (reinterpret_cast<uintptr_t>(new_sp) -\n            reinterpret_cast<uintptr_t>(old_sp) >\n        100000) {\n      return nullptr;\n    }\n  } else {\n    // In the non-strict mode, allow discontiguous stack frames.\n    // (alternate-signal-stacks for example).\n    if (new_sp == old_sp) return nullptr;\n    // And allow frames upto about 1MB.\n    if ((new_sp > old_sp) && (reinterpret_cast<uintptr_t>(new_sp) -\n                                  reinterpret_cast<uintptr_t>(old_sp) >\n                              1000000)) {\n      return nullptr;\n    }\n  }\n  if (reinterpret_cast<uintptr_t>(new_sp) & (sizeof(void*) - 1)) {\n    return nullptr;\n  }\n#ifdef __i386__\n  // On 64-bit machines, the stack pointer can be very close to\n  // 0xffffffff, so we explicitly check for a pointer into the\n  // last two pages in the address space\n  if ((uintptr_t)new_sp >= 0xffffe000) return nullptr;\n#endif\n#if !defined(GLOG_OS_WINDOWS)\n  if (!STRICT_UNWINDING) {\n    // Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test\n    // on AMD-based machines with VDSO-enabled kernels.\n    // Make an extra sanity check to insure new_sp is readable.\n    // Note: NextStackFrame<false>() is only called while the program\n    //       is already on its last leg, so it's ok to be slow here.\n    static int page_size = getpagesize();\n    void* new_sp_aligned =\n        reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(new_sp) &\n                                static_cast<uintptr_t>(~(page_size - 1)));\n    if (msync(new_sp_aligned, static_cast<size_t>(page_size), MS_ASYNC) == -1) {\n      return nullptr;\n    }\n  }\n#endif\n  return new_sp;\n}\n\n// If you change this function, also change GetStackFrames below.\nint GetStackTrace(void** result, int max_depth, int skip_count) {\n  void** sp;\n\n#ifdef __GNUC__\n#  if __GNUC__ * 100 + __GNUC_MINOR__ >= 402\n#    define USE_BUILTIN_FRAME_ADDRESS\n#  endif\n#endif\n\n#ifdef USE_BUILTIN_FRAME_ADDRESS\n  sp = reinterpret_cast<void**>(__builtin_frame_address(0));\n#elif defined(__i386__)\n  // Stack frame format:\n  //    sp[0]   pointer to previous frame\n  //    sp[1]   caller address\n  //    sp[2]   first argument\n  //    ...\n  sp = (void**)&result - 2;\n#elif defined(__x86_64__)\n  // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8\n  unsigned long rbp;\n  // Move the value of the register %rbp into the local variable rbp.\n  // We need 'volatile' to prevent this instruction from getting moved\n  // around during optimization to before function prologue is done.\n  // An alternative way to achieve this\n  // would be (before this __asm__ instruction) to call Noop() defined as\n  //   static void Noop() __attribute__ ((noinline));  // prevent inlining\n  //   static void Noop() { asm(\"\"); }  // prevent optimizing-away\n  __asm__ volatile(\"mov %%rbp, %0\" : \"=r\"(rbp));\n  // Arguments are passed in registers on x86-64, so we can't just\n  // offset from &result\n  sp = (void**)rbp;\n#endif\n\n  int n = 0;\n  while (sp && n < max_depth) {\n    if (*(sp + 1) == nullptr) {\n      // In 64-bit code, we often see a frame that\n      // points to itself and has a return address of 0.\n      break;\n    }\n    if (skip_count > 0) {\n      skip_count--;\n    } else {\n      result[n++] = *(sp + 1);\n    }\n    // Use strict unwinding rules.\n    sp = NextStackFrame<true>(sp);\n  }\n  return n;\n}\n}  // namespace glog_internal_namespace_\n}  // namespace google\n"
  },
  {
    "path": "src/stl_logging_unittest.cc",
    "content": "// Copyright (c) 2003, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#include \"glog/stl_logging.h\"\n\n#include <functional>\n#include <iostream>\n#include <map>\n#include <ostream>\n#include <string>\n#include <vector>\n\n#include \"config.h\"\n#include \"glog/logging.h\"\n#include \"googletest.h\"\n\nusing namespace std;\n\nstruct user_hash {\n  size_t operator()(int x) const { return static_cast<size_t>(x); }\n};\n\nstatic void TestSTLLogging() {\n  {\n    // Test a sequence.\n    vector<int> v;\n    v.push_back(10);\n    v.push_back(20);\n    v.push_back(30);\n    ostringstream ss;\n    ss << v;\n    EXPECT_EQ(ss.str(), \"10 20 30\");\n    vector<int> copied_v(v);\n    CHECK_EQ(v, copied_v);  // This must compile.\n  }\n\n  {\n    // Test a sorted pair associative container.\n    map<int, string> m;\n    m[20] = \"twenty\";\n    m[10] = \"ten\";\n    m[30] = \"thirty\";\n    ostringstream ss;\n    ss << m;\n    EXPECT_EQ(ss.str(), \"(10, ten) (20, twenty) (30, thirty)\");\n    map<int, string> copied_m(m);\n    CHECK_EQ(m, copied_m);  // This must compile.\n  }\n\n  {\n    // Test a long sequence.\n    vector<int> v;\n    string expected;\n    for (int i = 0; i < 100; i++) {\n      v.push_back(i);\n      if (i > 0) expected += ' ';\n      const size_t buf_size = 256;\n      char buf[buf_size];\n      std::snprintf(buf, buf_size, \"%d\", i);\n      expected += buf;\n    }\n    v.push_back(100);\n    expected += \" ...\";\n    ostringstream ss;\n    ss << v;\n    CHECK_EQ(ss.str(), expected.c_str());\n  }\n\n  {\n    // Test a sorted pair associative container.\n    // Use a non-default comparison functor.\n    map<int, string, greater<>> m;\n    m[20] = \"twenty\";\n    m[10] = \"ten\";\n    m[30] = \"thirty\";\n    ostringstream ss;\n    ss << m;\n    EXPECT_EQ(ss.str(), \"(30, thirty) (20, twenty) (10, ten)\");\n    map<int, string, greater<>> copied_m(m);\n    CHECK_EQ(m, copied_m);  // This must compile.\n  }\n}\n\nint main(int, char**) {\n  TestSTLLogging();\n  std::cout << \"PASS\\n\";\n  return 0;\n}\n"
  },
  {
    "path": "src/striplog_unittest.cc",
    "content": "// Copyright (c) 2023, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Sergey Ioffe\n\n// The common part of the striplog tests.\n\n#include <csignal>\n#include <cstdio>\n#include <cstdlib>\n#include <iosfwd>\n#include <string>\n\n#include \"base/commandlineflags.h\"\n#include \"config.h\"\n#include \"glog/logging.h\"\n\nGLOG_DEFINE_bool(check_mode, false, \"Prints 'opt' or 'dbg'\");\n\nusing std::string;\nusing namespace google;\n\nint CheckNoReturn(bool b) {\n  string s;\n  if (b) {\n    LOG(FATAL) << \"Fatal\";\n    return 0;  // Workaround for MSVC warning C4715\n  } else {\n    return 0;\n  }\n}\n\nstruct A {};\nstd::ostream& operator<<(std::ostream& str, const A&) { return str; }\n\nnamespace {\nvoid handle_abort(int /*code*/) { std::exit(EXIT_FAILURE); }\n}  // namespace\n\nint main(int, char* argv[]) {\n#if defined(_MSC_VER)\n  // Avoid presenting an interactive dialog that will cause the test to time\n  // out.\n  _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\n#endif  // defined(_MSC_VER)\n  std::signal(SIGABRT, handle_abort);\n\n  FLAGS_logtostderr = true;\n  InitGoogleLogging(argv[0]);\n  if (FLAGS_check_mode) {\n    printf(\"%s\\n\", DEBUG_MODE ? \"dbg\" : \"opt\");\n    return 0;\n  }\n  LOG(INFO) << \"TESTMESSAGE INFO\";\n  LOG(WARNING) << 2 << \"something\"\n               << \"TESTMESSAGE WARNING\" << 1 << 'c' << A() << std::endl;\n  LOG(ERROR) << \"TESTMESSAGE ERROR\";\n  bool flag = true;\n  (flag ? LOG(INFO) : LOG(ERROR)) << \"TESTMESSAGE COND\";\n  LOG(FATAL) << \"TESTMESSAGE FATAL\";\n}\n"
  },
  {
    "path": "src/symbolize.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Satoru Takabayashi\n// Stack-footprint reduction work done by Raksit Ashok\n//\n// Implementation note:\n//\n// We don't use heaps but only use stacks.  We want to reduce the\n// stack consumption so that the symbolizer can run on small stacks.\n//\n// Here are some numbers collected with GCC 4.1.0 on x86:\n// - sizeof(Elf32_Sym)  = 16\n// - sizeof(Elf32_Shdr) = 40\n// - sizeof(Elf64_Sym)  = 24\n// - sizeof(Elf64_Shdr) = 64\n//\n// This implementation is intended to be async-signal-safe but uses\n// some functions which are not guaranteed to be so, such as memchr()\n// and memmove().  We assume they are async-signal-safe.\n//\n// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE\n// macro to add platform specific defines (e.g. GLOG_OS_OPENBSD).\n\n#ifdef GLOG_BUILD_CONFIG_INCLUDE\n#  include GLOG_BUILD_CONFIG_INCLUDE\n#endif  // GLOG_BUILD_CONFIG_INCLUDE\n\n#include \"symbolize.h\"\n\n#include \"utilities.h\"\n\n#if defined(HAVE_SYMBOLIZE)\n\n#  include <algorithm>\n#  include <cstdlib>\n#  include <cstring>\n#  include <limits>\n\n#  include \"demangle.h\"\n\n// We don't use assert() since it's not guaranteed to be\n// async-signal-safe.  Instead we define a minimal assertion\n// macro. So far, we don't need pretty printing for __FILE__, etc.\n#  define GLOG_SAFE_ASSERT(expr) ((expr) ? 0 : (std::abort(), 0))\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\nnamespace {\n\nSymbolizeCallback g_symbolize_callback = nullptr;\nSymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback = nullptr;\n\n// This function wraps the Demangle function to provide an interface\n// where the input symbol is demangled in-place.\n// To keep stack consumption low, we would like this function to not\n// get inlined.\nATTRIBUTE_NOINLINE\nvoid DemangleInplace(char* out, size_t out_size) {\n  char demangled[256];  // Big enough for sane demangled symbols.\n  if (Demangle(out, demangled, sizeof(demangled))) {\n    // Demangling succeeded. Copy to out if the space allows.\n    size_t len = strlen(demangled);\n    if (len + 1 <= out_size) {  // +1 for '\\0'.\n      GLOG_SAFE_ASSERT(len < sizeof(demangled));\n      memmove(out, demangled, len + 1);\n    }\n  }\n}\n\n}  // namespace\n\nvoid InstallSymbolizeCallback(SymbolizeCallback callback) {\n  g_symbolize_callback = callback;\n}\n\nvoid InstallSymbolizeOpenObjectFileCallback(\n    SymbolizeOpenObjectFileCallback callback) {\n  g_symbolize_open_object_file_callback = callback;\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#  if defined(HAVE_LINK_H)\n\n#    if defined(HAVE_DLFCN_H)\n#      include <dlfcn.h>\n#    endif\n#    include <fcntl.h>\n#    include <sys/stat.h>\n#    include <sys/types.h>\n#    include <unistd.h>\n\n#    include <cerrno>\n#    include <climits>\n#    include <cstddef>\n#    include <cstdint>\n#    include <cstdio>\n#    include <cstdlib>\n#    include <cstring>\n\n#    include \"config.h\"\n#    include \"glog/raw_logging.h\"\n#    include \"symbolize.h\"\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\nnamespace {\n\n// Re-runs run until it doesn't cause EINTR.\n// Similar to the TEMP_FAILURE_RETRY macro from GNU C.\ntemplate <class Functor>\nauto FailureRetry(Functor run, int error = EINTR) noexcept(noexcept(run())) {\n  decltype(run()) result;\n\n  while ((result = run()) == -1 && errno == error) {\n  }\n\n  return result;\n}\n\n}  // namespace\n\n// Read up to \"count\" bytes from \"offset\" in the file pointed by file\n// descriptor \"fd\" into the buffer starting at \"buf\" while handling short reads\n// and EINTR.  On success, return the number of bytes read.  Otherwise, return\n// -1.\nstatic ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,\n                              const size_t offset) {\n  GLOG_SAFE_ASSERT(fd >= 0);\n  GLOG_SAFE_ASSERT(count <=\n                   static_cast<size_t>(std::numeric_limits<ssize_t>::max()));\n  char* buf0 = reinterpret_cast<char*>(buf);\n  size_t num_bytes = 0;\n  while (num_bytes < count) {\n    ssize_t len = FailureRetry([fd, p = buf0 + num_bytes, n = count - num_bytes,\n                                m = static_cast<off_t>(offset + num_bytes)] {\n      return pread(fd, p, n, m);\n    });\n    if (len < 0) {  // There was an error other than EINTR.\n      return -1;\n    }\n    if (len == 0) {  // Reached EOF.\n      break;\n    }\n    num_bytes += static_cast<size_t>(len);\n  }\n  GLOG_SAFE_ASSERT(num_bytes <= count);\n  return static_cast<ssize_t>(num_bytes);\n}\n\n// Try reading exactly \"count\" bytes from \"offset\" bytes in a file\n// pointed by \"fd\" into the buffer starting at \"buf\" while handling\n// short reads and EINTR.  On success, return true. Otherwise, return\n// false.\nstatic bool ReadFromOffsetExact(const int fd, void* buf, const size_t count,\n                                const size_t offset) {\n  ssize_t len = ReadFromOffset(fd, buf, count, offset);\n  return static_cast<size_t>(len) == count;\n}\n\n// Returns elf_header.e_type if the file pointed by fd is an ELF binary.\nstatic int FileGetElfType(const int fd) {\n  ElfW(Ehdr) elf_header;\n  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {\n    return -1;\n  }\n  if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {\n    return -1;\n  }\n  return elf_header.e_type;\n}\n\n// Read the section headers in the given ELF binary, and if a section\n// of the specified type is found, set the output to this section header\n// and return true.  Otherwise, return false.\n// To keep stack consumption low, we would like this function to not get\n// inlined.\nstatic ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,\n                                                      ElfW(Half) sh_num,\n                                                      const size_t sh_offset,\n                                                      ElfW(Word) type,\n                                                      ElfW(Shdr) * out) {\n  // Read at most 16 section headers at a time to save read calls.\n  ElfW(Shdr) buf[16];\n  for (size_t i = 0; i < sh_num;) {\n    const size_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);\n    const size_t num_bytes_to_read =\n        (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);\n    const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,\n                                       sh_offset + i * sizeof(buf[0]));\n    if (len == -1) {\n      return false;\n    }\n    GLOG_SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);\n    const size_t num_headers_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);\n    GLOG_SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));\n    for (size_t j = 0; j < num_headers_in_buf; ++j) {\n      if (buf[j].sh_type == type) {\n        *out = buf[j];\n        return true;\n      }\n    }\n    i += num_headers_in_buf;\n  }\n  return false;\n}\n\n// There is no particular reason to limit section name to 63 characters,\n// but there has (as yet) been no need for anything longer either.\nconst int kMaxSectionNameLen = 64;\n\n// name_len should include terminating '\\0'.\nbool GetSectionHeaderByName(int fd, const char* name, size_t name_len,\n                            ElfW(Shdr) * out) {\n  ElfW(Ehdr) elf_header;\n  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {\n    return false;\n  }\n\n  ElfW(Shdr) shstrtab;\n  size_t shstrtab_offset =\n      (elf_header.e_shoff + static_cast<size_t>(elf_header.e_shentsize) *\n                                static_cast<size_t>(elf_header.e_shstrndx));\n  if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {\n    return false;\n  }\n\n  for (size_t i = 0; i < elf_header.e_shnum; ++i) {\n    size_t section_header_offset =\n        (elf_header.e_shoff + elf_header.e_shentsize * i);\n    if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {\n      return false;\n    }\n    char header_name[kMaxSectionNameLen];\n    if (sizeof(header_name) < name_len) {\n      RAW_LOG(WARNING,\n              \"Section name '%s' is too long (%zu); \"\n              \"section will not be found (even if present).\",\n              name, name_len);\n      // No point in even trying.\n      return false;\n    }\n    size_t name_offset = shstrtab.sh_offset + out->sh_name;\n    ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);\n    if (n_read == -1) {\n      return false;\n    } else if (static_cast<size_t>(n_read) != name_len) {\n      // Short read -- name could be at end of file.\n      continue;\n    }\n    if (memcmp(header_name, name, name_len) == 0) {\n      return true;\n    }\n  }\n  return false;\n}\n\n// Read a symbol table and look for the symbol containing the\n// pc. Iterate over symbols in a symbol table and look for the symbol\n// containing \"pc\".  On success, return true and write the symbol name\n// to out.  Otherwise, return false.\n// To keep stack consumption low, we would like this function to not get\n// inlined.\nstatic ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,\n                                          size_t out_size,\n                                          uint64_t symbol_offset,\n                                          const ElfW(Shdr) * strtab,\n                                          const ElfW(Shdr) * symtab) {\n  if (symtab == nullptr) {\n    return false;\n  }\n  const size_t num_symbols = symtab->sh_size / symtab->sh_entsize;\n  for (unsigned i = 0; i < num_symbols;) {\n    size_t offset = symtab->sh_offset + i * symtab->sh_entsize;\n\n    // If we are reading Elf64_Sym's, we want to limit this array to\n    // 32 elements (to keep stack consumption low), otherwise we can\n    // have a 64 element Elf32_Sym array.\n#    if defined(__WORDSIZE) && __WORDSIZE == 64\n    const size_t NUM_SYMBOLS = 32U;\n#    else\n    const size_t NUM_SYMBOLS = 64U;\n#    endif\n\n    // Read at most NUM_SYMBOLS symbols at once to save read() calls.\n    ElfW(Sym) buf[NUM_SYMBOLS];\n    size_t num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i);\n    const ssize_t len =\n        ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset);\n    GLOG_SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);\n    const size_t num_symbols_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);\n    GLOG_SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read);\n    for (unsigned j = 0; j < num_symbols_in_buf; ++j) {\n      const ElfW(Sym)& symbol = buf[j];\n      uint64_t start_address = symbol.st_value;\n      start_address += symbol_offset;\n      uint64_t end_address = start_address + symbol.st_size;\n      if (symbol.st_value != 0 &&  // Skip null value symbols.\n          symbol.st_shndx != 0 &&  // Skip undefined symbols.\n          start_address <= pc && pc < end_address) {\n        ssize_t len1 = ReadFromOffset(fd, out, out_size,\n                                      strtab->sh_offset + symbol.st_name);\n        if (len1 <= 0 || memchr(out, '\\0', out_size) == nullptr) {\n          memset(out, 0, out_size);\n          return false;\n        }\n        return true;  // Obtained the symbol name.\n      }\n    }\n    i += num_symbols_in_buf;\n  }\n  return false;\n}\n\n// Get the symbol name of \"pc\" from the file pointed by \"fd\".  Process\n// both regular and dynamic symbol tables if necessary.  On success,\n// write the symbol name to \"out\" and return true.  Otherwise, return\n// false.\nstatic bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,\n                                    size_t out_size, uint64_t base_address) {\n  // Read the ELF header.\n  ElfW(Ehdr) elf_header;\n  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {\n    return false;\n  }\n\n  ElfW(Shdr) symtab, strtab;\n\n  // Consult a regular symbol table first.\n  if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,\n                             SHT_SYMTAB, &symtab)) {\n    if (!ReadFromOffsetExact(\n            fd, &strtab, sizeof(strtab),\n            elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {\n      return false;\n    }\n    if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {\n      return true;  // Found the symbol in a regular symbol table.\n    }\n  }\n\n  // If the symbol is not found, then consult a dynamic symbol table.\n  if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,\n                             SHT_DYNSYM, &symtab)) {\n    if (!ReadFromOffsetExact(\n            fd, &strtab, sizeof(strtab),\n            elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {\n      return false;\n    }\n    if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {\n      return true;  // Found the symbol in a dynamic symbol table.\n    }\n  }\n\n  return false;\n}\n\nnamespace {\n\n// Helper class for reading lines from file.\n//\n// Note: we don't use ProcMapsIterator since the object is big (it has\n// a 5k array member) and uses async-unsafe functions such as sscanf()\n// and std::snprintf().\nclass LineReader {\n public:\n  explicit LineReader(int fd, char* buf, size_t buf_len, size_t offset)\n      : fd_(fd),\n        buf_(buf),\n        buf_len_(buf_len),\n        offset_(offset),\n        bol_(buf),\n        eol_(buf),\n        eod_(buf) {}\n\n  // Read '\\n'-terminated line from file.  On success, modify \"bol\"\n  // and \"eol\", then return true.  Otherwise, return false.\n  //\n  // Note: if the last line doesn't end with '\\n', the line will be\n  // dropped.  It's an intentional behavior to make the code simple.\n  bool ReadLine(const char** bol, const char** eol) {\n    if (BufferIsEmpty()) {  // First time.\n      const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);\n      if (num_bytes <= 0) {  // EOF or error.\n        return false;\n      }\n      offset_ += static_cast<size_t>(num_bytes);\n      eod_ = buf_ + num_bytes;\n      bol_ = buf_;\n    } else {\n      bol_ = eol_ + 1;  // Advance to the next line in the buffer.\n      GLOG_SAFE_ASSERT(bol_ <= eod_);  // \"bol_\" can point to \"eod_\".\n      if (!HasCompleteLine()) {\n        const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_);\n        // Move the trailing incomplete line to the beginning.\n        memmove(buf_, bol_, incomplete_line_length);\n        // Read text from file and append it.\n        char* const append_pos = buf_ + incomplete_line_length;\n        const size_t capacity_left = buf_len_ - incomplete_line_length;\n        const ssize_t num_bytes =\n            ReadFromOffset(fd_, append_pos, capacity_left, offset_);\n        if (num_bytes <= 0) {  // EOF or error.\n          return false;\n        }\n        offset_ += static_cast<size_t>(num_bytes);\n        eod_ = append_pos + num_bytes;\n        bol_ = buf_;\n      }\n    }\n    eol_ = FindLineFeed();\n    if (eol_ == nullptr) {  // '\\n' not found.  Malformed line.\n      return false;\n    }\n    *eol_ = '\\0';  // Replace '\\n' with '\\0'.\n\n    *bol = bol_;\n    *eol = eol_;\n    return true;\n  }\n\n  // Beginning of line.\n  const char* bol() { return bol_; }\n\n  // End of line.\n  const char* eol() { return eol_; }\n\n private:\n  LineReader(const LineReader&) = delete;\n  void operator=(const LineReader&) = delete;\n\n  char* FindLineFeed() {\n    return reinterpret_cast<char*>(\n        memchr(bol_, '\\n', static_cast<size_t>(eod_ - bol_)));\n  }\n\n  bool BufferIsEmpty() { return buf_ == eod_; }\n\n  bool HasCompleteLine() {\n    return !BufferIsEmpty() && FindLineFeed() != nullptr;\n  }\n\n  const int fd_;\n  char* const buf_;\n  const size_t buf_len_;\n  size_t offset_;\n  char* bol_;\n  char* eol_;\n  const char* eod_;  // End of data in \"buf_\".\n};\n}  // namespace\n\n// Place the hex number read from \"start\" into \"*hex\".  The pointer to\n// the first non-hex character or \"end\" is returned.\nstatic char* GetHex(const char* start, const char* end, uint64_t* hex) {\n  *hex = 0;\n  const char* p;\n  for (p = start; p < end; ++p) {\n    int ch = *p;\n    if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') ||\n        (ch >= 'a' && ch <= 'f')) {\n      *hex = (*hex << 4U) |\n             (ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);\n    } else {  // Encountered the first non-hex character.\n      break;\n    }\n  }\n  GLOG_SAFE_ASSERT(p <= end);\n  return const_cast<char*>(p);\n}\n\n// Searches for the object file (from /proc/self/maps) that contains\n// the specified pc.  If found, sets |start_address| to the start address\n// of where this object file is mapped in memory, sets the module base\n// address into |base_address|, copies the object file name into\n// |out_file_name|, and attempts to open the object file.  If the object\n// file is opened successfully, returns the file descriptor.  Otherwise,\n// returns -1.  |out_file_name_size| is the size of the file name buffer\n// (including the null-terminator).\nstatic ATTRIBUTE_NOINLINE FileDescriptor\nOpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,\n                                             uint64_t& start_address,\n                                             uint64_t& base_address,\n                                             char* out_file_name,\n                                             size_t out_file_name_size) {\n  FileDescriptor maps_fd{\n      FailureRetry([] { return open(\"/proc/self/maps\", O_RDONLY); })};\n  if (!maps_fd) {\n    return nullptr;\n  }\n\n  FileDescriptor mem_fd{\n      FailureRetry([] { return open(\"/proc/self/mem\", O_RDONLY); })};\n  if (!mem_fd) {\n    return nullptr;\n  }\n\n  // Iterate over maps and look for the map containing the pc.  Then\n  // look into the symbol tables inside.\n  char buf[1024];  // Big enough for line of sane /proc/self/maps\n  LineReader reader(maps_fd.get(), buf, sizeof(buf), 0);\n  while (true) {\n    const char* cursor;\n    const char* eol;\n    if (!reader.ReadLine(&cursor, &eol)) {  // EOF or malformed line.\n      return nullptr;\n    }\n\n    // Start parsing line in /proc/self/maps.  Here is an example:\n    //\n    // 08048000-0804c000 r-xp 00000000 08:01 2142121    /bin/cat\n    //\n    // We want start address (08048000), end address (0804c000), flags\n    // (r-xp) and file name (/bin/cat).\n\n    // Read start address.\n    cursor = GetHex(cursor, eol, &start_address);\n    if (cursor == eol || *cursor != '-') {\n      return nullptr;  // Malformed line.\n    }\n    ++cursor;  // Skip '-'.\n\n    // Read end address.\n    uint64_t end_address;\n    cursor = GetHex(cursor, eol, &end_address);\n    if (cursor == eol || *cursor != ' ') {\n      return nullptr;  // Malformed line.\n    }\n    ++cursor;  // Skip ' '.\n\n    // Read flags.  Skip flags until we encounter a space or eol.\n    const char* const flags_start = cursor;\n    while (cursor < eol && *cursor != ' ') {\n      ++cursor;\n    }\n    // We expect at least four letters for flags (ex. \"r-xp\").\n    if (cursor == eol || cursor < flags_start + 4) {\n      return nullptr;  // Malformed line.\n    }\n\n    // Determine the base address by reading ELF headers in process memory.\n    ElfW(Ehdr) ehdr;\n    // Skip non-readable maps.\n    if (flags_start[0] == 'r' &&\n        ReadFromOffsetExact(mem_fd.get(), &ehdr, sizeof(ElfW(Ehdr)),\n                            start_address) &&\n        memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {\n      switch (ehdr.e_type) {\n        case ET_EXEC:\n          base_address = 0;\n          break;\n        case ET_DYN:\n          // Find the segment containing file offset 0. This will correspond\n          // to the ELF header that we just read. Normally this will have\n          // virtual address 0, but this is not guaranteed. We must subtract\n          // the virtual address from the address where the ELF header was\n          // mapped to get the base address.\n          //\n          // If we fail to find a segment for file offset 0, use the address\n          // of the ELF header as the base address.\n          base_address = start_address;\n          for (unsigned i = 0; i != ehdr.e_phnum; ++i) {\n            ElfW(Phdr) phdr;\n            if (ReadFromOffsetExact(\n                    mem_fd.get(), &phdr, sizeof(phdr),\n                    start_address + ehdr.e_phoff + i * sizeof(phdr)) &&\n                phdr.p_type == PT_LOAD && phdr.p_offset == 0) {\n              base_address = start_address - phdr.p_vaddr;\n              break;\n            }\n          }\n          break;\n        default:\n          // ET_REL or ET_CORE. These aren't directly executable, so they don't\n          // affect the base address.\n          break;\n      }\n    }\n\n    // Check start and end addresses.\n    if (start_address > pc || pc >= end_address) {\n      continue;  // We skip this map.  PC isn't in this map.\n    }\n\n    // Check flags.  We are only interested in \"r*x\" maps.\n    if (flags_start[0] != 'r' || flags_start[2] != 'x') {\n      continue;  // We skip this map.\n    }\n    ++cursor;  // Skip ' '.\n\n    // Read file offset.\n    uint64_t file_offset;\n    cursor = GetHex(cursor, eol, &file_offset);\n    if (cursor == eol || *cursor != ' ') {\n      return nullptr;  // Malformed line.\n    }\n    ++cursor;  // Skip ' '.\n\n    // Skip to file name.  \"cursor\" now points to dev.  We need to\n    // skip at least two spaces for dev and inode.\n    int num_spaces = 0;\n    while (cursor < eol) {\n      if (*cursor == ' ') {\n        ++num_spaces;\n      } else if (num_spaces >= 2) {\n        // The first non-space character after skipping two spaces\n        // is the beginning of the file name.\n        break;\n      }\n      ++cursor;\n    }\n    if (cursor == eol) {\n      return nullptr;  // Malformed line.\n    }\n\n    strncpy(out_file_name, cursor, out_file_name_size);\n    // Making sure |out_file_name| is always null-terminated.\n    out_file_name[out_file_name_size - 1] = '\\0';\n\n    // Finally, \"cursor\" now points to file name of our interest.\n    return FileDescriptor{\n        FailureRetry([cursor] { return open(cursor, O_RDONLY); })};\n  }\n}\n\n// POSIX doesn't define any async-signal safe function for converting\n// an integer to ASCII. We'll have to define our own version.\n// itoa_r() converts an (unsigned) integer to ASCII. It returns \"buf\", if the\n// conversion was successful or nullptr otherwise. It never writes more than\n// \"sz\" bytes. Output will be truncated as needed, and a NUL character is always\n// appended.\n// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.\nstatic char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,\n                    size_t padding) {\n  // Make sure we can write at least one NUL byte.\n  size_t n = 1;\n  if (n > sz) {\n    return nullptr;\n  }\n\n  if (base < 2 || base > 16) {\n    buf[0] = '\\000';\n    return nullptr;\n  }\n\n  char* start = buf;\n\n  // Loop until we have converted the entire number. Output at least one\n  // character (i.e. '0').\n  char* ptr = start;\n  do {\n    // Make sure there is still enough space left in our output buffer.\n    if (++n > sz) {\n      buf[0] = '\\000';\n      return nullptr;\n    }\n\n    // Output the next digit.\n    *ptr++ = \"0123456789abcdef\"[i % base];\n    i /= base;\n\n    if (padding > 0) {\n      padding--;\n    }\n  } while (i > 0 || padding > 0);\n\n  // Terminate the output with a NUL character.\n  *ptr = '\\000';\n\n  // Conversion to ASCII actually resulted in the digits being in reverse\n  // order. We can't easily generate them in forward order, as we can't tell\n  // the number of characters needed until we are done converting.\n  // So, now, we reverse the string (except for the possible \"-\" sign).\n  while (--ptr > start) {\n    char ch = *ptr;\n    *ptr = *start;\n    *start++ = ch;\n  }\n  return buf;\n}\n\n// Safely appends string |source| to string |dest|.  Never writes past the\n// buffer size |dest_size| and guarantees that |dest| is null-terminated.\nstatic void SafeAppendString(const char* source, char* dest, size_t dest_size) {\n  size_t dest_string_length = strlen(dest);\n  GLOG_SAFE_ASSERT(dest_string_length < dest_size);\n  dest += dest_string_length;\n  dest_size -= dest_string_length;\n  strncpy(dest, source, dest_size);\n  // Making sure |dest| is always null-terminated.\n  dest[dest_size - 1] = '\\0';\n}\n\n// Converts a 64-bit value into a hex string, and safely appends it to |dest|.\n// Never writes past the buffer size |dest_size| and guarantees that |dest| is\n// null-terminated.\nstatic void SafeAppendHexNumber(uint64_t value, char* dest, size_t dest_size) {\n  // 64-bit numbers in hex can have up to 16 digits.\n  char buf[17] = {'\\0'};\n  SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);\n}\n\n// The implementation of our symbolization routine.  If it\n// successfully finds the symbol containing \"pc\" and obtains the\n// symbol name, returns true and write the symbol name to \"out\".\n// Otherwise, returns false. If Callback function is installed via\n// InstallSymbolizeCallback(), the function is also called in this function,\n// and \"out\" is used as its output.\n// To keep stack consumption low, we would like this function to not\n// get inlined.\nstatic ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(\n    void* pc, char* out, size_t out_size, SymbolizeOptions /*options*/) {\n  auto pc0 = reinterpret_cast<uintptr_t>(pc);\n  uint64_t start_address = 0;\n  uint64_t base_address = 0;\n  FileDescriptor object_fd;\n\n  if (out_size < 1) {\n    return false;\n  }\n  out[0] = '\\0';\n  SafeAppendString(\"(\", out, out_size);\n\n  if (g_symbolize_open_object_file_callback) {\n    object_fd.reset(g_symbolize_open_object_file_callback(\n        pc0, start_address, base_address, out + 1, out_size - 1));\n  } else {\n    object_fd = OpenObjectFileContainingPcAndGetStartAddress(\n        pc0, start_address, base_address, out + 1, out_size - 1);\n  }\n\n#    if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)\n  {\n#    else\n  // Check whether a file name was returned.\n  if (!object_fd) {\n#    endif\n    if (out[1]) {\n      // The object file containing PC was determined successfully however the\n      // object file was not opened successfully.  This is still considered\n      // success because the object file name and offset are known and tools\n      // like asan_symbolize.py can be used for the symbolization.\n      out[out_size - 1] = '\\0';  // Making sure |out| is always null-terminated.\n      SafeAppendString(\"+0x\", out, out_size);\n      SafeAppendHexNumber(pc0 - base_address, out, out_size);\n      SafeAppendString(\")\", out, out_size);\n      return true;\n    }\n    // Failed to determine the object file containing PC.  Bail out.\n    return false;\n  }\n  int elf_type = FileGetElfType(object_fd.get());\n  if (elf_type == -1) {\n    return false;\n  }\n  if (g_symbolize_callback) {\n    // Run the call back if it's installed.\n    // Note: relocation (and much of the rest of this code) will be\n    // wrong for prelinked shared libraries and PIE executables.\n    uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;\n    int num_bytes_written =\n        g_symbolize_callback(object_fd.get(), pc, out, out_size, relocation);\n    if (num_bytes_written > 0) {\n      out += static_cast<size_t>(num_bytes_written);\n      out_size -= static_cast<size_t>(num_bytes_written);\n    }\n  }\n  if (!GetSymbolFromObjectFile(object_fd.get(), pc0, out, out_size,\n                               base_address)) {\n    if (out[1] && !g_symbolize_callback) {\n      // The object file containing PC was opened successfully however the\n      // symbol was not found. The object may have been stripped. This is still\n      // considered success because the object file name and offset are known\n      // and tools like asan_symbolize.py can be used for the symbolization.\n      out[out_size - 1] = '\\0';  // Making sure |out| is always null-terminated.\n      SafeAppendString(\"+0x\", out, out_size);\n      SafeAppendHexNumber(pc0 - base_address, out, out_size);\n      SafeAppendString(\")\", out, out_size);\n      return true;\n    }\n    return false;\n  }\n\n  // Symbolization succeeded.  Now we try to demangle the symbol.\n  DemangleInplace(out, out_size);\n  return true;\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#  elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)\n\n#    include <dlfcn.h>\n\n#    include <cstring>\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\nstatic ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(\n    void* pc, char* out, size_t out_size, SymbolizeOptions /*options*/) {\n  Dl_info info;\n  if (dladdr(pc, &info)) {\n    if (info.dli_sname) {\n      if (strlen(info.dli_sname) < out_size) {\n        strcpy(out, info.dli_sname);\n        // Symbolization succeeded.  Now we try to demangle the symbol.\n        DemangleInplace(out, out_size);\n        return true;\n      }\n    }\n  }\n  return false;\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#  elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)\n\n#    include <dbghelp.h>\n#    include <windows.h>\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\nnamespace {\n\nclass SymInitializer final {\n public:\n  HANDLE process;\n  bool ready;\n  SymInitializer() : process(GetCurrentProcess()), ready(false) {\n    // Initialize the symbol handler.\n    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx\n    // Defer symbol loading.\n    // We do not request undecorated symbols with SYMOPT_UNDNAME\n    // because the mangling library calls UnDecorateSymbolName.\n    SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);\n    if (SymInitialize(process, nullptr, true)) {\n      ready = true;\n    }\n  }\n  ~SymInitializer() {\n    SymCleanup(process);\n    // We do not need to close `HANDLE process` because it's a \"pseudo handle.\"\n  }\n\n  SymInitializer(const SymInitializer&) = delete;\n  SymInitializer& operator=(const SymInitializer&) = delete;\n  SymInitializer(SymInitializer&&) = delete;\n  SymInitializer& operator=(SymInitializer&&) = delete;\n};\n\n}  // namespace\n\nstatic ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,\n                                                    size_t out_size,\n                                                    SymbolizeOptions options) {\n  const static SymInitializer symInitializer;\n  if (!symInitializer.ready) {\n    return false;\n  }\n  // Resolve symbol information from address.\n  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx\n  char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];\n  SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(buf);\n  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);\n  symbol->MaxNameLen = MAX_SYM_NAME;\n  // We use the ANSI version to ensure the string type is always `char *`.\n  // This could break if a symbol has Unicode in it.\n  BOOL ret = SymFromAddr(symInitializer.process, reinterpret_cast<DWORD64>(pc),\n                         0, symbol);\n  std::size_t namelen = static_cast<size_t>(symbol->NameLen);\n  if (ret && namelen < out_size) {\n    std::strncpy(out, symbol->Name, namelen);\n    out[namelen] = '\\0';\n\n    DWORD displacement;\n    IMAGEHLP_LINE64 line{sizeof(IMAGEHLP_LINE64)};\n\n    BOOL found = FALSE;\n\n    if ((options & SymbolizeOptions::kNoLineNumbers) !=\n        SymbolizeOptions::kNoLineNumbers) {\n      found = SymGetLineFromAddr64(symInitializer.process,\n                                   reinterpret_cast<DWORD64>(pc), &displacement,\n                                   &line);\n    }\n\n    // Symbolization succeeded.  Now we try to demangle the symbol.\n    DemangleInplace(out, out_size);\n    out_size -= std::strlen(out);\n\n    if (found) {\n      std::size_t fnlen = std::strlen(line.FileName);\n      // Determine the number of digits (base 10) necessary to represent the\n      // line number\n      std::size_t digits = 1;  // At least one digit required\n      for (DWORD value = line.LineNumber; (value /= 10) != 0; ++digits) {\n      }\n      constexpr std::size_t extralen = 4;  // space + parens () + :\n      const std::size_t suffixlen = fnlen + extralen + fnlen + digits;\n\n      if (suffixlen < out_size) {\n        out_size -= std::snprintf(out + namelen, out_size, \" (%s:%lu)\",\n                                  line.FileName, line.LineNumber);\n      }\n    }\n\n    return true;\n  }\n  return false;\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#  else\n#    error BUG: HAVE_SYMBOLIZE was wrongly set\n#  endif\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\nbool Symbolize(void* pc, char* out, size_t out_size, SymbolizeOptions options) {\n  return SymbolizeAndDemangle(pc, out, out_size, options);\n}\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#endif\n"
  },
  {
    "path": "src/symbolize.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Satoru Takabayashi\n//\n// This library provides Symbolize() function that symbolizes program\n// counters to their corresponding symbol names on linux platforms.\n// This library has a minimal implementation of an ELF symbol table\n// reader (i.e. it doesn't depend on libelf, etc.).\n//\n// The algorithm used in Symbolize() is as follows.\n//\n//   1. Go through a list of maps in /proc/self/maps and find the map\n//   containing the program counter.\n//\n//   2. Open the mapped file and find a regular symbol table inside.\n//   Iterate over symbols in the symbol table and look for the symbol\n//   containing the program counter.  If such a symbol is found,\n//   obtain the symbol name, and demangle the symbol if possible.\n//   If the symbol isn't found in the regular symbol table (binary is\n//   stripped), try the same thing with a dynamic symbol table.\n//\n// Note that Symbolize() is originally implemented to be used in\n// FailureSignalHandler() in base/google.cc.  Hence it doesn't use\n// malloc() and other unsafe operations.  It should be both\n// thread-safe and async-signal-safe.\n\n#ifndef GLOG_INTERNAL_SYMBOLIZE_H\n#define GLOG_INTERNAL_SYMBOLIZE_H\n\n#include <cstddef>\n#include <cstdint>\n#include <type_traits>\n\n#include \"config.h\"\n#include \"glog/platform.h\"\n\n#if defined(HAVE_LINK_H)\n#  include <link.h>  // For ElfW() macro.\n#elif defined(HAVE_ELF_H)\n#  include <elf.h>\n#elif defined(HAVE_SYS_EXEC_ELF_H)\n#  include <sys/exec_elf.h>\n#endif\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_NO_EXPORT)\n#  error \"symbolize.h\" was not included correctly.\n#endif\n\n// We prefer to let the build system detect the availability of certain features\n// such as symbolization support. HAVE_SYMBOLIZE should therefore be defined by\n// the build system in general unless there is a good reason to perform the\n// detection using the preprocessor.\n#ifndef GLOG_NO_SYMBOLIZE_DETECTION\n#  ifndef HAVE_SYMBOLIZE\n// defined by gcc\n#    if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)\n#      define HAVE_SYMBOLIZE\n#    elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)\n// Use dladdr to symbolize.\n#      define HAVE_SYMBOLIZE\n#    elif defined(GLOG_OS_WINDOWS)\n// Use DbgHelp to symbolize\n#      define HAVE_SYMBOLIZE\n#    endif\n#  endif  // !defined(HAVE_SYMBOLIZE)\n#endif    // !defined(GLOG_NO_SYMBOLIZE_DETECTION)\n\n#ifdef HAVE_SYMBOLIZE\n\n#  if !defined(SIZEOF_VOID_P) && defined(__SIZEOF_POINTER__)\n#    define SIZEOF_VOID_P __SIZEOF_POINTER__\n#  endif\n\n#  if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)\n\n// If there is no ElfW macro, let's define it by ourself.\n#    ifndef ElfW\n#      if SIZEOF_VOID_P == 4\n#        define ElfW(type) Elf32_##type\n#      elif SIZEOF_VOID_P == 8\n#        define ElfW(type) Elf64_##type\n#      else\n#        error \"Unknown sizeof(void *)\"\n#      endif\n#    endif\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n// Gets the section header for the given name, if it exists. Returns true on\n// success. Otherwise, returns false.\nGLOG_NO_EXPORT\nbool GetSectionHeaderByName(int fd, const char* name, size_t name_len,\n                            ElfW(Shdr) * out);\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#  endif\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n// Restrictions on the callbacks that follow:\n//  - The callbacks must not use heaps but only use stacks.\n//  - The callbacks must be async-signal-safe.\n\n// Installs a callback function, which will be called right before a symbol name\n// is printed. The callback is intended to be used for showing a file name and a\n// line number preceding a symbol name.\n// \"fd\" is a file descriptor of the object file containing the program\n// counter \"pc\". The callback function should write output to \"out\"\n// and return the size of the output written. On error, the callback\n// function should return -1.\nusing SymbolizeCallback = int (*)(int, void*, char*, size_t, uint64_t);\nGLOG_NO_EXPORT\nvoid InstallSymbolizeCallback(SymbolizeCallback callback);\n\n// Installs a callback function, which will be called instead of\n// OpenObjectFileContainingPcAndGetStartAddress.  The callback is expected\n// to searches for the object file (from /proc/self/maps) that contains\n// the specified pc.  If found, sets |start_address| to the start address\n// of where this object file is mapped in memory, sets the module base\n// address into |base_address|, copies the object file name into\n// |out_file_name|, and attempts to open the object file.  If the object\n// file is opened successfully, returns the file descriptor.  Otherwise,\n// returns -1.  |out_file_name_size| is the size of the file name buffer\n// (including the null-terminator).\nusing SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t&, uint64_t&,\n                                                char*, size_t);\nGLOG_NO_EXPORT\nvoid InstallSymbolizeOpenObjectFileCallback(\n    SymbolizeOpenObjectFileCallback callback);\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#endif\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n#if defined(HAVE_SYMBOLIZE)\n\nenum class SymbolizeOptions {\n  // No additional options.\n  kNone = 0,\n  // Do not display source and line numbers in the symbolized output.\n  kNoLineNumbers = 1\n};\n\nconstexpr SymbolizeOptions operator&(SymbolizeOptions lhs,\n                                     SymbolizeOptions rhs) noexcept {\n  return static_cast<SymbolizeOptions>(\n      static_cast<std::underlying_type_t<SymbolizeOptions>>(lhs) &\n      static_cast<std::underlying_type_t<SymbolizeOptions>>(rhs));\n}\n\nconstexpr SymbolizeOptions operator|(SymbolizeOptions lhs,\n                                     SymbolizeOptions rhs) noexcept {\n  return static_cast<SymbolizeOptions>(\n      static_cast<std::underlying_type_t<SymbolizeOptions>>(lhs) |\n      static_cast<std::underlying_type_t<SymbolizeOptions>>(rhs));\n}\n\n// Symbolizes a program counter.  On success, returns true and write the\n// symbol name to \"out\".  The symbol name is demangled if possible\n// (supports symbols generated by GCC 3.x or newer).  Otherwise,\n// returns false.\nGLOG_NO_EXPORT bool Symbolize(\n    void* pc, char* out, size_t out_size,\n    SymbolizeOptions options = SymbolizeOptions::kNone);\n\n#endif  // defined(HAVE_SYMBOLIZE)\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#endif  // GLOG_INTERNAL_SYMBOLIZE_H\n"
  },
  {
    "path": "src/symbolize_unittest.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Satoru Takabayashi\n//\n// Unit tests for functions in symbolize.cc.\n\n#include \"symbolize.h\"\n\n#include <csignal>\n#include <iostream>\n\n#include \"config.h\"\n#include \"glog/logging.h\"\n#include \"googletest.h\"\n#include \"utilities.h\"\n#include \"stacktrace.h\"\n\n#ifdef GLOG_USE_GFLAGS\n#  include <gflags/gflags.h>\nusing namespace GFLAGS_NAMESPACE;\n#endif\n\nusing namespace std;\nusing namespace google;\n\n// Avoid compile error due to \"cast between pointer-to-function and\n// pointer-to-object is an extension\" warnings.\n#if defined(__GNUG__)\n#  pragma GCC diagnostic push\n#  pragma GCC diagnostic ignored \"-Wpedantic\"\n#endif\n\n#if defined(HAVE_STACKTRACE)\n\n#  define always_inline\n\n#  if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H) || \\\n      defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)\n// A wrapper function for Symbolize() to make the unit test simple.\nstatic const char* TrySymbolize(void* pc, google::SymbolizeOptions options =\n                                              google::SymbolizeOptions::kNone) {\n  static char symbol[4096];\n  if (Symbolize(pc, symbol, sizeof(symbol), options)) {\n    return symbol;\n  } else {\n    return nullptr;\n  }\n}\n#  endif\n\n#  if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)\n// This unit tests make sense only with GCC.\n// Uses lots of GCC specific features.\n#    if defined(__GNUC__) && !defined(__OPENCC__)\n#      if __GNUC__ >= 4\n#        define TEST_WITH_MODERN_GCC\n#        if defined(__i386__) && __i386__  // always_inline isn't supported for\n                                           // x86_64 with GCC 4.1.0.\n#          undef always_inline\n#          define always_inline __attribute__((always_inline))\n#          define HAVE_ALWAYS_INLINE\n#        endif  // __i386__\n#      else\n#      endif  // __GNUC__ >= 4\n#      define TEST_WITH_LABEL_ADDRESSES\n#    endif\n\n// Make them C linkage to avoid mangled names.\nextern \"C\" {\nvoid nonstatic_func();\nvoid nonstatic_func() {\n  volatile int a = 0;\n  // NOTE: In C++20, increment of object of volatile-qualified type is\n  // deprecated.\n  a = a + 1;\n}\n\nstatic void static_func() {\n  volatile int a = 0;\n  // NOTE: In C++20, increment of object of volatile-qualified type is\n  // deprecated.\n  a = a + 1;\n}\n}\n\nTEST(Symbolize, Symbolize) {\n  // We do C-style cast since GCC 2.95.3 doesn't allow\n  // reinterpret_cast<void *>(&func).\n\n  // Compilers should give us pointers to them.\n  EXPECT_STREQ(\"nonstatic_func\", TrySymbolize((void*)(&nonstatic_func)));\n\n  // The name of an internal linkage symbol is not specified; allow either a\n  // mangled or an unmangled name here.\n  const char* static_func_symbol =\n      TrySymbolize(reinterpret_cast<void*>(&static_func));\n\n#    if !defined(_MSC_VER) || !defined(NDEBUG)\n  CHECK(nullptr != static_func_symbol);\n  EXPECT_TRUE(strcmp(\"static_func\", static_func_symbol) == 0 ||\n              strcmp(\"static_func()\", static_func_symbol) == 0);\n#    endif\n\n  EXPECT_TRUE(nullptr == TrySymbolize(nullptr));\n}\n\nstruct Foo {\n  static void func(int x);\n};\n\nvoid ATTRIBUTE_NOINLINE Foo::func(int x) {\n  volatile int a = x;\n  // NOTE: In C++20, increment of object of volatile-qualified type is\n  // deprecated.\n  a = a + 1;\n}\n\n// With a modern GCC, Symbolize() should return demangled symbol\n// names.  Function parameters should be omitted.\n#    ifdef TEST_WITH_MODERN_GCC\nTEST(Symbolize, SymbolizeWithDemangling) {\n  Foo::func(100);\n#      if !defined(_MSC_VER) || !defined(NDEBUG)\n#        if defined(HAVE___CXA_DEMANGLE)\n  EXPECT_STREQ(\"Foo::func(int)\", TrySymbolize((void*)(&Foo::func)));\n#        else\n  EXPECT_STREQ(\"Foo::func()\", TrySymbolize((void*)(&Foo::func)));\n#        endif\n#      endif\n}\n#    endif\n\n// Tests that verify that Symbolize footprint is within some limit.\n\n// To measure the stack footprint of the Symbolize function, we create\n// a signal handler (for SIGUSR1 say) that calls the Symbolize function\n// on an alternate stack. This alternate stack is initialized to some\n// known pattern (0x55, 0x55, 0x55, ...). We then self-send this signal,\n// and after the signal handler returns, look at the alternate stack\n// buffer to see what portion has been touched.\n//\n// This trick gives us the the stack footprint of the signal handler.\n// But the signal handler, even before the call to Symbolize, consumes\n// some stack already. We however only want the stack usage of the\n// Symbolize function. To measure this accurately, we install two signal\n// handlers: one that does nothing and just returns, and another that\n// calls Symbolize. The difference between the stack consumption of these\n// two signals handlers should give us the Symbolize stack foorprint.\n\nstatic void* g_pc_to_symbolize;\nstatic char g_symbolize_buffer[4096];\nstatic char* g_symbolize_result;\n\nstatic void EmptySignalHandler(int /*signo*/) {}\n\nstatic void SymbolizeSignalHandler(int /*signo*/) {\n  if (Symbolize(g_pc_to_symbolize, g_symbolize_buffer,\n                sizeof(g_symbolize_buffer))) {\n    g_symbolize_result = g_symbolize_buffer;\n  } else {\n    g_symbolize_result = nullptr;\n  }\n}\n\nconst int kAlternateStackSize = 8096;\nconst char kAlternateStackFillValue = 0x55;\n\n// These helper functions look at the alternate stack buffer, and figure\n// out what portion of this buffer has been touched - this is the stack\n// consumption of the signal handler running on this alternate stack.\nstatic ATTRIBUTE_NOINLINE bool StackGrowsDown(int* x) {\n  int y;\n  return &y < x;\n}\nstatic int GetStackConsumption(const char* alt_stack) {\n  int x;\n  if (StackGrowsDown(&x)) {\n    for (int i = 0; i < kAlternateStackSize; i++) {\n      if (alt_stack[i] != kAlternateStackFillValue) {\n        return (kAlternateStackSize - i);\n      }\n    }\n  } else {\n    for (int i = (kAlternateStackSize - 1); i >= 0; i--) {\n      if (alt_stack[i] != kAlternateStackFillValue) {\n        return i;\n      }\n    }\n  }\n  return -1;\n}\n\n#    ifdef HAVE_SIGALTSTACK\n\n// Call Symbolize and figure out the stack footprint of this call.\nstatic const char* SymbolizeStackConsumption(void* pc, int* stack_consumed) {\n  g_pc_to_symbolize = pc;\n\n  // The alt-signal-stack cannot be heap allocated because there is a\n  // bug in glibc-2.2 where some signal handler setup code looks at the\n  // current stack pointer to figure out what thread is currently running.\n  // Therefore, the alternate stack must be allocated from the main stack\n  // itself.\n  char altstack[kAlternateStackSize];\n  memset(altstack, kAlternateStackFillValue, kAlternateStackSize);\n\n  // Set up the alt-signal-stack (and save the older one).\n  stack_t sigstk;\n  memset(&sigstk, 0, sizeof(stack_t));\n  stack_t old_sigstk;\n  sigstk.ss_sp = altstack;\n  sigstk.ss_size = kAlternateStackSize;\n  sigstk.ss_flags = 0;\n  CHECK_ERR(sigaltstack(&sigstk, &old_sigstk));\n\n  // Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones).\n  struct sigaction sa;\n  memset(&sa, 0, sizeof(struct sigaction));\n  struct sigaction old_sa1, old_sa2;\n  sigemptyset(&sa.sa_mask);\n  sa.sa_flags = SA_ONSTACK;\n\n  // SIGUSR1 maps to EmptySignalHandler.\n  sa.sa_handler = EmptySignalHandler;\n  CHECK_ERR(sigaction(SIGUSR1, &sa, &old_sa1));\n\n  // SIGUSR2 maps to SymbolizeSignalHanlder.\n  sa.sa_handler = SymbolizeSignalHandler;\n  CHECK_ERR(sigaction(SIGUSR2, &sa, &old_sa2));\n\n  // Send SIGUSR1 signal and measure the stack consumption of the empty\n  // signal handler.\n  CHECK_ERR(kill(getpid(), SIGUSR1));\n  int stack_consumption1 = GetStackConsumption(altstack);\n\n  // Send SIGUSR2 signal and measure the stack consumption of the symbolize\n  // signal handler.\n  CHECK_ERR(kill(getpid(), SIGUSR2));\n  int stack_consumption2 = GetStackConsumption(altstack);\n\n  // The difference between the two stack consumption values is the\n  // stack footprint of the Symbolize function.\n  if (stack_consumption1 != -1 && stack_consumption2 != -1) {\n    *stack_consumed = stack_consumption2 - stack_consumption1;\n  } else {\n    *stack_consumed = -1;\n  }\n\n  // Log the stack consumption values.\n  LOG(INFO) << \"Stack consumption of empty signal handler: \"\n            << stack_consumption1;\n  LOG(INFO) << \"Stack consumption of symbolize signal handler: \"\n            << stack_consumption2;\n  LOG(INFO) << \"Stack consumption of Symbolize: \" << *stack_consumed;\n\n  // Now restore the old alt-signal-stack and signal handlers.\n  CHECK_ERR(sigaltstack(&old_sigstk, nullptr));\n  CHECK_ERR(sigaction(SIGUSR1, &old_sa1, nullptr));\n  CHECK_ERR(sigaction(SIGUSR2, &old_sa2, nullptr));\n\n  return g_symbolize_result;\n}\n\n#      if !defined(HAVE___CXA_DEMANGLE)\n#        ifdef __ppc64__\n// Symbolize stack consumption should be within 4kB.\nconstexpr int kStackConsumptionUpperLimit = 4096;\n#        else\n// Symbolize stack consumption should be within 2kB.\nconstexpr int kStackConsumptionUpperLimit = 2048;\n#        endif\n#      endif\n\nTEST(Symbolize, SymbolizeStackConsumption) {\n  int stack_consumed;\n  const char* symbol;\n\n  symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&nonstatic_func),\n                                     &stack_consumed);\n  EXPECT_STREQ(\"nonstatic_func\", symbol);\n  EXPECT_GT(stack_consumed, 0);\n#      if !defined(HAVE___CXA_DEMANGLE)\n  EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);\n#      endif\n\n  // The name of an internal linkage symbol is not specified; allow either a\n  // mangled or an unmangled name here.\n  symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&static_func),\n                                     &stack_consumed);\n  CHECK(nullptr != symbol);\n  EXPECT_TRUE(strcmp(\"static_func\", symbol) == 0 ||\n              strcmp(\"static_func()\", symbol) == 0);\n  EXPECT_GT(stack_consumed, 0);\n#      if !defined(HAVE___CXA_DEMANGLE)\n  EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);\n#      endif\n}\n\n#      if defined(TEST_WITH_MODERN_GCC) && !defined(HAVE___CXA_DEMANGLE)\nTEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {\n  Foo::func(100);\n  int stack_consumed;\n  const char* symbol;\n\n  symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&Foo::func),\n                                     &stack_consumed);\n\n#        if defined(HAVE___CXA_DEMANGLE)\n  EXPECT_STREQ(\"Foo::func(int)\", symbol);\n#        else\n  EXPECT_STREQ(\"Foo::func()\", symbol);\n#        endif\n  EXPECT_GT(stack_consumed, 0);\n  EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);\n}\n#      endif\n\n#    endif  // HAVE_SIGALTSTACK\n\n// x86 specific tests.  Uses some inline assembler.\nextern \"C\" {\ninline void* always_inline inline_func() {\n  void* pc = nullptr;\n#    ifdef TEST_WITH_LABEL_ADDRESSES\n  pc = &&curr_pc;\ncurr_pc:\n#    endif\n  return pc;\n}\n\nvoid* ATTRIBUTE_NOINLINE non_inline_func();\nvoid* ATTRIBUTE_NOINLINE non_inline_func() {\n  void* pc = nullptr;\n#    ifdef TEST_WITH_LABEL_ADDRESSES\n  pc = &&curr_pc;\ncurr_pc:\n#    endif\n  return pc;\n}\n\nstatic void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {\n#    if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ATTRIBUTE_NOINLINE)\n  void* pc = non_inline_func();\n  const char* symbol = TrySymbolize(pc);\n\n#      if !defined(_MSC_VER) || !defined(NDEBUG)\n  CHECK(symbol != nullptr);\n  CHECK_STREQ(symbol, \"non_inline_func\");\n#      endif\n  cout << \"Test case TestWithPCInsideNonInlineFunction passed.\" << endl;\n#    endif\n}\n\nstatic void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {\n#    if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ALWAYS_INLINE)\n  void* pc = inline_func();  // Must be inlined.\n  const char* symbol = TrySymbolize(pc);\n\n#      if !defined(_MSC_VER) || !defined(NDEBUG)\n  CHECK(symbol != nullptr);\n  CHECK_STREQ(symbol, __FUNCTION__);\n#      endif\n  cout << \"Test case TestWithPCInsideInlineFunction passed.\" << endl;\n#    endif\n}\n}\n\n// Test with a return address.\nstatic void ATTRIBUTE_NOINLINE TestWithReturnAddress() {\n#    if defined(HAVE_ATTRIBUTE_NOINLINE)\n  void* return_address = __builtin_return_address(0);\n  const char* symbol =\n      TrySymbolize(return_address, google::SymbolizeOptions::kNoLineNumbers);\n\n#      if !defined(_MSC_VER) || !defined(NDEBUG)\n  CHECK(symbol != nullptr);\n  CHECK_STREQ(symbol, \"main\");\n#      endif\n  cout << \"Test case TestWithReturnAddress passed.\" << endl;\n#    endif\n}\n\n#  elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)\n\n#    ifdef _MSC_VER\n#      include <intrin.h>\n#      pragma intrinsic(_ReturnAddress)\n#    endif\n\nstruct Foo {\n  static void func(int x);\n};\n\n__declspec(noinline) void Foo::func(int x) {\n  volatile int a = x;\n  // NOTE: In C++20, increment of object of volatile-qualified type is\n  // deprecated.\n  a = a + 1;\n}\n\nTEST(Symbolize, SymbolizeWithDemangling) {\n  Foo::func(100);\n  const char* ret = TrySymbolize((void*)(&Foo::func));\n\n#    if defined(HAVE_DBGHELP) && !defined(NDEBUG)\n  EXPECT_STREQ(\"public: static void __cdecl Foo::func(int)\", ret);\n#    endif\n}\n\n__declspec(noinline) void TestWithReturnAddress() {\n  void* return_address =\n#    ifdef __GNUC__  // Cygwin and MinGW support\n      __builtin_return_address(0)\n#    else\n      _ReturnAddress()\n#    endif\n      ;\n  const char* symbol =\n      TrySymbolize(return_address, google::SymbolizeOptions::kNoLineNumbers);\n#    if !defined(_MSC_VER) || !defined(NDEBUG)\n  CHECK(symbol != nullptr);\n  CHECK_STREQ(symbol, \"main\");\n#    endif\n  cout << \"Test case TestWithReturnAddress passed.\" << endl;\n}\n#  endif\n#endif  // HAVE_STACKTRACE\n\nint main(int argc, char** argv) {\n  FLAGS_logtostderr = true;\n  InitGoogleLogging(argv[0]);\n  InitGoogleTest(&argc, argv);\n#if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE)\n#  if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)\n  // We don't want to get affected by the callback interface, that may be\n  // used to install some callback function at InitGoogle() time.\n  InstallSymbolizeCallback(nullptr);\n\n  TestWithPCInsideInlineFunction();\n  TestWithPCInsideNonInlineFunction();\n  TestWithReturnAddress();\n  return RUN_ALL_TESTS();\n#  elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)\n  TestWithReturnAddress();\n  return RUN_ALL_TESTS();\n#  else   // GLOG_OS_WINDOWS\n  printf(\"PASS (no symbolize_unittest support)\\n\");\n  return 0;\n#  endif  // defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)\n#else\n  printf(\"PASS (no symbolize support)\\n\");\n  return 0;\n#endif  // HAVE_SYMBOLIZE\n}\n\n#if defined(__GNUG__)\n#  pragma GCC diagnostic pop\n#endif\n"
  },
  {
    "path": "src/utilities.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Shinichiro Hamaji\n\n#define _GNU_SOURCE 1\n\n#include \"utilities.h\"\n\n#include <atomic>\n#include <cerrno>\n#include <csignal>\n#include <cstdio>\n#include <cstdlib>\n\n#include \"base/googleinit.h\"\n#include \"config.h\"\n#include \"glog/flags.h\"\n#include \"glog/logging.h\"\n#include \"stacktrace.h\"\n#include \"symbolize.h\"\n\n#ifdef GLOG_OS_ANDROID\n#  include <android/log.h>\n#endif\n#ifdef HAVE_SYS_TIME_H\n#  include <sys/time.h>\n#endif\n#if defined(HAVE_SYSCALL_H)\n#  include <syscall.h>  // for syscall()\n#elif defined(HAVE_SYS_SYSCALL_H)\n#  include <sys/syscall.h>  // for syscall()\n#endif\n#ifdef HAVE_SYSLOG_H\n#  include <syslog.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#  include <unistd.h>  // For geteuid.\n#endif\n#ifdef HAVE_PWD_H\n#  include <pwd.h>\n#endif\n\n#if defined(HAVE___PROGNAME)\nextern char* __progname;\n#endif\n\nusing std::string;\n\nnamespace google {\n\nstatic const char* g_program_invocation_short_name = nullptr;\n\nbool IsGoogleLoggingInitialized() {\n  return g_program_invocation_short_name != nullptr;\n}\n\ninline namespace glog_internal_namespace_ {\n\nconstexpr int FileDescriptor::InvalidHandle;\n\nvoid AlsoErrorWrite(LogSeverity severity, const char* tag,\n                    const char* message) noexcept {\n#if defined(GLOG_OS_WINDOWS)\n  (void)severity;\n  (void)tag;\n  // On Windows, also output to the debugger\n  ::OutputDebugStringA(message);\n#elif defined(GLOG_OS_ANDROID)\n  constexpr int android_log_levels[] = {\n      ANDROID_LOG_INFO,\n      ANDROID_LOG_WARN,\n      ANDROID_LOG_ERROR,\n      ANDROID_LOG_FATAL,\n  };\n\n  __android_log_write(android_log_levels[severity], tag, message);\n#else\n  (void)severity;\n  (void)tag;\n  (void)message;\n#endif\n}\n\n}  // namespace glog_internal_namespace_\n\n}  // namespace google\n\n// The following APIs are all internal.\n#ifdef HAVE_STACKTRACE\n\n#  include \"base/commandlineflags.h\"\n#  include \"stacktrace.h\"\n#  include \"symbolize.h\"\n\nnamespace google {\n\nusing DebugWriter = void(const char*, void*);\n\n// The %p field width for printf() functions is two characters per byte.\n// For some environments, add two extra bytes for the leading \"0x\".\nstatic const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);\n\nstatic void DebugWriteToStderr(const char* data, void*) {\n  // This one is signal-safe.\n  if (write(fileno(stderr), data, strlen(data)) < 0) {\n    // Ignore errors.\n  }\n  AlsoErrorWrite(GLOG_FATAL,\n                 glog_internal_namespace_::ProgramInvocationShortName(), data);\n}\n\nstatic void DebugWriteToString(const char* data, void* arg) {\n  reinterpret_cast<string*>(arg)->append(data);\n}\n\n#  ifdef HAVE_SYMBOLIZE\n// Print a program counter and its symbol name.\nstatic void DumpPCAndSymbol(DebugWriter* writerfn, void* arg, void* pc,\n                            const char* const prefix) {\n  char tmp[1024];\n  const char* symbol = \"(unknown)\";\n  // Symbolizes the previous address of pc because pc may be in the\n  // next function.  The overrun happens when the function ends with\n  // a call to a function annotated noreturn (e.g. CHECK).\n  if (Symbolize(reinterpret_cast<char*>(pc) - 1, tmp, sizeof(tmp))) {\n    symbol = tmp;\n  }\n  char buf[1024];\n  std::snprintf(buf, sizeof(buf), \"%s@ %*p  %s\\n\", prefix,\n                kPrintfPointerFieldWidth, pc, symbol);\n  writerfn(buf, arg);\n}\n#  endif\n\nstatic void DumpPC(DebugWriter* writerfn, void* arg, void* pc,\n                   const char* const prefix) {\n  char buf[100];\n  std::snprintf(buf, sizeof(buf), \"%s@ %*p\\n\", prefix, kPrintfPointerFieldWidth,\n                pc);\n  writerfn(buf, arg);\n}\n\n// Dump current stack trace as directed by writerfn\nstatic void DumpStackTrace(int skip_count, DebugWriter* writerfn, void* arg) {\n  // Print stack trace\n  void* stack[32];\n  int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count + 1);\n  for (int i = 0; i < depth; i++) {\n#  if defined(HAVE_SYMBOLIZE)\n    if (FLAGS_symbolize_stacktrace) {\n      DumpPCAndSymbol(writerfn, arg, stack[i], \"    \");\n    } else {\n      DumpPC(writerfn, arg, stack[i], \"    \");\n    }\n#  else\n    DumpPC(writerfn, arg, stack[i], \"    \");\n#  endif\n  }\n}\n\n#  ifdef __GNUC__\n__attribute__((noreturn))\n#  endif\nstatic void\nDumpStackTraceAndExit() {\n  DumpStackTrace(1, DebugWriteToStderr, nullptr);\n\n  // TODO(hamaji): Use signal instead of sigaction?\n  if (IsFailureSignalHandlerInstalled()) {\n    // Set the default signal handler for SIGABRT, to avoid invoking our\n    // own signal handler installed by InstallFailureSignalHandler().\n#  ifdef HAVE_SIGACTION\n    struct sigaction sig_action;\n    memset(&sig_action, 0, sizeof(sig_action));\n    sigemptyset(&sig_action.sa_mask);\n    sig_action.sa_handler = SIG_DFL;\n    sigaction(SIGABRT, &sig_action, nullptr);\n#  elif defined(GLOG_OS_WINDOWS)\n    signal(SIGABRT, SIG_DFL);\n#  endif  // HAVE_SIGACTION\n  }\n\n  abort();\n}\n\n}  // namespace google\n\n#endif  // HAVE_STACKTRACE\n\nnamespace google {\n\ninline namespace glog_internal_namespace_ {\n\nconst char* const_basename(const char* filepath) {\n  const char* base = strrchr(filepath, '/');\n#ifdef GLOG_OS_WINDOWS  // Look for either path separator in Windows\n  if (!base) base = strrchr(filepath, '\\\\');\n#endif\n  return base ? (base + 1) : filepath;\n}\n\nconst char* ProgramInvocationShortName() {\n  if (g_program_invocation_short_name != nullptr) {\n    return g_program_invocation_short_name;\n  }\n#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)\n  return program_invocation_short_name;\n#elif defined(HAVE_GETPROGNAME)\n  return getprogname();\n#elif defined(HAVE___PROGNAME)\n  return __progname;\n#elif defined(HAVE___ARGV)\n  return const_basename(__argv[0]);\n#else\n  return \"UNKNOWN\";\n#endif\n}\n\nstatic int32 g_main_thread_pid = getpid();\nint32 GetMainThreadPid() { return g_main_thread_pid; }\n\nbool PidHasChanged() {\n  int32 pid = getpid();\n  if (g_main_thread_pid == pid) {\n    return false;\n  }\n  g_main_thread_pid = pid;\n  return true;\n}\n\nstatic string g_my_user_name;\nconst string& MyUserName() { return g_my_user_name; }\nstatic void MyUserNameInitializer() {\n  // TODO(hamaji): Probably this is not portable.\n#if defined(GLOG_OS_WINDOWS)\n  const char* user = getenv(\"USERNAME\");\n#else\n  const char* user = getenv(\"USER\");\n#endif\n  if (user != nullptr) {\n    g_my_user_name = user;\n  } else {\n#if defined(HAVE_PWD_H) && defined(HAVE_UNISTD_H)\n    struct passwd pwd;\n    struct passwd* result = nullptr;\n    char buffer[1024] = {'\\0'};\n    uid_t uid = geteuid();\n    int pwuid_res = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &result);\n    if (pwuid_res == 0 && result) {\n      g_my_user_name = pwd.pw_name;\n    } else {\n      std::snprintf(buffer, sizeof(buffer), \"uid%d\", uid);\n      g_my_user_name = buffer;\n    }\n#endif\n    if (g_my_user_name.empty()) {\n      g_my_user_name = \"invalid-user\";\n    }\n  }\n}\nREGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer())\n\n// We use an atomic operation to prevent problems with calling CrashReason\n// from inside the Mutex implementation (potentially through RAW_CHECK).\nstatic std::atomic<const logging::internal::CrashReason*> g_reason{nullptr};\n\nvoid SetCrashReason(const logging::internal::CrashReason* r) {\n  const logging::internal::CrashReason* expected = nullptr;\n  g_reason.compare_exchange_strong(expected, r);\n}\n\nvoid InitGoogleLoggingUtilities(const char* argv0) {\n  CHECK(!IsGoogleLoggingInitialized())\n      << \"You called InitGoogleLogging() twice!\";\n  g_program_invocation_short_name = const_basename(argv0);\n\n#ifdef HAVE_STACKTRACE\n  InstallFailureFunction(&DumpStackTraceAndExit);\n#endif\n}\n\nvoid ShutdownGoogleLoggingUtilities() {\n  CHECK(IsGoogleLoggingInitialized())\n      << \"You called ShutdownGoogleLogging() without calling \"\n         \"InitGoogleLogging() first!\";\n  g_program_invocation_short_name = nullptr;\n#ifdef HAVE_SYSLOG_H\n  closelog();\n#endif\n}\n\n}  // namespace glog_internal_namespace_\n\n#ifdef HAVE_STACKTRACE\nstd::string GetStackTrace() {\n  std::string stacktrace;\n  DumpStackTrace(1, DebugWriteToString, &stacktrace);\n  return stacktrace;\n}\n#endif\n\n}  // namespace google\n"
  },
  {
    "path": "src/utilities.h",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Shinichiro Hamaji\n//         Sergiu Deitsch\n//\n// Define utilities for glog internal usage.\n\n#ifndef GLOG_INTERNAL_UTILITIES_H\n#define GLOG_INTERNAL_UTILITIES_H\n\n#include <cstddef>\n#include <cstdio>\n#include <memory>\n#include <string>\n#include <type_traits>\n#include <utility>\n\n// printf macros for size_t, in the style of inttypes.h\n#ifdef _LP64\n#  define __PRIS_PREFIX \"z\"\n#else\n#  define __PRIS_PREFIX\n#endif\n\n// Use these macros after a % in a printf format string\n// to get correct 32/64 bit behavior, like this:\n// size_t size = records.size();\n// printf(\"%\"PRIuS\"\\n\", size);\n\n#define PRIdS __PRIS_PREFIX \"d\"\n#define PRIxS __PRIS_PREFIX \"x\"\n#define PRIuS __PRIS_PREFIX \"u\"\n#define PRIXS __PRIS_PREFIX \"X\"\n#define PRIoS __PRIS_PREFIX \"o\"\n\n#include \"config.h\"\n#include \"glog/platform.h\"\n#if defined(GLOG_USE_WINDOWS_PORT)\n#  include \"port.h\"\n#endif\n#if defined(HAVE_UNISTD_H)\n#  include <unistd.h>\n#endif\n#if !defined(HAVE_SSIZE_T)\n#  if defined(GLOG_OS_WINDOWS)\n#    include <basetsd.h>\nusing ssize_t = SSIZE_T;\n#  else\nusing ssize_t = std::ptrdiff_t;\n#  endif\n#endif\n\n#include \"glog/log_severity.h\"\n#include \"glog/types.h\"\n\n// There are three different ways we can try to get the stack trace:\n//\n// 1) The libunwind library.  This is still in development, and as a\n//    separate library adds a new dependency, but doesn't need a frame\n//    pointer.  It also doesn't call malloc.\n//\n// 2) Our hand-coded stack-unwinder.  This depends on a certain stack\n//    layout, which is used by gcc (and those systems using a\n//    gcc-compatible ABI) on x86 systems, at least since gcc 2.95.\n//    It uses the frame pointer to do its work.\n//\n// 3) The gdb unwinder -- also the one used by the c++ exception code.\n//    It's obviously well-tested, but has a fatal flaw: it can call\n//    malloc() from the unwinder.  This is a problem because we're\n//    trying to use the unwinder to instrument malloc().\n//\n// 4) The Windows API CaptureStackTrace.\n//\n// Note: if you add a new implementation here, make sure it works\n// correctly when GetStackTrace() is called with max_depth == 0.\n// Some code may do that.\n\n#ifndef ARRAYSIZE\n// There is a better way, but this is good enough for our purpose.\n#  define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))\n#endif\n\nnamespace google {\n\nnamespace logging {\nnamespace internal {\n\nstruct CrashReason {\n  CrashReason() = default;\n\n  const char* filename{nullptr};\n  int line_number{0};\n  const char* message{nullptr};\n\n  // We'll also store a bit of stack trace context at the time of crash as\n  // it may not be available later on.\n  void* stack[32];\n  int depth{0};\n};\n\n}  // namespace internal\n}  // namespace logging\n\ninline namespace glog_internal_namespace_ {\n\n#if defined(__has_attribute)\n#  if __has_attribute(noinline)\n#    define ATTRIBUTE_NOINLINE __attribute__((noinline))\n#    define HAVE_ATTRIBUTE_NOINLINE\n#  endif\n#endif\n\n#if !defined(HAVE_ATTRIBUTE_NOINLINE)\n#  if defined(GLOG_OS_WINDOWS)\n#    define ATTRIBUTE_NOINLINE __declspec(noinline)\n#    define HAVE_ATTRIBUTE_NOINLINE\n#  endif\n#endif\n\n#if !defined(HAVE_ATTRIBUTE_NOINLINE)\n#  define ATTRIBUTE_NOINLINE\n#endif\n\nvoid AlsoErrorWrite(LogSeverity severity, const char* tag,\n                    const char* message) noexcept;\n\nconst char* ProgramInvocationShortName();\n\nint32 GetMainThreadPid();\nbool PidHasChanged();\n\nconst std::string& MyUserName();\n\n// Get the part of filepath after the last path separator.\n// (Doesn't modify filepath, contrary to basename() in libgen.h.)\nconst char* const_basename(const char* filepath);\n\nvoid SetCrashReason(const logging::internal::CrashReason* r);\n\nvoid InitGoogleLoggingUtilities(const char* argv0);\nvoid ShutdownGoogleLoggingUtilities();\n\ntemplate <class Functor>\nclass ScopedExit final {\n public:\n  template <class F, std::enable_if_t<\n                         std::is_constructible<Functor, F&&>::value>* = nullptr>\n  constexpr explicit ScopedExit(F&& functor) noexcept(\n      std::is_nothrow_constructible<Functor, F&&>::value)\n      : functor_{std::forward<F>(functor)} {}\n  ~ScopedExit() noexcept(noexcept(std::declval<Functor&>()())) { functor_(); }\n  ScopedExit(const ScopedExit& other) = delete;\n  ScopedExit& operator=(const ScopedExit& other) = delete;\n  ScopedExit(ScopedExit&& other) noexcept = delete;\n  ScopedExit& operator=(ScopedExit&& other) noexcept = delete;\n\n private:\n  Functor functor_;\n};\n\n// Thin wrapper around a file descriptor so that the file descriptor\n// gets closed for sure.\nclass GLOG_NO_EXPORT FileDescriptor final {\n  static constexpr int InvalidHandle = -1;\n\n public:\n  constexpr FileDescriptor() noexcept : FileDescriptor{nullptr} {}\n  constexpr explicit FileDescriptor(int fd) noexcept : fd_{fd} {}\n  // NOLINTNEXTLINE(google-explicit-constructor)\n  constexpr FileDescriptor(std::nullptr_t) noexcept : fd_{InvalidHandle} {}\n\n  FileDescriptor(const FileDescriptor& other) = delete;\n  FileDescriptor& operator=(const FileDescriptor& other) = delete;\n\n  FileDescriptor(FileDescriptor&& other) noexcept : fd_{other.release()} {}\n  FileDescriptor& operator=(FileDescriptor&& other) noexcept {\n    // Close the file descriptor being held and assign a new file descriptor\n    // previously held by 'other' without closing it.\n    reset(other.release());\n    return *this;\n  }\n\n  constexpr explicit operator bool() const noexcept {\n    return fd_ != InvalidHandle;\n  }\n\n  constexpr int get() const noexcept { return fd_; }\n\n  int release() noexcept { return std::exchange(fd_, InvalidHandle); }\n  void reset(std::nullptr_t) noexcept { safe_close(); }\n  void reset() noexcept { reset(nullptr); }\n  void reset(int fd) noexcept {\n    reset();\n    fd_ = fd;\n  }\n\n  int close() noexcept { return unsafe_close(); }\n\n  ~FileDescriptor() { safe_close(); }\n\n private:\n  int unsafe_close() noexcept { return ::close(release()); }\n  void safe_close() noexcept {\n    if (*this) {\n      unsafe_close();\n    }\n  }\n\n  int fd_;\n};\n\n// Provide variants of (in)equality comparison operators to avoid constructing\n// temporaries.\n\nconstexpr bool operator==(const FileDescriptor& lhs, int rhs) noexcept {\n  return lhs.get() == rhs;\n}\n\nconstexpr bool operator==(int lhs, const FileDescriptor& rhs) noexcept {\n  return rhs == lhs;\n}\n\nconstexpr bool operator!=(const FileDescriptor& lhs, int rhs) noexcept {\n  return !(lhs == rhs);\n}\n\nconstexpr bool operator!=(int lhs, const FileDescriptor& rhs) noexcept {\n  return !(lhs == rhs);\n}\n\nconstexpr bool operator==(const FileDescriptor& lhs, std::nullptr_t) noexcept {\n  return !lhs;\n}\n\nconstexpr bool operator==(std::nullptr_t, const FileDescriptor& rhs) noexcept {\n  return !rhs;\n}\n\nconstexpr bool operator!=(const FileDescriptor& lhs, std::nullptr_t) noexcept {\n  return static_cast<bool>(lhs);\n}\n\nconstexpr bool operator!=(std::nullptr_t, const FileDescriptor& rhs) noexcept {\n  return static_cast<bool>(rhs);\n}\n\n}  // namespace glog_internal_namespace_\n\n}  // namespace google\n\ntemplate <>\nstruct std::default_delete<std::FILE> {\n  void operator()(FILE* p) const noexcept { fclose(p); }\n};\n\n#endif  // GLOG_INTERNAL_UTILITIES_H\n"
  },
  {
    "path": "src/utilities_unittest.cc",
    "content": "// Copyright (c) 2008, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Shinichiro Hamaji\n#include \"utilities.h\"\n\n#include \"glog/logging.h\"\n#include \"googletest.h\"\n\n#ifdef GLOG_USE_GFLAGS\n#  include <gflags/gflags.h>\nusing namespace GFLAGS_NAMESPACE;\n#endif\n\nusing namespace google;\n\nTEST(utilities, InitGoogleLoggingDeathTest) {\n  ASSERT_DEATH(InitGoogleLogging(\"foobar\"), \"\");\n}\n\nint main(int argc, char** argv) {\n  InitGoogleLogging(argv[0]);\n  InitGoogleTest(&argc, argv);\n\n  CHECK_EQ(RUN_ALL_TESTS(), 0);\n}\n"
  },
  {
    "path": "src/vlog_is_on.cc",
    "content": "// Copyright (c) 2024, Google Inc.\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//     * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n//\n// Author: Ray Sidney and many others\n//\n// Broken out from logging.cc by Soren Lassen\n// logging_unittest.cc covers the functionality herein\n\n#include <cerrno>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <mutex>\n#include <string>\n\n#include \"glog/raw_logging.h\"\n\n// glog doesn't have annotation\n#define ANNOTATE_BENIGN_RACE(address, description)\n\nusing std::string;\n\nnamespace google {\n\ninline namespace glog_internal_namespace_ {\n\n// Implementation of fnmatch that does not need 0-termination\n// of arguments and does not allocate any memory,\n// but we only support \"*\" and \"?\" wildcards, not the \"[...]\" patterns.\n// It's not a static function for the unittest.\nGLOG_NO_EXPORT bool SafeFNMatch_(const char* pattern, size_t patt_len,\n                                 const char* str, size_t str_len) {\n  size_t p = 0;\n  size_t s = 0;\n  while (true) {\n    if (p == patt_len && s == str_len) return true;\n    if (p == patt_len) return false;\n    if (s == str_len) return p + 1 == patt_len && pattern[p] == '*';\n    if (pattern[p] == str[s] || pattern[p] == '?') {\n      p += 1;\n      s += 1;\n      continue;\n    }\n    if (pattern[p] == '*') {\n      if (p + 1 == patt_len) return true;\n      do {\n        if (SafeFNMatch_(pattern + (p + 1), patt_len - (p + 1), str + s,\n                         str_len - s)) {\n          return true;\n        }\n        s += 1;\n      } while (s != str_len);\n      return false;\n    }\n    return false;\n  }\n}\n\n}  // namespace glog_internal_namespace_\n\nusing glog_internal_namespace_::SafeFNMatch_;\n\n// List of per-module log levels from FLAGS_vmodule.\n// Once created each element is never deleted/modified\n// except for the vlog_level: other threads will read VModuleInfo blobs\n// w/o locks and we'll store pointers to vlog_level at VLOG locations\n// that will never go away.\n// We can't use an STL struct here as we wouldn't know\n// when it's safe to delete/update it: other threads need to use it w/o locks.\nstruct VModuleInfo {\n  string module_pattern;\n  mutable int32 vlog_level;  // Conceptually this is an AtomicWord, but it's\n                             // too much work to use AtomicWord type here\n                             // w/o much actual benefit.\n  const VModuleInfo* next;\n};\n\n// This protects the following global variables.\nstatic std::mutex vmodule_mutex;\n// Pointer to head of the VModuleInfo list.\n// It's a map from module pattern to logging level for those module(s).\nstatic VModuleInfo* vmodule_list = nullptr;\nstatic SiteFlag* cached_site_list = nullptr;\n\n// Boolean initialization flag.\nstatic bool inited_vmodule = false;\n\n// L >= vmodule_mutex.\nstatic void VLOG2Initializer() {\n  // Can now parse --vmodule flag and initialize mapping of module-specific\n  // logging levels.\n  inited_vmodule = false;\n  const char* vmodule = FLAGS_vmodule.c_str();\n  const char* sep;\n  VModuleInfo* head = nullptr;\n  VModuleInfo* tail = nullptr;\n  while ((sep = strchr(vmodule, '=')) != nullptr) {\n    string pattern(vmodule, static_cast<size_t>(sep - vmodule));\n    int module_level;\n    if (sscanf(sep, \"=%d\", &module_level) == 1) {\n      auto* info = new VModuleInfo;\n      info->module_pattern = pattern;\n      info->vlog_level = module_level;\n      if (head) {\n        tail->next = info;\n      } else {\n        head = info;\n      }\n      tail = info;\n    }\n    // Skip past this entry\n    vmodule = strchr(sep, ',');\n    if (vmodule == nullptr) break;\n    vmodule++;  // Skip past \",\"\n  }\n  if (head) {  // Put them into the list at the head:\n    tail->next = vmodule_list;\n    vmodule_list = head;\n  }\n  inited_vmodule = true;\n}\n\n// This can be called very early, so we use SpinLock and RAW_VLOG here.\nint SetVLOGLevel(const char* module_pattern, int log_level) {\n  int result = FLAGS_v;\n  size_t const pattern_len = strlen(module_pattern);\n  bool found = false;\n  {\n    std::lock_guard<std::mutex> l(\n        vmodule_mutex);  // protect whole read-modify-write\n    for (const VModuleInfo* info = vmodule_list; info != nullptr;\n         info = info->next) {\n      if (info->module_pattern == module_pattern) {\n        if (!found) {\n          result = info->vlog_level;\n          found = true;\n        }\n        info->vlog_level = log_level;\n      } else if (!found && SafeFNMatch_(info->module_pattern.c_str(),\n                                        info->module_pattern.size(),\n                                        module_pattern, pattern_len)) {\n        result = info->vlog_level;\n        found = true;\n      }\n    }\n    if (!found) {\n      auto* info = new VModuleInfo;\n      info->module_pattern = module_pattern;\n      info->vlog_level = log_level;\n      info->next = vmodule_list;\n      vmodule_list = info;\n\n      SiteFlag** item_ptr = &cached_site_list;\n      SiteFlag* item = cached_site_list;\n\n      // We traverse the list fully because the pattern can match several items\n      // from the list.\n      while (item) {\n        if (SafeFNMatch_(module_pattern, pattern_len, item->base_name,\n                         item->base_len)) {\n          // Redirect the cached value to its module override.\n          item->level = &info->vlog_level;\n          *item_ptr = item->next;  // Remove the item from the list.\n        } else {\n          item_ptr = &item->next;\n        }\n        item = *item_ptr;\n      }\n    }\n  }\n  RAW_VLOG(1, \"Set VLOG level for \\\"%s\\\" to %d\", module_pattern, log_level);\n  return result;\n}\n\n// NOTE: Individual VLOG statements cache the integer log level pointers.\n// NOTE: This function must not allocate memory or require any locks.\nbool InitVLOG3__(SiteFlag* site_flag, int32* level_default, const char* fname,\n                 int32 verbose_level) {\n  std::lock_guard<std::mutex> l(vmodule_mutex);\n  bool read_vmodule_flag = inited_vmodule;\n  if (!read_vmodule_flag) {\n    VLOG2Initializer();\n  }\n\n  // protect the errno global in case someone writes:\n  // VLOG(..) << \"The last error was \" << strerror(errno)\n  int old_errno = errno;\n\n  // site_default normally points to FLAGS_v\n  int32* site_flag_value = level_default;\n\n  // Get basename for file\n  const char* base = strrchr(fname, '/');\n\n#ifdef _WIN32\n  if (!base) {\n    base = strrchr(fname, '\\\\');\n  }\n#endif\n\n  base = base ? (base + 1) : fname;\n  const char* base_end = strchr(base, '.');\n  size_t base_length =\n      base_end ? static_cast<size_t>(base_end - base) : strlen(base);\n\n  // Trim out trailing \"-inl\" if any\n  if (base_length >= 4 && (memcmp(base + base_length - 4, \"-inl\", 4) == 0)) {\n    base_length -= 4;\n  }\n\n  // TODO: Trim out _unittest suffix?  Perhaps it is better to have\n  // the extra control and just leave it there.\n\n  // find target in vector of modules, replace site_flag_value with\n  // a module-specific verbose level, if any.\n  for (const VModuleInfo* info = vmodule_list; info != nullptr;\n       info = info->next) {\n    if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),\n                     base, base_length)) {\n      site_flag_value = &info->vlog_level;\n      // value at info->vlog_level is now what controls\n      // the VLOG at the caller site forever\n      break;\n    }\n  }\n\n  // Cache the vlog value pointer if --vmodule flag has been parsed.\n  ANNOTATE_BENIGN_RACE(site_flag,\n                       \"*site_flag may be written by several threads,\"\n                       \" but the value will be the same\");\n  if (read_vmodule_flag) {\n    site_flag->level = site_flag_value;\n    // If VLOG flag has been cached to the default site pointer,\n    // we want to add to the cached list in order to invalidate in case\n    // SetVModule is called afterwards with new modules.\n    // The performance penalty here is neglible, because InitVLOG3__ is called\n    // once per site.\n    if (site_flag_value == level_default && !site_flag->base_name) {\n      site_flag->base_name = base;\n      site_flag->base_len = base_length;\n      site_flag->next = cached_site_list;\n      cached_site_list = site_flag;\n    }\n  }\n\n  // restore the errno in case something recoverable went wrong during\n  // the initialization of the VLOG mechanism (see above note \"protect the..\")\n  errno = old_errno;\n  return *site_flag_value >= verbose_level;\n}\n\n}  // namespace google\n"
  },
  {
    "path": "src/windows/dirent.h",
    "content": "/*\n * Dirent interface for Microsoft Visual Studio\n *\n * Copyright (C) 1998-2019 Toni Ronkko\n * This file is part of dirent.  Dirent may be freely distributed\n * under the MIT license.  For all details and documentation, see\n * https://github.com/tronkko/dirent\n */\n#ifndef GLOG_INTERNAL_WINDOWS_DIRENT_H\n#define GLOG_INTERNAL_WINDOWS_DIRENT_H\n\n/* Hide warnings about unreferenced local functions */\n#if defined(__clang__)\n#  pragma clang diagnostic ignored \"-Wunused-function\"\n#elif defined(_MSC_VER)\n#  pragma warning(disable : 4505)\n#elif defined(__GNUC__)\n#  pragma GCC diagnostic ignored \"-Wunused-function\"\n#endif\n\n/*\n * Include windows.h without Windows Sockets 1.1 to prevent conflicts with\n * Windows Sockets 2.0.\n */\n#ifndef WIN32_LEAN_AND_MEAN\n#  define WIN32_LEAN_AND_MEAN\n#endif\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <windows.h>\n\n#include <cerrno>\n#include <cstdarg>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <cwchar>\n#include <memory>\n\n/* Indicates that d_type field is available in dirent structure */\n#define _DIRENT_HAVE_D_TYPE\n\n/* Indicates that d_namlen field is available in dirent structure */\n#define _DIRENT_HAVE_D_NAMLEN\n\n/* Entries missing from MSVC 6.0 */\n#if !defined(FILE_ATTRIBUTE_DEVICE)\n#  define FILE_ATTRIBUTE_DEVICE 0x40\n#endif\n\n/* File type and permission flags for stat(), general mask */\n#if !defined(S_IFMT)\n#  define S_IFMT _S_IFMT\n#endif\n\n/* Directory bit */\n#if !defined(S_IFDIR)\n#  define S_IFDIR _S_IFDIR\n#endif\n\n/* Character device bit */\n#if !defined(S_IFCHR)\n#  define S_IFCHR _S_IFCHR\n#endif\n\n/* Pipe bit */\n#if !defined(S_IFFIFO)\n#  define S_IFFIFO _S_IFFIFO\n#endif\n\n/* Regular file bit */\n#if !defined(S_IFREG)\n#  define S_IFREG _S_IFREG\n#endif\n\n/* Read permission */\n#if !defined(S_IREAD)\n#  define S_IREAD _S_IREAD\n#endif\n\n/* Write permission */\n#if !defined(S_IWRITE)\n#  define S_IWRITE _S_IWRITE\n#endif\n\n/* Execute permission */\n#if !defined(S_IEXEC)\n#  define S_IEXEC _S_IEXEC\n#endif\n\n/* Pipe */\n#if !defined(S_IFIFO)\n#  define S_IFIFO _S_IFIFO\n#endif\n\n/* Block device */\n#if !defined(S_IFBLK)\n#  define S_IFBLK 0\n#endif\n\n/* Link */\n#if !defined(S_IFLNK)\n#  define S_IFLNK 0\n#endif\n\n/* Socket */\n#if !defined(S_IFSOCK)\n#  define S_IFSOCK 0\n#endif\n\n/* Read user permission */\n#if !defined(S_IRUSR)\n#  define S_IRUSR S_IREAD\n#endif\n\n/* Write user permission */\n#if !defined(S_IWUSR)\n#  define S_IWUSR S_IWRITE\n#endif\n\n/* Execute user permission */\n#if !defined(S_IXUSR)\n#  define S_IXUSR 0\n#endif\n\n/* Read group permission */\n#if !defined(S_IRGRP)\n#  define S_IRGRP 0\n#endif\n\n/* Write group permission */\n#if !defined(S_IWGRP)\n#  define S_IWGRP 0\n#endif\n\n/* Execute group permission */\n#if !defined(S_IXGRP)\n#  define S_IXGRP 0\n#endif\n\n/* Read others permission */\n#if !defined(S_IROTH)\n#  define S_IROTH 0\n#endif\n\n/* Write others permission */\n#if !defined(S_IWOTH)\n#  define S_IWOTH 0\n#endif\n\n/* Execute others permission */\n#if !defined(S_IXOTH)\n#  define S_IXOTH 0\n#endif\n\n/* Maximum length of file name */\n#if !defined(PATH_MAX)\n#  define PATH_MAX MAX_PATH\n#endif\n#if !defined(FILENAME_MAX)\n#  define FILENAME_MAX MAX_PATH\n#endif\n#if !defined(NAME_MAX)\n#  define NAME_MAX FILENAME_MAX\n#endif\n\n/* File type flags for d_type */\n#define DT_UNKNOWN 0\n#define DT_REG S_IFREG\n#define DT_DIR S_IFDIR\n#define DT_FIFO S_IFIFO\n#define DT_SOCK S_IFSOCK\n#define DT_CHR S_IFCHR\n#define DT_BLK S_IFBLK\n#define DT_LNK S_IFLNK\n\n/* Macros for converting between st_mode and d_type */\n#define IFTODT(mode) ((mode)&S_IFMT)\n#define DTTOIF(type) (type)\n\n/*\n * File type macros.  Note that block devices, sockets and links cannot be\n * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are\n * only defined for compatibility.  These macros should always return false\n * on Windows.\n */\n#if !defined(S_ISFIFO)\n#  define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO)\n#endif\n#if !defined(S_ISDIR)\n#  define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)\n#endif\n#if !defined(S_ISREG)\n#  define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG)\n#endif\n#if !defined(S_ISLNK)\n#  define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK)\n#endif\n#if !defined(S_ISSOCK)\n#  define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK)\n#endif\n#if !defined(S_ISCHR)\n#  define S_ISCHR(mode) (((mode)&S_IFMT) == S_IFCHR)\n#endif\n#if !defined(S_ISBLK)\n#  define S_ISBLK(mode) (((mode)&S_IFMT) == S_IFBLK)\n#endif\n\n/* Return the exact length of the file name without zero terminator */\n#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)\n\n/* Return the maximum size of a file name */\n#define _D_ALLOC_NAMLEN(p) ((PATH_MAX) + 1)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Wide-character version */\nstruct _wdirent {\n  /* Always zero */\n  long d_ino;\n\n  /* File position within stream */\n  long d_off;\n\n  /* Structure size */\n  unsigned short d_reclen;\n\n  /* Length of name without \\0 */\n  size_t d_namlen;\n\n  /* File type */\n  int d_type;\n\n  /* File name */\n  wchar_t d_name[PATH_MAX + 1];\n};\n\nstruct _WDIR {\n  /* Current directory entry */\n  _wdirent ent;\n\n  /* Private file data */\n  WIN32_FIND_DATAW data;\n\n  /* True if data is valid */\n  int cached;\n\n  /* Win32 search handle */\n  HANDLE handle;\n\n  /* Initial directory name */\n  wchar_t* patt;\n};\n\n/* Multi-byte character version */\nstruct dirent {\n  /* Always zero */\n  long d_ino;\n\n  /* File position within stream */\n  long d_off;\n\n  /* Structure size */\n  unsigned short d_reclen;\n\n  /* Length of name without \\0 */\n  size_t d_namlen;\n\n  /* File type */\n  int d_type;\n\n  /* File name */\n  char d_name[PATH_MAX + 1];\n};\n\nstruct DIR {\n  struct dirent ent;\n  struct _WDIR* wdirp;\n};\n\n/* Dirent functions */\nstatic DIR* opendir(const char* dirname);\nstatic _WDIR* _wopendir(const wchar_t* dirname);\n\nstatic struct dirent* readdir(DIR* dirp);\nstatic struct _wdirent* _wreaddir(_WDIR* dirp);\n\nstatic int readdir_r(DIR* dirp, struct dirent* entry, struct dirent** result);\nstatic int _wreaddir_r(_WDIR* dirp, struct _wdirent* entry,\n                       struct _wdirent** result);\n\nstatic int closedir(DIR* dirp);\nstatic int _wclosedir(_WDIR* dirp);\n\nstatic void rewinddir(DIR* dirp);\nstatic void _wrewinddir(_WDIR* dirp);\n\nstatic int scandir(const char* dirname, struct dirent*** namelist,\n                   int (*filter)(const struct dirent*),\n                   int (*compare)(const struct dirent**,\n                                  const struct dirent**));\n\nstatic int alphasort(const struct dirent** a, const struct dirent** b);\n\nstatic int versionsort(const struct dirent** a, const struct dirent** b);\n\n/* For compatibility with Symbian */\n#define wdirent _wdirent\n#define WDIR _WDIR\n#define wopendir _wopendir\n#define wreaddir _wreaddir\n#define wclosedir _wclosedir\n#define wrewinddir _wrewinddir\n\n/* Internal utility functions */\nstatic WIN32_FIND_DATAW* dirent_first(_WDIR* dirp);\nstatic WIN32_FIND_DATAW* dirent_next(_WDIR* dirp);\n\nstatic int dirent_mbstowcs_s(size_t* pReturnValue, wchar_t* wcstr,\n                             size_t sizeInWords, const char* mbstr,\n                             size_t count);\n\nstatic int dirent_wcstombs_s(size_t* pReturnValue, char* mbstr,\n                             size_t sizeInBytes, const wchar_t* wcstr,\n                             size_t count);\n\nstatic void dirent_set_errno(int error);\n\n/*\n * Open directory stream DIRNAME for read and return a pointer to the\n * internal working area that is used to retrieve individual directory\n * entries.\n */\nstatic _WDIR* _wopendir(const wchar_t* dirname) {\n  _WDIR* dirp;\n  DWORD n;\n  wchar_t* p;\n\n  /* Must have directory name */\n  if (dirname == nullptr || dirname[0] == '\\0') {\n    dirent_set_errno(ENOENT);\n    return nullptr;\n  }\n\n  /* Allocate new _WDIR structure */\n  dirp = (_WDIR*)malloc(sizeof(struct _WDIR));\n  if (!dirp) {\n    return nullptr;\n  }\n\n  /* Reset _WDIR structure */\n  dirp->handle = INVALID_HANDLE_VALUE;\n  dirp->patt = nullptr;\n  dirp->cached = 0;\n\n  /*\n   * Compute the length of full path plus zero terminator\n   *\n   * Note that on WinRT there's no way to convert relative paths\n   * into absolute paths, so just assume it is an absolute path.\n   */\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)\n  /* Desktop */\n  n = GetFullPathNameW(dirname, 0, nullptr, nullptr);\n#else\n  /* WinRT */\n  n = wcslen(dirname);\n#endif\n\n  /* Allocate room for absolute directory name and search pattern */\n  dirp->patt = (wchar_t*)malloc(sizeof(wchar_t) * n + 16);\n  if (dirp->patt == nullptr) {\n    goto exit_closedir;\n  }\n\n  /*\n   * Convert relative directory name to an absolute one.  This\n   * allows rewinddir() to function correctly even when current\n   * working directory is changed between opendir() and rewinddir().\n   *\n   * Note that on WinRT there's no way to convert relative paths\n   * into absolute paths, so just assume it is an absolute path.\n   */\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)\n  /* Desktop */\n  n = GetFullPathNameW(dirname, n, dirp->patt, nullptr);\n  if (n <= 0) {\n    goto exit_closedir;\n  }\n#else\n  /* WinRT */\n  wcsncpy_s(dirp->patt, n + 1, dirname, n);\n#endif\n\n  /* Append search pattern \\* to the directory name */\n  p = dirp->patt + n;\n  switch (p[-1]) {\n    case '\\\\':\n    case '/':\n    case ':':\n        /* Directory ends in path separator, e.g. c:\\temp\\ */\n        /*NOP*/;\n      break;\n\n    default:\n      /* Directory name doesn't end in path separator */\n      *p++ = '\\\\';\n  }\n  *p++ = '*';\n  *p = '\\0';\n\n  /* Open directory stream and retrieve the first entry */\n  if (!dirent_first(dirp)) {\n    goto exit_closedir;\n  }\n\n  /* Success */\n  return dirp;\n\n  /* Failure */\nexit_closedir:\n  _wclosedir(dirp);\n  return nullptr;\n}\n\n/*\n * Read next directory entry.\n *\n * Returns pointer to static directory entry which may be overwritten by\n * subsequent calls to _wreaddir().\n */\nstatic struct _wdirent* _wreaddir(_WDIR* dirp) {\n  struct _wdirent* entry;\n\n  /*\n   * Read directory entry to buffer.  We can safely ignore the return value\n   * as entry will be set to nullptr in case of error.\n   */\n  (void)_wreaddir_r(dirp, &dirp->ent, &entry);\n\n  /* Return pointer to statically allocated directory entry */\n  return entry;\n}\n\n/*\n * Read next directory entry.\n *\n * Returns zero on success.  If end of directory stream is reached, then sets\n * result to nullptr and returns zero.\n */\nstatic int _wreaddir_r(_WDIR* dirp, struct _wdirent* entry,\n                       struct _wdirent** result) {\n  WIN32_FIND_DATAW* datap;\n\n  /* Read next directory entry */\n  datap = dirent_next(dirp);\n  if (datap) {\n    size_t n;\n    DWORD attr;\n\n    /*\n     * Copy file name as wide-character string.  If the file name is too\n     * long to fit in to the destination buffer, then truncate file name\n     * to PATH_MAX characters and zero-terminate the buffer.\n     */\n    n = 0;\n    while (n < PATH_MAX && datap->cFileName[n] != 0) {\n      entry->d_name[n] = datap->cFileName[n];\n      n++;\n    }\n    entry->d_name[n] = 0;\n\n    /* Length of file name excluding zero terminator */\n    entry->d_namlen = n;\n\n    /* File type */\n    attr = datap->dwFileAttributes;\n    if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {\n      entry->d_type = DT_CHR;\n    } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {\n      entry->d_type = DT_DIR;\n    } else {\n      entry->d_type = DT_REG;\n    }\n\n    /* Reset dummy fields */\n    entry->d_ino = 0;\n    entry->d_off = 0;\n    entry->d_reclen = sizeof(struct _wdirent);\n\n    /* Set result address */\n    *result = entry;\n\n  } else {\n    /* Return nullptr to indicate end of directory */\n    *result = nullptr;\n  }\n\n  return /*OK*/ 0;\n}\n\n/*\n * Close directory stream opened by opendir() function.  This invalidates the\n * DIR structure as well as any directory entry read previously by\n * _wreaddir().\n */\nstatic int _wclosedir(_WDIR* dirp) {\n  int ok;\n  if (dirp) {\n    /* Release search handle */\n    if (dirp->handle != INVALID_HANDLE_VALUE) {\n      FindClose(dirp->handle);\n    }\n\n    /* Release search pattern */\n    free(dirp->patt);\n\n    /* Release directory structure */\n    free(dirp);\n    ok = /*success*/ 0;\n\n  } else {\n    /* Invalid directory stream */\n    dirent_set_errno(EBADF);\n    ok = /*failure*/ -1;\n  }\n  return ok;\n}\n\n/*\n * Rewind directory stream such that _wreaddir() returns the very first\n * file name again.\n */\nstatic void _wrewinddir(_WDIR* dirp) {\n  if (dirp) {\n    /* Release existing search handle */\n    if (dirp->handle != INVALID_HANDLE_VALUE) {\n      FindClose(dirp->handle);\n    }\n\n    /* Open new search handle */\n    dirent_first(dirp);\n  }\n}\n\n/* Get first directory entry (internal) */\nstatic WIN32_FIND_DATAW* dirent_first(_WDIR* dirp) {\n  WIN32_FIND_DATAW* datap;\n  DWORD error;\n\n  /* Open directory and retrieve the first entry */\n  dirp->handle = FindFirstFileExW(dirp->patt, FindExInfoStandard, &dirp->data,\n                                  FindExSearchNameMatch, nullptr, 0);\n  if (dirp->handle != INVALID_HANDLE_VALUE) {\n    /* a directory entry is now waiting in memory */\n    datap = &dirp->data;\n    dirp->cached = 1;\n\n  } else {\n    /* Failed to open directory: no directory entry in memory */\n    dirp->cached = 0;\n    datap = nullptr;\n\n    /* Set error code */\n    error = GetLastError();\n    switch (error) {\n      case ERROR_ACCESS_DENIED:\n        /* No read access to directory */\n        dirent_set_errno(EACCES);\n        break;\n\n      case ERROR_DIRECTORY:\n        /* Directory name is invalid */\n        dirent_set_errno(ENOTDIR);\n        break;\n\n      case ERROR_PATH_NOT_FOUND:\n      default:\n        /* Cannot find the file */\n        dirent_set_errno(ENOENT);\n    }\n  }\n  return datap;\n}\n\n/*\n * Get next directory entry (internal).\n *\n * Returns\n */\nstatic WIN32_FIND_DATAW* dirent_next(_WDIR* dirp) {\n  WIN32_FIND_DATAW* p;\n\n  /* Get next directory entry */\n  if (dirp->cached != 0) {\n    /* A valid directory entry already in memory */\n    p = &dirp->data;\n    dirp->cached = 0;\n\n  } else if (dirp->handle != INVALID_HANDLE_VALUE) {\n    /* Get the next directory entry from stream */\n    if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {\n      /* Got a file */\n      p = &dirp->data;\n    } else {\n      /* The very last entry has been processed or an error occurred */\n      FindClose(dirp->handle);\n      dirp->handle = INVALID_HANDLE_VALUE;\n      p = nullptr;\n    }\n\n  } else {\n    /* End of directory stream reached */\n    p = nullptr;\n  }\n\n  return p;\n}\n\n/*\n * Open directory stream using plain old C-string.\n */\nstatic DIR* opendir(const char* dirname) {\n  /* Must have directory name */\n  if (dirname == nullptr || dirname[0] == '\\0') {\n    dirent_set_errno(ENOENT);\n    return nullptr;\n  }\n\n  /* Allocate memory for DIR structure */\n  std::unique_ptr<DIR, decltype(&free)> dirp{\n      static_cast<DIR*>(malloc(sizeof(struct DIR))), &free};\n\n  if (!dirp) {\n    return nullptr;\n  }\n  {\n    int error;\n    wchar_t wname[PATH_MAX + 1];\n    size_t n;\n\n    /* Convert directory name to wide-character string */\n    error = dirent_mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);\n    if (error) {\n      /*\n       * Cannot convert file name to wide-character string.  This\n       * occurs if the string contains invalid multi-byte sequences or\n       * the output buffer is too small to contain the resulting\n       * string.\n       */\n      return nullptr;\n    }\n\n    /* Open directory stream using wide-character name */\n    dirp->wdirp = _wopendir(wname);\n    if (!dirp->wdirp) {\n      return nullptr;\n    }\n  }\n\n  /* Success */\n  return dirp.release();\n}\n\n/*\n * Read next directory entry.\n */\nstatic struct dirent* readdir(DIR* dirp) {\n  struct dirent* entry;\n\n  /*\n   * Read directory entry to buffer.  We can safely ignore the return value\n   * as entry will be set to nullptr in case of error.\n   */\n  (void)readdir_r(dirp, &dirp->ent, &entry);\n\n  /* Return pointer to statically allocated directory entry */\n  return entry;\n}\n\n/*\n * Read next directory entry into called-allocated buffer.\n *\n * Returns zero on success.  If the end of directory stream is reached, then\n * sets result to nullptr and returns zero.\n */\nstatic int readdir_r(DIR* dirp, struct dirent* entry, struct dirent** result) {\n  WIN32_FIND_DATAW* datap;\n\n  /* Read next directory entry */\n  datap = dirent_next(dirp->wdirp);\n  if (datap) {\n    size_t n;\n    int error;\n\n    /* Attempt to convert file name to multi-byte string */\n    error = dirent_wcstombs_s(&n, entry->d_name, PATH_MAX + 1, datap->cFileName,\n                              PATH_MAX + 1);\n\n    /*\n     * If the file name cannot be represented by a multi-byte string,\n     * then attempt to use old 8+3 file name.  This allows traditional\n     * Unix-code to access some file names despite of unicode\n     * characters, although file names may seem unfamiliar to the user.\n     *\n     * Be ware that the code below cannot come up with a short file\n     * name unless the file system provides one.  At least\n     * VirtualBox shared folders fail to do this.\n     */\n    if (error && datap->cAlternateFileName[0] != '\\0') {\n      error = dirent_wcstombs_s(&n, entry->d_name, PATH_MAX + 1,\n                                datap->cAlternateFileName, PATH_MAX + 1);\n    }\n\n    if (!error) {\n      DWORD attr;\n\n      /* Length of file name excluding zero terminator */\n      entry->d_namlen = n - 1;\n\n      /* File attributes */\n      attr = datap->dwFileAttributes;\n      if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {\n        entry->d_type = DT_CHR;\n      } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {\n        entry->d_type = DT_DIR;\n      } else {\n        entry->d_type = DT_REG;\n      }\n\n      /* Reset dummy fields */\n      entry->d_ino = 0;\n      entry->d_off = 0;\n      entry->d_reclen = sizeof(struct dirent);\n\n    } else {\n      /*\n       * Cannot convert file name to multi-byte string so construct\n       * an erroneous directory entry and return that.  Note that\n       * we cannot return nullptr as that would stop the processing\n       * of directory entries completely.\n       */\n      entry->d_name[0] = '?';\n      entry->d_name[1] = '\\0';\n      entry->d_namlen = 1;\n      entry->d_type = DT_UNKNOWN;\n      entry->d_ino = 0;\n      entry->d_off = -1;\n      entry->d_reclen = 0;\n    }\n\n    /* Return pointer to directory entry */\n    *result = entry;\n\n  } else {\n    /* No more directory entries */\n    *result = nullptr;\n  }\n\n  return /*OK*/ 0;\n}\n\n/*\n * Close directory stream.\n */\nstatic int closedir(DIR* dirp) {\n  int ok;\n  if (dirp) {\n    /* Close wide-character directory stream */\n    ok = _wclosedir(dirp->wdirp);\n    dirp->wdirp = nullptr;\n\n    /* Release multi-byte character version */\n    free(dirp);\n\n  } else {\n    /* Invalid directory stream */\n    dirent_set_errno(EBADF);\n    ok = /*failure*/ -1;\n  }\n  return ok;\n}\n\n/*\n * Rewind directory stream to beginning.\n */\nstatic void rewinddir(DIR* dirp) {\n  /* Rewind wide-character string directory stream */\n  _wrewinddir(dirp->wdirp);\n}\n\n/*\n * Scan directory for entries.\n */\nstatic int scandir(const char* dirname, struct dirent*** namelist,\n                   int (*filter)(const struct dirent*),\n                   int (*compare)(const struct dirent**,\n                                  const struct dirent**)) {\n  struct dirent** files = nullptr;\n  size_t size = 0;\n  size_t allocated = 0;\n  const size_t init_size = 1;\n  DIR* dir = nullptr;\n  struct dirent* entry;\n  struct dirent* tmp = nullptr;\n  size_t i;\n  int result = 0;\n\n  /* Open directory stream */\n  dir = opendir(dirname);\n  if (dir) {\n    /* Read directory entries to memory */\n    while (1) {\n      /* Enlarge pointer table to make room for another pointer */\n      if (size >= allocated) {\n        void* p;\n        size_t num_entries;\n\n        /* Compute number of entries in the enlarged pointer table */\n        if (size < init_size) {\n          /* Allocate initial pointer table */\n          num_entries = init_size;\n        } else {\n          /* Double the size */\n          num_entries = size * 2;\n        }\n\n        /* Allocate first pointer table or enlarge existing table */\n        p = realloc(files, sizeof(void*) * num_entries);\n        if (p != nullptr) {\n          /* Got the memory */\n          files = (dirent**)p;\n          allocated = num_entries;\n        } else {\n          /* Out of memory */\n          result = -1;\n          break;\n        }\n      }\n\n      /* Allocate room for temporary directory entry */\n      if (tmp == nullptr) {\n        tmp = (struct dirent*)malloc(sizeof(struct dirent));\n        if (tmp == nullptr) {\n          /* Cannot allocate temporary directory entry */\n          result = -1;\n          break;\n        }\n      }\n\n      /* Read directory entry to temporary area */\n      if (readdir_r(dir, tmp, &entry) == /*OK*/ 0) {\n        /* Did we get an entry? */\n        if (entry != nullptr) {\n          int pass;\n\n          /* Determine whether to include the entry in result */\n          if (filter) {\n            /* Let the filter function decide */\n            pass = filter(tmp);\n          } else {\n            /* No filter function, include everything */\n            pass = 1;\n          }\n\n          if (pass) {\n            /* Store the temporary entry to pointer table */\n            files[size++] = tmp;\n            tmp = nullptr;\n\n            /* Keep up with the number of files */\n            result++;\n          }\n\n        } else {\n          /*\n           * End of directory stream reached => sort entries and\n           * exit.\n           */\n          qsort(files, size, sizeof(void*),\n                (int (*)(const void*, const void*))compare);\n          break;\n        }\n\n      } else {\n        /* Error reading directory entry */\n        result = /*Error*/ -1;\n        break;\n      }\n    }\n\n  } else {\n    /* Cannot open directory */\n    result = /*Error*/ -1;\n  }\n\n  /* Release temporary directory entry */\n  free(tmp);\n\n  /* Release allocated memory on error */\n  if (result < 0) {\n    for (i = 0; i < size; i++) {\n      free(files[i]);\n    }\n    free(files);\n    files = nullptr;\n  }\n\n  /* Close directory stream */\n  if (dir) {\n    closedir(dir);\n  }\n\n  /* Pass pointer table to caller */\n  if (namelist) {\n    *namelist = files;\n  }\n  return result;\n}\n\n/* Alphabetical sorting */\nstatic int alphasort(const struct dirent** a, const struct dirent** b) {\n  return strcoll((*a)->d_name, (*b)->d_name);\n}\n\n/* Sort versions */\nstatic int versionsort(const struct dirent** a, const struct dirent** b) {\n  /* FIXME: implement strverscmp and use that */\n  return alphasort(a, b);\n}\n\n/* Convert multi-byte string to wide character string */\nstatic int dirent_mbstowcs_s(size_t* pReturnValue, wchar_t* wcstr,\n                             size_t sizeInWords, const char* mbstr,\n                             size_t count) {\n  int error;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\n  /* Microsoft Visual Studio 2005 or later */\n  error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count);\n\n#else\n\n  /* Older Visual Studio or non-Microsoft compiler */\n  size_t n;\n\n  /* Convert to wide-character string (or count characters) */\n  n = mbstowcs(wcstr, mbstr, sizeInWords);\n  if (!wcstr || n < count) {\n    /* Zero-terminate output buffer */\n    if (wcstr && sizeInWords) {\n      if (n >= sizeInWords) {\n        n = sizeInWords - 1;\n      }\n      wcstr[n] = 0;\n    }\n\n    /* Length of resulting multi-byte string WITH zero terminator */\n    if (pReturnValue) {\n      *pReturnValue = n + 1;\n    }\n\n    /* Success */\n    error = 0;\n\n  } else {\n    /* Could not convert string */\n    error = 1;\n  }\n\n#endif\n  return error;\n}\n\n/* Convert wide-character string to multi-byte string */\nstatic int dirent_wcstombs_s(size_t* pReturnValue, char* mbstr,\n                             size_t sizeInBytes, /* max size of mbstr */\n                             const wchar_t* wcstr, size_t count) {\n  int error;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\n  /* Microsoft Visual Studio 2005 or later */\n  error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count);\n\n#else\n\n  /* Older Visual Studio or non-Microsoft compiler */\n  size_t n;\n\n  /* Convert to multi-byte string (or count the number of bytes needed) */\n  n = wcstombs(mbstr, wcstr, sizeInBytes);\n  if (!mbstr || n < count) {\n    /* Zero-terminate output buffer */\n    if (mbstr && sizeInBytes) {\n      if (n >= sizeInBytes) {\n        n = sizeInBytes - 1;\n      }\n      mbstr[n] = '\\0';\n    }\n\n    /* Length of resulting multi-bytes string WITH zero-terminator */\n    if (pReturnValue) {\n      *pReturnValue = n + 1;\n    }\n\n    /* Success */\n    error = 0;\n\n  } else {\n    /* Cannot convert string */\n    error = 1;\n  }\n\n#endif\n  return error;\n}\n\n/* Set errno variable */\nstatic void dirent_set_errno(int error) {\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\n  /* Microsoft Visual Studio 2005 and later */\n  _set_errno(error);\n\n#else\n\n  /* Non-Microsoft compiler or older Microsoft compiler */\n  errno = error;\n\n#endif\n}\n\n#ifdef __cplusplus\n}\n#endif\n#endif /*GLOG_INTERNAL_WINDOWS_DIRENT_H*/\n"
  },
  {
    "path": "src/windows/port.cc",
    "content": "/* Copyright (c) 2023, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above\n * copyright notice, this list of conditions and the following disclaimer\n * in the documentation and/or other materials provided with the\n * distribution.\n *     * Neither the name of Google Inc. nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * ---\n * Author: Craig Silverstein\n * Copied from google-perftools and modified by Shinichiro Hamaji\n */\n\n#ifndef _WIN32\n#  error You should only be including windows/port.cc in a windows environment!\n#endif\n\n#include \"port.h\"\n\n#include <ctime>\n\n#include \"config.h\"\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n\n#ifndef HAVE_LOCALTIME_R\nstruct tm* localtime_r(const std::time_t* timep, std::tm* result) {\n  localtime_s(result, timep);\n  return result;\n}\n#endif  // not HAVE_LOCALTIME_R\n#ifndef HAVE_GMTIME_R\nstruct tm* gmtime_r(const std::time_t* timep, std::tm* result) {\n  gmtime_s(result, timep);\n  return result;\n}\n#endif  // not HAVE_GMTIME_R\n\n}  // namespace glog_internal_namespace_\n}  // namespace google\n"
  },
  {
    "path": "src/windows/port.h",
    "content": "/* Copyright (c) 2023, Google Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n *     * Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above\n * copyright notice, this list of conditions and the following disclaimer\n * in the documentation and/or other materials provided with the\n * distribution.\n *     * Neither the name of Google Inc. nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * ---\n * Author: Craig Silverstein\n * Copied from google-perftools and modified by Shinichiro Hamaji\n *\n * These are some portability typedefs and defines to make it a bit\n * easier to compile this code under VC++.\n *\n * Several of these are taken from glib:\n *    http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html\n */\n\n#ifndef CTEMPLATE_WINDOWS_PORT_H_\n#define CTEMPLATE_WINDOWS_PORT_H_\n\n#include \"config.h\"\n\n#if defined(GLOG_USE_GLOG_EXPORT)\n#  include \"glog/export.h\"\n#endif\n\n#if !defined(GLOG_EXPORT)\n#  error \"port.h\" was not included correctly.\n#endif\n\n#ifdef _WIN32\n\n#  ifndef WIN32_LEAN_AND_MEAN\n#    define WIN32_LEAN_AND_MEAN /* We always want minimal includes */\n#  endif\n\n#  include <direct.h>  /* for _getcwd() */\n#  include <io.h>      /* because we so often use open/close/etc */\n#  include <process.h> /* for _getpid() */\n#  include <windows.h>\n#  include <winsock.h> /* for gethostname */\n\n#  include <cstdarg> /* template_dictionary.cc uses va_copy */\n#  include <cstring> /* for _strnicmp(), strerror_s() */\n#  include <ctime>   /* for localtime_s() */\n/* Note: the C++ #includes are all together at the bottom.  This file is\n * used by both C and C++ code, so we put all the C++ together.\n */\n\n#  ifdef _MSC_VER\n\n/* 4244: otherwise we get problems when substracting two size_t's to an int\n * 4251: it's complaining about a private struct I've chosen not to dllexport\n * 4355: we use this in a constructor, but we do it safely\n * 4715: for some reason VC++ stopped realizing you can't return after abort()\n * 4800: we know we're casting ints/char*'s to bools, and we're ok with that\n * 4996: Yes, we're ok using \"unsafe\" functions like fopen() and strerror()\n * 4312: Converting uint32_t to a pointer when testing %p\n * 4267: also subtracting two size_t to int\n * 4722: Destructor never returns due to abort()\n */\n#    pragma warning(disable : 4244 4251 4355 4715 4800 4996 4267 4312 4722)\n\n/* file I/O */\n#    define PATH_MAX 1024\n#    define popen _popen\n#    define pclose _pclose\n#    define R_OK 04 /* read-only (for access()) */\n#    define S_ISDIR(m) (((m)&_S_IFMT) == _S_IFDIR)\n\n#    define O_WRONLY _O_WRONLY\n#    define O_CREAT _O_CREAT\n#    define O_EXCL _O_EXCL\n\n#    define S_IRUSR S_IREAD\n#    define S_IWUSR S_IWRITE\n\n/* Not quite as lightweight as a hard-link, but more than good enough for us. */\n#    define link(oldpath, newpath) CopyFileA(oldpath, newpath, false)\n\n#    define strcasecmp _stricmp\n#    define strncasecmp _strnicmp\n\n/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */\n/* VC11 provides std::hash */\n#    if defined(_MSC_VER) && (_MSC_VER < 1700)\n#      define hash hash_compare\n#    endif\n\n/* Windows doesn't support specifying the number of buckets as a\n * hash_map constructor arg, so we leave this blank.\n */\n#    define CTEMPLATE_SMALL_HASHTABLE\n\n#    define DEFAULT_TEMPLATE_ROOTDIR \"..\"\n\n#  endif  // _MSC_VER\n\nnamespace google {\ninline namespace glog_internal_namespace_ {\n#  ifndef HAVE_LOCALTIME_R\nGLOG_NO_EXPORT std::tm* localtime_r(const std::time_t* timep, std::tm* result);\n#  endif  // not HAVE_LOCALTIME_R\n\n#  ifndef HAVE_GMTIME_R\nGLOG_NO_EXPORT std::tm* gmtime_r(const std::time_t* timep, std::tm* result);\n#  endif  // not HAVE_GMTIME_R\n\nGLOG_NO_EXPORT\ninline char* strerror_r(int errnum, char* buf, std::size_t buflen) {\n  strerror_s(buf, buflen, errnum);\n  return buf;\n}\n}  // namespace glog_internal_namespace_\n}  // namespace google\n\n#endif /* _WIN32 */\n\n#endif /* CTEMPLATE_WINDOWS_PORT_H_ */\n"
  }
]