summaryrefslogtreecommitdiffstats
path: root/Utilities
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities')
-rw-r--r--Utilities/Doxygen/CMakeLists.txt2
-rwxr-xr-xUtilities/Release/macos/sign-notarize.bash1
-rw-r--r--Utilities/Release/win/x86/cache-i386.txt3
-rw-r--r--Utilities/Release/win/x86/cache-x86_64.txt3
-rwxr-xr-xUtilities/Release/win/x86/test/test-ninja.bat1
-rwxr-xr-xUtilities/Release/win/x86/test/test-nmake.bat1
-rwxr-xr-xUtilities/Scripts/update-curl.bash4
-rwxr-xr-xUtilities/Scripts/update-expat.bash2
-rwxr-xr-xUtilities/Scripts/update-jsoncpp.bash2
-rwxr-xr-xUtilities/Scripts/update-pdcurses.bash32
-rw-r--r--Utilities/Sphinx/CMakeLists.txt3
-rw-r--r--Utilities/Sphinx/CTestCustom.cmake.in3
-rw-r--r--Utilities/cmbzip2/CMakeLists.txt2
-rw-r--r--Utilities/cmcurl/CMake/CurlTests.c20
-rw-r--r--Utilities/cmcurl/CMake/FindMbedTLS.cmake4
-rw-r--r--Utilities/cmcurl/CMake/OtherTests.cmake1
-rw-r--r--Utilities/cmcurl/CMakeLists.txt189
-rw-r--r--Utilities/cmcurl/include/curl/curl.h42
-rw-r--r--Utilities/cmcurl/include/curl/curlver.h8
-rw-r--r--Utilities/cmcurl/include/curl/multi.h5
-rw-r--r--Utilities/cmcurl/include/curl/typecheck-gcc.h2
-rw-r--r--Utilities/cmcurl/include/curl/urlapi.h21
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt9
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c6
-rw-r--r--Utilities/cmcurl/lib/c-hyper.c203
-rw-r--r--Utilities/cmcurl/lib/conncache.c13
-rw-r--r--Utilities/cmcurl/lib/connect.c38
-rw-r--r--Utilities/cmcurl/lib/content_encoding.c3
-rw-r--r--Utilities/cmcurl/lib/cookie.c2
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake3
-rw-r--r--Utilities/cmcurl/lib/curl_des.c4
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.c10
-rw-r--r--Utilities/cmcurl/lib/curl_hmac.h4
-rw-r--r--Utilities/cmcurl/lib/curl_md5.h8
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c19
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c117
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.h67
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h2
-rw-r--r--Utilities/cmcurl/lib/curl_sha256.h13
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.c4
-rw-r--r--Utilities/cmcurl/lib/doh.c25
-rw-r--r--Utilities/cmcurl/lib/easy.c10
-rw-r--r--Utilities/cmcurl/lib/easyoptions.c8
-rw-r--r--Utilities/cmcurl/lib/ftp.c24
-rw-r--r--Utilities/cmcurl/lib/hash.c82
-rw-r--r--Utilities/cmcurl/lib/hash.h12
-rw-r--r--Utilities/cmcurl/lib/hostcheck.c2
-rw-r--r--Utilities/cmcurl/lib/hostip.c31
-rw-r--r--Utilities/cmcurl/lib/hostip.h4
-rw-r--r--Utilities/cmcurl/lib/http.c89
-rw-r--r--Utilities/cmcurl/lib/http.h6
-rw-r--r--Utilities/cmcurl/lib/http2.c31
-rw-r--r--Utilities/cmcurl/lib/http_aws_sigv4.c21
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.c11
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c110
-rw-r--r--Utilities/cmcurl/lib/http_proxy.h3
-rw-r--r--Utilities/cmcurl/lib/if2ip.c4
-rw-r--r--Utilities/cmcurl/lib/imap.c157
-rw-r--r--Utilities/cmcurl/lib/inet_pton.c6
-rw-r--r--Utilities/cmcurl/lib/krb5.c8
-rw-r--r--Utilities/cmcurl/lib/ldap.c7
-rw-r--r--Utilities/cmcurl/lib/libcurl.rc4
-rw-r--r--Utilities/cmcurl/lib/llist.c4
-rw-r--r--Utilities/cmcurl/lib/md4.c17
-rw-r--r--Utilities/cmcurl/lib/md5.c42
-rw-r--r--Utilities/cmcurl/lib/mime.c80
-rw-r--r--Utilities/cmcurl/lib/mprintf.c2
-rw-r--r--Utilities/cmcurl/lib/multi.c252
-rw-r--r--Utilities/cmcurl/lib/multihandle.h2
-rw-r--r--Utilities/cmcurl/lib/multiif.h4
-rw-r--r--Utilities/cmcurl/lib/openldap.c833
-rw-r--r--Utilities/cmcurl/lib/pop3.c100
-rw-r--r--Utilities/cmcurl/lib/select.c2
-rw-r--r--Utilities/cmcurl/lib/sendf.c8
-rw-r--r--Utilities/cmcurl/lib/setopt.c38
-rw-r--r--Utilities/cmcurl/lib/setup-win32.h14
-rw-r--r--Utilities/cmcurl/lib/sha256.c141
-rw-r--r--Utilities/cmcurl/lib/share.c6
-rw-r--r--Utilities/cmcurl/lib/smtp.c103
-rw-r--r--Utilities/cmcurl/lib/socks.c33
-rw-r--r--Utilities/cmcurl/lib/socks_gssapi.c4
-rw-r--r--Utilities/cmcurl/lib/socks_sspi.c2
-rw-r--r--Utilities/cmcurl/lib/splay.c4
-rw-r--r--Utilities/cmcurl/lib/strerror.c111
-rw-r--r--Utilities/cmcurl/lib/system_win32.c4
-rw-r--r--Utilities/cmcurl/lib/tftp.c6
-rw-r--r--Utilities/cmcurl/lib/transfer.c2
-rw-r--r--Utilities/cmcurl/lib/url.c76
-rw-r--r--Utilities/cmcurl/lib/urlapi-int.h4
-rw-r--r--Utilities/cmcurl/lib/urlapi.c402
-rw-r--r--Utilities/cmcurl/lib/urldata.h14
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.c11
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.c4
-rw-r--r--Utilities/cmcurl/lib/version_win32.c113
-rw-r--r--Utilities/cmcurl/lib/version_win32.h3
-rw-r--r--Utilities/cmcurl/lib/vquic/ngtcp2.c107
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh2.c154
-rw-r--r--Utilities/cmcurl/lib/vssh/wolfssh.c6
-rw-r--r--Utilities/cmcurl/lib/vtls/bearssl.c6
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c79
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h8
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c60
-rw-r--r--Utilities/cmcurl/lib/vtls/mesalink.c93
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c107
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c290
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.h8
-rw-r--r--Utilities/cmcurl/lib/vtls/rustls.c61
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c447
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c5
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c32
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c10
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h3
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.c75
-rw-r--r--Utilities/cmcurl/lib/x509asn1.c127
-rw-r--r--Utilities/cmexpat/CMakeLists.txt2
-rw-r--r--Utilities/cmexpat/ConfigureChecks.cmake1
-rw-r--r--Utilities/cmexpat/README.md2
-rw-r--r--Utilities/cmexpat/lib/expat.h4
-rw-r--r--Utilities/cmexpat/lib/xmlparse.c405
-rw-r--r--Utilities/cmexpat/lib/xmlrole.c7
-rw-r--r--Utilities/cmexpat/lib/xmltok.c14
-rw-r--r--Utilities/cmexpat/lib/xmltok_impl.c20
-rw-r--r--Utilities/cmexpat/lib/xmltok_ns.c4
-rw-r--r--Utilities/cmjsoncpp/CMakeLists.txt2
-rw-r--r--Utilities/cmjsoncpp/LICENSE14
-rw-r--r--Utilities/cmjsoncpp/README-CMake.txt66
-rw-r--r--Utilities/cmjsoncpp/include/json/allocator.h10
-rw-r--r--Utilities/cmjsoncpp/include/json/json_features.h3
-rw-r--r--Utilities/cmjsoncpp/include/json/reader.h13
-rw-r--r--Utilities/cmjsoncpp/include/json/value.h21
-rw-r--r--Utilities/cmjsoncpp/include/json/version.h4
-rw-r--r--Utilities/cmjsoncpp/include/json/writer.h17
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_reader.cpp25
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_tool.h10
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_value.cpp26
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_writer.cpp43
-rw-r--r--Utilities/cmlibarchive/CMakeLists.txt16
-rw-r--r--Utilities/cmliblzma/CMakeLists.txt4
-rw-r--r--Utilities/cmlibrhash/CMakeLists.txt2
-rw-r--r--Utilities/cmlibuv/CMakeLists.txt3
-rw-r--r--Utilities/cmlibuv/LICENSE4
-rw-r--r--Utilities/cmlibuv/include/uv.h33
-rw-r--r--Utilities/cmlibuv/include/uv/android-ifaddrs.h54
-rw-r--r--Utilities/cmlibuv/include/uv/errno.h14
-rw-r--r--Utilities/cmlibuv/include/uv/tree.h2
-rw-r--r--Utilities/cmlibuv/include/uv/unix.h6
-rw-r--r--Utilities/cmlibuv/include/uv/version.h2
-rw-r--r--Utilities/cmlibuv/include/uv/win.h23
-rw-r--r--Utilities/cmlibuv/src/idna.c49
-rw-r--r--Utilities/cmlibuv/src/inet.c3
-rw-r--r--Utilities/cmlibuv/src/threadpool.c9
-rw-r--r--Utilities/cmlibuv/src/timer.c1
-rw-r--r--Utilities/cmlibuv/src/unix/android-ifaddrs.c713
-rw-r--r--Utilities/cmlibuv/src/unix/async.c2
-rw-r--r--Utilities/cmlibuv/src/unix/atomic-ops.h6
-rw-r--r--Utilities/cmlibuv/src/unix/bsd-ifaddrs.c6
-rw-r--r--Utilities/cmlibuv/src/unix/bsd-proctitle.c4
-rw-r--r--Utilities/cmlibuv/src/unix/cmake-bootstrap.c21
-rw-r--r--Utilities/cmlibuv/src/unix/core.c32
-rw-r--r--Utilities/cmlibuv/src/unix/darwin.c28
-rw-r--r--Utilities/cmlibuv/src/unix/dl.c2
-rw-r--r--Utilities/cmlibuv/src/unix/epoll.c422
-rw-r--r--Utilities/cmlibuv/src/unix/freebsd.c15
-rw-r--r--Utilities/cmlibuv/src/unix/fs.c194
-rw-r--r--Utilities/cmlibuv/src/unix/fsevents.c23
-rw-r--r--Utilities/cmlibuv/src/unix/getaddrinfo.c3
-rw-r--r--Utilities/cmlibuv/src/unix/ibmi.c47
-rw-r--r--Utilities/cmlibuv/src/unix/internal.h30
-rw-r--r--Utilities/cmlibuv/src/unix/kqueue.c5
-rw-r--r--Utilities/cmlibuv/src/unix/linux-core.c579
-rw-r--r--Utilities/cmlibuv/src/unix/linux-inotify.c2
-rw-r--r--Utilities/cmlibuv/src/unix/linux-syscalls.c37
-rw-r--r--Utilities/cmlibuv/src/unix/linux-syscalls.h7
-rw-r--r--Utilities/cmlibuv/src/unix/os390-proctitle.c136
-rw-r--r--Utilities/cmlibuv/src/unix/os390-syscalls.c62
-rw-r--r--Utilities/cmlibuv/src/unix/os390-syscalls.h3
-rw-r--r--Utilities/cmlibuv/src/unix/os390.c136
-rw-r--r--Utilities/cmlibuv/src/unix/pipe.c54
-rw-r--r--Utilities/cmlibuv/src/unix/poll.c14
-rw-r--r--Utilities/cmlibuv/src/unix/process.c210
-rw-r--r--Utilities/cmlibuv/src/unix/proctitle.c4
-rw-r--r--Utilities/cmlibuv/src/unix/signal.c2
-rw-r--r--Utilities/cmlibuv/src/unix/stream.c259
-rw-r--r--Utilities/cmlibuv/src/unix/sunos.c11
-rw-r--r--Utilities/cmlibuv/src/unix/tcp.c53
-rw-r--r--Utilities/cmlibuv/src/unix/thread.c12
-rw-r--r--Utilities/cmlibuv/src/unix/tty.c18
-rw-r--r--Utilities/cmlibuv/src/unix/udp.c94
-rw-r--r--Utilities/cmlibuv/src/uv-common.c44
-rw-r--r--Utilities/cmlibuv/src/uv-common.h9
-rw-r--r--Utilities/cmlibuv/src/win/error.c2
-rw-r--r--Utilities/cmlibuv/src/win/fs-event.c6
-rw-r--r--Utilities/cmlibuv/src/win/fs.c67
-rw-r--r--Utilities/cmlibuv/src/win/internal.h4
-rw-r--r--Utilities/cmlibuv/src/win/pipe.c230
-rw-r--r--Utilities/cmlibuv/src/win/poll.c3
-rw-r--r--Utilities/cmlibuv/src/win/process-stdio.c96
-rw-r--r--Utilities/cmlibuv/src/win/process.c9
-rw-r--r--Utilities/cmlibuv/src/win/stream.c23
-rw-r--r--Utilities/cmlibuv/src/win/tcp.c263
-rw-r--r--Utilities/cmlibuv/src/win/thread.c106
-rw-r--r--Utilities/cmlibuv/src/win/udp.c8
-rw-r--r--Utilities/cmlibuv/src/win/util.c20
-rw-r--r--Utilities/cmlibuv/src/win/winapi.c10
-rw-r--r--Utilities/cmlibuv/src/win/winapi.h7
-rw-r--r--Utilities/cmnghttp2/CMakeLists.txt10
-rw-r--r--Utilities/cmpdcurses/.gitattributes1
-rw-r--r--Utilities/cmpdcurses/CMakeLists.txt73
-rw-r--r--Utilities/cmpdcurses/README.md65
-rw-r--r--Utilities/cmpdcurses/common/acs437.h35
-rw-r--r--Utilities/cmpdcurses/common/acsuni.h35
-rw-r--r--Utilities/cmpdcurses/curses.h1417
-rw-r--r--Utilities/cmpdcurses/curspriv.h122
-rw-r--r--Utilities/cmpdcurses/panel.h54
-rw-r--r--Utilities/cmpdcurses/pdcurses/README.md25
-rw-r--r--Utilities/cmpdcurses/pdcurses/addch.c408
-rw-r--r--Utilities/cmpdcurses/pdcurses/addchstr.c244
-rw-r--r--Utilities/cmpdcurses/pdcurses/addstr.c239
-rw-r--r--Utilities/cmpdcurses/pdcurses/attr.c409
-rw-r--r--Utilities/cmpdcurses/pdcurses/beep.c74
-rw-r--r--Utilities/cmpdcurses/pdcurses/bkgd.c226
-rw-r--r--Utilities/cmpdcurses/pdcurses/border.c414
-rw-r--r--Utilities/cmpdcurses/pdcurses/clear.c159
-rw-r--r--Utilities/cmpdcurses/pdcurses/color.c362
-rw-r--r--Utilities/cmpdcurses/pdcurses/debug.c106
-rw-r--r--Utilities/cmpdcurses/pdcurses/delch.c96
-rw-r--r--Utilities/cmpdcurses/pdcurses/deleteln.c211
-rw-r--r--Utilities/cmpdcurses/pdcurses/getch.c589
-rw-r--r--Utilities/cmpdcurses/pdcurses/getstr.c473
-rw-r--r--Utilities/cmpdcurses/pdcurses/getyx.c142
-rw-r--r--Utilities/cmpdcurses/pdcurses/inch.c126
-rw-r--r--Utilities/cmpdcurses/pdcurses/inchstr.c213
-rw-r--r--Utilities/cmpdcurses/pdcurses/initscr.c431
-rw-r--r--Utilities/cmpdcurses/pdcurses/inopts.c368
-rw-r--r--Utilities/cmpdcurses/pdcurses/insch.c270
-rw-r--r--Utilities/cmpdcurses/pdcurses/insstr.c263
-rw-r--r--Utilities/cmpdcurses/pdcurses/instr.c245
-rw-r--r--Utilities/cmpdcurses/pdcurses/kernel.c297
-rw-r--r--Utilities/cmpdcurses/pdcurses/keyname.c129
-rw-r--r--Utilities/cmpdcurses/pdcurses/mouse.c421
-rw-r--r--Utilities/cmpdcurses/pdcurses/move.c77
-rw-r--r--Utilities/cmpdcurses/pdcurses/outopts.c175
-rw-r--r--Utilities/cmpdcurses/pdcurses/overlay.c214
-rw-r--r--Utilities/cmpdcurses/pdcurses/pad.c280
-rw-r--r--Utilities/cmpdcurses/pdcurses/panel.c633
-rw-r--r--Utilities/cmpdcurses/pdcurses/printw.c129
-rw-r--r--Utilities/cmpdcurses/pdcurses/refresh.c279
-rw-r--r--Utilities/cmpdcurses/pdcurses/scanw.c581
-rw-r--r--Utilities/cmpdcurses/pdcurses/scr_dump.c217
-rw-r--r--Utilities/cmpdcurses/pdcurses/scroll.c101
-rw-r--r--Utilities/cmpdcurses/pdcurses/slk.c671
-rw-r--r--Utilities/cmpdcurses/pdcurses/termattr.c172
-rw-r--r--Utilities/cmpdcurses/pdcurses/touch.c199
-rw-r--r--Utilities/cmpdcurses/pdcurses/util.c308
-rw-r--r--Utilities/cmpdcurses/pdcurses/window.c582
-rw-r--r--Utilities/cmpdcurses/wincon/README.md76
-rw-r--r--Utilities/cmpdcurses/wincon/pdcclip.c149
-rw-r--r--Utilities/cmpdcurses/wincon/pdcdisp.c329
-rw-r--r--Utilities/cmpdcurses/wincon/pdcgetsc.c42
-rw-r--r--Utilities/cmpdcurses/wincon/pdckbd.c699
-rw-r--r--Utilities/cmpdcurses/wincon/pdcscrn.c686
-rw-r--r--Utilities/cmpdcurses/wincon/pdcsetsc.c130
-rw-r--r--Utilities/cmpdcurses/wincon/pdcutil.c26
-rw-r--r--Utilities/cmpdcurses/wincon/pdcwin.h27
-rw-r--r--Utilities/cmzlib/CMakeLists.txt2
-rw-r--r--Utilities/cmzstd/CMakeLists.txt2
266 files changed, 21801 insertions, 4478 deletions
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index 69b4e2f..72cfc05 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -3,7 +3,7 @@
if(NOT CMake_SOURCE_DIR)
set(CMakeDeveloperReference_STANDALONE 1)
- cmake_minimum_required(VERSION 3.1...3.20 FATAL_ERROR)
+ cmake_minimum_required(VERSION 3.1...3.21 FATAL_ERROR)
get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/Release/macos/sign-notarize.bash b/Utilities/Release/macos/sign-notarize.bash
index 377eced..8283c90 100755
--- a/Utilities/Release/macos/sign-notarize.bash
+++ b/Utilities/Release/macos/sign-notarize.bash
@@ -99,7 +99,6 @@ codesign --verify --timestamp --options=runtime --verbose --deep \
"$vol_path/CMake.app/Contents/bin/ccmake" \
"$vol_path/CMake.app/Contents/bin/ctest" \
"$vol_path/CMake.app/Contents/bin/cpack" \
- "$vol_path/CMake.app/Contents/share/cmake"*"/Modules/Internal/CPack/CPack.OSXScriptLauncher.in" \
"$vol_path/CMake.app"
xcnotary notarize "$vol_path/CMake.app" -d "$dev_acct" -k "$key_item" $provider
diff --git a/Utilities/Release/win/x86/cache-i386.txt b/Utilities/Release/win/x86/cache-i386.txt
index 54a45d8..2dcd4dd 100644
--- a/Utilities/Release/win/x86/cache-i386.txt
+++ b/Utilities/Release/win/x86/cache-i386.txt
@@ -29,9 +29,6 @@ QCOLLECTIONGENERATOR_EXECUTABLE:PATH=C:/qt-i386/bin/qhelpgenerator.exe
# No bootstrap with MSVC tools.
CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-# No MFC in base image.
-CTEST_RUN_MFC:BOOL=OFF
-
# No Fortran compiler.
CMAKE_Fortran_COMPILER:FILEPATH=FALSE
diff --git a/Utilities/Release/win/x86/cache-x86_64.txt b/Utilities/Release/win/x86/cache-x86_64.txt
index 0b78c72..3c5593e 100644
--- a/Utilities/Release/win/x86/cache-x86_64.txt
+++ b/Utilities/Release/win/x86/cache-x86_64.txt
@@ -29,9 +29,6 @@ QCOLLECTIONGENERATOR_EXECUTABLE:PATH=C:/qt-x86_64/bin/qhelpgenerator.exe
# No bootstrap with MSVC tools.
CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-# No MFC in base image.
-CTEST_RUN_MFC:BOOL=OFF
-
# No Fortran compiler.
CMAKE_Fortran_COMPILER:FILEPATH=FALSE
diff --git a/Utilities/Release/win/x86/test/test-ninja.bat b/Utilities/Release/win/x86/test/test-ninja.bat
index b8347ef..fb43589 100755
--- a/Utilities/Release/win/x86/test/test-ninja.bat
+++ b/Utilities/Release/win/x86/test/test-ninja.bat
@@ -12,7 +12,6 @@ cd \cmake\src\cmake-ninja && ^
@echo CMake_TEST_IPO_WORKS_C:BOOL=ON
@echo CMake_TEST_IPO_WORKS_CXX:BOOL=ON
@echo CMake_TEST_NO_NETWORK:BOOL=ON
- @echo CTEST_RUN_MFC:BOOL=OFF
) && ^
cmake ..\cmake -DCMake_TEST_HOST_CMAKE=1 -G "Ninja" && ^
ninja && ^
diff --git a/Utilities/Release/win/x86/test/test-nmake.bat b/Utilities/Release/win/x86/test/test-nmake.bat
index 5008711..9d7e447 100755
--- a/Utilities/Release/win/x86/test/test-nmake.bat
+++ b/Utilities/Release/win/x86/test/test-nmake.bat
@@ -12,7 +12,6 @@ cd \cmake\src\cmake-nmake && ^
@echo CMake_TEST_IPO_WORKS_C:BOOL=ON
@echo CMake_TEST_IPO_WORKS_CXX:BOOL=ON
@echo CMake_TEST_NO_NETWORK:BOOL=ON
- @echo CTEST_RUN_MFC:BOOL=OFF
) && ^
cmake ..\cmake -DCMake_TEST_HOST_CMAKE=1 -G "NMake Makefiles" && ^
nmake && ^
diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash
index dd8e7a8..50d8029 100755
--- a/Utilities/Scripts/update-curl.bash
+++ b/Utilities/Scripts/update-curl.bash
@@ -5,10 +5,10 @@ set -x
shopt -s dotglob
readonly name="curl"
-readonly ownership="Curl Upstream <curl-library@cool.haxx.se>"
+readonly ownership="Curl Upstream <curl-library@lists.haxx.se>"
readonly subtree="Utilities/cmcurl"
readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-7_79_1"
+readonly tag="curl-7_81_0"
readonly shortlog=false
readonly paths="
CMake/*
diff --git a/Utilities/Scripts/update-expat.bash b/Utilities/Scripts/update-expat.bash
index a052c0e..a061adc 100755
--- a/Utilities/Scripts/update-expat.bash
+++ b/Utilities/Scripts/update-expat.bash
@@ -8,7 +8,7 @@ readonly name="expat"
readonly ownership="Expat Upstream <kwrobot@kitware.com>"
readonly subtree="Utilities/cmexpat"
readonly repo="https://github.com/libexpat/libexpat.git"
-readonly tag="R_2_4_1"
+readonly tag="R_2_4_6"
readonly shortlog=false
readonly paths="
expat/lib/asciitab.h
diff --git a/Utilities/Scripts/update-jsoncpp.bash b/Utilities/Scripts/update-jsoncpp.bash
index 5ed00e7..a05dcb8 100755
--- a/Utilities/Scripts/update-jsoncpp.bash
+++ b/Utilities/Scripts/update-jsoncpp.bash
@@ -8,7 +8,7 @@ readonly name="jsoncpp"
readonly ownership="JsonCpp Upstream <kwrobot@kitware.com>"
readonly subtree="Utilities/cmjsoncpp"
readonly repo="https://github.com/open-source-parsers/jsoncpp.git"
-readonly tag="1.9.4"
+readonly tag="42e892d96e47b1f6e29844cc705e148ec4856448"
readonly shortlog=false
readonly paths="
LICENSE
diff --git a/Utilities/Scripts/update-pdcurses.bash b/Utilities/Scripts/update-pdcurses.bash
new file mode 100755
index 0000000..b1a2815
--- /dev/null
+++ b/Utilities/Scripts/update-pdcurses.bash
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="PDCurses"
+readonly ownership="PDCurses Upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/cmpdcurses"
+readonly repo="https://github.com/wmcbrine/PDCurses.git"
+readonly tag="f1cd4f4569451a5028ddf3d3c202f0ad6b1ae446"
+readonly shortlog=false
+readonly paths="
+ README.md
+ *.h
+ common/acs437.h
+ common/acsuni.h
+ pdcurses/README.md
+ pdcurses/*.c
+ wincon/README.md
+ wincon/*.c
+ wincon/*.h
+"
+
+extract_source () {
+ git_archive
+ pushd "${extractdir}/${name}-reduced"
+ echo "* -whitespace" > .gitattributes
+ popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index 14d0e14..1dc65e7 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -3,12 +3,13 @@
if(NOT CMake_SOURCE_DIR)
set(CMakeHelp_STANDALONE 1)
- cmake_minimum_required(VERSION 3.1...3.20 FATAL_ERROR)
+ cmake_minimum_required(VERSION 3.1...3.21 FATAL_ERROR)
get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
include(${CMake_SOURCE_DIR}/Source/CMakeVersion.cmake)
include(${CMake_SOURCE_DIR}/Source/CMakeInstallDestinations.cmake)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CTestCustom.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake @ONLY)
unset(CMAKE_DATA_DIR)
unset(CMAKE_DATA_DIR CACHE)
macro(CMake_OPTIONAL_COMPONENT)
diff --git a/Utilities/Sphinx/CTestCustom.cmake.in b/Utilities/Sphinx/CTestCustom.cmake.in
new file mode 100644
index 0000000..840121b
--- /dev/null
+++ b/Utilities/Sphinx/CTestCustom.cmake.in
@@ -0,0 +1,3 @@
+list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION
+ "cmake.texi:[0-9]+: warning: .definfoenclose is obsolete"
+ )
diff --git a/Utilities/cmbzip2/CMakeLists.txt b/Utilities/cmbzip2/CMakeLists.txt
index ff90bb6..52efe14 100644
--- a/Utilities/cmbzip2/CMakeLists.txt
+++ b/Utilities/cmbzip2/CMakeLists.txt
@@ -2,7 +2,7 @@ project(bzip2)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmcurl/CMake/CurlTests.c b/Utilities/cmcurl/CMake/CurlTests.c
index e418146..8666da0 100644
--- a/Utilities/cmcurl/CMake/CurlTests.c
+++ b/Utilities/cmcurl/CMake/CurlTests.c
@@ -229,10 +229,6 @@ int main () { ; return 0; }
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
@@ -258,10 +254,6 @@ main ()
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
@@ -285,10 +277,6 @@ main ()
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
@@ -313,10 +301,6 @@ main ()
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
@@ -403,10 +387,6 @@ main ()
# include <windows.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
#endif
/* includes start */
diff --git a/Utilities/cmcurl/CMake/FindMbedTLS.cmake b/Utilities/cmcurl/CMake/FindMbedTLS.cmake
index 1746093..7bdb197 100644
--- a/Utilities/cmcurl/CMake/FindMbedTLS.cmake
+++ b/Utilities/cmcurl/CMake/FindMbedTLS.cmake
@@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
@@ -28,7 +28,7 @@ find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(MBEDTLS DEFAULT_MSG
+find_package_handle_standard_args(MbedTLS DEFAULT_MSG
MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake
index 7fda7ac..d06b3ed 100644
--- a/Utilities/cmcurl/CMake/OtherTests.cmake
+++ b/Utilities/cmcurl/CMake/OtherTests.cmake
@@ -33,7 +33,6 @@ set(signature_call_conv)
if(HAVE_WINDOWS_H)
add_header_include(HAVE_WINSOCK2_H "winsock2.h")
add_header_include(HAVE_WINDOWS_H "windows.h")
- add_header_include(HAVE_WINSOCK_H "winsock.h")
set(_source_epilogue
"${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif")
set(signature_call_conv "PASCAL")
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index 9eef01a..07f1d4f 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -3,10 +3,17 @@ set(BUILD_CURL_EXE OFF CACHE INTERNAL "No curl exe")
set(BUILD_DASHBOARD_REPORTS OFF CACHE INTERNAL "No curl dashboard reports")
set(BUILD_RELEASE_DEBUG_DIRS OFF CACHE INTERNAL "No curl release/debug dirs")
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Build shared libraries")
-set(CMAKE_USE_GSSAPI OFF CACHE INTERNAL "Disable curl gssapi")
-set(CMAKE_USE_LIBSSH2 OFF CACHE INTERNAL "Disable curl libssh2")
-set(CMAKE_USE_LIBSSH OFF)
-set(CMAKE_USE_OPENLDAP OFF CACHE INTERNAL "No curl OpenLDAP")
+set(CURL_USE_BEARSSL OFF)
+set(CURL_USE_GSSAPI OFF)
+set(CURL_USE_LIBSSH2 OFF)
+set(CURL_USE_LIBSSH OFF)
+set(CURL_USE_MBEDTLS OFF)
+set(CURL_USE_NSS OFF)
+set(CURL_USE_OPENLDAP OFF)
+set(CURL_USE_OPENSSL "${CMAKE_USE_OPENSSL}")
+set(CURL_USE_SCHANNEL OFF)
+set(CURL_USE_SECTRANSP OFF)
+set(CURL_USE_WOLFSSL OFF)
set(CURL_BROTLI OFF)
set(CURL_DISABLE_ALTSVC ON)
set(CURL_DISABLE_COOKIES OFF CACHE INTERNAL "Do not disable curl cookie support")
@@ -66,11 +73,10 @@ set(USE_NGTCP2 OFF)
set(USE_QUICHE OFF)
set(USE_WIN32_IDN OFF)
set(USE_WIN32_LDAP OFF CACHE INTERNAL "No curl Windows LDAP")
-if(CMAKE_USE_OPENSSL)
+if(CURL_USE_OPENSSL)
elseif(WIN32)
- unset(CMAKE_USE_WINSSL CACHE)
- set(CMAKE_USE_SCHANNEL ON)
- set(CURL_WINDOWS_SSPI ON CACHE INTERNAL "Use windows libraries to allow NTLM authentication without openssl")
+ set(CURL_USE_SCHANNEL ON)
+ set(CURL_WINDOWS_SSPI ON)
elseif(APPLE)
# Use OS X SSL/TLS native implementation if available on target version.
if(CMAKE_OSX_DEPLOYMENT_TARGET)
@@ -83,17 +89,12 @@ elseif(APPLE)
)
endif()
if(NOT OSX_VERSION VERSION_LESS 10.6 AND
- CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
- set(CMAKE_USE_SECTRANSP ON CACHE INTERNAL "enable Apple OS native SSL/TLS")
+ CMAKE_C_COMPILER_ID MATCHES "GNU|LCC|Clang|AppleClang")
+ set(CURL_USE_SECTRANSP ON)
else()
- set(CMAKE_USE_SECTRANSP OFF CACHE INTERNAL "enable Apple OS native SSL/TLS")
+ set(CURL_USE_SECTRANSP OFF)
endif()
- unset(CMAKE_USE_DARWINSSL CACHE)
endif()
-set(CMAKE_USE_MBEDTLS OFF CACHE INTERNAL "Enable mbedTLS for SSL/TLS")
-set(CMAKE_USE_BEARSSL OFF CACHE INTERNAL "Enable BearSSL for SSL/TLS")
-set(CMAKE_USE_NSS OFF CACHE INTERNAL "Enable NSS for SSL/TLS")
-set(CMAKE_USE_WOLFSSL OFF)
# Windows Vista and above have inet_pton, but this will link on
# older versions and then the executable will fail to launch at
@@ -112,7 +113,7 @@ endif(APPLE)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -387,6 +388,17 @@ if(ENABLE_IPV6 AND NOT WIN32)
set(ENABLE_IPV6 OFF
CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
endif()
+
+ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT ENABLE_ARES)
+ set(use_core_foundation ON)
+
+ find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
+ if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
+ message(FATAL_ERROR "SystemConfiguration framework not found")
+ endif()
+
+ list(APPEND CURL_LIBS "-framework SystemConfiguration")
+ endif()
endif()
if(0) # This code not needed for building within CMake.
@@ -479,84 +491,96 @@ if(WIN32)
check_library_exists_concat("winmm" getch HAVE_LIBWINMM)
endif()
-# check SSL libraries
-# TODO support GnuTLS
+if(0) # This code not needed for building within CMake.
+# This check below for use of deprecated symbols is only temporary and is to
+# be removed again after a year's service. Remove after November 25, 2022.
+set(CURL_RECONFIG_REQUIRED 0)
+foreach(_LIB GSSAPI OPENLDAP LIBSSH LIBSSH2 BEARSSL MBEDTLS NSS OPENSSL
+ SCHANNEL SECTRANSP WOLFSSL)
+ if(CMAKE_USE_${_LIB})
+ set(CURL_RECONFIG_REQUIRED 1)
+ message(SEND_ERROR "The option CMAKE_USE_${_LIB} was renamed to CURL_USE_${_LIB}.")
+ endif()
+endforeach()
if(CMAKE_USE_WINSSL)
- message(FATAL_ERROR "The cmake option CMAKE_USE_WINSSL was renamed to CMAKE_USE_SCHANNEL.")
+ set(CURL_RECONFIG_REQUIRED 1)
+ message(SEND_ERROR "The option CMAKE_USE_WINSSL was renamed to CURL_USE_SCHANNEL.")
endif()
+if(CURL_RECONFIG_REQUIRED)
+ message(FATAL_ERROR "Reconfig required")
+endif()
+
+# check SSL libraries
+# TODO support GnuTLS
+option(CURL_ENABLE_SSL "Enable SSL support" ON)
if(APPLE)
- option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF)
+ cmake_dependent_option(CURL_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
endif()
if(WIN32)
- option(CMAKE_USE_SCHANNEL "enable Windows native SSL/TLS" OFF)
+ cmake_dependent_option(CURL_USE_SCHANNEL "enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON
- CMAKE_USE_SCHANNEL OFF)
+ CURL_USE_SCHANNEL OFF)
endif()
-option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF)
-option(CMAKE_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF)
-option(CMAKE_USE_NSS "Enable NSS for SSL/TLS" OFF)
-option(CMAKE_USE_WOLFSSL "enable wolfSSL for SSL/TLS" OFF)
+cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+cmake_dependent_option(CURL_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+cmake_dependent_option(CURL_USE_NSS "Enable NSS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+cmake_dependent_option(CURL_USE_WOLFSSL "enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
set(openssl_default ON)
-if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_SCHANNEL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS OR CMAKE_USE_WOLFSSL)
+if(WIN32 OR CURL_USE_SECTRANSP OR CURL_USE_SCHANNEL OR CURL_USE_MBEDTLS OR CURL_USE_NSS OR CURL_USE_WOLFSSL)
set(openssl_default OFF)
endif()
+cmake_dependent_option(CURL_USE_OPENSSL "Use OpenSSL code. Experimental" ${openssl_default} CURL_ENABLE_SSL OFF)
option(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG "Disable automatic loading of OpenSSL configuration" OFF)
+endif()
count_true(enabled_ssl_options_count
- CMAKE_USE_SCHANNEL
- CMAKE_USE_SECTRANSP
- CMAKE_USE_OPENSSL
- CMAKE_USE_MBEDTLS
- CMAKE_USE_BEARSSL
- CMAKE_USE_NSS
- CMAKE_USE_WOLFSSL
+ CURL_USE_SCHANNEL
+ CURL_USE_SECTRANSP
+ CURL_USE_OPENSSL
+ CURL_USE_MBEDTLS
+ CURL_USE_BEARSSL
+ CURL_USE_NSS
+ CURL_USE_WOLFSSL
)
if(enabled_ssl_options_count GREATER "1")
set(CURL_WITH_MULTI_SSL ON)
endif()
-if(CMAKE_USE_SCHANNEL)
+if(CURL_USE_SCHANNEL)
set(SSL_ENABLED ON)
set(USE_SCHANNEL ON) # Windows native SSL/TLS support
- set(USE_WINDOWS_SSPI ON) # CMAKE_USE_SCHANNEL implies CURL_WINDOWS_SSPI
+ set(USE_WINDOWS_SSPI ON) # CURL_USE_SCHANNEL implies CURL_WINDOWS_SSPI
endif()
if(CURL_WINDOWS_SSPI)
set(USE_WINDOWS_SSPI ON)
set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32")
endif()
-if(CMAKE_USE_DARWINSSL)
- message(FATAL_ERROR "The cmake option CMAKE_USE_DARWINSSL was renamed to CMAKE_USE_SECTRANSP.")
+if(CURL_USE_SECTRANSP)
+ set(use_core_foundation ON)
+
+ find_library(SECURITY_FRAMEWORK "Security")
+ if(NOT SECURITY_FRAMEWORK)
+ message(FATAL_ERROR "Security framework not found")
+ endif()
+
+ set(SSL_ENABLED ON)
+ set(USE_SECTRANSP ON)
+ list(APPEND CURL_LIBS "-framework Security")
endif()
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+if(use_core_foundation)
find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation")
if(NOT COREFOUNDATION_FRAMEWORK)
message(FATAL_ERROR "CoreFoundation framework not found")
endif()
- find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
- if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
- message(FATAL_ERROR "SystemConfiguration framework not found")
- endif()
-
- list(APPEND CURL_LIBS "-framework CoreFoundation" "-framework SystemConfiguration")
-
- if(CMAKE_USE_SECTRANSP)
- find_library(SECURITY_FRAMEWORK "Security")
- if(NOT SECURITY_FRAMEWORK)
- message(FATAL_ERROR "Security framework not found")
- endif()
-
- set(SSL_ENABLED ON)
- set(USE_SECTRANSP ON)
- list(APPEND CURL_LIBS "-framework Security")
- endif()
+ list(APPEND CURL_LIBS "-framework CoreFoundation")
endif()
-if(CMAKE_USE_OPENSSL)
+if(CURL_USE_OPENSSL)
find_package(OpenSSL)
if(NOT OpenSSL_FOUND)
message(FATAL_ERROR
@@ -588,9 +612,11 @@ if(CMAKE_USE_OPENSSL)
if(CURL_CA_PATH)
add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}")
endif()
+
+ add_definitions(-DOPENSSL_SUPPRESS_DEPRECATED)
endif()
-if(CMAKE_USE_MBEDTLS)
+if(CURL_USE_MBEDTLS)
find_package(MbedTLS REQUIRED)
set(SSL_ENABLED ON)
set(USE_MBEDTLS ON)
@@ -598,7 +624,7 @@ if(CMAKE_USE_MBEDTLS)
include_directories(${MBEDTLS_INCLUDE_DIRS})
endif()
-if(CMAKE_USE_BEARSSL)
+if(CURL_USE_BEARSSL)
find_package(BearSSL REQUIRED)
set(SSL_ENABLED ON)
set(USE_BEARSSL ON)
@@ -606,7 +632,7 @@ if(CMAKE_USE_BEARSSL)
include_directories(${BEARSSL_INCLUDE_DIRS})
endif()
-if(CMAKE_USE_WOLFSSL)
+if(CURL_USE_WOLFSSL)
find_package(WolfSSL REQUIRED)
set(SSL_ENABLED ON)
set(USE_WOLFSSL ON)
@@ -614,7 +640,7 @@ if(CMAKE_USE_WOLFSSL)
include_directories(${WolfSSL_INCLUDE_DIRS})
endif()
-if(CMAKE_USE_NSS)
+if(CURL_USE_NSS)
find_package(NSS REQUIRED)
include_directories(${NSS_INCLUDE_DIRS})
list(APPEND CURL_LIBS ${NSS_LIBRARIES})
@@ -695,13 +721,13 @@ if(NOT CURL_DISABLE_LDAP)
endif()
endif()
- option(CMAKE_USE_OPENLDAP "Use OpenLDAP code." OFF)
- mark_as_advanced(CMAKE_USE_OPENLDAP)
+ option(CURL_USE_OPENLDAP "Use OpenLDAP code." OFF)
+ mark_as_advanced(CURL_USE_OPENLDAP)
set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library")
set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library")
- if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP)
- message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time")
+ if(CURL_USE_OPENLDAP AND USE_WIN32_LDAP)
+ message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CURL_USE_OPENLDAP at the same time")
endif()
# Now that we know, we're not using windows LDAP...
@@ -731,7 +757,7 @@ if(NOT CURL_DISABLE_LDAP)
set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
else()
- if(CMAKE_USE_OPENLDAP)
+ if(CURL_USE_OPENLDAP)
set(USE_OPENLDAP ON)
endif()
if(CMAKE_LDAP_INCLUDE_DIR)
@@ -873,13 +899,13 @@ if(CURL_ZSTD)
endif()
#libSSH2
-option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON)
-mark_as_advanced(CMAKE_USE_LIBSSH2)
+option(CURL_USE_LIBSSH2 "Use libSSH2" ON)
+mark_as_advanced(CURL_USE_LIBSSH2)
set(USE_LIBSSH2 OFF)
set(HAVE_LIBSSH2 OFF)
set(HAVE_LIBSSH2_H OFF)
-if(CMAKE_USE_LIBSSH2)
+if(CURL_USE_LIBSSH2)
find_package(LibSSH2)
if(LIBSSH2_FOUND)
list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
@@ -898,9 +924,9 @@ if(CMAKE_USE_LIBSSH2)
endif()
# libssh
-option(CMAKE_USE_LIBSSH "Use libSSH" OFF)
-mark_as_advanced(CMAKE_USE_LIBSSH)
-if(NOT HAVE_LIBSSH2 AND CMAKE_USE_LIBSSH)
+option(CURL_USE_LIBSSH "Use libSSH" OFF)
+mark_as_advanced(CURL_USE_LIBSSH)
+if(NOT HAVE_LIBSSH2 AND CURL_USE_LIBSSH)
find_package(libssh CONFIG)
if(libssh_FOUND)
message(STATUS "Found libssh ${libssh_VERSION}")
@@ -911,10 +937,10 @@ if(NOT HAVE_LIBSSH2 AND CMAKE_USE_LIBSSH)
endif()
endif()
-option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
-mark_as_advanced(CMAKE_USE_GSSAPI)
+option(CURL_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
+mark_as_advanced(CURL_USE_GSSAPI)
-if(CMAKE_USE_GSSAPI)
+if(CURL_USE_GSSAPI)
find_package(GSS)
set(HAVE_GSSAPI ${GSS_FOUND})
@@ -1065,7 +1091,6 @@ endif()
# Check for header files
if(NOT UNIX)
check_include_file_concat("windows.h" HAVE_WINDOWS_H)
- check_include_file_concat("winsock.h" HAVE_WINSOCK_H)
check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H)
check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H)
check_include_file_concat("wincrypt.h" HAVE_WINCRYPT_H)
@@ -1643,12 +1668,10 @@ set(libdir "${CMAKE_INSTALL_PREFIX}/lib")
foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
if(TARGET "${_lib}")
set(_libname "${_lib}")
- get_target_property(_libtype "${_libname}" TYPE)
- if(_libtype STREQUAL INTERFACE_LIBRARY)
- # Interface libraries can occur when an external project embeds curl and
- # defined targets such as ZLIB::ZLIB by themselves. Ignore these as
- # reading the LOCATION property will error out. Assume the user won't need
- # this information in the .pc file.
+ get_target_property(_imported "${_libname}" IMPORTED)
+ if(NOT _imported)
+ # Reading the LOCATION property on non-imported target will error out.
+ # Assume the user won't need this information in the .pc file.
continue()
endif()
get_target_property(_lib "${_libname}" LOCATION)
diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h
index 7b50b7c..ec2e245 100644
--- a/Utilities/cmcurl/include/curl/curl.h
+++ b/Utilities/cmcurl/include/curl/curl.h
@@ -46,8 +46,8 @@
#include <stdio.h>
#include <limits.h>
-#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
-/* Needed for __FreeBSD_version symbol definition */
+#if (defined(__FreeBSD__) && (__FreeBSD__ >= 2)) || defined(__MidnightBSD__)
+/* Needed for __FreeBSD_version or __MidnightBSD_version symbol definition */
#include <osreldate.h>
#endif
@@ -73,6 +73,7 @@
defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
(defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
+ (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
defined(__VXWORKS__)
#include <sys/select.h>
#endif
@@ -470,6 +471,20 @@ typedef int (*curl_debug_callback)
size_t size, /* size of the data pointed to */
void *userptr); /* whatever the user please */
+/* This is the CURLOPT_PREREQFUNCTION callback prototype. */
+typedef int (*curl_prereq_callback)(void *clientp,
+ char *conn_primary_ip,
+ char *conn_local_ip,
+ int conn_primary_port,
+ int conn_local_port);
+
+/* Return code for when the pre-request callback has terminated without
+ any errors */
+#define CURL_PREREQFUNC_OK 0
+/* Return code for when the pre-request callback wants to abort the
+ request */
+#define CURL_PREREQFUNC_ABORT 1
+
/* All possible error codes from all sorts of curl functions. Future versions
may return other values, stay prepared.
@@ -2043,7 +2058,8 @@ typedef enum {
/* alt-svc cache file name to possibly read from/write to */
CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),
- /* maximum age of a connection to consider it for reuse (in seconds) */
+ /* maximum age (idle time) of a connection to consider it for reuse
+ * (in seconds) */
CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),
/* SASL authorisation identity */
@@ -2102,6 +2118,23 @@ typedef enum {
this option is used only if PROXY_SSL_VERIFYPEER is true */
CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
+ /* used by scp/sftp to verify the host's public key */
+ CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPTTYPE_STRINGPOINT, 311),
+
+ /* Function that will be called immediately before the initial request
+ is made on a connection (after any protocol negotiation step). */
+ CURLOPT(CURLOPT_PREREQFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 312),
+
+ /* Data passed to the CURLOPT_PREREQFUNCTION callback */
+ CURLOPT(CURLOPT_PREREQDATA, CURLOPTTYPE_CBPOINT, 313),
+
+ /* maximum age (since creation) of a connection to consider it for reuse
+ * (in seconds) */
+ CURLOPT(CURLOPT_MAXLIFETIME_CONN, CURLOPTTYPE_LONG, 314),
+
+ /* Set MIME option flags. */
+ CURLOPT(CURLOPT_MIME_OPTIONS, CURLOPTTYPE_LONG, 315),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@@ -2261,6 +2294,9 @@ CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n);
typedef struct curl_mime curl_mime; /* Mime context. */
typedef struct curl_mimepart curl_mimepart; /* Mime part context. */
+/* CURLMIMEOPT_ defines are for the CURLOPT_MIME_OPTIONS option. */
+#define CURLMIMEOPT_FORMESCAPE (1<<0) /* Use backslash-escaping for forms. */
+
/*
* NAME curl_mime_init()
*
diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h
index 9019868..1f268fa 100644
--- a/Utilities/cmcurl/include/curl/curlver.h
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@ -30,13 +30,13 @@
/* This is the version number of the libcurl package from which this header
file origins: */
-#define LIBCURL_VERSION "7.79.1"
+#define LIBCURL_VERSION "7.81.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 79
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 81
+#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -57,7 +57,7 @@
CURL_VERSION_BITS() macro since curl's own configure script greps for it
and needs it to contain the full number.
*/
-#define LIBCURL_VERSION_NUM 0x074f01
+#define LIBCURL_VERSION_NUM 0x075100
/*
* This is the date and time when the full source package was created. The
diff --git a/Utilities/cmcurl/include/curl/multi.h b/Utilities/cmcurl/include/curl/multi.h
index 37f9829..91cd95d 100644
--- a/Utilities/cmcurl/include/curl/multi.h
+++ b/Utilities/cmcurl/include/curl/multi.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -73,7 +73,8 @@ typedef enum {
CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
callback */
CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */
- CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */
+ CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */
+ CURLM_ABORTED_BY_CALLBACK,
CURLM_LAST
} CURLMcode;
diff --git a/Utilities/cmcurl/include/curl/typecheck-gcc.h b/Utilities/cmcurl/include/curl/typecheck-gcc.h
index 34d0267..9e14d8a 100644
--- a/Utilities/cmcurl/include/curl/typecheck-gcc.h
+++ b/Utilities/cmcurl/include/curl/typecheck-gcc.h
@@ -317,6 +317,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_SERVICE_NAME || \
(option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
(option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
+ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 || \
(option) == CURLOPT_SSH_KNOWNHOSTS || \
(option) == CURLOPT_SSH_PRIVATE_KEYFILE || \
(option) == CURLOPT_SSH_PUBLIC_KEYFILE || \
@@ -363,6 +364,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_INTERLEAVEDATA || \
(option) == CURLOPT_IOCTLDATA || \
(option) == CURLOPT_OPENSOCKETDATA || \
+ (option) == CURLOPT_PREREQDATA || \
(option) == CURLOPT_PROGRESSDATA || \
(option) == CURLOPT_READDATA || \
(option) == CURLOPT_SEEKDATA || \
diff --git a/Utilities/cmcurl/include/curl/urlapi.h b/Utilities/cmcurl/include/curl/urlapi.h
index 1d70880..a475f91 100644
--- a/Utilities/cmcurl/include/curl/urlapi.h
+++ b/Utilities/cmcurl/include/curl/urlapi.h
@@ -47,7 +47,20 @@ typedef enum {
CURLUE_NO_HOST, /* 14 */
CURLUE_NO_PORT, /* 15 */
CURLUE_NO_QUERY, /* 16 */
- CURLUE_NO_FRAGMENT /* 17 */
+ CURLUE_NO_FRAGMENT, /* 17 */
+ CURLUE_NO_ZONEID, /* 18 */
+ CURLUE_BAD_FILE_URL, /* 19 */
+ CURLUE_BAD_FRAGMENT, /* 20 */
+ CURLUE_BAD_HOSTNAME, /* 21 */
+ CURLUE_BAD_IPV6, /* 22 */
+ CURLUE_BAD_LOGIN, /* 23 */
+ CURLUE_BAD_PASSWORD, /* 24 */
+ CURLUE_BAD_PATH, /* 25 */
+ CURLUE_BAD_QUERY, /* 26 */
+ CURLUE_BAD_SCHEME, /* 27 */
+ CURLUE_BAD_SLASHES, /* 28 */
+ CURLUE_BAD_USER, /* 29 */
+ CURLUE_LAST
} CURLUcode;
typedef enum {
@@ -118,6 +131,12 @@ CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
const char *part, unsigned int flags);
+/*
+ * curl_url_strerror() turns a CURLUcode value into the equivalent human
+ * readable error string. This is useful for printing meaningful error
+ * messages.
+ */
+CURL_EXTERN const char *curl_url_strerror(CURLUcode);
#ifdef __cplusplus
} /* end of extern "C" */
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index d8fd7bd..6cf45ad 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -82,7 +82,7 @@ endif()
# For windows we want to install OPENSSL_LIBRARIES dlls
# and also copy them into the build tree so that testing
# can find them.
-if(CMAKE_USE_OPENSSL AND OPENSSL_FOUND AND WIN32)
+if(CURL_USE_OPENSSL AND OPENSSL_FOUND AND WIN32)
find_file(CMAKE_EAY_DLL NAME libeay32.dll HINTS ${OPENSSL_INCLUDE_DIR}/..)
find_file(CMAKE_SSL_DLL NAME ssleay32.dll HINTS ${OPENSSL_INCLUDE_DIR}/..)
mark_as_advanced(CMAKE_EAY_DLL CMAKE_SSL_DLL)
@@ -120,12 +120,6 @@ endif()
target_link_libraries(${LIB_NAME} PRIVATE ${CURL_LIBS})
-if(0) # This code not needed for building within CMake.
-if(WIN32)
- add_definitions(-D_USRDLL)
-endif()
-endif()
-
set_target_properties(${LIB_NAME} PROPERTIES
COMPILE_DEFINITIONS BUILDING_LIBCURL
OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
@@ -149,6 +143,7 @@ endif()
if(WIN32)
if(BUILD_SHARED_LIBS)
+ set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "_USRDLL")
if(MSVC)
# Add "_imp" as a suffix before the extension to avoid conflicting with
# the statically linked "libcurl.lib"
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
index 763a4aa..fd0bb6c 100644
--- a/Utilities/cmcurl/lib/asyn-ares.c
+++ b/Utilities/cmcurl/lib/asyn-ares.c
@@ -109,7 +109,9 @@ struct thread_data {
struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
parts */
int last_status;
+#ifndef HAVE_CARES_GETADDRINFO
struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
+#endif
};
/* How long we are willing to wait for additional parallel responses after
@@ -341,7 +343,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
nfds = 0;
if(!nfds)
- /* Call ares_process() unconditonally here, even if we simply timed out
+ /* Call ares_process() unconditionally here, even if we simply timed out
above, as otherwise the ares name resolve won't timeout! */
ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
ARES_SOCKET_BAD);
@@ -375,6 +377,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
waitperform(data, 0);
+#ifndef HAVE_CARES_GETADDRINFO
/* Now that we've checked for any last minute results above, see if there are
any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
expires. */
@@ -397,6 +400,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
ares_cancel((ares_channel)data->state.async.resolver);
DEBUGASSERT(res->num_pending == 0);
}
+#endif
if(res && !res->num_pending) {
(void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
diff --git a/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c
index 26635cd..c253cd3 100644
--- a/Utilities/cmcurl/lib/c-hyper.c
+++ b/Utilities/cmcurl/lib/c-hyper.c
@@ -156,13 +156,15 @@ static int hyper_each_header(void *userdata,
Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
- writetype = CLIENTWRITE_HEADER;
- if(data->set.include_header)
- writetype |= CLIENTWRITE_BODY;
- result = Curl_client_write(data, writetype, headp, len);
- if(result) {
- data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
- return HYPER_ITER_BREAK;
+ if(!data->state.hconnect || !data->set.suppress_connect_headers) {
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+ result = Curl_client_write(data, writetype, headp, len);
+ if(result) {
+ data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+ return HYPER_ITER_BREAK;
+ }
}
data->info.header_size += (long)len;
@@ -205,7 +207,8 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
k->exp100 = EXP100_FAILED;
}
}
- if(data->state.hconnect && (data->req.httpcode/100 != 2)) {
+ if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
+ data->state.authproxy.done) {
done = TRUE;
result = CURLE_OK;
}
@@ -260,6 +263,12 @@ static CURLcode status_line(struct Curl_easy *data,
if(http_version == HYPER_HTTP_VERSION_1_0)
data->state.httpwant = CURL_HTTP_VERSION_1_0;
+ if(data->state.hconnect)
+ /* CONNECT */
+ data->info.httpproxycode = http_status;
+
+ /* We need to set 'httpcodeq' for functions that check the response code in
+ a single place. */
data->req.httpcode = http_status;
result = Curl_http_statusline(data, conn);
@@ -277,16 +286,18 @@ static CURLcode status_line(struct Curl_easy *data,
len = Curl_dyn_len(&data->state.headerb);
Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
len);
- writetype = CLIENTWRITE_HEADER;
- if(data->set.include_header)
- writetype |= CLIENTWRITE_BODY;
- result = Curl_client_write(data, writetype,
- Curl_dyn_ptr(&data->state.headerb), len);
- if(result) {
- data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
- return HYPER_ITER_BREAK;
- }
+ if(!data->state.hconnect || !data->set.suppress_connect_headers) {
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+ result = Curl_client_write(data, writetype,
+ Curl_dyn_ptr(&data->state.headerb), len);
+ if(result) {
+ data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+ return HYPER_ITER_BREAK;
+ }
+ }
data->info.header_size += (long)len;
data->req.headerbytecount += (long)len;
data->req.httpcode = http_status;
@@ -299,8 +310,14 @@ static CURLcode status_line(struct Curl_easy *data,
*/
static CURLcode empty_header(struct Curl_easy *data)
{
- return hyper_each_header(data, NULL, 0, NULL, 0) ?
- CURLE_WRITE_ERROR : CURLE_OK;
+ CURLcode result = Curl_http_size(data);
+ if(!result) {
+ result = hyper_each_header(data, NULL, 0, NULL, 0) ?
+ CURLE_WRITE_ERROR : CURLE_OK;
+ if(result)
+ failf(data, "hyperstream: couldn't pass blank header");
+ }
+ return result;
}
CURLcode Curl_hyper_stream(struct Curl_easy *data,
@@ -443,11 +460,9 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
break;
}
- if(empty_header(data)) {
- failf(data, "hyperstream: couldn't pass blank header");
- result = CURLE_OUT_OF_MEMORY;
+ result = empty_header(data);
+ if(result)
break;
- }
/* Curl_http_auth_act() checks what authentication methods that are
* available and decides which one (if any) to use. It will set 'newurl'
@@ -584,9 +599,22 @@ static CURLcode request_target(struct Curl_easy *data,
if(result)
return result;
- if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
- Curl_dyn_len(&r))) {
- failf(data, "error setting path");
+ if(h2 && hyper_request_set_uri_parts(req,
+ /* scheme */
+ (uint8_t *)data->state.up.scheme,
+ strlen(data->state.up.scheme),
+ /* authority */
+ (uint8_t *)conn->host.name,
+ strlen(conn->host.name),
+ /* path_and_query */
+ (uint8_t *)Curl_dyn_uptr(&r),
+ Curl_dyn_len(&r))) {
+ failf(data, "error setting uri parts to hyper");
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else if(!h2 && hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
+ Curl_dyn_len(&r))) {
+ failf(data, "error setting uri to hyper");
result = CURLE_OUT_OF_MEMORY;
}
else
@@ -850,6 +878,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
io = hyper_io_new();
if(!io) {
failf(data, "Couldn't create hyper IO");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
/* tell Hyper how to read/write network data */
@@ -862,6 +891,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
h->exec = hyper_executor_new();
if(!h->exec) {
failf(data, "Couldn't create hyper executor");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
}
@@ -869,6 +899,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
options = hyper_clientconn_options_new();
if(!options) {
failf(data, "Couldn't create hyper client options");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(conn->negnpn == CURL_HTTP_VERSION_2) {
@@ -882,6 +913,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
handshake = hyper_clientconn_handshake(io, options);
if(!handshake) {
failf(data, "Couldn't create hyper client handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
io = NULL;
@@ -889,6 +921,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
failf(data, "Couldn't hyper_executor_push the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
handshake = NULL; /* ownership passed on */
@@ -896,6 +929,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
task = hyper_executor_poll(h->exec);
if(!task) {
failf(data, "Couldn't hyper_executor_poll the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -905,6 +939,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
req = hyper_request_new();
if(!req) {
failf(data, "Couldn't hyper_request_new");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -912,12 +947,14 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(HYPERE_OK != hyper_request_set_version(req,
HYPER_HTTP_VERSION_1_0)) {
failf(data, "error setting HTTP version");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
}
if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
failf(data, "error setting method");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -928,51 +965,81 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
headers = hyper_request_headers(req);
if(!headers) {
failf(data, "hyper_request_headers");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
rc = hyper_request_on_informational(req, http1xx_cb, data);
- if(rc)
- return CURLE_OUT_OF_MEMORY;
+ if(rc) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
result = Curl_http_body(data, conn, httpreq, &te);
if(result)
- return result;
-
- if(data->state.aptr.host &&
- Curl_hyper_header(data, headers, data->state.aptr.host))
goto error;
- if(data->state.aptr.proxyuserpwd &&
- Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
- goto error;
+ if(!h2) {
+ if(data->state.aptr.host) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.host);
+ if(result)
+ goto error;
+ }
+ }
+ else {
+ /* For HTTP/2, we show the Host: header as if we sent it, to make it look
+ like for HTTP/1 but it isn't actually sent since :authority is then
+ used. */
+ result = Curl_debug(data, CURLINFO_HEADER_OUT, data->state.aptr.host,
+ strlen(data->state.aptr.host));
+ if(result)
+ goto error;
+ }
- if(data->state.aptr.userpwd &&
- Curl_hyper_header(data, headers, data->state.aptr.userpwd))
- goto error;
+ if(data->state.aptr.proxyuserpwd) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
+ if(result)
+ goto error;
+ }
- if((data->state.use_range && data->state.aptr.rangeline) &&
- Curl_hyper_header(data, headers, data->state.aptr.rangeline))
- goto error;
+ if(data->state.aptr.userpwd) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
+ if(result)
+ goto error;
+ }
+
+ if((data->state.use_range && data->state.aptr.rangeline)) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
+ if(result)
+ goto error;
+ }
if(data->set.str[STRING_USERAGENT] &&
*data->set.str[STRING_USERAGENT] &&
- data->state.aptr.uagent &&
- Curl_hyper_header(data, headers, data->state.aptr.uagent))
- goto error;
+ data->state.aptr.uagent) {
+ result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
+ if(result)
+ goto error;
+ }
p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
- if(p_accept && Curl_hyper_header(data, headers, p_accept))
- goto error;
-
- if(te && Curl_hyper_header(data, headers, te))
- goto error;
+ if(p_accept) {
+ result = Curl_hyper_header(data, headers, p_accept);
+ if(result)
+ goto error;
+ }
+ if(te) {
+ result = Curl_hyper_header(data, headers, te);
+ if(result)
+ goto error;
+ }
#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
!Curl_checkheaders(data, "Proxy-Connection") &&
!Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
- if(Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
+ result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
+ if(result)
goto error;
}
#endif
@@ -981,8 +1048,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
if(!data->state.aptr.ref)
- return CURLE_OUT_OF_MEMORY;
- if(Curl_hyper_header(data, headers, data->state.aptr.ref))
+ result = CURLE_OUT_OF_MEMORY;
+ else
+ result = Curl_hyper_header(data, headers, data->state.aptr.ref);
+ if(result)
goto error;
}
@@ -992,8 +1061,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
if(!data->state.aptr.accept_encoding)
- return CURLE_OUT_OF_MEMORY;
- if(Curl_hyper_header(data, headers, data->state.aptr.accept_encoding))
+ result = CURLE_OUT_OF_MEMORY;
+ else
+ result = Curl_hyper_header(data, headers,
+ data->state.aptr.accept_encoding);
+ if(result)
goto error;
}
else
@@ -1003,38 +1075,43 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* we only consider transfer-encoding magic if libz support is built-in */
result = Curl_transferencode(data);
if(result)
- return result;
- if(Curl_hyper_header(data, headers, data->state.aptr.te))
+ goto error;
+ result = Curl_hyper_header(data, headers, data->state.aptr.te);
+ if(result)
goto error;
#endif
result = cookies(data, conn, headers);
if(result)
- return result;
+ goto error;
result = Curl_add_timecondition(data, headers);
if(result)
- return result;
+ goto error;
result = Curl_add_custom_headers(data, FALSE, headers);
if(result)
- return result;
+ goto error;
result = bodysend(data, conn, headers, req, httpreq);
if(result)
- return result;
+ goto error;
- Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
+ result = Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
+ if(result)
+ goto error;
data->req.upload_chunky = FALSE;
sendtask = hyper_clientconn_send(client, req);
if(!sendtask) {
failf(data, "hyper_clientconn_send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
failf(data, "Couldn't hyper_executor_push the send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -1057,7 +1134,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
Curl_safefree(data->state.aptr.proxyuserpwd);
return CURLE_OK;
error:
-
+ DEBUGASSERT(result);
if(io)
hyper_io_free(io);
@@ -1067,7 +1144,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(handshake)
hyper_task_free(handshake);
- return CURLE_OUT_OF_MEMORY;
+ return result;
}
void Curl_hyper_done(struct Curl_easy *data)
diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
index f5ba8ff..fec1937 100644
--- a/Utilities/cmcurl/lib/conncache.c
+++ b/Utilities/cmcurl/lib/conncache.c
@@ -113,21 +113,16 @@ static void free_bundle_hash_entry(void *freethis)
int Curl_conncache_init(struct conncache *connc, int size)
{
- int rc;
-
/* allocate a new easy handle to use when closing cached connections */
connc->closure_handle = curl_easy_init();
if(!connc->closure_handle)
return 1; /* bad */
- rc = Curl_hash_init(&connc->hash, size, Curl_hash_str,
- Curl_str_key_compare, free_bundle_hash_entry);
- if(rc)
- Curl_close(&connc->closure_handle);
- else
- connc->closure_handle->state.conn_cache = connc;
+ Curl_hash_init(&connc->hash, size, Curl_hash_str,
+ Curl_str_key_compare, free_bundle_hash_entry);
+ connc->closure_handle->state.conn_cache = connc;
- return rc;
+ return 0; /* good */
}
void Curl_conncache_destroy(struct conncache *connc)
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index d61b037..5252f97 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -85,7 +85,7 @@
static bool verifyconnect(curl_socket_t sockfd, int *error);
-#if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
+#if defined(__DragonFly__) || defined(HAVE_WINSOCK2_H)
/* DragonFlyBSD and Windows use millisecond units */
#define KEEPALIVE_FACTOR(x) (x *= 1000)
#else
@@ -629,7 +629,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
#ifdef ENABLE_IPV6
struct sockaddr_in6 *si6 = NULL;
#endif
-#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
struct sockaddr_un *su = NULL;
#else
(void)salen;
@@ -656,7 +656,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
}
break;
#endif
-#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
case AF_UNIX:
if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
su = (struct sockaddr_un*)sa;
@@ -894,6 +894,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
connkeep(conn, "HTTP/3 default");
return CURLE_OK;
}
+ /* When a QUIC connect attempt fails, the better error explanation is in
+ 'result' and not in errno */
if(result) {
conn->tempsock[i] = CURL_SOCKET_BAD;
error = SOCKERRNO;
@@ -977,6 +979,13 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
char buffer[STRERROR_LEN];
Curl_printable_address(conn->tempaddr[i], ipaddress,
sizeof(ipaddress));
+#ifdef ENABLE_QUIC
+ if(conn->transport == TRNSPRT_QUIC) {
+ infof(data, "connect to %s port %u failed: %s",
+ ipaddress, conn->port, curl_easy_strerror(result));
+ }
+ else
+#endif
infof(data, "connect to %s port %u failed: %s",
ipaddress, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
@@ -988,9 +997,11 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
ainext(conn, i, TRUE);
status = trynextip(data, conn, sockindex, i);
if((status != CURLE_COULDNT_CONNECT) ||
- conn->tempsock[other] == CURL_SOCKET_BAD)
+ conn->tempsock[other] == CURL_SOCKET_BAD) {
/* the last attempt failed and no other sockets remain open */
- result = status;
+ if(!result)
+ result = status;
+ }
}
}
}
@@ -1016,6 +1027,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
/* no more addresses to try */
const char *hostname;
char buffer[STRERROR_LEN];
+ CURLcode failreason = result;
/* if the first address family runs out of addresses to try before the
happy eyeball timeout, go ahead and try the next family now */
@@ -1023,6 +1035,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
if(!result)
return result;
+ result = failreason;
+
#ifndef CURL_DISABLE_PROXY
if(conn->bits.socksproxy)
hostname = conn->socks_proxy.host.name;
@@ -1036,10 +1050,14 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
hostname = conn->host.name;
failf(data, "Failed to connect to %s port %u after "
- "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
- hostname, conn->port,
- Curl_timediff(now, data->progress.t_startsingle),
- Curl_strerror(error, buffer, sizeof(buffer)));
+ "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
+ hostname, conn->port,
+ Curl_timediff(now, data->progress.t_startsingle),
+#ifdef ENABLE_QUIC
+ (conn->transport == TRNSPRT_QUIC) ?
+ curl_easy_strerror(result) :
+#endif
+ Curl_strerror(error, buffer, sizeof(buffer)));
Curl_quic_disconnect(data, conn, 0);
Curl_quic_disconnect(data, conn, 1);
@@ -1127,7 +1145,7 @@ void Curl_sndbufset(curl_socket_t sockfd)
static int detectOsState = DETECT_OS_NONE;
if(detectOsState == DETECT_OS_NONE) {
- if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT,
+ if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL))
detectOsState = DETECT_OS_VISTA_OR_LATER;
else
diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c
index a84ff54..c03637a 100644
--- a/Utilities/cmcurl/lib/content_encoding.c
+++ b/Utilities/cmcurl/lib/content_encoding.c
@@ -240,7 +240,8 @@ static CURLcode inflate_stream(struct Curl_easy *data,
}
zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */
}
- /* FALLTHROUGH */
+ result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
+ break;
default:
result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
break;
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index b7531f7..d418efa 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/cookie.c
@@ -1164,7 +1164,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
bool fromfile = TRUE;
char *line = NULL;
- if(NULL == inc) {
+ if(!inc) {
/* we didn't get a struct, create one */
c = calloc(1, sizeof(struct CookieInfo));
if(!c)
diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
index de03550..6349ec3 100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -702,9 +702,6 @@
/* Define to 1 if you have the winsock2.h header file. */
#cmakedefine HAVE_WINSOCK2_H 1
-/* Define to 1 if you have the winsock.h header file. */
-#cmakedefine HAVE_WINSOCK_H 1
-
/* Define this symbol if your OS supports changing the contents of argv */
#cmakedefine HAVE_WRITABLE_ARGV 1
diff --git a/Utilities/cmcurl/lib/curl_des.c b/Utilities/cmcurl/lib/curl_des.c
index 8c5af19..76185cb 100644
--- a/Utilities/cmcurl/lib/curl_des.c
+++ b/Utilities/cmcurl/lib/curl_des.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2015 - 2020, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2015 - 2021, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,7 +22,7 @@
#include "curl_setup.h"
-#if defined(USE_NTLM) && !defined(USE_OPENSSL)
+#if defined(USE_NTLM) && !defined(USE_OPENSSL) && !defined(USE_WOLFSSL)
#include "curl_des.h"
diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c
index 5810dad..8f34056 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.c
+++ b/Utilities/cmcurl/lib/curl_gssapi.c
@@ -32,10 +32,12 @@
#include "curl_memory.h"
#include "memdebug.h"
-static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02";
-gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes };
-static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02";
-gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes };
+gss_OID_desc Curl_spnego_mech_oid = {
+ 6, (char *)"\x2b\x06\x01\x05\x05\x02"
+};
+gss_OID_desc Curl_krb5_mech_oid = {
+ 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
+};
OM_uint32 Curl_gss_init_sec_context(
struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/curl_hmac.h b/Utilities/cmcurl/lib/curl_hmac.h
index 84c7312..5755655 100644
--- a/Utilities/cmcurl/lib/curl_hmac.h
+++ b/Utilities/cmcurl/lib/curl_hmac.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,7 +26,7 @@
#define HMAC_MD5_LENGTH 16
-typedef void (* HMAC_hinit_func)(void *context);
+typedef CURLcode (* HMAC_hinit_func)(void *context);
typedef void (* HMAC_hupdate_func)(void *context,
const unsigned char *data,
unsigned int len);
diff --git a/Utilities/cmcurl/lib/curl_md5.h b/Utilities/cmcurl/lib/curl_md5.h
index 5739c89..b7d7c1f 100644
--- a/Utilities/cmcurl/lib/curl_md5.h
+++ b/Utilities/cmcurl/lib/curl_md5.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -27,7 +27,7 @@
#define MD5_DIGEST_LEN 16
-typedef void (* Curl_MD5_init_func)(void *context);
+typedef CURLcode (* Curl_MD5_init_func)(void *context);
typedef void (* Curl_MD5_update_func)(void *context,
const unsigned char *data,
unsigned int len);
@@ -49,8 +49,8 @@ struct MD5_context {
extern const struct MD5_params Curl_DIGEST_MD5[1];
extern const struct HMAC_params Curl_HMAC_MD5[1];
-void Curl_md5it(unsigned char *output, const unsigned char *input,
- const size_t len);
+CURLcode Curl_md5it(unsigned char *output, const unsigned char *input,
+ const size_t len);
struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params);
CURLcode Curl_MD5_update(struct MD5_context *context,
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
index 749b44e..ed123d0 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.c
@@ -49,7 +49,14 @@
in NTLM type-3 messages.
*/
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL)
+ #include <openssl/opensslconf.h>
+ #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+ #define USE_OPENSSL_DES
+ #endif
+#endif
+
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
#ifdef USE_WOLFSSL
#include <wolfssl/options.h>
@@ -97,7 +104,7 @@
#elif defined(USE_WIN32_CRYPTO)
# include <wincrypt.h>
#else
-# error "Can't compile NTLM support without a crypto library."
+# error "Can't compile NTLM support without a crypto library with DES."
#endif
#include "urldata.h"
@@ -133,7 +140,7 @@ static void extend_key_56_to_64(const unsigned char *key_56, char *key)
key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
}
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
/*
* Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
* key schedule ks is also set.
@@ -150,7 +157,7 @@ static void setup_des_key(const unsigned char *key_56,
DES_set_odd_parity(&key);
/* Set the key */
- DES_set_key(&key, ks);
+ DES_set_key_unchecked(&key, ks);
}
#elif defined(USE_GNUTLS)
@@ -362,7 +369,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
const unsigned char *plaintext,
unsigned char *results)
{
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
DES_key_schedule ks;
setup_des_key(keys, DESKEY(ks));
@@ -420,7 +427,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
{
/* Create LanManager hashed password. */
-#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
DES_key_schedule ks;
setup_des_key(pw, DESKEY(ks));
diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c
index 4a24887..8d39e4f 100644
--- a/Utilities/cmcurl/lib/curl_sasl.c
+++ b/Utilities/cmcurl/lib/curl_sasl.c
@@ -56,8 +56,8 @@
/* Supported mechanisms */
static const struct {
- const char *name; /* Name */
- size_t len; /* Name length */
+ const char *name; /* Name */
+ size_t len; /* Name length */
unsigned short bit; /* Flag bit */
} mechtable[] = {
{ "LOGIN", 5, SASL_MECH_LOGIN },
@@ -85,8 +85,11 @@ static const struct {
* conn [in] - The connection data.
* authused [in] - The authentication mechanism used.
*/
-void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
{
+ (void)conn;
+ (void)authused;
+
#if defined(USE_KERBEROS5)
/* Cleanup the gssapi structure */
if(authused == SASL_MECH_GSSAPI) {
@@ -107,12 +110,6 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
Curl_auth_cleanup_ntlm(&conn->ntlm);
}
#endif
-
-#if !defined(USE_KERBEROS5) && !defined(USE_NTLM)
- /* Reserved for future use */
- (void)conn;
- (void)authused;
-#endif
}
/*
@@ -189,16 +186,35 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
*
* Initializes the SASL structure.
*/
-void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
+void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
+ const struct SASLproto *params)
{
+ unsigned long auth = data->set.httpauth;
+
sasl->params = params; /* Set protocol dependent parameters */
sasl->state = SASL_STOP; /* Not yet running */
+ sasl->curmech = NULL; /* No mechanism yet. */
sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
- sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */
- sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */
+ sasl->prefmech = params->defmechs; /* Default preferred mechanisms */
+ sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */
sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
sasl->force_ir = FALSE; /* Respect external option */
+
+ if(auth != CURLAUTH_BASIC) {
+ sasl->resetprefs = FALSE;
+ sasl->prefmech = SASL_AUTH_NONE;
+ if(auth & CURLAUTH_BASIC)
+ sasl->prefmech |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
+ if(auth & CURLAUTH_DIGEST)
+ sasl->prefmech |= SASL_MECH_DIGEST_MD5;
+ if(auth & CURLAUTH_NTLM)
+ sasl->prefmech |= SASL_MECH_NTLM;
+ if(auth & CURLAUTH_BEARER)
+ sasl->prefmech |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
+ if(auth & CURLAUTH_GSSAPI)
+ sasl->prefmech |= SASL_MECH_GSSAPI;
+ }
}
/*
@@ -247,40 +263,45 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
struct bufref *out)
{
- unsigned char *msg;
- size_t msglen;
- char *serverdata = NULL;
CURLcode result = CURLE_OK;
- sasl->params->getmessage(data->state.buffer, &serverdata);
- if(!serverdata)
- result = CURLE_BAD_CONTENT_ENCODING;
- else if(!*serverdata || *serverdata == '=')
- Curl_bufref_set(out, NULL, 0, NULL);
- else {
- result = Curl_base64_decode(serverdata, &msg, &msglen);
- if(!result)
- Curl_bufref_set(out, msg, msglen, curl_free);
+ result = sasl->params->getmessage(data, out);
+ if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
+ unsigned char *msg;
+ size_t msglen;
+ const char *serverdata = (const char *) Curl_bufref_ptr(out);
+
+ if(!*serverdata || *serverdata == '=')
+ Curl_bufref_set(out, NULL, 0, NULL);
+ else {
+ result = Curl_base64_decode(serverdata, &msg, &msglen);
+ if(!result)
+ Curl_bufref_set(out, msg, msglen, curl_free);
+ }
}
return result;
}
/* Encode the outgoing SASL message. */
-static CURLcode build_message(struct Curl_easy *data, struct bufref *msg)
+static CURLcode build_message(struct SASL *sasl, struct Curl_easy *data,
+ struct bufref *msg)
{
CURLcode result = CURLE_OK;
- char *base64;
- size_t base64len;
- if(!Curl_bufref_ptr(msg)) /* Empty mesage. */
- Curl_bufref_set(msg, "", 0, NULL);
- else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
- Curl_bufref_set(msg, "=", 1, NULL);
- else {
- result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg),
- Curl_bufref_len(msg), &base64, &base64len);
- if(!result)
- Curl_bufref_set(msg, base64, base64len, curl_free);
+ if(sasl->params->flags & SASL_FLAG_BASE64) {
+ if(!Curl_bufref_ptr(msg)) /* Empty message. */
+ Curl_bufref_set(msg, "", 0, NULL);
+ else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
+ Curl_bufref_set(msg, "=", 1, NULL);
+ else {
+ char *base64;
+ size_t base64len;
+
+ result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg),
+ Curl_bufref_len(msg), &base64, &base64len);
+ if(!result)
+ Curl_bufref_set(msg, base64, base64len, curl_free);
+ }
}
return result;
@@ -310,11 +331,11 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
* Calculate the required login details for SASL authentication.
*/
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
- struct connectdata *conn,
bool force_ir, saslprogress *progress)
{
CURLcode result = CURLE_OK;
- unsigned int enabledmechs;
+ struct connectdata *conn = data->conn;
+ unsigned short enabledmechs;
const char *mech = NULL;
struct bufref resp;
saslstate state1 = SASL_STOP;
@@ -471,16 +492,16 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
}
if(!result && mech) {
+ sasl->curmech = mech;
if(Curl_bufref_ptr(&resp))
- result = build_message(data, &resp);
+ result = build_message(sasl, data, &resp);
if(sasl->params->maxirlen &&
strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
Curl_bufref_free(&resp);
if(!result)
- result = sasl->params->sendauth(data, conn, mech,
- (const char *) Curl_bufref_ptr(&resp));
+ result = sasl->params->sendauth(data, mech, &resp);
if(!result) {
*progress = SASL_INPROGRESS;
@@ -498,10 +519,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
* Continue the authentication.
*/
CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
- struct connectdata *conn,
int code, saslprogress *progress)
{
CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
saslstate newstate = SASL_FINAL;
struct bufref resp;
const char * const hostname = SSL_HOST_NAME();
@@ -574,7 +595,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_digest_md5_message(data, &serverdata,
conn->user, conn->passwd,
service, &resp);
- newstate = SASL_DIGESTMD5_RESP;
+ if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
+ newstate = SASL_DIGESTMD5_RESP;
break;
case SASL_DIGESTMD5_RESP:
/* Keep response NULL to output an empty line. */
@@ -691,7 +713,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
sasl->authmechs ^= sasl->authused;
/* Start an alternative SASL authentication */
- return Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
+ return Curl_sasl_start(sasl, data, sasl->force_ir, progress);
default:
failf(data, "Unsupported SASL authentication mechanism");
result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
@@ -703,14 +725,13 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
switch(result) {
case CURLE_BAD_CONTENT_ENCODING:
/* Cancel dialog */
- result = sasl->params->sendcont(data, conn, "*");
+ result = sasl->params->cancelauth(data, sasl->curmech);
newstate = SASL_CANCEL;
break;
case CURLE_OK:
- result = build_message(data, &resp);
+ result = build_message(sasl, data, &resp);
if(!result)
- result = sasl->params->sendcont(data, conn,
- (const char *) Curl_bufref_ptr(&resp));
+ result = sasl->params->contauth(data, sasl->curmech, &resp);
break;
default:
newstate = SASL_STOP; /* Stop on error */
diff --git a/Utilities/cmcurl/lib/curl_sasl.h b/Utilities/cmcurl/lib/curl_sasl.h
index e17d323..91458c7 100644
--- a/Utilities/cmcurl/lib/curl_sasl.h
+++ b/Utilities/cmcurl/lib/curl_sasl.h
@@ -24,6 +24,8 @@
#include <curl/curl.h>
+#include "bufref.h"
+
struct Curl_easy;
struct connectdata;
@@ -46,17 +48,20 @@ struct connectdata;
#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
/* Authentication mechanism strings */
-#define SASL_MECH_STRING_LOGIN "LOGIN"
-#define SASL_MECH_STRING_PLAIN "PLAIN"
-#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5"
-#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
-#define SASL_MECH_STRING_GSSAPI "GSSAPI"
-#define SASL_MECH_STRING_EXTERNAL "EXTERNAL"
-#define SASL_MECH_STRING_NTLM "NTLM"
-#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2"
-#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER"
-#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1"
-#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256"
+#define SASL_MECH_STRING_LOGIN "LOGIN"
+#define SASL_MECH_STRING_PLAIN "PLAIN"
+#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5"
+#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
+#define SASL_MECH_STRING_GSSAPI "GSSAPI"
+#define SASL_MECH_STRING_EXTERNAL "EXTERNAL"
+#define SASL_MECH_STRING_NTLM "NTLM"
+#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2"
+#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER"
+#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1"
+#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256"
+
+/* SASL flags */
+#define SASL_FLAG_BASE64 0x0001 /* Messages are base64-encoded */
/* SASL machine states */
typedef enum {
@@ -90,30 +95,37 @@ typedef enum {
/* Protocol dependent SASL parameters */
struct SASLproto {
const char *service; /* The service name */
- int contcode; /* Code to receive when continuation is expected */
- int finalcode; /* Code to receive upon authentication success */
- size_t maxirlen; /* Maximum initial response length */
- CURLcode (*sendauth)(struct Curl_easy *data,
- struct connectdata *conn,
- const char *mech, const char *ir);
+ CURLcode (*sendauth)(struct Curl_easy *data, const char *mech,
+ const struct bufref *ir);
/* Send authentication command */
- CURLcode (*sendcont)(struct Curl_easy *data,
- struct connectdata *conn, const char *contauth);
+ CURLcode (*contauth)(struct Curl_easy *data, const char *mech,
+ const struct bufref *contauth);
/* Send authentication continuation */
- void (*getmessage)(char *buffer, char **outptr);
+ CURLcode (*cancelauth)(struct Curl_easy *data, const char *mech);
+ /* Cancel authentication. */
+ CURLcode (*getmessage)(struct Curl_easy *data, struct bufref *out);
/* Get SASL response message */
+ size_t maxirlen; /* Maximum initial response + mechanism length,
+ or zero if no max. This is normally the max
+ command length - other characters count.
+ This has to be zero for non-base64 protocols. */
+ int contcode; /* Code to receive when continuation is expected */
+ int finalcode; /* Code to receive upon authentication success */
+ unsigned short defmechs; /* Mechanisms enabled by default */
+ unsigned short flags; /* Configuration flags. */
};
/* Per-connection parameters */
struct SASL {
const struct SASLproto *params; /* Protocol dependent parameters */
- saslstate state; /* Current machine state */
+ saslstate state; /* Current machine state */
+ const char *curmech; /* Current mechanism id. */
unsigned short authmechs; /* Accepted authentication mechanisms */
unsigned short prefmech; /* Preferred authentication mechanism */
unsigned short authused; /* Auth mechanism used for the connection */
- bool resetprefs; /* For URL auth option parsing. */
- bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */
- bool force_ir; /* Protocol always supports initial response */
+ bool resetprefs; /* For URL auth option parsing. */
+ bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */
+ bool force_ir; /* Protocol always supports initial response */
};
/* This is used to test whether the line starts with the given mechanism */
@@ -123,7 +135,7 @@ struct SASL {
/* This is used to cleanup any libraries or curl modules used by the sasl
functions */
-void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused);
/* Convert a mechanism name to a token */
unsigned short Curl_sasl_decode_mech(const char *ptr,
@@ -134,19 +146,18 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
const char *value, size_t len);
/* Initializes an SASL structure */
-void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params);
+void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
+ const struct SASLproto *params);
/* Check if we have enough auth data and capabilities to authenticate */
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
/* Calculate the required login details for SASL authentication */
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
- struct connectdata *conn,
bool force_ir, saslprogress *progress);
/* Continue an SASL authentication */
CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
- struct connectdata *conn,
int code, saslprogress *progress);
#endif /* HEADER_CURL_SASL_H */
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index 554dcc1..7421b67 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -732,7 +732,6 @@ int netware_init(void);
#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
# if defined(SOCKET) || \
defined(USE_WINSOCK) || \
- defined(HAVE_WINSOCK_H) || \
defined(HAVE_WINSOCK2_H) || \
defined(HAVE_WS2TCPIP_H)
# error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
@@ -854,6 +853,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
ADDRESS_FAMILY sun_family;
char sun_path[UNIX_PATH_MAX];
} SOCKADDR_UN, *PSOCKADDR_UN;
+# define WIN32_SOCKADDR_UN
# endif
#endif
diff --git a/Utilities/cmcurl/lib/curl_sha256.h b/Utilities/cmcurl/lib/curl_sha256.h
index b4579d7..55dc30a 100644
--- a/Utilities/cmcurl/lib/curl_sha256.h
+++ b/Utilities/cmcurl/lib/curl_sha256.h
@@ -8,7 +8,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2017, Florin Petriuc, <petriuc.florin@gmail.com>
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -28,10 +28,17 @@
extern const struct HMAC_params Curl_HMAC_SHA256[1];
+#ifdef USE_WOLFSSL
+/* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from
+ * sha.h*/
+#include <wolfssl/options.h>
+#include <openssl/sha.h>
+#else
#define SHA256_DIGEST_LENGTH 32
+#endif
-void Curl_sha256it(unsigned char *outbuffer, const unsigned char *input,
- const size_t len);
+CURLcode Curl_sha256it(unsigned char *outbuffer, const unsigned char *input,
+ const size_t len);
#endif
diff --git a/Utilities/cmcurl/lib/curl_sspi.c b/Utilities/cmcurl/lib/curl_sspi.c
index 06841dd..339bf54 100644
--- a/Utilities/cmcurl/lib/curl_sspi.c
+++ b/Utilities/cmcurl/lib/curl_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -83,7 +83,7 @@ CURLcode Curl_sspi_global_init(void)
* have both these DLLs (security.dll forwards calls to secur32.dll) */
/* Load SSPI dll into the address space of the calling process */
- if(curlx_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL))
+ if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL))
s_hSecDll = Curl_load_library(TEXT("security.dll"));
else
s_hSecDll = Curl_load_library(TEXT("secur32.dll"));
diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c
index de0c902..d6a2167 100644
--- a/Utilities/cmcurl/lib/doh.c
+++ b/Utilities/cmcurl/lib/doh.c
@@ -235,25 +235,6 @@ static CURLcode dohprobe(struct Curl_easy *data,
p->dnstype = dnstype;
Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
- /* Note: this is code for sending the DoH request with GET but there's still
- no logic that actually enables this. We should either add that ability or
- yank out the GET code. Discuss! */
- if(data->set.doh_get) {
- char *b64;
- size_t b64len;
- result = Curl_base64url_encode(data, (char *)p->dohbuffer, p->dohlen,
- &b64, &b64len);
- if(result)
- goto error;
- nurl = aprintf("%s?dns=%s", url, b64);
- free(b64);
- if(!nurl) {
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- url = nurl;
- }
-
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms <= 0) {
result = CURLE_OPERATION_TIMEDOUT;
@@ -268,10 +249,8 @@ static CURLcode dohprobe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_URL, url);
ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
- if(!data->set.doh_get) {
- ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
- ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
- }
+ ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
+ ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
#ifdef USE_NGHTTP2
ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index 2aca938..20293a7 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/easy.c
@@ -822,7 +822,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
{
struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
- if(NULL == outcurl)
+ if(!outcurl)
goto fail;
/*
@@ -1087,14 +1087,16 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
/* if not pausing again, force a recv/send check of this connection as
the data might've been read off the socket already */
data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
- if(data->multi)
- Curl_update_timer(data->multi);
+ if(data->multi) {
+ if(Curl_update_timer(data->multi))
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
}
if(!data->state.done)
/* This transfer may have been moved in or out of the bundle, update the
corresponding socket callback, if used */
- Curl_updatesocket(data);
+ result = Curl_updatesocket(data);
return result;
}
diff --git a/Utilities/cmcurl/lib/easyoptions.c b/Utilities/cmcurl/lib/easyoptions.c
index 4e65e35..04871ad 100644
--- a/Utilities/cmcurl/lib/easyoptions.c
+++ b/Utilities/cmcurl/lib/easyoptions.c
@@ -165,10 +165,12 @@ struct curl_easyoption Curl_easyopts[] = {
{"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0},
{"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0},
{"MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE, CURLOT_OFF_T, 0},
+ {"MAXLIFETIME_CONN", CURLOPT_MAXLIFETIME_CONN, CURLOT_LONG, 0},
{"MAXREDIRS", CURLOPT_MAXREDIRS, CURLOT_LONG, 0},
{"MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE, CURLOT_OFF_T, 0},
{"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0},
{"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0},
+ {"MIME_OPTIONS", CURLOPT_MIME_OPTIONS, CURLOT_LONG, 0},
{"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0},
{"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0},
{"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS, CURLOT_LONG, 0},
@@ -192,6 +194,8 @@ struct curl_easyoption Curl_easyopts[] = {
{"POSTQUOTE", CURLOPT_POSTQUOTE, CURLOT_SLIST, 0},
{"POSTREDIR", CURLOPT_POSTREDIR, CURLOT_VALUES, 0},
{"PREQUOTE", CURLOPT_PREQUOTE, CURLOT_SLIST, 0},
+ {"PREREQDATA", CURLOPT_PREREQDATA, CURLOT_CBPTR, 0},
+ {"PREREQFUNCTION", CURLOPT_PREREQFUNCTION, CURLOT_FUNCTION, 0},
{"PRE_PROXY", CURLOPT_PRE_PROXY, CURLOT_STRING, 0},
{"PRIVATE", CURLOPT_PRIVATE, CURLOT_OBJECT, 0},
{"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS},
@@ -271,6 +275,8 @@ struct curl_easyoption Curl_easyopts[] = {
{"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0},
{"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
CURLOT_STRING, 0},
+ {"SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
+ CURLOT_STRING, 0},
{"SSH_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0},
{"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
{"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
@@ -354,6 +360,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
- return ((CURLOPT_LASTENTRY%10000) != (310 + 1));
+ return ((CURLOPT_LASTENTRY%10000) != (315 + 1));
}
#endif
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index cad584f..5c39edb 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -876,11 +876,6 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data,
ftpc->count2 = 0; /* count2 counts failed CWDs */
- /* count3 is set to allow a MKD to fail once. In the case when first CWD
- fails and then MKD fails (due to another session raced it to create the
- dir) this then allows for a second try to CWD to it */
- ftpc->count3 = (data->set.ftp_create_missing_dirs == 2)?1:0;
-
if(conn->bits.reuse && ftpc->entrypath &&
/* no need to go to entrypath when we have an absolute path */
!(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
@@ -1009,7 +1004,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
}
/* parse the port */
- if(ip_end != NULL) {
+ if(ip_end) {
port_start = strchr(ip_end, ':');
if(port_start) {
port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
@@ -3002,6 +2997,12 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
ftpc->cwdcount && !ftpc->count2) {
/* try making it */
ftpc->count2++; /* counter to prevent CWD-MKD loops */
+
+ /* count3 is set to allow MKD to fail once per dir. In the case when
+ CWD fails and then MKD fails (due to another session raced it to
+ create the dir) this then allows for a second try to CWD to it. */
+ ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0;
+
result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s",
ftpc->dirs[ftpc->cwdcount - 1]);
if(!result)
@@ -4102,6 +4103,11 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
return CURLE_OK;
}
+#ifdef _MSC_VER
+/* warning C4706: assignment within conditional expression */
+#pragma warning(disable:4706)
+#endif
+
/***********************************************************************
*
* ftp_parse_url_path()
@@ -4190,7 +4196,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
}
/* parse the URL path into separate path components */
- while((slashPos = strchr(curPos, '/')) != NULL) {
+ while((slashPos = strchr(curPos, '/'))) {
size_t compLen = slashPos - curPos;
/* path starts with a slash: add that as a directory */
@@ -4357,7 +4363,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
struct FTP *ftp;
data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
- if(NULL == ftp)
+ if(!ftp)
return CURLE_OUT_OF_MEMORY;
ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
diff --git a/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c
index 12e7aa5..8848906 100644
--- a/Utilities/cmcurl/lib/hash.c
+++ b/Utilities/cmcurl/lib/hash.c
@@ -53,32 +53,25 @@ hash_element_dtor(void *user, void *element)
* @unittest: 1602
* @unittest: 1603
*/
-int
+void
Curl_hash_init(struct Curl_hash *h,
int slots,
hash_function hfunc,
comp_function comparator,
Curl_hash_dtor dtor)
{
- if(!slots || !hfunc || !comparator ||!dtor) {
- return 1; /* failure */
- }
+ DEBUGASSERT(h);
+ DEBUGASSERT(slots);
+ DEBUGASSERT(hfunc);
+ DEBUGASSERT(comparator);
+ DEBUGASSERT(dtor);
+ h->table = NULL;
h->hash_func = hfunc;
h->comp_func = comparator;
h->dtor = dtor;
h->size = 0;
h->slots = slots;
-
- h->table = malloc(slots * sizeof(struct Curl_llist));
- if(h->table) {
- int i;
- for(i = 0; i < slots; ++i)
- Curl_llist_init(&h->table[i], (Curl_llist_dtor) hash_element_dtor);
- return 0; /* fine */
- }
- h->slots = 0;
- return 1; /* failure */
}
static struct Curl_hash_element *
@@ -98,8 +91,9 @@ mk_hash_element(const void *key, size_t key_len, const void *p)
#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
-/* Insert the data in the hash. If there already was a match in the hash,
- * that data is replaced.
+/* Insert the data in the hash. If there already was a match in the hash, that
+ * data is replaced. This function also "lazily" allocates the table if
+ * needed, as it isn't done in the _init function (anymore).
*
* @unittest: 1305
* @unittest: 1602
@@ -110,7 +104,20 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
{
struct Curl_hash_element *he;
struct Curl_llist_element *le;
- struct Curl_llist *l = FETCH_LIST(h, key, key_len);
+ struct Curl_llist *l;
+
+ DEBUGASSERT(h);
+ DEBUGASSERT(h->slots);
+ if(!h->table) {
+ int i;
+ h->table = malloc(h->slots * sizeof(struct Curl_llist));
+ if(!h->table)
+ return NULL; /* OOM */
+ for(i = 0; i < h->slots; ++i)
+ Curl_llist_init(&h->table[i], hash_element_dtor);
+ }
+
+ l = FETCH_LIST(h, key, key_len);
for(le = l->head; le; le = le->next) {
he = (struct Curl_hash_element *) le->ptr;
@@ -139,14 +146,20 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
{
struct Curl_llist_element *le;
- struct Curl_llist *l = FETCH_LIST(h, key, key_len);
+ struct Curl_llist *l;
- for(le = l->head; le; le = le->next) {
- struct Curl_hash_element *he = le->ptr;
- if(h->comp_func(he->key, he->key_len, key, key_len)) {
- Curl_llist_remove(l, le, (void *) h);
- --h->size;
- return 0;
+ DEBUGASSERT(h);
+ DEBUGASSERT(h->slots);
+ if(h->table) {
+ l = FETCH_LIST(h, key, key_len);
+
+ for(le = l->head; le; le = le->next) {
+ struct Curl_hash_element *he = le->ptr;
+ if(h->comp_func(he->key, he->key_len, key, key_len)) {
+ Curl_llist_remove(l, le, (void *) h);
+ --h->size;
+ return 0;
+ }
}
}
return 1;
@@ -162,7 +175,9 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
struct Curl_llist_element *le;
struct Curl_llist *l;
- if(h) {
+ DEBUGASSERT(h);
+ if(h->table) {
+ DEBUGASSERT(h->slots);
l = FETCH_LIST(h, key, key_len);
for(le = l->head; le; le = le->next) {
struct Curl_hash_element *he = le->ptr;
@@ -204,13 +219,13 @@ Curl_hash_apply(Curl_hash *h, void *user,
void
Curl_hash_destroy(struct Curl_hash *h)
{
- int i;
-
- for(i = 0; i < h->slots; ++i) {
- Curl_llist_destroy(&h->table[i], (void *) h);
+ if(h->table) {
+ int i;
+ for(i = 0; i < h->slots; ++i) {
+ Curl_llist_destroy(&h->table[i], (void *) h);
+ }
+ Curl_safefree(h->table);
}
-
- Curl_safefree(h->table);
h->size = 0;
h->slots = 0;
}
@@ -235,7 +250,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
struct Curl_llist *list;
int i;
- if(!h)
+ if(!h || !h->table)
return;
for(i = 0; i < h->slots; ++i) {
@@ -290,6 +305,9 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
{
struct Curl_hash *h = iter->hash;
+ if(!h->table)
+ return NULL; /* empty hash, nothing to return */
+
/* Get the next element in the current list, if any */
if(iter->current_element)
iter->current_element = iter->current_element->next;
diff --git a/Utilities/cmcurl/lib/hash.h b/Utilities/cmcurl/lib/hash.h
index b7f828e..e166916 100644
--- a/Utilities/cmcurl/lib/hash.h
+++ b/Utilities/cmcurl/lib/hash.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -69,11 +69,11 @@ struct Curl_hash_iterator {
struct Curl_llist_element *current_element;
};
-int Curl_hash_init(struct Curl_hash *h,
- int slots,
- hash_function hfunc,
- comp_function comparator,
- Curl_hash_dtor dtor);
+void Curl_hash_init(struct Curl_hash *h,
+ int slots,
+ hash_function hfunc,
+ comp_function comparator,
+ Curl_hash_dtor dtor);
void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
diff --git a/Utilities/cmcurl/lib/hostcheck.c b/Utilities/cmcurl/lib/hostcheck.c
index cf267a7..cd45bd0 100644
--- a/Utilities/cmcurl/lib/hostcheck.c
+++ b/Utilities/cmcurl/lib/hostcheck.c
@@ -89,7 +89,7 @@ static int hostmatch(char *hostname, char *pattern)
match. */
wildcard_enabled = 1;
pattern_label_end = strchr(pattern, '.');
- if(!pattern_label_end || strchr(pattern_label_end + 1, '.') == NULL ||
+ if(!pattern_label_end || !strchr(pattern_label_end + 1, '.') ||
pattern_wildcard > pattern_label_end ||
strncasecompare(pattern, "xn--", 4)) {
wildcard_enabled = 0;
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index 117caa2..911d5ed 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -507,9 +507,6 @@ static struct Curl_addrinfo *get_localhost(int port)
struct sockaddr_in sa;
unsigned int ipv4;
unsigned short port16 = (unsigned short)(port & 0xffff);
- ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
- if(!ca)
- return NULL;
/* memset to clear the sa.sin_zero field */
memset(&sa, 0, sizeof(sa));
@@ -519,6 +516,9 @@ static struct Curl_addrinfo *get_localhost(int port)
return NULL;
memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4));
+ ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
+ if(!ca)
+ return NULL;
ca->ai_flags = 0;
ca->ai_family = AF_INET;
ca->ai_socktype = SOCK_STREAM;
@@ -609,7 +609,11 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
struct connectdata *conn = data->conn;
*entry = NULL;
+#ifndef CURL_DISABLE_DOH
conn->bits.doh = FALSE; /* default is not */
+#else
+ (void)allowDOH;
+#endif
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
@@ -630,11 +634,15 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
struct Curl_addrinfo *addr = NULL;
int respwait = 0;
+#if !defined(CURL_DISABLE_DOH) || !defined(USE_RESOLVE_ON_IPS)
struct in_addr in;
+#endif
+#ifndef CURL_DISABLE_DOH
#ifndef USE_RESOLVE_ON_IPS
const
#endif
bool ipnum = FALSE;
+#endif
/* notify the resolver start callback */
if(data->set.resolver_start) {
@@ -686,6 +694,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
#endif /* ENABLE_IPV6 */
#else /* if USE_RESOLVE_ON_IPS */
+#ifndef CURL_DISABLE_DOH
/* First check if this is an IPv4 address string */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
@@ -699,6 +708,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
ipnum = TRUE;
}
#endif /* ENABLE_IPV6 */
+#endif /* CURL_DISABLE_DOH */
#endif /* !USE_RESOLVE_ON_IPS */
@@ -708,8 +718,10 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(strcasecompare(hostname, "localhost"))
addr = get_localhost(port);
+#ifndef CURL_DISABLE_DOH
else if(allowDOH && data->set.doh && !ipnum)
addr = Curl_doh(data, hostname, port, &respwait);
+#endif
else {
/* Check what IP specifics the app has requested and if we can provide
* it. If not, bail out. */
@@ -977,12 +989,12 @@ static void freednsentry(void *freethis)
}
/*
- * Curl_mk_dnscache() inits a new DNS cache and returns success/failure.
+ * Curl_init_dnscache() inits a new DNS cache.
*/
-int Curl_mk_dnscache(struct Curl_hash *hash)
+void Curl_init_dnscache(struct Curl_hash *hash)
{
- return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare,
- freednsentry);
+ Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare,
+ freednsentry);
}
/*
@@ -1210,9 +1222,10 @@ CURLcode Curl_resolv_check(struct Curl_easy *data,
#if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
(void)dns;
#endif
-
+#ifndef CURL_DISABLE_DOH
if(data->conn->bits.doh)
return Curl_doh_is_resolved(data, dns);
+#endif
return Curl_resolver_is_resolved(data, dns);
}
@@ -1220,10 +1233,12 @@ int Curl_resolv_getsock(struct Curl_easy *data,
curl_socket_t *socks)
{
#ifdef CURLRES_ASYNCH
+#ifndef CURL_DISABLE_DOH
if(data->conn->bits.doh)
/* nothing to wait for during DoH resolve, those handles have their own
sockets */
return GETSOCK_BLANK;
+#endif
return Curl_resolver_getsock(data, socks);
#else
(void)data;
diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h
index 67a688a..1db5981 100644
--- a/Utilities/cmcurl/lib/hostip.h
+++ b/Utilities/cmcurl/lib/hostip.h
@@ -129,8 +129,8 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
void Curl_resolv_unlock(struct Curl_easy *data,
struct Curl_dns_entry *dns);
-/* init a new dns cache and return success */
-int Curl_mk_dnscache(struct Curl_hash *hash);
+/* init a new dns cache */
+void Curl_init_dnscache(struct Curl_hash *hash);
/* prune old entries from the DNS cache */
void Curl_hostcache_prune(struct Curl_easy *data);
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index 648583c..f08a343 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -323,7 +323,7 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
pwd = data->state.aptr.passwd;
}
- out = aprintf("%s:%s", user, pwd ? pwd : "");
+ out = aprintf("%s:%s", user ? user : "", pwd ? pwd : "");
if(!out)
return CURLE_OUT_OF_MEMORY;
@@ -1153,7 +1153,6 @@ static bool http_should_fail(struct Curl_easy *data)
return data->state.authproblem;
}
-#ifndef USE_HYPER
/*
* readmoredata() is a "fread() emulation" to provide POST and/or request
* data. It is used when a huge POST is to be made and the entire chunk wasn't
@@ -1412,8 +1411,6 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
return result;
}
-#endif
-
/* end of the add_buffer functions */
/* ------------------------------------------------------------------------- */
@@ -2375,6 +2372,9 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
#ifndef USE_HYPER
/* Hyper always handles the body separately */
curl_off_t included_body = 0;
+#else
+ /* from this point down, this function should not be used */
+#define Curl_buffer_send(a,b,c,d,e) CURLE_OK
#endif
CURLcode result = CURLE_OK;
struct HTTP *http = data->req.p.http;
@@ -2685,7 +2685,6 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
/* issue the request */
result = Curl_buffer_send(r, data, &data->info.request_size, 0,
FIRSTSOCKET);
-
if(result)
failf(data, "Failed sending HTTP request");
else
@@ -2902,20 +2901,6 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
bool *done)
{
struct SingleRequest *k = &data->req;
- DEBUGASSERT(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP));
- if(data->req.ignore_cl) {
- k->size = k->maxdownload = -1;
- }
- else if(k->size != -1) {
- /* We wait until after all headers have been received to set this so that
- we know for sure Content-Length is valid. */
- if(data->set.max_filesize &&
- k->size > data->set.max_filesize) {
- failf(data, "Maximum file size exceeded");
- return CURLE_FILESIZE_EXCEEDED;
- }
- Curl_pgrsSetDownloadSize(data, k->size);
- }
if(data->req.newurl) {
if(conn->bits.close) {
@@ -3326,7 +3311,7 @@ checkhttpprefix(struct Curl_easy *data,
#ifdef CURL_DOES_CONVERSIONS
/* convert from the network encoding using a scratch area */
char *scratch = strdup(s);
- if(NULL == scratch) {
+ if(!scratch) {
failf(data, "Failed to allocate memory for conversion!");
return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
}
@@ -3366,7 +3351,7 @@ checkrtspprefix(struct Curl_easy *data,
#ifdef CURL_DOES_CONVERSIONS
/* convert from the network encoding using a scratch area */
char *scratch = strdup(s);
- if(NULL == scratch) {
+ if(!scratch) {
failf(data, "Failed to allocate memory for conversion!");
return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
}
@@ -3787,6 +3772,29 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
return CURLE_OK;
}
+/* Content-Length must be ignored if any Transfer-Encoding is present in the
+ response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
+ figured out here after all headers have been received but before the final
+ call to the user's header callback, so that a valid content length can be
+ retrieved by the user in the final call. */
+CURLcode Curl_http_size(struct Curl_easy *data)
+{
+ struct SingleRequest *k = &data->req;
+ if(data->req.ignore_cl || k->chunk) {
+ k->size = k->maxdownload = -1;
+ }
+ else if(k->size != -1) {
+ if(data->set.max_filesize &&
+ k->size > data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
+ }
+ Curl_pgrsSetDownloadSize(data, k->size);
+ k->maxdownload = k->size;
+ }
+ return CURLE_OK;
+}
+
/*
* Read any HTTP header lines from the server and pass them to the client app.
*/
@@ -3981,6 +3989,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
+ if(!k->header) {
+ result = Curl_http_size(data);
+ if(result)
+ return result;
+ }
+
/* At this point we have some idea about the fate of the connection.
If we are closing the connection it may result auth failure. */
#if defined(USE_NTLM)
@@ -4137,31 +4151,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
reason */
*stop_reading = TRUE;
#endif
- else {
- /* If we know the expected size of this document, we set the
- maximum download size to the size of the expected
- document or else, we won't know when to stop reading!
-
- Note that we set the download maximum even if we read a
- "Connection: close" header, to make sure that
- "Content-Length: 0" still prevents us from attempting to
- read the (missing) response-body.
- */
- /* According to RFC2616 section 4.4, we MUST ignore
- Content-Length: headers if we are now receiving data
- using chunked Transfer-Encoding.
- */
- if(k->chunk)
- k->maxdownload = k->size = -1;
- }
- if(-1 != k->size) {
- /* We do this operation even if no_body is true, since this
- data might be retrieved later with curl_easy_getinfo()
- and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */
-
- Curl_pgrsSetDownloadSize(data, k->size);
- k->maxdownload = k->size;
- }
/* If max download size is *zero* (nothing) we already have
nothing and can safely return ok now! But for HTTP/2, we'd
@@ -4250,8 +4239,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* There can only be a 4th response code digit stored in 'digit4' if
all the other fields were parsed and stored first, so nc is 5 when
- digit4 a digit */
- else if(ISDIGIT(digit4)) {
+ digit4 a digit.
+
+ The sscanf() line above will also allow zero-prefixed and negative
+ numbers, so we check for that too here.
+ */
+ else if(ISDIGIT(digit4) || (nc >= 4 && k->httpcode < 100)) {
failf(data, "Unsupported response code in HTTP response");
return CURLE_UNSUPPORTED_PROTOCOL;
}
diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h
index e4ab466..b4aaba2 100644
--- a/Utilities/cmcurl/lib/http.h
+++ b/Utilities/cmcurl/lib/http.h
@@ -54,15 +54,11 @@ char *Curl_copy_header_value(const char *header);
char *Curl_checkProxyheaders(struct Curl_easy *data,
const struct connectdata *conn,
const char *thisheader);
-#ifndef USE_HYPER
CURLcode Curl_buffer_send(struct dynbuf *in,
struct Curl_easy *data,
curl_off_t *bytes_written,
curl_off_t included_body_bytes,
int socketindex);
-#else
-#define Curl_buffer_send(a,b,c,d,e) CURLE_OK
-#endif
CURLcode Curl_add_timecondition(struct Curl_easy *data,
#ifndef USE_HYPER
@@ -289,6 +285,8 @@ struct http_conn {
#endif
};
+CURLcode Curl_http_size(struct Curl_easy *data);
+
CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
struct connectdata *conn,
ssize_t *nread,
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index 6d63f43..e74400a 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -100,6 +100,7 @@ static int http2_getsock(struct Curl_easy *data,
const struct http_conn *c = &conn->proto.httpc;
struct SingleRequest *k = &data->req;
int bitmap = GETSOCK_BLANK;
+ struct HTTP *stream = data->req.p.http;
sock[0] = conn->sock[FIRSTSOCKET];
@@ -108,9 +109,13 @@ static int http2_getsock(struct Curl_easy *data,
frame so we should always be ready for one */
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
- /* we're still uploading or the HTTP/2 layer wants to send data */
- if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
- nghttp2_session_want_write(c->h2))
+ /* we're (still uploading OR the HTTP/2 layer wants to send data) AND
+ there's a window to send data in */
+ if((((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
+ nghttp2_session_want_write(c->h2)) &&
+ (nghttp2_session_get_remote_window_size(c->h2) &&
+ nghttp2_session_get_stream_remote_window_size(c->h2,
+ stream->stream_id)))
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
return bitmap;
@@ -500,10 +505,13 @@ static int set_transfer_url(struct Curl_easy *data,
struct curl_pushheaders *hp)
{
const char *v;
- CURLU *u = curl_url();
CURLUcode uc;
char *url = NULL;
int rc = 0;
+ CURLU *u = curl_url();
+
+ if(!u)
+ return 5;
v = curl_pushheader_byname(hp, ":scheme");
if(v) {
@@ -1953,8 +1961,19 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
nghttp2_session_resume_data(h2, stream->stream_id);
}
- H2BUGF(infof(data, "http2_send returns %zu for stream %u", len,
- stream->stream_id));
+#ifdef DEBUG_HTTP2
+ if(!len) {
+ infof(data, "http2_send: easy %p (stream %u) win %u/%u",
+ data, stream->stream_id,
+ nghttp2_session_get_remote_window_size(httpc->h2),
+ nghttp2_session_get_stream_remote_window_size(httpc->h2,
+ stream->stream_id)
+ );
+
+ }
+ infof(data, "http2_send returns %zu for stream %u", len,
+ stream->stream_id);
+#endif
return len;
}
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
index 02663ab..751e5af 100644
--- a/Utilities/cmcurl/lib/http_aws_sigv4.c
+++ b/Utilities/cmcurl/lib/http_aws_sigv4.c
@@ -92,6 +92,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
char *signed_headers = NULL;
Curl_HttpReq httpreq;
const char *method;
+ size_t post_data_len;
const char *post_data = data->set.postfields ? data->set.postfields : "";
unsigned char sha_hash[32];
char sha_hex[65];
@@ -281,8 +282,15 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
goto fail;
}
- Curl_sha256it(sha_hash,
- (const unsigned char *) post_data, strlen(post_data));
+ if(data->set.postfieldsize < 0)
+ post_data_len = strlen(post_data);
+ else
+ post_data_len = (size_t)data->set.postfieldsize;
+ if(Curl_sha256it(sha_hash, (const unsigned char *) post_data,
+ post_data_len)) {
+ goto fail;
+ }
+
sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
Curl_http_method(data, conn, &method, &httpreq);
@@ -315,13 +323,16 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
goto fail;
}
- Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
- strlen(canonical_request));
+ if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
+ strlen(canonical_request))) {
+ goto fail;
+ }
+
sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
/*
* Google allow to use rsa key instead of HMAC, so this code might change
- * In the furure, but for now we support only HMAC version
+ * In the future, but for now we support only HMAC version
*/
str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
"%s\n" /* RequestDateTime */
diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c
index 627a11c..a6526db 100644
--- a/Utilities/cmcurl/lib/http_ntlm.c
+++ b/Utilities/cmcurl/lib/http_ntlm.c
@@ -198,6 +198,12 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
#endif
Curl_bufref_init(&ntlmmsg);
+
+ /* connection is already authenticated, don't send a header in future
+ * requests so go directly to NTLMSTATE_LAST */
+ if(*state == NTLMSTATE_TYPE3)
+ *state = NTLMSTATE_LAST;
+
switch(*state) {
case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */
@@ -246,11 +252,6 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
}
break;
- case NTLMSTATE_TYPE3:
- /* connection is already authenticated,
- * don't send a header in future requests */
- *state = NTLMSTATE_LAST;
- /* FALLTHROUGH */
case NTLMSTATE_LAST:
Curl_safefree(*allocuserpwd);
authp->done = TRUE;
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index 58489ab..e13f485 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -158,6 +158,10 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit)
{
struct http_connect_state *s;
struct connectdata *conn = data->conn;
+ if(conn->handler->flags & PROTOPT_NOTCPPROXY) {
+ failf(data, "%s cannot be done over CONNECT", conn->handler->scheme);
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
if(!reinit) {
CURLcode result;
DEBUGASSERT(!conn->connect_state);
@@ -198,18 +202,25 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit)
return CURLE_OK;
}
-static void connect_done(struct Curl_easy *data)
+void Curl_connect_done(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
struct http_connect_state *s = conn->connect_state;
- if(s->tunnel_state != TUNNEL_EXIT) {
+ if(s && (s->tunnel_state != TUNNEL_EXIT)) {
s->tunnel_state = TUNNEL_EXIT;
Curl_dyn_free(&s->rcvbuf);
Curl_dyn_free(&s->req);
- /* retore the protocol pointer */
- data->req.p.http = s->prot_save;
+ /* restore the protocol pointer, if not already done */
+ if(s->prot_save)
+ data->req.p.http = s->prot_save;
s->prot_save = NULL;
+ data->info.httpcode = 0; /* clear it as it might've been used for the
+ proxy */
+ data->req.ignorebody = FALSE;
+#ifdef USE_HYPER
+ data->state.hconnect = FALSE;
+#endif
infof(data, "CONNECT phase completed!");
}
}
@@ -284,8 +295,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
/* This only happens if we've looped here due to authentication
reasons, and we don't really use the newly cloned URL here
then. Just free() it. */
- free(data->req.newurl);
- data->req.newurl = NULL;
+ Curl_safefree(data->req.newurl);
/* initialize send-buffer */
Curl_dyn_init(req, DYN_HTTP_REQUEST);
@@ -657,15 +667,13 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(s->close_connection && data->req.newurl) {
conn->bits.proxy_connect_closed = TRUE;
infof(data, "Connect me again please");
- connect_done(data);
+ Curl_connect_done(data);
}
else {
free(data->req.newurl);
data->req.newurl = NULL;
/* failure, close this connection to avoid re-use */
streamclose(conn, "proxy CONNECT failure");
- Curl_closesocket(data, conn, conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
}
/* to back to init state */
@@ -735,6 +743,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
io = hyper_io_new();
if(!io) {
failf(data, "Couldn't create hyper IO");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
/* tell Hyper how to read/write network data */
@@ -750,6 +759,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
h->exec = hyper_executor_new();
if(!h->exec) {
failf(data, "Couldn't create hyper executor");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
}
@@ -757,6 +767,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
options = hyper_clientconn_options_new();
if(!options) {
failf(data, "Couldn't create hyper client options");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -767,6 +778,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
handshake = hyper_clientconn_handshake(io, options);
if(!handshake) {
failf(data, "Couldn't create hyper client handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
io = NULL;
@@ -774,6 +786,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
failf(data, "Couldn't hyper_executor_push the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
handshake = NULL; /* ownership passed on */
@@ -781,6 +794,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
task = hyper_executor_poll(h->exec);
if(!task) {
failf(data, "Couldn't hyper_executor_poll the handshake");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -789,14 +803,24 @@ static CURLcode CONNECT(struct Curl_easy *data,
req = hyper_request_new();
if(!req) {
failf(data, "Couldn't hyper_request_new");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
strlen("CONNECT"))) {
failf(data, "error setting method");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
+ infof(data, "Establish HTTP proxy tunnel to %s:%d",
+ hostname, remote_port);
+
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
+ then. Just free() it. */
+ Curl_safefree(data->req.newurl);
+
result = CONNECT_host(data, conn, hostname, remote_port,
&hostheader, &host);
if(result)
@@ -806,6 +830,16 @@ static CURLcode CONNECT(struct Curl_easy *data,
strlen(hostheader))) {
failf(data, "error setting path");
result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ if(data->set.verbose) {
+ char *se = aprintf("CONNECT %s HTTP/1.1\r\n", hostheader);
+ if(!se) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se));
+ free(se);
}
/* Setup the proxy-authorization header, if any */
result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
@@ -819,21 +853,29 @@ static CURLcode CONNECT(struct Curl_easy *data,
(HYPERE_OK != hyper_request_set_version(req,
HYPER_HTTP_VERSION_1_0))) {
failf(data, "error setting HTTP version");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
headers = hyper_request_headers(req);
if(!headers) {
failf(data, "hyper_request_headers");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
- if(host && Curl_hyper_header(data, headers, host))
- goto error;
- Curl_safefree(host);
+ if(host) {
+ result = Curl_hyper_header(data, headers, host);
+ if(result)
+ goto error;
+ Curl_safefree(host);
+ }
- if(data->state.aptr.proxyuserpwd &&
- Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
- goto error;
+ if(data->state.aptr.proxyuserpwd) {
+ result = Curl_hyper_header(data, headers,
+ data->state.aptr.proxyuserpwd);
+ if(result)
+ goto error;
+ }
if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
data->set.str[STRING_USERAGENT]) {
@@ -843,26 +885,33 @@ static CURLcode CONNECT(struct Curl_easy *data,
data->set.str[STRING_USERAGENT]);
if(result)
goto error;
- if(Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua)))
+ result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua));
+ if(result)
goto error;
Curl_dyn_free(&ua);
}
- if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") &&
- Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
- goto error;
+ if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
+ result = Curl_hyper_header(data, headers,
+ "Proxy-Connection: Keep-Alive");
+ if(result)
+ goto error;
+ }
- if(Curl_add_custom_headers(data, TRUE, headers))
+ result = Curl_add_custom_headers(data, TRUE, headers);
+ if(result)
goto error;
sendtask = hyper_clientconn_send(client, req);
if(!sendtask) {
failf(data, "hyper_clientconn_send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
failf(data, "Couldn't hyper_executor_push the send");
+ result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -875,8 +924,11 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(error)
hypererr = hyper_task_value(task);
hyper_task_free(task);
- if(error)
+ if(error) {
+ /* this could probably use a better error code? */
+ result = CURLE_OUT_OF_MEMORY;
goto error;
+ }
}
} while(task);
s->tunnel_state = TUNNEL_CONNECT;
@@ -904,20 +956,28 @@ static CURLcode CONNECT(struct Curl_easy *data,
h->write_waker = NULL;
}
}
- /* FALLTHROUGH */
+ break;
+
default:
break;
}
+
+ /* If we are supposed to continue and request a new URL, which basically
+ * means the HTTP authentication is still going on so if the tunnel
+ * is complete we start over in INIT state */
+ if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) {
+ infof(data, "CONNECT request done, loop to make another");
+ connect_init(data, TRUE); /* reinit */
+ }
} while(data->req.newurl);
result = CURLE_OK;
if(s->tunnel_state == TUNNEL_COMPLETE) {
- data->info.httpproxycode = data->req.httpcode;
if(data->info.httpproxycode/100 != 2) {
if(conn->bits.close && data->req.newurl) {
conn->bits.proxy_connect_closed = TRUE;
infof(data, "Connect me again please");
- connect_done(data);
+ Curl_connect_done(data);
}
else {
free(data->req.newurl);
@@ -991,7 +1051,7 @@ CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
result = CONNECT(data, sockindex, hostname, remote_port);
if(result || Curl_connect_complete(conn))
- connect_done(data);
+ Curl_connect_done(data);
return result;
}
diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h
index cdf8de4..2820e11 100644
--- a/Utilities/cmcurl/lib/http_proxy.h
+++ b/Utilities/cmcurl/lib/http_proxy.h
@@ -39,6 +39,7 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex);
bool Curl_connect_complete(struct connectdata *conn);
bool Curl_connect_ongoing(struct connectdata *conn);
int Curl_connect_getsock(struct connectdata *conn);
+void Curl_connect_done(struct Curl_easy *data);
#else
#define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
@@ -46,10 +47,10 @@ int Curl_connect_getsock(struct connectdata *conn);
#define Curl_connect_complete(x) CURLE_OK
#define Curl_connect_ongoing(x) FALSE
#define Curl_connect_getsock(x) 0
+#define Curl_connect_done(x)
#endif
void Curl_connect_free(struct Curl_easy *data);
-void Curl_connect_done(struct Curl_easy *data);
/* struct for HTTP CONNECT state data */
struct http_connect_state {
diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c
index 21e00b1..132b3ee 100644
--- a/Utilities/cmcurl/lib/if2ip.c
+++ b/Utilities/cmcurl/lib/if2ip.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -114,7 +114,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
if(getifaddrs(&head) >= 0) {
for(iface = head; iface != NULL; iface = iface->ifa_next) {
- if(iface->ifa_addr != NULL) {
+ if(iface->ifa_addr) {
if(iface->ifa_addr->sa_family == af) {
if(strcasecompare(iface->ifa_name, interf)) {
void *addr;
diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
index 6163899..958ad14 100644
--- a/Utilities/cmcurl/lib/imap.c
+++ b/Utilities/cmcurl/lib/imap.c
@@ -78,6 +78,7 @@
#include "multiif.h"
#include "url.h"
#include "strcase.h"
+#include "bufref.h"
#include "curl_sasl.h"
#include "warnless.h"
@@ -101,19 +102,19 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode imap_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static char *imap_atom(const char *str, bool escape_only);
-static CURLcode imap_sendf(struct Curl_easy *data,
- struct connectdata *conn, const char *fmt, ...);
+static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...);
static CURLcode imap_parse_url_options(struct connectdata *conn);
static CURLcode imap_parse_url_path(struct Curl_easy *data);
static CURLcode imap_parse_custom_request(struct Curl_easy *data);
static CURLcode imap_perform_authenticate(struct Curl_easy *data,
- struct connectdata *conn,
const char *mech,
- const char *initresp);
+ const struct bufref *initresp);
static CURLcode imap_continue_authenticate(struct Curl_easy *data,
- struct connectdata *conn,
- const char *resp);
-static void imap_get_message(char *buffer, char **outptr);
+ const char *mech,
+ const struct bufref *resp);
+static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
+ const char *mech);
+static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
/*
* IMAP protocol handler.
@@ -180,12 +181,15 @@ const struct Curl_handler Curl_handler_imaps = {
/* SASL parameters for the imap protocol */
static const struct SASLproto saslimap = {
"imap", /* The service name */
- '+', /* Code received when continuation is expected */
- IMAP_RESP_OK, /* Code to receive upon authentication success */
- 0, /* Maximum initial response length (no max) */
imap_perform_authenticate, /* Send authentication command */
imap_continue_authenticate, /* Send authentication continuation */
- imap_get_message /* Get SASL response message */
+ imap_cancel_authenticate, /* Send authentication cancellation */
+ imap_get_message, /* Get SASL response message */
+ 0, /* No maximum initial response length */
+ '+', /* Code received when continuation is expected */
+ IMAP_RESP_OK, /* Code to receive upon authentication success */
+ SASL_AUTH_DEFAULT, /* Default mechanisms */
+ SASL_FLAG_BASE64 /* Configuration flags */
};
@@ -293,6 +297,7 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
!strcasecompare(imap->custom, "EXPUNGE") &&
!strcasecompare(imap->custom, "LSUB") &&
!strcasecompare(imap->custom, "UID") &&
+ !strcasecompare(imap->custom, "GETQUOTAROOT") &&
!strcasecompare(imap->custom, "NOOP")))
return FALSE;
break;
@@ -324,7 +329,7 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
/* Do we have a continuation response? This should be a + symbol followed by
a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
- some e-mail servers ignore this and only send a single + instead. */
+ some email servers ignore this and only send a single + instead. */
if(imap && !imap->custom && ((len == 3 && line[0] == '+') ||
(len >= 2 && !memcmp("+ ", line, 2)))) {
switch(imapc->state) {
@@ -352,34 +357,32 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
*
* Gets the authentication message from the response buffer.
*/
-static void imap_get_message(char *buffer, char **outptr)
+static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
{
- size_t len = strlen(buffer);
- char *message = NULL;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 2) {
/* Find the start of the message */
len -= 2;
- for(message = buffer + 2; *message == ' ' || *message == '\t';
- message++, len--)
+ for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
;
/* Find the end of the message */
- for(; len--;)
+ while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t')
break;
/* Terminate the message */
- if(++len) {
- message[len] = '\0';
- }
+ message[++len] = '\0';
+ Curl_bufref_set(out, message, len, NULL);
}
else
/* junk input => zero length output */
- message = &buffer[len];
+ Curl_bufref_set(out, "", 0, NULL);
- *outptr = message;
+ return CURLE_OK;
}
/***********************************************************************
@@ -437,7 +440,7 @@ static CURLcode imap_perform_capability(struct Curl_easy *data,
imapc->tls_supported = FALSE; /* Clear the TLS capability */
/* Send the CAPABILITY command */
- result = imap_sendf(data, conn, "CAPABILITY");
+ result = imap_sendf(data, "CAPABILITY");
if(!result)
state(data, IMAP_CAPABILITY);
@@ -451,11 +454,10 @@ static CURLcode imap_perform_capability(struct Curl_easy *data,
*
* Sends the STARTTLS command to start the upgrade to TLS.
*/
-static CURLcode imap_perform_starttls(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode imap_perform_starttls(struct Curl_easy *data)
{
/* Send the STARTTLS command */
- CURLcode result = imap_sendf(data, conn, "STARTTLS");
+ CURLcode result = imap_sendf(data, "STARTTLS");
if(!result)
state(data, IMAP_STARTTLS);
@@ -516,7 +518,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
passwd = imap_atom(conn->passwd, false);
/* Send the LOGIN command */
- result = imap_sendf(data, conn, "LOGIN %s %s", user ? user : "",
+ result = imap_sendf(data, "LOGIN %s %s", user ? user : "",
passwd ? passwd : "");
free(user);
@@ -536,20 +538,19 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
* SASL authentication mechanism.
*/
static CURLcode imap_perform_authenticate(struct Curl_easy *data,
- struct connectdata *conn,
const char *mech,
- const char *initresp)
+ const struct bufref *initresp)
{
CURLcode result = CURLE_OK;
- (void)data;
+ const char *ir = (const char *) Curl_bufref_ptr(initresp);
- if(initresp) {
+ if(ir) {
/* Send the AUTHENTICATE command with the initial response */
- result = imap_sendf(data, conn, "AUTHENTICATE %s %s", mech, initresp);
+ result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir);
}
else {
/* Send the AUTHENTICATE command */
- result = imap_sendf(data, conn, "AUTHENTICATE %s", mech);
+ result = imap_sendf(data, "AUTHENTICATE %s", mech);
}
return result;
@@ -559,15 +560,34 @@ static CURLcode imap_perform_authenticate(struct Curl_easy *data,
*
* imap_continue_authenticate()
*
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
*/
static CURLcode imap_continue_authenticate(struct Curl_easy *data,
- struct connectdata *conn,
- const char *resp)
+ const char *mech,
+ const struct bufref *resp)
{
- struct imap_conn *imapc = &conn->proto.imapc;
+ struct imap_conn *imapc = &data->conn->proto.imapc;
+
+ (void)mech;
- return Curl_pp_sendf(data, &imapc->pp, "%s", resp);
+ return Curl_pp_sendf(data, &imapc->pp,
+ "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * imap_cancel_authenticate()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode imap_cancel_authenticate(struct Curl_easy *data,
+ const char *mech)
+{
+ struct imap_conn *imapc = &data->conn->proto.imapc;
+
+ (void)mech;
+
+ return Curl_pp_sendf(data, &imapc->pp, "*");
}
/***********************************************************************
@@ -594,8 +614,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
}
/* Calculate the SASL login details */
- result = Curl_sasl_start(&imapc->sasl, data, conn,
- imapc->ir_supported, &progress);
+ result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress);
if(!result) {
if(progress == SASL_INPROGRESS)
@@ -622,12 +641,11 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
static CURLcode imap_perform_list(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap;
if(imap->custom)
/* Send the custom request */
- result = imap_sendf(data, conn, "%s%s", imap->custom,
+ result = imap_sendf(data, "%s%s", imap->custom,
imap->custom_params ? imap->custom_params : "");
else {
/* Make sure the mailbox is in the correct atom format if necessary */
@@ -637,7 +655,7 @@ static CURLcode imap_perform_list(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
/* Send the LIST command */
- result = imap_sendf(data, conn, "LIST \"%s\" *", mailbox);
+ result = imap_sendf(data, "LIST \"%s\" *", mailbox);
free(mailbox);
}
@@ -678,7 +696,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
/* Send the SELECT command */
- result = imap_sendf(data, conn, "SELECT %s", mailbox);
+ result = imap_sendf(data, "SELECT %s", mailbox);
free(mailbox);
@@ -694,8 +712,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data)
*
* Sends a FETCH command to initiate the download of a message.
*/
-static CURLcode imap_perform_fetch(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode imap_perform_fetch(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
struct IMAP *imap = data->req.p.imap;
@@ -704,21 +721,21 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data,
/* Send the FETCH command */
if(imap->partial)
- result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]<%s>",
+ result = imap_sendf(data, "UID FETCH %s BODY[%s]<%s>",
imap->uid, imap->section ? imap->section : "",
imap->partial);
else
- result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]",
+ result = imap_sendf(data, "UID FETCH %s BODY[%s]",
imap->uid, imap->section ? imap->section : "");
}
else if(imap->mindex) {
/* Send the FETCH command */
if(imap->partial)
- result = imap_sendf(data, conn, "FETCH %s BODY[%s]<%s>",
+ result = imap_sendf(data, "FETCH %s BODY[%s]<%s>",
imap->mindex, imap->section ? imap->section : "",
imap->partial);
else
- result = imap_sendf(data, conn, "FETCH %s BODY[%s]",
+ result = imap_sendf(data, "FETCH %s BODY[%s]",
imap->mindex, imap->section ? imap->section : "");
}
else {
@@ -740,7 +757,6 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data,
static CURLcode imap_perform_append(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap;
char *mailbox;
@@ -791,7 +807,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
/* Send the APPEND command */
- result = imap_sendf(data, conn,
+ result = imap_sendf(data,
"APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
mailbox, data->state.infilesize);
@@ -809,8 +825,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
*
* Sends a SEARCH command.
*/
-static CURLcode imap_perform_search(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode imap_perform_search(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
struct IMAP *imap = data->req.p.imap;
@@ -822,7 +837,7 @@ static CURLcode imap_perform_search(struct Curl_easy *data,
}
/* Send the SEARCH command */
- result = imap_sendf(data, conn, "SEARCH %s", imap->query);
+ result = imap_sendf(data, "SEARCH %s", imap->query);
if(!result)
state(data, IMAP_SEARCH);
@@ -836,11 +851,10 @@ static CURLcode imap_perform_search(struct Curl_easy *data,
*
* Performs the logout action prior to sclose() being called.
*/
-static CURLcode imap_perform_logout(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode imap_perform_logout(struct Curl_easy *data)
{
/* Send the LOGOUT command */
- CURLcode result = imap_sendf(data, conn, "LOGOUT");
+ CURLcode result = imap_sendf(data, "LOGOUT");
if(!result)
state(data, IMAP_LOGOUT);
@@ -938,7 +952,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
/* PREAUTH is not compatible with STARTTLS. */
if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) {
/* Switch to TLS connection now */
- result = imap_perform_starttls(data, conn);
+ result = imap_perform_starttls(data);
}
else if(data->set.use_ssl <= CURLUSESSL_TRY)
result = imap_perform_authentication(data, conn);
@@ -993,7 +1007,7 @@ static CURLcode imap_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
- result = Curl_sasl_continue(&imapc->sasl, data, conn, imapcode, &progress);
+ result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress);
if(!result)
switch(progress) {
case SASL_DONE:
@@ -1094,9 +1108,9 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
if(imap->custom)
result = imap_perform_list(data);
else if(imap->query)
- result = imap_perform_search(data, conn);
+ result = imap_perform_search(data);
else
- result = imap_perform_fetch(data, conn);
+ result = imap_perform_fetch(data);
}
}
else {
@@ -1441,7 +1455,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done)
/* Set the default preferred authentication type and mechanism */
imapc->preftype = IMAP_TYPE_ANY;
- Curl_sasl_init(&imapc->sasl, &saslimap);
+ Curl_sasl_init(&imapc->sasl, data, &saslimap);
Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
/* Initialise the pingpong layer */
@@ -1568,10 +1582,10 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
result = imap_perform_list(data);
else if(!imap->custom && selected && (imap->uid || imap->mindex))
/* FETCH from the same mailbox */
- result = imap_perform_fetch(data, conn);
+ result = imap_perform_fetch(data);
else if(!imap->custom && selected && imap->query)
/* SEARCH the current mailbox */
- result = imap_perform_search(data, conn);
+ result = imap_perform_search(data);
else if(imap->mailbox && !selected &&
(imap->custom || imap->uid || imap->mindex || imap->query))
/* SELECT the mailbox */
@@ -1643,7 +1657,7 @@ static CURLcode imap_disconnect(struct Curl_easy *data,
/* The IMAP session may or may not have been allocated/setup at this
point! */
if(!dead_connection && conn->bits.protoconnstart) {
- if(!imap_perform_logout(data, conn))
+ if(!imap_perform_logout(data))
(void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
}
@@ -1747,17 +1761,16 @@ static CURLcode imap_setup_connection(struct Curl_easy *data,
*
* Designed to never block.
*/
-static CURLcode imap_sendf(struct Curl_easy *data,
- struct connectdata *conn, const char *fmt, ...)
+static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
{
CURLcode result = CURLE_OK;
- struct imap_conn *imapc = &conn->proto.imapc;
+ struct imap_conn *imapc = &data->conn->proto.imapc;
DEBUGASSERT(fmt);
/* Calculate the tag based on the connection ID and command ID */
msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
- 'A' + curlx_sltosi(conn->connection_id % 26),
+ 'A' + curlx_sltosi(data->conn->connection_id % 26),
(++imapc->cmdid)%1000);
/* start with a blank buffer */
@@ -1911,8 +1924,6 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)
struct imap_conn *imapc = &conn->proto.imapc;
const char *ptr = conn->options;
- imapc->sasl.resetprefs = TRUE;
-
while(!result && ptr && *ptr) {
const char *key = ptr;
const char *value;
diff --git a/Utilities/cmcurl/lib/inet_pton.c b/Utilities/cmcurl/lib/inet_pton.c
index 4923cae..ada57af 100644
--- a/Utilities/cmcurl/lib/inet_pton.c
+++ b/Utilities/cmcurl/lib/inet_pton.c
@@ -1,6 +1,6 @@
/* This is from the BIND 4.9.4 release, modified to compile by itself */
-/* Copyright (c) 1996 - 2020 by Internet Software Consortium.
+/* Copyright (c) 1996 - 2021 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -174,7 +174,7 @@ inet_pton6(const char *src, unsigned char *dst)
pch = strchr((xdigits = xdigits_l), ch);
if(!pch)
pch = strchr((xdigits = xdigits_u), ch);
- if(pch != NULL) {
+ if(pch) {
val <<= 4;
val |= (pch - xdigits);
if(++saw_xdigit > 4)
@@ -211,7 +211,7 @@ inet_pton6(const char *src, unsigned char *dst)
*tp++ = (unsigned char) ((val >> 8) & 0xff);
*tp++ = (unsigned char) (val & 0xff);
}
- if(colonp != NULL) {
+ if(colonp) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c
index 659947d..54edb47 100644
--- a/Utilities/cmcurl/lib/krb5.c
+++ b/Utilities/cmcurl/lib/krb5.c
@@ -374,7 +374,7 @@ static void krb5_end(void *app_data)
}
}
-static struct Curl_sec_client_mech Curl_krb5_client_mech = {
+static const struct Curl_sec_client_mech Curl_krb5_client_mech = {
"GSSAPI",
sizeof(gss_ctx_id_t),
krb5_init,
@@ -684,7 +684,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
(void) data;
if(!conn->mech)
- /* not inititalized, return error */
+ /* not initialized, return error */
return -1;
DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
@@ -768,7 +768,7 @@ static int sec_set_protection_level(struct Curl_easy *data)
}
}
- /* Now try to negiociate the protection level. */
+ /* Now try to negotiate the protection level. */
code = ftp_send_command(data, "PROT %c", level_to_char(level));
if(code < 0)
@@ -880,7 +880,7 @@ Curl_sec_login(struct Curl_easy *data, struct connectdata *conn)
void
Curl_sec_end(struct connectdata *conn)
{
- if(conn->mech != NULL && conn->mech->end)
+ if(conn->mech && conn->mech->end)
conn->mech->end(conn->app_data);
free(conn->app_data);
conn->app_data = NULL;
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index 1d9e44c..3154db5 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -464,6 +464,11 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
#endif
#endif /* CURL_LDAP_USE_SSL */
}
+ else if(data->set.use_ssl > CURLUSESSL_TRY) {
+ failf(data, "LDAP local: explicit TLS not supported");
+ result = CURLE_NOT_BUILT_IN;
+ goto quit;
+ }
else {
server = ldap_init(host, (int)conn->port);
if(!server) {
@@ -590,7 +595,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
attr_len = strlen(attr);
vals = ldap_get_values_len(server, entryIterator, attribute);
- if(vals != NULL) {
+ if(vals) {
for(i = 0; (vals[i] != NULL); i++) {
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
if(result) {
diff --git a/Utilities/cmcurl/lib/libcurl.rc b/Utilities/cmcurl/lib/libcurl.rc
index 3f7ae16..fde6c8c 100644
--- a/Utilities/cmcurl/lib/libcurl.rc
+++ b/Utilities/cmcurl/lib/libcurl.rc
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -51,7 +51,7 @@ BEGIN
VALUE "OriginalFilename", "libcurl.dll\0"
VALUE "ProductName", "The curl library\0"
VALUE "ProductVersion", LIBCURL_VERSION "\0"
- VALUE "LegalCopyright", "\xa9 " LIBCURL_COPYRIGHT "\0" /* a9: Copyright symbol */
+ VALUE "LegalCopyright", "Copyright (C) " LIBCURL_COPYRIGHT "\0"
VALUE "License", "https://curl.se/docs/copyright.html\0"
END
END
diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c
index e0ec739..e78da7d 100644
--- a/Utilities/cmcurl/lib/llist.c
+++ b/Utilities/cmcurl/lib/llist.c
@@ -106,9 +106,7 @@ Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e,
e->next->prev = NULL;
}
else {
- if(!e->prev)
- list->head = e->next;
- else
+ if(e->prev)
e->prev->next = e->next;
if(!e->next)
diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c
index e7a428f..117cce4 100644
--- a/Utilities/cmcurl/lib/md4.c
+++ b/Utilities/cmcurl/lib/md4.c
@@ -27,6 +27,7 @@
#include "curl_md4.h"
#include "warnless.h"
+
#ifdef USE_OPENSSL
#include <openssl/opensslconf.h>
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
@@ -35,6 +36,13 @@
#endif
#endif /* USE_OPENSSL */
+#ifdef USE_WOLFSSL
+#include <wolfssl/options.h>
+#ifdef NO_MD4
+#define OPENSSL_NO_MD4
+#endif
+#endif
+
#ifdef USE_MBEDTLS
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
@@ -74,8 +82,9 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
md4_digest(ctx, MD4_DIGEST_SIZE, result);
}
-#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
-/* When OpenSSL is available we use the MD4-functions from OpenSSL */
+#elif (defined(USE_OPENSSL) || defined(USE_WOLFSSL)) && \
+ !defined(OPENSSL_NO_MD4)
+/* When OpenSSL or wolfSSL is available, we use their MD4 functions. */
#include <openssl/md4.h>
#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
@@ -180,7 +189,7 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
{
if(!ctx->data) {
ctx->data = malloc(size);
- if(ctx->data != NULL) {
+ if(ctx->data) {
memcpy(ctx->data, data, size);
ctx->size = size;
}
@@ -189,7 +198,7 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
{
- if(ctx->data != NULL) {
+ if(ctx->data) {
#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
mbedtls_md4(ctx->data, ctx->size, result);
#else
diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c
index 983ed97..c6923e0 100644
--- a/Utilities/cmcurl/lib/md5.c
+++ b/Utilities/cmcurl/lib/md5.c
@@ -39,6 +39,20 @@
#endif
#endif /* USE_MBEDTLS */
+#if defined(USE_OPENSSL) && !defined(USE_AMISSL)
+ #include <openssl/opensslconf.h>
+ #if !defined(OPENSSL_NO_MD5) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+ #define USE_OPENSSL_MD5
+ #endif
+#endif
+
+#ifdef USE_WOLFSSL
+ #include <wolfssl/options.h>
+ #ifndef NO_MD5
+ #define USE_WOLFSSL_MD5
+ #endif
+#endif
+
#if defined(USE_GNUTLS)
#include <nettle/md5.h>
@@ -48,9 +62,10 @@
typedef struct md5_ctx MD5_CTX;
-static void MD5_Init(MD5_CTX *ctx)
+static CURLcode MD5_Init(MD5_CTX *ctx)
{
md5_init(ctx);
+ return CURLE_OK;
}
static void MD5_Update(MD5_CTX *ctx,
@@ -65,8 +80,9 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
md5_digest(ctx, 16, digest);
}
-#elif defined(USE_OPENSSL) && !defined(USE_AMISSL)
-/* When OpenSSL is available we use the MD5-function from OpenSSL */
+#elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5)
+
+/* When OpenSSL or wolfSSL is available, we use their MD5 functions. */
#include <openssl/md5.h>
#include "curl_memory.h"
/* The last #include file should be: */
@@ -83,13 +99,14 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
typedef mbedtls_md5_context MD5_CTX;
-static void MD5_Init(MD5_CTX *ctx)
+static CURLcode MD5_Init(MD5_CTX *ctx)
{
#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
(void) mbedtls_md5_starts(ctx);
#else
(void) mbedtls_md5_starts_ret(ctx);
#endif
+ return CURLE_OK;
}
static void MD5_Update(MD5_CTX *ctx,
@@ -131,9 +148,10 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
/* The last #include file should be: */
#include "memdebug.h"
-static void MD5_Init(MD5_CTX *ctx)
+static CURLcode MD5_Init(MD5_CTX *ctx)
{
CC_MD5_Init(ctx);
+ return CURLE_OK;
}
static void MD5_Update(MD5_CTX *ctx,
@@ -161,12 +179,13 @@ struct md5_ctx {
};
typedef struct md5_ctx MD5_CTX;
-static void MD5_Init(MD5_CTX *ctx)
+static CURLcode MD5_Init(MD5_CTX *ctx)
{
if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
}
+ return CURLE_OK;
}
static void MD5_Update(MD5_CTX *ctx,
@@ -246,7 +265,7 @@ struct md5_ctx {
};
typedef struct md5_ctx MD5_CTX;
-static void MD5_Init(MD5_CTX *ctx);
+static CURLcode MD5_Init(MD5_CTX *ctx);
static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
@@ -407,7 +426,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
return ptr;
}
-static void MD5_Init(MD5_CTX *ctx)
+static CURLcode MD5_Init(MD5_CTX *ctx)
{
ctx->a = 0x67452301;
ctx->b = 0xefcdab89;
@@ -416,6 +435,8 @@ static void MD5_Init(MD5_CTX *ctx)
ctx->lo = 0;
ctx->hi = 0;
+
+ return CURLE_OK;
}
static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
@@ -540,8 +561,9 @@ const struct MD5_params Curl_DIGEST_MD5[] = {
/*
* @unittest: 1601
+ * Returns CURLE_OK on success.
*/
-void Curl_md5it(unsigned char *outbuffer, const unsigned char *input,
+CURLcode Curl_md5it(unsigned char *outbuffer, const unsigned char *input,
const size_t len)
{
MD5_CTX ctx;
@@ -549,6 +571,8 @@ void Curl_md5it(unsigned char *outbuffer, const unsigned char *input,
MD5_Init(&ctx);
MD5_Update(&ctx, input, curlx_uztoui(len));
MD5_Final(outbuffer, &ctx);
+
+ return CURLE_OK;
}
struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params)
diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c
index 0bf1b46..7783b89 100644
--- a/Utilities/cmcurl/lib/mime.c
+++ b/Utilities/cmcurl/lib/mime.c
@@ -40,6 +40,7 @@
#include "rand.h"
#include "slist.h"
#include "strcase.h"
+#include "dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -279,29 +280,52 @@ static void mimesetstate(struct mime_state *state,
/* Escape header string into allocated memory. */
-static char *escape_string(const char *src)
-{
- size_t bytecount = 0;
- size_t i;
- char *dst;
+static char *escape_string(struct Curl_easy *data,
+ const char *src, enum mimestrategy strategy)
+{
+ CURLcode result;
+ struct dynbuf db;
+ const char * const *table;
+ const char * const *p;
+ /* replace first character by rest of string. */
+ static const char * const mimetable[] = {
+ "\\\\\\",
+ "\"\\\"",
+ NULL
+ };
+ /* WHATWG HTML living standard 4.10.21.8 2 specifies:
+ For field names and filenames for file fields, the result of the
+ encoding in the previous bullet point must be escaped by replacing
+ any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D`
+ and 0x22 (") with `%22`.
+ The user agent must not perform any other escapes. */
+ static const char * const formtable[] = {
+ "\"%22",
+ "\r%0D",
+ "\n%0A",
+ NULL
+ };
- for(i = 0; src[i]; i++)
- if(src[i] == '"' || src[i] == '\\')
- bytecount++;
+ table = formtable;
+ /* data can be NULL when this function is called indirectly from
+ curl_formget(). */
+ if(strategy == MIMESTRATEGY_MAIL ||
+ (data && (data->set.mime_options & CURLMIMEOPT_FORMESCAPE)))
+ table = mimetable;
- bytecount += i;
- dst = malloc(bytecount + 1);
- if(!dst)
- return NULL;
+ Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
+
+ for(result = Curl_dyn_add(&db, ""); !result && *src; src++) {
+ for(p = table; *p && **p != *src; p++)
+ ;
- for(i = 0; *src; src++) {
- if(*src == '"' || *src == '\\')
- dst[i++] = '\\';
- dst[i++] = *src;
+ if(*p)
+ result = Curl_dyn_add(&db, *p + 1);
+ else
+ result = Curl_dyn_addn(&db, src, 1);
}
- dst[i] = '\0';
- return dst;
+ return Curl_dyn_ptr(&db);
}
/* Check if header matches. */
@@ -462,11 +486,13 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
/* Buffered data size can only be 0, 1 or 2. */
ptr[2] = ptr[3] = '=';
i = 0;
- switch(st->bufend - st->bufbeg) {
- case 2:
- i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
- /* FALLTHROUGH */
- case 1:
+
+ /* If there is buffered data */
+ if(st->bufend != st->bufbeg) {
+
+ if(st->bufend - st->bufbeg == 2)
+ i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
+
i |= (st->buf[st->bufbeg] & 0xFF) << 16;
ptr[0] = base64[(i >> 18) & 0x3F];
ptr[1] = base64[(i >> 12) & 0x3F];
@@ -476,7 +502,6 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
}
cursize += 4;
st->pos += 4;
- break;
}
}
}
@@ -1865,12 +1890,12 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
char *filename = NULL;
if(part->name) {
- name = escape_string(part->name);
+ name = escape_string(part->easy, part->name, strategy);
if(!name)
ret = CURLE_OUT_OF_MEMORY;
}
if(!ret && part->filename) {
- filename = escape_string(part->filename);
+ filename = escape_string(part->easy, part->filename, strategy);
if(!filename)
ret = CURLE_OUT_OF_MEMORY;
}
@@ -1954,7 +1979,8 @@ void Curl_mime_unpause(curl_mimepart *part)
}
-#else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
+#else /* !CURL_DISABLE_HTTP && !CURL_DISABLE_MIME ||
+ !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
/* Mime not compiled in: define stubs for externally-referenced functions. */
curl_mime *curl_mime_init(CURL *easy)
diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c
index 7a1aec5..0fd3afc 100644
--- a/Utilities/cmcurl/lib/mprintf.c
+++ b/Utilities/cmcurl/lib/mprintf.c
@@ -858,7 +858,7 @@ static int dprintf_formatf(
{
void *ptr;
ptr = (void *) p->data.ptr;
- if(ptr != NULL) {
+ if(ptr) {
/* If the pointer is not NULL, write it as a %#x spec. */
base = 16;
digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 518ceb5..f8dcc63 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -243,6 +243,26 @@ static void trhash_dtor(void *nada)
(void)nada;
}
+/*
+ * The sockhash has its own separate subhash in each entry that need to be
+ * safely destroyed first.
+ */
+static void sockhash_destroy(struct Curl_hash *h)
+{
+ struct Curl_hash_iterator iter;
+ struct Curl_hash_element *he;
+
+ DEBUGASSERT(h);
+ Curl_hash_start_iterate(h, &iter);
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr;
+ Curl_hash_destroy(&sh->transfers);
+ he = Curl_hash_next_element(&iter);
+ }
+ Curl_hash_destroy(h);
+}
+
/* make sure this socket is present in the hash for this handle */
static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
@@ -261,11 +281,8 @@ static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
if(!check)
return NULL; /* major failure */
- if(Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash,
- trhash_compare, trhash_dtor)) {
- free(check);
- return NULL;
- }
+ Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare,
+ trhash_dtor);
/* make/add new hash entry */
if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
@@ -332,10 +349,10 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
* per call."
*
*/
-static int sh_init(struct Curl_hash *hash, int hashsize)
+static void sh_init(struct Curl_hash *hash, int hashsize)
{
- return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
- sh_freeentry);
+ Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
+ sh_freeentry);
}
/*
@@ -362,11 +379,9 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
multi->magic = CURL_MULTI_HANDLE;
- if(Curl_mk_dnscache(&multi->hostcache))
- goto error;
+ Curl_init_dnscache(&multi->hostcache);
- if(sh_init(&multi->sockhash, hashsize))
- goto error;
+ sh_init(&multi->sockhash, hashsize);
if(Curl_conncache_init(&multi->conn_cache, chashsize))
goto error;
@@ -405,7 +420,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
error:
- Curl_hash_destroy(&multi->sockhash);
+ sockhash_destroy(&multi->sockhash);
Curl_hash_destroy(&multi->hostcache);
Curl_conncache_destroy(&multi->conn_cache);
Curl_llist_destroy(&multi->msglist, NULL);
@@ -424,6 +439,7 @@ struct Curl_multi *curl_multi_init(void)
CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
struct Curl_easy *data)
{
+ CURLMcode rc;
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -440,6 +456,15 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
+ if(multi->dead) {
+ /* a "dead" handle cannot get added transfers while any existing easy
+ handles are still alive - but if there are none alive anymore, it is
+ fine to start over and unmark the "deadness" of this handle */
+ if(multi->num_alive)
+ return CURLM_ABORTED_BY_CALLBACK;
+ multi->dead = FALSE;
+ }
+
/* Initialize timeout list for this handle */
Curl_llist_init(&data->state.timeoutlist, NULL);
@@ -452,6 +477,34 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
if(data->set.errorbuffer)
data->set.errorbuffer[0] = 0;
+ /* make the Curl_easy refer back to this multi handle - before Curl_expire()
+ is called. */
+ data->multi = multi;
+
+ /* Set the timeout for this handle to expire really soon so that it will
+ be taken care of even when this handle is added in the midst of operation
+ when only the curl_multi_socket() API is used. During that flow, only
+ sockets that time-out or have actions will be dealt with. Since this
+ handle has no action yet, we make sure it times out to get things to
+ happen. */
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+ /* A somewhat crude work-around for a little glitch in Curl_update_timer()
+ that happens if the lastcall time is set to the same time when the handle
+ is removed as when the next handle is added, as then the check in
+ Curl_update_timer() that prevents calling the application multiple times
+ with the same timer info will not trigger and then the new handle's
+ timeout will not be notified to the app.
+
+ The work-around is thus simply to clear the 'lastcall' variable to force
+ Curl_update_timer() to always trigger a callback to the app when a new
+ easy handle is added */
+ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+
+ rc = Curl_update_timer(multi);
+ if(rc)
+ return rc;
+
/* set the easy handle */
multistate(data, MSTATE_INIT);
@@ -492,35 +545,12 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
multi->easylp = multi->easyp = data; /* both first and last */
}
- /* make the Curl_easy refer back to this multi handle */
- data->multi = multi;
-
- /* Set the timeout for this handle to expire really soon so that it will
- be taken care of even when this handle is added in the midst of operation
- when only the curl_multi_socket() API is used. During that flow, only
- sockets that time-out or have actions will be dealt with. Since this
- handle has no action yet, we make sure it times out to get things to
- happen. */
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
-
/* increase the node-counter */
multi->num_easy++;
/* increase the alive-counter */
multi->num_alive++;
- /* A somewhat crude work-around for a little glitch in Curl_update_timer()
- that happens if the lastcall time is set to the same time when the handle
- is removed as when the next handle is added, as then the check in
- Curl_update_timer() that prevents calling the application multiple times
- with the same timer info will not trigger and then the new handle's
- timeout will not be notified to the app.
-
- The work-around is thus simply to clear the 'lastcall' variable to force
- Curl_update_timer() to always trigger a callback to the app when a new
- easy handle is added */
- memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
-
CONNCACHE_LOCK(data);
/* The closure handle only ever has default timeouts set. To improve the
state somewhat we clone the timeouts from each added handle so that the
@@ -533,14 +563,13 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->set.no_signal;
CONNCACHE_UNLOCK(data);
- Curl_update_timer(multi);
return CURLM_OK;
}
#if 0
/* Debug-function, used like this:
*
- * Curl_hash_print(multi->sockhash, debug_print_sock_hash);
+ * Curl_hash_print(&multi->sockhash, debug_print_sock_hash);
*
* Enable the hash print function first by editing hash.c
*/
@@ -548,8 +577,8 @@ static void debug_print_sock_hash(void *p)
{
struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
- fprintf(stderr, " [easy %p/magic %x/socket %d]",
- (void *)sh->data, sh->data->magic, (int)sh->socket);
+ fprintf(stderr, " [readers %u][writers %u]",
+ sh->readers, sh->writers);
}
#endif
@@ -562,7 +591,8 @@ static CURLcode multi_done(struct Curl_easy *data,
struct connectdata *conn = data->conn;
unsigned int i;
- DEBUGF(infof(data, "multi_done"));
+ DEBUGF(infof(data, "multi_done: status: %d prem: %d done: %d",
+ (int)status, (int)premature, data->state.done));
if(data->state.done)
/* Stop if multi_done() has already been called */
@@ -719,6 +749,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
struct Curl_easy *easy = data;
bool premature;
struct Curl_llist_element *e;
+ CURLMcode rc;
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
@@ -792,8 +823,11 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* change state without using multistate(), only to make singlesocket() do
what we want */
data->mstate = MSTATE_COMPLETED;
- singlesocket(multi, easy); /* to let the application know what sockets that
- vanish with this handle */
+
+ /* This ignores the return code even in case of problems because there's
+ nothing more to do about that, here */
+ (void)singlesocket(multi, easy); /* to let the application know what sockets
+ that vanish with this handle */
/* Remove the association between the connection and the handle */
Curl_detach_connnection(data);
@@ -858,7 +892,9 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
process_pending_handles(multi);
- Curl_update_timer(multi);
+ rc = Curl_update_timer(multi);
+ if(rc)
+ return rc;
return CURLM_OK;
}
@@ -878,6 +914,7 @@ void Curl_detach_connnection(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
if(conn) {
+ Curl_connect_done(data); /* if mid-CONNECT, shut it down */
Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
Curl_ssl_detach_conn(data, conn);
}
@@ -1742,6 +1779,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(!GOOD_EASY_HANDLE(data))
return CURLM_BAD_EASY_HANDLE;
+ if(multi->dead) {
+ /* a multi-level callback returned error before, meaning every individual
+ transfer now has failed */
+ result = CURLE_ABORTED_BY_CALLBACK;
+ Curl_posttransfer(data);
+ multi_done(data, result, FALSE);
+ multistate(data, MSTATE_COMPLETED);
+ }
+
do {
/* A "stream" here is a logical stream if the protocol can handle that
(HTTP/2), or the full connection for older protocols */
@@ -1892,7 +1938,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
down. If the name has not yet been resolved, it is likely
that new sockets have been opened in an attempt to contact
another resolver. */
- singlesocket(multi, data);
+ rc = singlesocket(multi, data);
+ if(rc)
+ return rc;
if(dns) {
/* Perform the next step in the connection phase, and then move on
@@ -2028,6 +2076,28 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case MSTATE_DO:
+ if(data->set.fprereq) {
+ int prereq_rc;
+
+ /* call the prerequest callback function */
+ Curl_set_in_callback(data, true);
+ prereq_rc = data->set.fprereq(data->set.prereq_userp,
+ data->info.conn_primary_ip,
+ data->info.conn_local_ip,
+ data->info.conn_primary_port,
+ data->info.conn_local_port);
+ Curl_set_in_callback(data, false);
+ if(prereq_rc != CURL_PREREQFUNC_OK) {
+ failf(data, "operation aborted by pre-request callback");
+ /* failure in pre-request callback - don't do any other processing */
+ result = CURLE_ABORTED_BY_CALLBACK;
+ Curl_posttransfer(data);
+ multi_done(data, result, FALSE);
+ stream_error = TRUE;
+ break;
+ }
+ }
+
if(data->set.connect_only) {
/* keep connection open for application to use the socket */
connkeep(data->conn, "CONNECT_ONLY");
@@ -2595,7 +2665,7 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
*running_handles = multi->num_alive;
if(CURLM_OK >= returncode)
- Curl_update_timer(multi);
+ returncode = Curl_update_timer(multi);
return returncode;
}
@@ -2611,7 +2681,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
multi->magic = 0; /* not good anymore */
- /* Firsrt remove all remaining easy handles */
+ /* First remove all remaining easy handles */
data = multi->easyp;
while(data) {
nextdata = data->next;
@@ -2640,7 +2710,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
/* Close all the connections in the connection cache */
Curl_conncache_close_all_connections(&multi->conn_cache);
- Curl_hash_destroy(&multi->sockhash);
+ sockhash_destroy(&multi->sockhash);
Curl_conncache_destroy(&multi->conn_cache);
Curl_llist_destroy(&multi->msglist, NULL);
Curl_llist_destroy(&multi->pending, NULL);
@@ -2715,6 +2785,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
int num;
unsigned int curraction;
unsigned char actions[MAX_SOCKSPEREASYHANDLE];
+ int rc;
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
socks[i] = CURL_SOCKET_BAD;
@@ -2786,8 +2857,10 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
/* add 'data' to the transfer hash on this socket! */
if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
- sizeof(struct Curl_easy *), data))
+ sizeof(struct Curl_easy *), data)) {
+ Curl_hash_destroy(&entry->transfers);
return CURLM_OUT_OF_MEMORY;
+ }
}
comboaction = (entry->writers? CURL_POLL_OUT : 0) |
@@ -2798,9 +2871,14 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
/* same, continue */
continue;
- if(multi->socket_cb)
- multi->socket_cb(data, s, comboaction, multi->socket_userp,
- entry->socketp);
+ if(multi->socket_cb) {
+ rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
+ entry->socketp);
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
+ }
+ }
entry->action = comboaction; /* store the current action state */
}
@@ -2835,10 +2913,14 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
if(oldactions & CURL_POLL_IN)
entry->readers--;
if(!entry->users) {
- if(multi->socket_cb)
- multi->socket_cb(data, s, CURL_POLL_REMOVE,
- multi->socket_userp,
- entry->socketp);
+ if(multi->socket_cb) {
+ rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
+ multi->socket_userp, entry->socketp);
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
+ }
+ }
sh_delentry(entry, &multi->sockhash, s);
}
else {
@@ -2857,9 +2939,11 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
return CURLM_OK;
}
-void Curl_updatesocket(struct Curl_easy *data)
+CURLcode Curl_updatesocket(struct Curl_easy *data)
{
- singlesocket(data->multi, data);
+ if(singlesocket(data->multi, data))
+ return CURLE_ABORTED_BY_CALLBACK;
+ return CURLE_OK;
}
@@ -2884,13 +2968,18 @@ void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
if(entry) {
+ int rc = 0;
if(multi->socket_cb)
- multi->socket_cb(data, s, CURL_POLL_REMOVE,
- multi->socket_userp,
- entry->socketp);
+ rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
+ multi->socket_userp, entry->socketp);
/* now remove it from the socket hash */
sh_delentry(entry, &multi->sockhash, s);
+ if(rc == -1)
+ /* This just marks the multi handle as "dead" without returning an
+ error code primarily because this function is used from many
+ places where propagating an error back is tricky. */
+ multi->dead = TRUE;
}
}
}
@@ -3150,7 +3239,7 @@ CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
return CURLM_RECURSIVE_API_CALL;
result = multi_socket(multi, FALSE, s, 0, running_handles);
if(CURLM_OK >= result)
- Curl_update_timer(multi);
+ result = Curl_update_timer(multi);
return result;
}
@@ -3162,7 +3251,7 @@ CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
return CURLM_RECURSIVE_API_CALL;
result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
if(CURLM_OK >= result)
- Curl_update_timer(multi);
+ result = Curl_update_timer(multi);
return result;
}
@@ -3173,14 +3262,19 @@ CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
return CURLM_RECURSIVE_API_CALL;
result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
if(CURLM_OK >= result)
- Curl_update_timer(multi);
+ result = Curl_update_timer(multi);
return result;
}
static CURLMcode multi_timeout(struct Curl_multi *multi,
long *timeout_ms)
{
- static struct curltime tv_zero = {0, 0};
+ static const struct curltime tv_zero = {0, 0};
+
+ if(multi->dead) {
+ *timeout_ms = 0;
+ return CURLM_OK;
+ }
if(multi->timetree) {
/* we have a tree of expire times */
@@ -3233,14 +3327,15 @@ CURLMcode curl_multi_timeout(struct Curl_multi *multi,
* Tell the application it should update its timers, if it subscribes to the
* update timer callback.
*/
-void Curl_update_timer(struct Curl_multi *multi)
+CURLMcode Curl_update_timer(struct Curl_multi *multi)
{
long timeout_ms;
+ int rc;
- if(!multi->timer_cb)
- return;
+ if(!multi->timer_cb || multi->dead)
+ return CURLM_OK;
if(multi_timeout(multi, &timeout_ms)) {
- return;
+ return CURLM_OK;
}
if(timeout_ms < 0) {
static const struct curltime none = {0, 0};
@@ -3248,10 +3343,14 @@ void Curl_update_timer(struct Curl_multi *multi)
multi->timer_lastcall = none;
/* there's no timeout now but there was one previously, tell the app to
disable it */
- multi->timer_cb(multi, -1, multi->timer_userp);
- return;
+ rc = multi->timer_cb(multi, -1, multi->timer_userp);
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
+ }
+ return CURLM_OK;
}
- return;
+ return CURLM_OK;
}
/* When multi_timeout() is done, multi->timetree points to the node with the
@@ -3259,11 +3358,16 @@ void Curl_update_timer(struct Curl_multi *multi)
* if this is the same (fixed) time as we got in a previous call and then
* avoid calling the callback again. */
if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
- return;
+ return CURLM_OK;
multi->timer_lastcall = multi->timetree->key;
- multi->timer_cb(multi, timeout_ms, multi->timer_userp);
+ rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
+ }
+ return CURLM_OK;
}
/*
diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
index 2e4a6ff..db7f130 100644
--- a/Utilities/cmcurl/lib/multihandle.h
+++ b/Utilities/cmcurl/lib/multihandle.h
@@ -156,6 +156,8 @@ struct Curl_multi {
#ifdef USE_OPENSSL
bool ssl_seeded;
#endif
+ bool dead; /* a callback returned error, everything needs to crash and
+ burn */
};
#endif /* HEADER_CURL_MULTIHANDLE_H */
diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h
index 2fbef53..f4d0ada 100644
--- a/Utilities/cmcurl/lib/multiif.h
+++ b/Utilities/cmcurl/lib/multiif.h
@@ -26,11 +26,11 @@
* Prototypes for library-wide functions provided by multi.c
*/
-void Curl_updatesocket(struct Curl_easy *data);
+CURLcode Curl_updatesocket(struct Curl_easy *data);
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id);
void Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id);
-void Curl_update_timer(struct Curl_multi *multi);
+CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT;
void Curl_attach_connnection(struct Curl_easy *data,
struct connectdata *conn);
void Curl_detach_connnection(struct Curl_easy *data);
diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
index fb5e743..0ffb6a3 100644
--- a/Utilities/cmcurl/lib/openldap.c
+++ b/Utilities/cmcurl/lib/openldap.c
@@ -70,6 +70,17 @@
*/
/* #define CURL_OPENLDAP_DEBUG */
+/* Machine states. */
+typedef enum {
+ OLDAP_STOP, /* Do nothing state, stops the state machine */
+ OLDAP_SSL, /* Performing SSL handshake. */
+ OLDAP_STARTTLS, /* STARTTLS request sent. */
+ OLDAP_TLS, /* Performing TLS handshake. */
+ OLDAP_BIND, /* Simple bind reply. */
+ OLDAP_BINDV2, /* Simple bind reply in protocol version 2. */
+ OLDAP_LAST /* Never used */
+} ldapstate;
+
#ifndef _LDAP_PVT_H
extern int ldap_pvt_url_scheme2proto(const char *);
extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
@@ -143,29 +154,13 @@ const struct Curl_handler Curl_handler_ldaps = {
};
#endif
-static const char *url_errs[] = {
- "success",
- "out of memory",
- "bad parameter",
- "unrecognized scheme",
- "unbalanced delimiter",
- "bad URL",
- "bad host or port",
- "bad or missing attributes",
- "bad or missing scope",
- "bad or missing filter",
- "bad or missing extensions"
-};
-
struct ldapconninfo {
- LDAP *ld;
- Curl_recv *recv; /* for stacking SSL handler */
+ LDAP *ld; /* Openldap connection handle. */
+ Curl_recv *recv; /* For stacking SSL handler */
Curl_send *send;
- int proto;
- int msgid;
- bool ssldone;
- bool sslinst;
- bool didbind;
+ ldapstate state; /* Current machine state. */
+ int proto; /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */
+ int msgid; /* Current message id. */
};
struct ldapreqinfo {
@@ -173,194 +168,379 @@ struct ldapreqinfo {
int nument;
};
-static CURLcode oldap_setup_connection(struct Curl_easy *data,
- struct connectdata *conn)
+/*
+ * state()
+ *
+ * This is the ONLY way to change LDAP state!
+ */
+static void state(struct Curl_easy *data, ldapstate newstate)
{
- struct ldapconninfo *li;
- LDAPURLDesc *lud;
- int rc, proto;
- CURLcode status;
+ struct ldapconninfo *ldapc = data->conn->proto.ldapc;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[] = {
+ "STOP",
+ "SSL",
+ "STARTTLS",
+ "TLS",
+ "BIND",
+ "BINDV2",
+ /* LAST */
+ };
+
+ if(ldapc->state != newstate)
+ infof(data, "LDAP %p state change from %s to %s",
+ (void *)ldapc, names[ldapc->state], names[newstate]);
+#endif
+
+ ldapc->state = newstate;
+}
- rc = ldap_url_parse(data->state.url, &lud);
+/* Map some particular LDAP error codes to CURLcode values. */
+static CURLcode oldap_map_error(int rc, CURLcode result)
+{
+ switch(rc) {
+ case LDAP_NO_MEMORY:
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ case LDAP_INVALID_CREDENTIALS:
+ result = CURLE_LOGIN_DENIED;
+ break;
+ case LDAP_PROTOCOL_ERROR:
+ result = CURLE_UNSUPPORTED_PROTOCOL;
+ break;
+ case LDAP_INSUFFICIENT_ACCESS:
+ result = CURLE_REMOTE_ACCESS_DENIED;
+ break;
+ }
+ return result;
+}
+
+static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
+{
+ CURLcode result = CURLE_OK;
+ int rc = LDAP_URL_ERR_BADURL;
+ static const char * const url_errs[] = {
+ "success",
+ "out of memory",
+ "bad parameter",
+ "unrecognized scheme",
+ "unbalanced delimiter",
+ "bad URL",
+ "bad host or port",
+ "bad or missing attributes",
+ "bad or missing scope",
+ "bad or missing filter",
+ "bad or missing extensions"
+ };
+
+ *ludp = NULL;
+ if(!data->state.up.user && !data->state.up.password &&
+ !data->state.up.options)
+ rc = ldap_url_parse(data->state.url, ludp);
if(rc != LDAP_URL_SUCCESS) {
const char *msg = "url parsing problem";
- status = CURLE_URL_MALFORMAT;
- if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
- if(rc == LDAP_URL_ERR_MEM)
- status = CURLE_OUT_OF_MEMORY;
+
+ result = rc == LDAP_URL_ERR_MEM? CURLE_OUT_OF_MEMORY: CURLE_URL_MALFORMAT;
+ rc -= LDAP_URL_SUCCESS;
+ if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0]))
msg = url_errs[rc];
- }
failf(data, "LDAP local: %s", msg);
- return status;
}
- proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
+ return result;
+}
+
+static CURLcode oldap_setup_connection(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ CURLcode result;
+ LDAPURLDesc *lud;
+ struct ldapconninfo *li;
+
+ /* Early URL syntax check. */
+ result = oldap_url_parse(data, &lud);
ldap_free_urldesc(lud);
- li = calloc(1, sizeof(struct ldapconninfo));
- if(!li)
- return CURLE_OUT_OF_MEMORY;
- li->proto = proto;
- conn->proto.ldapc = li;
- connkeep(conn, "OpenLDAP default");
- return CURLE_OK;
+ if(!result) {
+ li = calloc(1, sizeof(struct ldapconninfo));
+ if(!li)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
+ conn->proto.ldapc = li;
+ connkeep(conn, "OpenLDAP default");
+
+ /* Clear the TLS upgraded flag */
+ conn->bits.tls_upgraded = FALSE;
+ }
+ }
+
+ return result;
+}
+
+/* Starts LDAP simple bind. */
+static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
+{
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
+ struct ldapconninfo *li = conn->proto.ldapc;
+ char *binddn = NULL;
+ struct berval passwd;
+ int rc;
+
+ passwd.bv_val = NULL;
+ passwd.bv_len = 0;
+
+ if(conn->bits.user_passwd) {
+ binddn = conn->user;
+ passwd.bv_val = conn->passwd;
+ passwd.bv_len = strlen(passwd.bv_val);
+ }
+
+ rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
+ NULL, NULL, &li->msgid);
+ if(rc == LDAP_SUCCESS)
+ state(data, newstate);
+ else
+ result = oldap_map_error(rc,
+ conn->bits.user_passwd?
+ CURLE_LOGIN_DENIED: CURLE_LDAP_CANNOT_BIND);
+ return result;
}
#ifdef USE_SSL
static Sockbuf_IO ldapsb_tls;
-#endif
-static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
+static bool ssl_installed(struct connectdata *conn)
+{
+ return conn->proto.ldapc->recv != NULL;
+}
+
+static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
{
+ CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
- int rc, proto = LDAP_VERSION3;
- char hosturl[1024];
- char *ptr;
+ bool ssldone = 0;
- (void)done;
+ result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
+ FIRSTSOCKET, &ssldone);
+ if(!result) {
+ state(data, newstate);
- strcpy(hosturl, "ldap");
- ptr = hosturl + 4;
- if(conn->handler->flags & PROTOPT_SSL)
- *ptr++ = 's';
- msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
- conn->host.name, conn->remote_port);
+ if(ssldone) {
+ Sockbuf *sb;
-#ifdef CURL_OPENLDAP_DEBUG
- static int do_trace = 0;
- const char *env = getenv("CURL_OPENLDAP_TRACE");
- do_trace = (env && strtol(env, NULL, 10) > 0);
- if(do_trace) {
- ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
+ /* Install the libcurl SSL handlers into the sockbuf. */
+ ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+ ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
+ li->recv = conn->recv[FIRSTSOCKET];
+ li->send = conn->send[FIRSTSOCKET];
+ }
}
+
+ return result;
+}
+
+/* Send the STARTTLS request */
+static CURLcode oldap_perform_starttls(struct Curl_easy *data)
+{
+ CURLcode result = CURLE_OK;
+ struct ldapconninfo *li = data->conn->proto.ldapc;
+ int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
+
+ if(rc == LDAP_SUCCESS)
+ state(data, OLDAP_STARTTLS);
+ else
+ result = oldap_map_error(rc, CURLE_USE_SSL_FAILED);
+ return result;
+}
#endif
+static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
+{
+ struct connectdata *conn = data->conn;
+ struct ldapconninfo *li = conn->proto.ldapc;
+ static const int version = LDAP_VERSION3;
+ int rc;
+ char *hosturl;
+#ifdef CURL_OPENLDAP_DEBUG
+ static int do_trace = -1;
+#endif
+
+ (void)done;
+
+ hosturl = aprintf("ldap%s://%s:%d",
+ conn->handler->flags & PROTOPT_SSL? "s": "",
+ conn->host.name, conn->remote_port);
+ if(!hosturl)
+ return CURLE_OUT_OF_MEMORY;
+
rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
if(rc) {
failf(data, "LDAP local: Cannot connect to %s, %s",
hosturl, ldap_err2string(rc));
+ free(hosturl);
return CURLE_COULDNT_CONNECT;
}
- ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
+ free(hosturl);
+
+#ifdef CURL_OPENLDAP_DEBUG
+ if(do_trace < 0) {
+ const char *env = getenv("CURL_OPENLDAP_TRACE");
+ do_trace = (env && strtol(env, NULL, 10) > 0);
+ }
+ if(do_trace)
+ ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
+#endif
+
+ /* Try version 3 first. */
+ ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ /* Do not chase referrals. */
+ ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
#ifdef USE_SSL
- if(conn->handler->flags & PROTOPT_SSL) {
- CURLcode result;
- result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET, &li->ssldone);
- if(result)
+ if(conn->handler->flags & PROTOPT_SSL)
+ return oldap_ssl_connect(data, OLDAP_SSL);
+
+ if(data->set.use_ssl) {
+ CURLcode result = oldap_perform_starttls(data);
+
+ if(!result || data->set.use_ssl != CURLUSESSL_TRY)
return result;
}
#endif
- return CURLE_OK;
+ /* Force bind even if anonymous bind is not needed in protocol version 3
+ to detect missing version 3 support. */
+ return oldap_perform_bind(data, OLDAP_BIND);
}
-static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
+/* Handle a simple bind response. */
+static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
+ int code)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
- LDAPMessage *msg = NULL;
- struct timeval tv = {0, 1}, *tvp;
- int rc, err;
- char *info = NULL;
+ CURLcode result = CURLE_OK;
+ struct berval *bv = NULL;
+ int rc;
-#ifdef USE_SSL
- if(conn->handler->flags & PROTOPT_SSL) {
- /* Is the SSL handshake complete yet? */
- if(!li->ssldone) {
- CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
- FIRSTSOCKET,
- &li->ssldone);
- if(result || !li->ssldone)
- return result;
- }
+ if(code != LDAP_SUCCESS)
+ return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND);
- /* Have we installed the libcurl SSL handlers into the sockbuf yet? */
- if(!li->sslinst) {
- Sockbuf *sb;
- ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
- ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
- li->sslinst = TRUE;
- li->recv = conn->recv[FIRSTSOCKET];
- li->send = conn->send[FIRSTSOCKET];
- }
+ rc = ldap_parse_sasl_bind_result(li->ld, msg, &bv, 0);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: bind ldap_parse_sasl_bind_result %s",
+ ldap_err2string(rc));
+ result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
}
-#endif
+ else
+ state(data, OLDAP_STOP);
- tvp = &tv;
-
- retry:
- if(!li->didbind) {
- char *binddn;
- struct berval passwd;
+ if(bv)
+ ber_bvfree(bv);
+ return result;
+}
- if(conn->bits.user_passwd) {
- binddn = conn->user;
- passwd.bv_val = conn->passwd;
- passwd.bv_len = strlen(passwd.bv_val);
+static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
+ struct ldapconninfo *li = conn->proto.ldapc;
+ LDAPMessage *msg = NULL;
+ struct timeval tv = {0, 0};
+ int code = LDAP_SUCCESS;
+ int rc;
+
+ if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) {
+ /* Get response to last command. */
+ rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg);
+ if(!rc)
+ return CURLE_OK; /* Timed out. */
+ if(rc < 0) {
+ failf(data, "LDAP local: connecting ldap_result %s",
+ ldap_err2string(rc));
+ return oldap_map_error(rc, CURLE_COULDNT_CONNECT);
}
+
+ /* Get error code from message. */
+ rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0);
+ if(rc)
+ code = rc;
else {
- binddn = NULL;
- passwd.bv_val = NULL;
- passwd.bv_len = 0;
+ /* store the latest code for later retrieval */
+ data->info.httpcode = code;
}
- rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
- NULL, NULL, &li->msgid);
- if(rc)
- return CURLE_LDAP_CANNOT_BIND;
- li->didbind = TRUE;
- if(tvp)
- return CURLE_OK;
- }
- rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg);
- if(rc < 0) {
- failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc));
- return CURLE_LDAP_CANNOT_BIND;
- }
- if(rc == 0) {
- /* timed out */
- return CURLE_OK;
- }
+ /* If protocol version 3 is not supported, fallback to version 2. */
+ if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2
+#ifdef USE_SSL
+ && (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY)
+#endif
+ ) {
+ static const int version = LDAP_VERSION2;
- rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1);
- if(rc) {
- failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc));
- return CURLE_LDAP_CANNOT_BIND;
+ ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+ ldap_msgfree(msg);
+ return oldap_perform_bind(data, OLDAP_BINDV2);
+ }
}
- /* Try to fallback to LDAPv2? */
- if(err == LDAP_PROTOCOL_ERROR) {
- int proto;
- ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
- if(proto == LDAP_VERSION3) {
- if(info) {
- ldap_memfree(info);
- info = NULL;
+ /* Handle response message according to current state. */
+ switch(li->state) {
+
+#ifdef USE_SSL
+ case OLDAP_SSL:
+ result = oldap_ssl_connect(data, OLDAP_SSL);
+ if(!result && ssl_installed(conn))
+ result = oldap_perform_bind(data, OLDAP_BIND);
+ break;
+ case OLDAP_STARTTLS:
+ if(code != LDAP_SUCCESS) {
+ if(data->set.use_ssl != CURLUSESSL_TRY)
+ result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
+ else
+ result = oldap_perform_bind(data, OLDAP_BIND);
+ break;
+ }
+ /* FALLTHROUGH */
+ case OLDAP_TLS:
+ result = oldap_ssl_connect(data, OLDAP_TLS);
+ if(result && data->set.use_ssl != CURLUSESSL_TRY)
+ result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
+ else if(ssl_installed(conn)) {
+ conn->bits.tls_upgraded = TRUE;
+ if(conn->bits.user_passwd)
+ result = oldap_perform_bind(data, OLDAP_BIND);
+ else {
+ state(data, OLDAP_STOP); /* Version 3 supported: no bind required */
+ result = CURLE_OK;
}
- proto = LDAP_VERSION2;
- ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
- li->didbind = FALSE;
- goto retry;
}
- }
+ break;
+#endif
- if(err) {
- failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc),
- info ? info : "");
- if(info)
- ldap_memfree(info);
- return CURLE_LOGIN_DENIED;
+ case OLDAP_BIND:
+ case OLDAP_BINDV2:
+ result = oldap_state_bind_resp(data, msg, code);
+ break;
+ default:
+ /* internal error */
+ result = CURLE_COULDNT_CONNECT;
+ break;
}
- if(info)
- ldap_memfree(info);
- conn->recv[FIRSTSOCKET] = oldap_recv;
- *done = TRUE;
+ ldap_msgfree(msg);
- return CURLE_OK;
+ *done = li->state == OLDAP_STOP;
+ if(*done)
+ conn->recv[FIRSTSOCKET] = oldap_recv;
+
+ return result;
}
static CURLcode oldap_disconnect(struct Curl_easy *data,
@@ -373,7 +553,7 @@ static CURLcode oldap_disconnect(struct Curl_easy *data,
if(li) {
if(li->ld) {
#ifdef USE_SSL
- if(conn->ssl[FIRSTSOCKET].use) {
+ if(ssl_installed(conn)) {
Sockbuf *sb;
ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
@@ -393,44 +573,40 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapreqinfo *lr;
- CURLcode status = CURLE_OK;
- int rc = 0;
- LDAPURLDesc *ludp = NULL;
+ CURLcode result;
+ int rc;
+ LDAPURLDesc *lud;
int msgid;
connkeep(conn, "OpenLDAP do");
infof(data, "LDAP local: %s", data->state.url);
- rc = ldap_url_parse(data->state.url, &ludp);
- if(rc != LDAP_URL_SUCCESS) {
- const char *msg = "url parsing problem";
- status = CURLE_URL_MALFORMAT;
- if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
- if(rc == LDAP_URL_ERR_MEM)
- status = CURLE_OUT_OF_MEMORY;
- msg = url_errs[rc];
+ result = oldap_url_parse(data, &lud);
+ if(!result) {
+ rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
+ lud->lud_filter, lud->lud_attrs, 0,
+ NULL, NULL, NULL, 0, &msgid);
+ ldap_free_urldesc(lud);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
+ result = CURLE_LDAP_SEARCH_FAILED;
+ }
+ else {
+ lr = calloc(1, sizeof(struct ldapreqinfo));
+ if(!lr) {
+ ldap_abandon_ext(li->ld, msgid, NULL, NULL);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ lr->msgid = msgid;
+ data->req.p.ldap = lr;
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ *done = TRUE;
+ }
}
- failf(data, "LDAP local: %s", msg);
- return status;
- }
-
- rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
- ludp->lud_filter, ludp->lud_attrs, 0,
- NULL, NULL, NULL, 0, &msgid);
- ldap_free_urldesc(ludp);
- if(rc != LDAP_SUCCESS) {
- failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
- return CURLE_LDAP_SEARCH_FAILED;
}
- lr = calloc(1, sizeof(struct ldapreqinfo));
- if(!lr)
- return CURLE_OUT_OF_MEMORY;
- lr->msgid = msgid;
- data->req.p.ldap = lr;
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
- *done = TRUE;
- return CURLE_OK;
+ return result;
}
static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
@@ -456,163 +632,146 @@ static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
return CURLE_OK;
}
+static CURLcode client_write(struct Curl_easy *data, const char *prefix,
+ const char *value, size_t len, const char *suffix)
+{
+ CURLcode result = CURLE_OK;
+ size_t l;
+
+ if(prefix) {
+ l = strlen(prefix);
+ /* If we have a zero-length value and the prefix ends with a space
+ separator, drop the latter. */
+ if(!len && l && prefix[l - 1] == ' ')
+ l--;
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, l);
+ if(!result)
+ data->req.bytecount += l;
+ }
+ if(!result && value) {
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len);
+ if(!result)
+ data->req.bytecount += len;
+ }
+ if(!result && suffix) {
+ l = strlen(suffix);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, l);
+ if(!result)
+ data->req.bytecount += l;
+ }
+ return result;
+}
+
static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
size_t len, CURLcode *err)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapreqinfo *lr = data->req.p.ldap;
- int rc, ret;
+ int rc;
LDAPMessage *msg = NULL;
- LDAPMessage *ent;
BerElement *ber = NULL;
- struct timeval tv = {0, 1};
+ struct timeval tv = {0, 0};
+ struct berval bv, *bvals;
+ int binary = 0;
+ CURLcode result = CURLE_AGAIN;
+ int code;
+ char *info = NULL;
(void)len;
(void)buf;
(void)sockindex;
- rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg);
+ rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg);
if(rc < 0) {
failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
- *err = CURLE_RECV_ERROR;
- return -1;
+ result = CURLE_RECV_ERROR;
}
- *err = CURLE_AGAIN;
- ret = -1;
+ *err = result;
- /* timed out */
+ /* error or timed out */
if(!msg)
- return ret;
-
- for(ent = ldap_first_message(li->ld, msg); ent;
- ent = ldap_next_message(li->ld, ent)) {
- struct berval bv, *bvals;
- int binary = 0, msgtype;
- CURLcode writeerr;
-
- msgtype = ldap_msgtype(ent);
- if(msgtype == LDAP_RES_SEARCH_RESULT) {
- int code;
- char *info = NULL;
- rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0);
- if(rc) {
- failf(data, "LDAP local: search ldap_parse_result %s",
- ldap_err2string(rc));
- *err = CURLE_LDAP_SEARCH_FAILED;
- }
- else if(code && code != LDAP_SIZELIMIT_EXCEEDED) {
- failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc),
- info ? info : "");
- *err = CURLE_LDAP_SEARCH_FAILED;
- }
- else {
- /* successful */
- if(code == LDAP_SIZELIMIT_EXCEEDED)
- infof(data, "There are more than %d entries", lr->nument);
- data->req.size = data->req.bytecount;
- *err = CURLE_OK;
- ret = 0;
- }
- lr->msgid = 0;
- ldap_memfree(info);
+ return -1;
+
+ result = CURLE_OK;
+
+ switch(ldap_msgtype(msg)) {
+ case LDAP_RES_SEARCH_RESULT:
+ lr->msgid = 0;
+ rc = ldap_parse_result(li->ld, msg, &code, NULL, &info, NULL, NULL, 0);
+ if(rc) {
+ failf(data, "LDAP local: search ldap_parse_result %s",
+ ldap_err2string(rc));
+ result = CURLE_LDAP_SEARCH_FAILED;
break;
}
- else if(msgtype != LDAP_RES_SEARCH_ENTRY)
- continue;
+ /* store the latest code for later retrieval */
+ data->info.httpcode = code;
+
+ switch(code) {
+ case LDAP_SIZELIMIT_EXCEEDED:
+ infof(data, "There are more than %d entries", lr->nument);
+ /* FALLTHROUGH */
+ case LDAP_SUCCESS:
+ data->req.size = data->req.bytecount;
+ break;
+ default:
+ failf(data, "LDAP remote: search failed %s %s", ldap_err2string(code),
+ info ? info : "");
+ result = CURLE_LDAP_SEARCH_FAILED;
+ break;
+ }
+ if(info)
+ ldap_memfree(info);
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
lr->nument++;
- rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv);
+ rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
if(rc < 0) {
- *err = CURLE_RECV_ERROR;
- return -1;
- }
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
-
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
- bv.bv_len);
- if(writeerr) {
- *err = writeerr;
- return -1;
+ result = CURLE_RECV_ERROR;
+ break;
}
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- data->req.bytecount += bv.bv_len + 5;
+ result = client_write(data, "DN: ", bv.bv_val, bv.bv_len, "\n");
+ if(result)
+ break;
- for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals);
+ for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
rc == LDAP_SUCCESS;
- rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) {
+ rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
int i;
if(!bv.bv_val)
break;
- if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
- binary = 1;
- else
- binary = 0;
-
if(!bvals) {
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
- bv.bv_len);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":\n", 2);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- data->req.bytecount += bv.bv_len + 3;
+ result = client_write(data, "\t", bv.bv_val, bv.bv_len, ":\n");
+ if(result)
+ break;
continue;
}
+ binary = bv.bv_len > 7 &&
+ !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7);
+
for(i = 0; bvals[i].bv_val != NULL; i++) {
int binval = 0;
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
- bv.bv_len);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
-
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":", 1);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- data->req.bytecount += bv.bv_len + 2;
+ result = client_write(data, "\t", bv.bv_val, bv.bv_len, ":");
+ if(result)
+ break;
if(!binary) {
/* check for leading or trailing whitespace */
if(ISSPACE(bvals[i].bv_val[0]) ||
- ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
+ ISSPACE(bvals[i].bv_val[bvals[i].bv_len - 1]))
binval = 1;
else {
/* check for unprintable characters */
unsigned int j;
- for(j = 0; j<bvals[i].bv_len; j++)
+ for(j = 0; j < bvals[i].bv_len; j++)
if(!ISPRINT(bvals[i].bv_val[j])) {
binval = 1;
break;
@@ -622,80 +781,42 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
if(binary || binval) {
char *val_b64 = NULL;
size_t val_b64_sz = 0;
- /* Binary value, encode to base64. */
- CURLcode error = Curl_base64_encode(data,
- bvals[i].bv_val,
- bvals[i].bv_len,
- &val_b64,
- &val_b64_sz);
- if(error) {
- ber_memfree(bvals);
- ber_free(ber, 0);
- ldap_msgfree(msg);
- *err = error;
- return -1;
- }
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY,
- (char *)": ", 2);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
-
- data->req.bytecount += 2;
- if(val_b64_sz > 0) {
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, val_b64,
- val_b64_sz);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- free(val_b64);
- data->req.bytecount += val_b64_sz;
- }
- }
- else {
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)" ", 1);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, bvals[i].bv_val,
- bvals[i].bv_len);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
-
- data->req.bytecount += bvals[i].bv_len + 1;
- }
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
- if(writeerr) {
- *err = writeerr;
- return -1;
+ /* Binary value, encode to base64. */
+ if(bvals[i].bv_len)
+ result = Curl_base64_encode(data, bvals[i].bv_val, bvals[i].bv_len,
+ &val_b64, &val_b64_sz);
+ if(!result)
+ result = client_write(data, ": ", val_b64, val_b64_sz, "\n");
+ free(val_b64);
}
-
- data->req.bytecount++;
+ else
+ result = client_write(data, " ",
+ bvals[i].bv_val, bvals[i].bv_len, "\n");
+ if(result)
+ break;
}
+
ber_memfree(bvals);
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
- if(writeerr) {
- *err = writeerr;
- return -1;
- }
- data->req.bytecount++;
- }
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
- if(writeerr) {
- *err = writeerr;
- return -1;
+ bvals = NULL;
+ if(!result)
+ result = client_write(data, "\n", NULL, 0, NULL);
+ if(result)
+ break;
}
- data->req.bytecount++;
+
ber_free(ber, 0);
+
+ if(!result)
+ result = client_write(data, "\n", NULL, 0, NULL);
+ if(!result)
+ result = CURLE_AGAIN;
+ break;
}
+
ldap_msgfree(msg);
- return ret;
+ *err = result;
+ return result? -1: 0;
}
#ifdef USE_SSL
diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
index d3f3de6..d4ca678 100644
--- a/Utilities/cmcurl/lib/pop3.c
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -78,6 +78,7 @@
#include "select.h"
#include "multiif.h"
#include "url.h"
+#include "bufref.h"
#include "curl_sasl.h"
#include "curl_md5.h"
#include "warnless.h"
@@ -103,12 +104,12 @@ static CURLcode pop3_setup_connection(struct Curl_easy *data,
static CURLcode pop3_parse_url_options(struct connectdata *conn);
static CURLcode pop3_parse_url_path(struct Curl_easy *data);
static CURLcode pop3_parse_custom_request(struct Curl_easy *data);
-static CURLcode pop3_perform_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *mech,
- const char *initresp);
-static CURLcode pop3_continue_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *resp);
-static void pop3_get_message(char *buffer, char **outptr);
+static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech,
+ const struct bufref *initresp);
+static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech,
+ const struct bufref *resp);
+static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech);
+static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
/*
* POP3 protocol handler.
@@ -170,13 +171,16 @@ const struct Curl_handler Curl_handler_pop3s = {
/* SASL parameters for the pop3 protocol */
static const struct SASLproto saslpop3 = {
- "pop", /* The service name */
- '*', /* Code received when continuation is expected */
- '+', /* Code to receive upon authentication success */
- 255 - 8, /* Maximum initial response length (no max) */
- pop3_perform_auth, /* Send authentication command */
- pop3_continue_auth, /* Send authentication continuation */
- pop3_get_message /* Get SASL response message */
+ "pop", /* The service name */
+ pop3_perform_auth, /* Send authentication command */
+ pop3_continue_auth, /* Send authentication continuation */
+ pop3_cancel_auth, /* Send authentication cancellation */
+ pop3_get_message, /* Get SASL response message */
+ 255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
+ '*', /* Code received when continuation is expected */
+ '+', /* Code to receive upon authentication success */
+ SASL_AUTH_DEFAULT, /* Default mechanisms */
+ SASL_FLAG_BASE64 /* Configuration flags */
};
#ifdef USE_SSL
@@ -250,34 +254,32 @@ static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
*
* Gets the authentication message from the response buffer.
*/
-static void pop3_get_message(char *buffer, char **outptr)
+static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
{
- size_t len = strlen(buffer);
- char *message = NULL;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 2) {
/* Find the start of the message */
len -= 2;
- for(message = buffer + 2; *message == ' ' || *message == '\t';
- message++, len--)
+ for(message += 2; *message == ' ' || *message == '\t'; message++, len--)
;
/* Find the end of the message */
- for(; len--;)
+ while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t')
break;
/* Terminate the message */
- if(++len) {
- message[len] = '\0';
- }
+ message[++len] = '\0';
+ Curl_bufref_set(out, message, len, NULL);
}
else
/* junk input => zero length output */
- message = &buffer[len];
+ Curl_bufref_set(out, "", 0, NULL);
- *outptr = message;
+ return CURLE_OK;
}
/***********************************************************************
@@ -474,16 +476,16 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
* authentication mechanism.
*/
static CURLcode pop3_perform_auth(struct Curl_easy *data,
- struct connectdata *conn,
const char *mech,
- const char *initresp)
+ const struct bufref *initresp)
{
CURLcode result = CURLE_OK;
- struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+ const char *ir = (const char *) Curl_bufref_ptr(initresp);
- if(initresp) { /* AUTH <mech> ...<crlf> */
+ if(ir) { /* AUTH <mech> ...<crlf> */
/* Send the AUTH command with the initial response */
- result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, initresp);
+ result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, ir);
}
else {
/* Send the AUTH command */
@@ -497,15 +499,33 @@ static CURLcode pop3_perform_auth(struct Curl_easy *data,
*
* pop3_continue_auth()
*
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
*/
static CURLcode pop3_continue_auth(struct Curl_easy *data,
- struct connectdata *conn,
- const char *resp)
+ const char *mech,
+ const struct bufref *resp)
{
- struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+
+ (void)mech;
- return Curl_pp_sendf(data, &pop3c->pp, "%s", resp);
+ return Curl_pp_sendf(data, &pop3c->pp,
+ "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * pop3_cancel_auth()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech)
+{
+ struct pop3_conn *pop3c = &data->conn->proto.pop3c;
+
+ (void)mech;
+
+ return Curl_pp_sendf(data, &pop3c->pp, "*");
}
/***********************************************************************
@@ -532,7 +552,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
/* Calculate the SASL login details */
- result = Curl_sasl_start(&pop3c->sasl, data, conn, FALSE, &progress);
+ result = Curl_sasl_start(&pop3c->sasl, data, FALSE, &progress);
if(!result)
if(progress == SASL_INPROGRESS)
@@ -801,7 +821,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
- result = Curl_sasl_continue(&pop3c->sasl, data, conn, pop3code, &progress);
+ result = Curl_sasl_continue(&pop3c->sasl, data, pop3code, &progress);
if(!result)
switch(progress) {
case SASL_DONE:
@@ -1011,7 +1031,9 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
break;
case POP3_QUIT:
- /* fallthrough, just stop! */
+ state(data, POP3_STOP);
+ break;
+
default:
/* internal error */
state(data, POP3_STOP);
@@ -1102,7 +1124,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
/* Set the default preferred authentication type and mechanism */
pop3c->preftype = POP3_TYPE_ANY;
- Curl_sasl_init(&pop3c->sasl, &saslpop3);
+ Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
/* Initialise the pingpong layer */
Curl_pp_setup(pp);
@@ -1343,8 +1365,6 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)
struct pop3_conn *pop3c = &conn->proto.pop3c;
const char *ptr = conn->options;
- pop3c->sasl.resetprefs = TRUE;
-
while(!result && ptr && *ptr) {
const char *key = ptr;
const char *value;
diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c
index 84d0b8f..5f31870 100644
--- a/Utilities/cmcurl/lib/select.c
+++ b/Utilities/cmcurl/lib/select.c
@@ -64,7 +64,7 @@
* Waiting indefinitely with this function is not allowed, a
* zero or negative timeout value will return immediately.
* Timeout resolution, accuracy, as well as maximum supported
- * value is system dependent, neither factor is a citical issue
+ * value is system dependent, neither factor is a critical issue
* for the intended use of this function in the library.
*
* Return values:
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
index 14ca84b..bcfa27a 100644
--- a/Utilities/cmcurl/lib/sendf.c
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -608,7 +608,7 @@ static CURLcode chop_write(struct Curl_easy *data,
/* Curl_client_write() sends data to the write callback(s)
The bit pattern defines to what "streams" to write to. Body and/or header.
- The defines are in sendf.h of course. "len" is not allowed to be 0.
+ The defines are in sendf.h of course.
If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
local character encoding. This is a problem and should be changed in
@@ -621,8 +621,10 @@ CURLcode Curl_client_write(struct Curl_easy *data,
{
struct connectdata *conn = data->conn;
- DEBUGASSERT(len);
- DEBUGASSERT(type <= 3);
+ DEBUGASSERT(!(type & ~CLIENTWRITE_BOTH));
+
+ if(!len)
+ return CURLE_OK;
/* FTP data may need conversion. */
if((type & CLIENTWRITE_BODY) &&
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index 08827d1..599ed5d 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/setopt.c
@@ -1870,6 +1870,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.ssl.primary.verifypeer;
}
break;
+#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_SSL_VERIFYPEER:
/*
* Enable peer SSL verifying for DoH.
@@ -1877,6 +1878,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.doh_verifypeer = (0 != va_arg(param, long)) ?
TRUE : FALSE;
break;
+#endif
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_VERIFYPEER:
/*
@@ -1909,6 +1911,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.ssl.primary.verifyhost;
}
break;
+#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_SSL_VERIFYHOST:
/*
* Enable verification of the host name in the peer certificate for DoH
@@ -1918,6 +1921,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* Treat both 1 and 2 as TRUE */
data->set.doh_verifyhost = (bool)((arg & 3) ? TRUE : FALSE);
break;
+#endif
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_VERIFYHOST:
/*
@@ -1953,6 +1957,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.ssl.primary.verifystatus;
}
break;
+#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_SSL_VERIFYSTATUS:
/*
* Enable certificate status verifying for DoH.
@@ -1965,6 +1970,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.doh_verifystatus = (0 != va_arg(param, long)) ?
TRUE : FALSE;
break;
+#endif
case CURLOPT_SSL_CTX_FUNCTION:
/*
* Set a SSL_CTX callback
@@ -2477,6 +2483,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
va_arg(param, char *));
break;
+ case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
+ /*
+ * Option to allow for the SHA256 of the host public key to be checked
+ * for validation purposes.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256],
+ va_arg(param, char *));
+ break;
+
case CURLOPT_SSH_KNOWNHOSTS:
/*
* Store the file name to read known hosts from.
@@ -2507,8 +2522,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* disable libcurl transfer encoding is used
*/
+#ifndef USE_HYPER
data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
break;
+#else
+ return CURLE_NOT_BUILT_IN; /* hyper doesn't support */
+#endif
case CURLOPT_HTTP_CONTENT_DECODING:
/*
@@ -2596,6 +2615,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#endif
+#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \
+ !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP)
+ case CURLOPT_MIME_OPTIONS:
+ data->set.mime_options = va_arg(param, long);
+ break;
+#endif
+
case CURLOPT_SASL_AUTHZID:
/* Authorisation identity (identity to act as) */
result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID],
@@ -2929,6 +2955,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.maxage_conn = arg;
break;
+ case CURLOPT_MAXLIFETIME_CONN:
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.maxlifetime_conn = arg;
+ break;
case CURLOPT_TRAILERFUNCTION:
#ifndef CURL_DISABLE_HTTP
data->set.trailer_callback = va_arg(param, curl_trailer_callback);
@@ -3004,6 +3036,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return result;
break;
#endif
+ case CURLOPT_PREREQFUNCTION:
+ data->set.fprereq = va_arg(param, curl_prereq_callback);
+ break;
+ case CURLOPT_PREREQDATA:
+ data->set.prereq_userp = va_arg(param, void *);
+ break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
diff --git a/Utilities/cmcurl/lib/setup-win32.h b/Utilities/cmcurl/lib/setup-win32.h
index c35dec8..fa8742f 100644
--- a/Utilities/cmcurl/lib/setup-win32.h
+++ b/Utilities/cmcurl/lib/setup-win32.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -25,11 +25,11 @@
/*
* Include header files for windows builds before redefining anything.
* Use this preprocessor block only to include or exclude windows.h,
- * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
+ * winsock2.h or ws2tcpip.h. Any other windows thing belongs
* to any other further and independent block. Under Cygwin things work
* just as under linux (e.g. <sys/socket.h>) and the winsock headers should
* never be included when __CYGWIN__ is defined. configure script takes
- * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H,
+ * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK2_H,
* neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
*/
@@ -47,10 +47,6 @@
# ifdef HAVE_WS2TCPIP_H
# include <ws2tcpip.h>
# endif
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
# endif
# include <tchar.h>
# ifdef UNICODE
@@ -67,10 +63,6 @@
#ifdef HAVE_WINSOCK2_H
# define USE_WINSOCK 2
-#else
-# ifdef HAVE_WINSOCK_H
-# error "WinSock version 1 is no longer supported, version 2 is required!"
-# endif
#endif
/*
diff --git a/Utilities/cmcurl/lib/sha256.c b/Utilities/cmcurl/lib/sha256.c
index a2e7e41..cf7ea4f 100644
--- a/Utilities/cmcurl/lib/sha256.c
+++ b/Utilities/cmcurl/lib/sha256.c
@@ -29,11 +29,18 @@
#include "curl_sha256.h"
#include "curl_hmac.h"
+#ifdef USE_WOLFSSL
+#include <wolfssl/options.h>
+#ifndef NO_SHA256
+#define USE_OPENSSL_SHA256
+#endif
+#endif
+
#if defined(USE_OPENSSL)
#include <openssl/opensslv.h>
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
+#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL)
#define USE_OPENSSL_SHA256
#endif
@@ -63,7 +70,40 @@
#if defined(USE_OPENSSL_SHA256)
/* When OpenSSL is available we use the SHA256-function from OpenSSL */
-#include <openssl/sha.h>
+#include <openssl/evp.h>
+
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct sha256_ctx {
+ EVP_MD_CTX *openssl_ctx;
+};
+typedef struct sha256_ctx my_sha256_ctx;
+
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
+{
+ ctx->openssl_ctx = EVP_MD_CTX_create();
+ if(!ctx->openssl_ctx)
+ return CURLE_OUT_OF_MEMORY;
+
+ EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL);
+ return CURLE_OK;
+}
+
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
+{
+ EVP_DigestUpdate(ctx->openssl_ctx, data, length);
+}
+
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
+{
+ EVP_DigestFinal_ex(ctx->openssl_ctx, digest, NULL);
+ EVP_MD_CTX_destroy(ctx->openssl_ctx);
+}
#elif defined(USE_GNUTLS)
@@ -74,21 +114,22 @@
/* The last #include file should be: */
#include "memdebug.h"
-typedef struct sha256_ctx SHA256_CTX;
+typedef struct sha256_ctx my_sha256_ctx;
-static void SHA256_Init(SHA256_CTX *ctx)
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
{
sha256_init(ctx);
+ return CURLE_OK;
}
-static void SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
{
sha256_update(ctx, length, data);
}
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
{
sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
}
@@ -102,20 +143,21 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
/* The last #include file should be: */
#include "memdebug.h"
-typedef mbedtls_sha256_context SHA256_CTX;
+typedef mbedtls_sha256_context my_sha256_ctx;
-static void SHA256_Init(SHA256_CTX *ctx)
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
{
#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
(void) mbedtls_sha256_starts(ctx, 0);
#else
(void) mbedtls_sha256_starts_ret(ctx, 0);
#endif
+ return CURLE_OK;
}
-static void SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
{
#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
(void) mbedtls_sha256_update(ctx, data, length);
@@ -124,7 +166,7 @@ static void SHA256_Update(SHA256_CTX *ctx,
#endif
}
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
{
#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
(void) mbedtls_sha256_finish(ctx, digest);
@@ -145,21 +187,22 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
/* The last #include file should be: */
#include "memdebug.h"
-typedef CC_SHA256_CTX SHA256_CTX;
+typedef CC_SHA256_CTX my_sha256_ctx;
-static void SHA256_Init(SHA256_CTX *ctx)
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
{
(void) CC_SHA256_Init(ctx);
+ return CURLE_OK;
}
-static void SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
{
(void) CC_SHA256_Update(ctx, data, length);
}
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
{
(void) CC_SHA256_Final(digest, ctx);
}
@@ -172,28 +215,30 @@ struct sha256_ctx {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
};
-typedef struct sha256_ctx SHA256_CTX;
+typedef struct sha256_ctx my_sha256_ctx;
#if !defined(CALG_SHA_256)
#define CALG_SHA_256 0x0000800c
#endif
-static void SHA256_Init(SHA256_CTX *ctx)
+static CURLcode my_sha256_init(my_sha256_ctx *ctx)
{
if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
}
+
+ return CURLE_OK;
}
-static void SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
+static void my_sha256_update(my_sha256_ctx *ctx,
+ const unsigned char *data,
+ unsigned int length)
{
CryptHashData(ctx->hHash, (unsigned char *) data, length, 0);
}
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
+static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
{
unsigned long length = 0;
@@ -262,7 +307,7 @@ struct sha256_state {
unsigned long state[8], curlen;
unsigned char buf[64];
};
-typedef struct sha256_state SHA256_CTX;
+typedef struct sha256_state my_sha256_ctx;
/* The K array */
static const unsigned long K[64] = {
@@ -339,7 +384,7 @@ static int sha256_compress(struct sha256_state *md,
}
/* Initialize the hash state */
-static void SHA256_Init(struct sha256_state *md)
+static CURLcode my_sha256_init(struct sha256_state *md)
{
md->curlen = 0;
md->length = 0;
@@ -351,6 +396,8 @@ static void SHA256_Init(struct sha256_state *md)
md->state[5] = 0x9B05688CUL;
md->state[6] = 0x1F83D9ABUL;
md->state[7] = 0x5BE0CD19UL;
+
+ return CURLE_OK;
}
/*
@@ -358,11 +405,11 @@ static void SHA256_Init(struct sha256_state *md)
@param md The hash state
@param in The data to hash
@param inlen The length of the data (octets)
- @return CRYPT_OK if successful
+ @return 0 if successful
*/
-static int SHA256_Update(struct sha256_state *md,
- const unsigned char *in,
- unsigned long inlen)
+static int my_sha256_update(struct sha256_state *md,
+ const unsigned char *in,
+ unsigned long inlen)
{
unsigned long n;
@@ -399,10 +446,10 @@ static int SHA256_Update(struct sha256_state *md,
Terminate the hash to get the digest
@param md The hash state
@param out [out] The destination of the hash (32 bytes)
- @return CRYPT_OK if successful
+ @return 0 if successful
*/
-static int SHA256_Final(unsigned char *out,
- struct sha256_state *md)
+static int my_sha256_final(unsigned char *out,
+ struct sha256_state *md)
{
int i;
@@ -455,28 +502,34 @@ static int SHA256_Final(unsigned char *out,
* output [in/out] - The output buffer.
* input [in] - The input data.
* length [in] - The input length.
+ *
+ * Returns CURLE_OK on success.
*/
-void Curl_sha256it(unsigned char *output, const unsigned char *input,
+CURLcode Curl_sha256it(unsigned char *output, const unsigned char *input,
const size_t length)
{
- SHA256_CTX ctx;
+ CURLcode result;
+ my_sha256_ctx ctx;
- SHA256_Init(&ctx);
- SHA256_Update(&ctx, input, curlx_uztoui(length));
- SHA256_Final(output, &ctx);
+ result = my_sha256_init(&ctx);
+ if(!result) {
+ my_sha256_update(&ctx, input, curlx_uztoui(length));
+ my_sha256_final(output, &ctx);
+ }
+ return result;
}
const struct HMAC_params Curl_HMAC_SHA256[] = {
{
/* Hash initialization function. */
- CURLX_FUNCTION_CAST(HMAC_hinit_func, SHA256_Init),
+ CURLX_FUNCTION_CAST(HMAC_hinit_func, my_sha256_init),
/* Hash update function. */
- CURLX_FUNCTION_CAST(HMAC_hupdate_func, SHA256_Update),
+ CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_sha256_update),
/* Hash computation end function. */
- CURLX_FUNCTION_CAST(HMAC_hfinal_func, SHA256_Final),
+ CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_sha256_final),
/* Size of hash context structure. */
- sizeof(SHA256_CTX),
+ sizeof(my_sha256_ctx),
/* Maximum key length. */
64,
/* Result size. */
diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c
index 9c43c8f..403563f 100644
--- a/Utilities/cmcurl/lib/share.c
+++ b/Utilities/cmcurl/lib/share.c
@@ -39,11 +39,7 @@ curl_share_init(void)
if(share) {
share->magic = CURL_GOOD_SHARE;
share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
-
- if(Curl_mk_dnscache(&share->hostcache)) {
- free(share);
- return NULL;
- }
+ Curl_init_dnscache(&share->hostcache);
}
return share;
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index 02ddaca..6c08293 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -82,6 +82,7 @@
#include "multiif.h"
#include "url.h"
#include "curl_gethostname.h"
+#include "bufref.h"
#include "curl_sasl.h"
#include "warnless.h"
/* The last 3 #include files should be in this order */
@@ -108,12 +109,12 @@ static CURLcode smtp_parse_url_path(struct Curl_easy *data);
static CURLcode smtp_parse_custom_request(struct Curl_easy *data);
static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma,
char **address, struct hostname *host);
-static CURLcode smtp_perform_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *mech,
- const char *initresp);
-static CURLcode smtp_continue_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *resp);
-static void smtp_get_message(char *buffer, char **outptr);
+static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech,
+ const struct bufref *initresp);
+static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech,
+ const struct bufref *resp);
+static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech);
+static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out);
/*
* SMTP protocol handler.
@@ -175,13 +176,16 @@ const struct Curl_handler Curl_handler_smtps = {
/* SASL parameters for the smtp protocol */
static const struct SASLproto saslsmtp = {
- "smtp", /* The service name */
- 334, /* Code received when continuation is expected */
- 235, /* Code to receive upon authentication success */
- 512 - 8, /* Maximum initial response length (no max) */
- smtp_perform_auth, /* Send authentication command */
- smtp_continue_auth, /* Send authentication continuation */
- smtp_get_message /* Get SASL response message */
+ "smtp", /* The service name */
+ smtp_perform_auth, /* Send authentication command */
+ smtp_continue_auth, /* Send authentication continuation */
+ smtp_cancel_auth, /* Cancel authentication */
+ smtp_get_message, /* Get SASL response message */
+ 512 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */
+ 334, /* Code received when continuation is expected */
+ 235, /* Code to receive upon authentication success */
+ SASL_AUTH_DEFAULT, /* Default mechanisms */
+ SASL_FLAG_BASE64 /* Configuration flags */
};
#ifdef USE_SSL
@@ -218,7 +222,7 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
/* Do we have a command response? This should be the response code followed
by a space and optionally some text as per RFC-5321 and as outlined in
- Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
+ Section 4. Examples of RFC-4954 but some email servers ignore this and
only send the response code instead as per Section 4.2. */
if(line[3] == ' ' || len == 5) {
char tmpline[6];
@@ -248,34 +252,32 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
*
* Gets the authentication message from the response buffer.
*/
-static void smtp_get_message(char *buffer, char **outptr)
+static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
{
- size_t len = strlen(buffer);
- char *message = NULL;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 4) {
/* Find the start of the message */
len -= 4;
- for(message = buffer + 4; *message == ' ' || *message == '\t';
- message++, len--)
+ for(message += 4; *message == ' ' || *message == '\t'; message++, len--)
;
/* Find the end of the message */
- for(; len--;)
+ while(len--)
if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
message[len] != '\t')
break;
/* Terminate the message */
- if(++len) {
- message[len] = '\0';
- }
+ message[++len] = '\0';
+ Curl_bufref_set(out, message, len, NULL);
}
else
/* junk input => zero length output */
- message = &buffer[len];
+ Curl_bufref_set(out, "", 0, NULL);
- *outptr = message;
+ return CURLE_OK;
}
/***********************************************************************
@@ -421,16 +423,16 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
* authentication mechanism.
*/
static CURLcode smtp_perform_auth(struct Curl_easy *data,
- struct connectdata *conn,
const char *mech,
- const char *initresp)
+ const struct bufref *initresp)
{
CURLcode result = CURLE_OK;
- struct smtp_conn *smtpc = &conn->proto.smtpc;
+ struct smtp_conn *smtpc = &data->conn->proto.smtpc;
+ const char *ir = (const char *) Curl_bufref_ptr(initresp);
- if(initresp) { /* AUTH <mech> ...<crlf> */
+ if(ir) { /* AUTH <mech> ...<crlf> */
/* Send the AUTH command with the initial response */
- result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, initresp);
+ result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, ir);
}
else {
/* Send the AUTH command */
@@ -444,14 +446,33 @@ static CURLcode smtp_perform_auth(struct Curl_easy *data,
*
* smtp_continue_auth()
*
- * Sends SASL continuation data or cancellation.
+ * Sends SASL continuation data.
*/
static CURLcode smtp_continue_auth(struct Curl_easy *data,
- struct connectdata *conn, const char *resp)
+ const char *mech,
+ const struct bufref *resp)
{
- struct smtp_conn *smtpc = &conn->proto.smtpc;
+ struct smtp_conn *smtpc = &data->conn->proto.smtpc;
+
+ (void)mech;
+
+ return Curl_pp_sendf(data, &smtpc->pp,
+ "%s", (const char *) Curl_bufref_ptr(resp));
+}
+
+/***********************************************************************
+ *
+ * smtp_cancel_auth()
+ *
+ * Sends SASL cancellation.
+ */
+static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech)
+{
+ struct smtp_conn *smtpc = &data->conn->proto.smtpc;
- return Curl_pp_sendf(data, &smtpc->pp, "%s", resp);
+ (void)mech;
+
+ return Curl_pp_sendf(data, &smtpc->pp, "*");
}
/***********************************************************************
@@ -469,7 +490,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
saslprogress progress;
/* Check we have enough data to authenticate with, and the
- server supports authentiation, and end the connect phase if not */
+ server supports authentication, and end the connect phase if not */
if(!smtpc->auth_supported ||
!Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
state(data, SMTP_STOP);
@@ -477,7 +498,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
}
/* Calculate the SASL login details */
- result = Curl_sasl_start(&smtpc->sasl, data, conn, FALSE, &progress);
+ result = Curl_sasl_start(&smtpc->sasl, data, FALSE, &progress);
if(!result) {
if(progress == SASL_INPROGRESS)
@@ -506,7 +527,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
if(smtp->rcpt) {
/* We notify the server we are sending UTF-8 data if a) it supports the
- SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
+ SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
either the local address or host name parts. This is regardless of
whether the host name is encoded using IDN ACE */
bool utf8 = FALSE;
@@ -579,7 +600,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
struct connectdata *conn = data->conn;
/* We notify the server we are sending UTF-8 data if a) it supports the
- SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in
+ SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
either the local address or host name parts. This is regardless of
whether the host name is encoded using IDN ACE */
bool utf8 = FALSE;
@@ -985,7 +1006,7 @@ static CURLcode smtp_state_auth_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
- result = Curl_sasl_continue(&smtpc->sasl, data, conn, smtpcode, &progress);
+ result = Curl_sasl_continue(&smtpc->sasl, data, smtpcode, &progress);
if(!result)
switch(progress) {
case SASL_DONE:
@@ -1333,7 +1354,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp);
/* Initialize the SASL storage */
- Curl_sasl_init(&smtpc->sasl, &saslsmtp);
+ Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
/* Initialise the pingpong layer */
Curl_pp_setup(pp);
@@ -1655,8 +1676,6 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn)
struct smtp_conn *smtpc = &conn->proto.smtpc;
const char *ptr = conn->options;
- smtpc->sasl.resetprefs = TRUE;
-
while(!result && ptr && *ptr) {
const char *key = ptr;
const char *value;
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
index db4c808..a014aa6 100644
--- a/Utilities/cmcurl/lib/socks.c
+++ b/Utilities/cmcurl/lib/socks.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -38,6 +38,7 @@
#include "timeval.h"
#include "socks.h"
#include "multiif.h" /* for getsock macros */
+#include "inet_pton.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -856,10 +857,32 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
socksreq[len++] = 0; /* must be zero */
if(!socks5_resolve_local) {
- socksreq[len++] = 3; /* ATYP: domain name = 3 */
- socksreq[len++] = (char) hostname_len; /* one byte address length */
- memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */
- len += hostname_len;
+ /* ATYP: domain name = 3,
+ IPv6 == 4,
+ IPv4 == 1 */
+ unsigned char ip4[4];
+#ifdef ENABLE_IPV6
+ if(conn->bits.ipv6_ip) {
+ char ip6[16];
+ if(1 != Curl_inet_pton(AF_INET6, hostname, ip6))
+ return CURLPX_BAD_ADDRESS_TYPE;
+ socksreq[len++] = 4;
+ memcpy(&socksreq[len], ip6, sizeof(ip6));
+ len += sizeof(ip6);
+ }
+ else
+#endif
+ if(1 == Curl_inet_pton(AF_INET, hostname, ip4)) {
+ socksreq[len++] = 1;
+ memcpy(&socksreq[len], ip4, sizeof(ip4));
+ len += sizeof(ip4);
+ }
+ else {
+ socksreq[len++] = 3;
+ socksreq[len++] = (char) hostname_len; /* one byte address length */
+ memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */
+ len += hostname_len;
+ }
infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
hostname, remote_port);
}
diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c
index 34bfa37..8ef2f8f 100644
--- a/Utilities/cmcurl/lib/socks_gssapi.c
+++ b/Utilities/cmcurl/lib/socks_gssapi.c
@@ -257,7 +257,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- if(socksreq[1] != 1) { /* status / messgae type */
+ if(socksreq[1] != 1) { /* status / message type */
failf(data, "Invalid GSS-API authentication response type (%d %d).",
socksreq[0], socksreq[1]);
gss_release_name(&gss_status, &server);
@@ -452,7 +452,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- if(socksreq[1] != 2) { /* status / messgae type */
+ if(socksreq[1] != 2) { /* status / message type */
failf(data, "Invalid GSS-API encryption response type (%d %d).",
socksreq[0], socksreq[1]);
gss_delete_sec_context(&gss_status, &gss_context, NULL);
diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c
index cb225b9..ffc8703 100644
--- a/Utilities/cmcurl/lib/socks_sspi.c
+++ b/Utilities/cmcurl/lib/socks_sspi.c
@@ -277,7 +277,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- if(socksreq[1] != 1) { /* status / messgae type */
+ if(socksreq[1] != 1) { /* status / message type */
failf(data, "Invalid SSPI authentication response type (%u %u).",
(unsigned int)socksreq[0], (unsigned int)socksreq[1]);
free(service_name);
diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c
index a94e2c8..bcc0795 100644
--- a/Utilities/cmcurl/lib/splay.c
+++ b/Utilities/cmcurl/lib/splay.c
@@ -107,7 +107,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
if(!node)
return t;
- if(t != NULL) {
+ if(t) {
t = Curl_splay(i, t);
if(compare(i, t->key) == 0) {
/* There already exists a node in the tree with the very same key. Build
@@ -154,7 +154,7 @@ struct Curl_tree *Curl_splaygetbest(struct curltime i,
struct Curl_tree *t,
struct Curl_tree **removed)
{
- static struct curltime tv_zero = {0, 0};
+ static const struct curltime tv_zero = {0, 0};
struct Curl_tree *x;
if(!t) {
diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c
index 8a27197..07d73a7 100644
--- a/Utilities/cmcurl/lib/strerror.c
+++ b/Utilities/cmcurl/lib/strerror.c
@@ -404,6 +404,9 @@ curl_multi_strerror(CURLMcode error)
case CURLM_BAD_FUNCTION_ARGUMENT:
return "A libcurl function was given a bad argument";
+ case CURLM_ABORTED_BY_CALLBACK:
+ return "Operation was aborted by an application callback";
+
case CURLM_LAST:
break;
}
@@ -453,6 +456,114 @@ curl_share_strerror(CURLSHcode error)
#endif
}
+const char *
+curl_url_strerror(CURLUcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch(error) {
+ case CURLUE_OK:
+ return "No error";
+
+ case CURLUE_BAD_HANDLE:
+ return "An invalid CURLU pointer was passed as argument";
+
+ case CURLUE_BAD_PARTPOINTER:
+ return "An invalid 'part' argument was passed as argument";
+
+ case CURLUE_MALFORMED_INPUT:
+ return "Malformed input to a URL function";
+
+ case CURLUE_BAD_PORT_NUMBER:
+ return "Port number was not a decimal number between 0 and 65535";
+
+ case CURLUE_UNSUPPORTED_SCHEME:
+ return "This libcurl build doesn't support the given URL scheme";
+
+ case CURLUE_URLDECODE:
+ return "URL decode error, most likely because of rubbish in the input";
+
+ case CURLUE_OUT_OF_MEMORY:
+ return "A memory function failed";
+
+ case CURLUE_USER_NOT_ALLOWED:
+ return "Credentials was passed in the URL when prohibited";
+
+ case CURLUE_UNKNOWN_PART:
+ return "An unknown part ID was passed to a URL API function";
+
+ case CURLUE_NO_SCHEME:
+ return "No scheme part in the URL";
+
+ case CURLUE_NO_USER:
+ return "No user part in the URL";
+
+ case CURLUE_NO_PASSWORD:
+ return "No password part in the URL";
+
+ case CURLUE_NO_OPTIONS:
+ return "No options part in the URL";
+
+ case CURLUE_NO_HOST:
+ return "No host part in the URL";
+
+ case CURLUE_NO_PORT:
+ return "No port part in the URL";
+
+ case CURLUE_NO_QUERY:
+ return "No query part in the URL";
+
+ case CURLUE_NO_FRAGMENT:
+ return "No fragment part in the URL";
+
+ case CURLUE_NO_ZONEID:
+ return "No zoneid part in the URL";
+
+ case CURLUE_BAD_LOGIN:
+ return "Bad login part";
+
+ case CURLUE_BAD_IPV6:
+ return "Bad IPv6 address";
+
+ case CURLUE_BAD_HOSTNAME:
+ return "Bad hostname";
+
+ case CURLUE_BAD_FILE_URL:
+ return "Bad file:// URL";
+
+ case CURLUE_BAD_SLASHES:
+ return "Unsupported number of slashes";
+
+ case CURLUE_BAD_SCHEME:
+ return "Bad scheme";
+
+ case CURLUE_BAD_PATH:
+ return "Bad path";
+
+ case CURLUE_BAD_FRAGMENT:
+ return "Bad fragment";
+
+ case CURLUE_BAD_QUERY:
+ return "Bad query";
+
+ case CURLUE_BAD_PASSWORD:
+ return "Bad password";
+
+ case CURLUE_BAD_USER:
+ return "Bad user";
+
+ case CURLUE_LAST:
+ break;
+ }
+
+ return "CURLUcode unknown";
+#else
+ if(error == CURLUE_OK)
+ return "No error";
+ else
+ return "Error";
+#endif
+}
+
#ifdef USE_WINSOCK
/* This is a helper function for Curl_strerror that converts Winsock error
* codes (WSAGetLastError) to error messages.
diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c
index 2939fd0..9a6dd9c 100644
--- a/Utilities/cmcurl/lib/system_win32.c
+++ b/Utilities/cmcurl/lib/system_win32.c
@@ -102,7 +102,9 @@ CURLcode Curl_win32_init(long flags)
Curl_if_nametoindex = pIfNameToIndex;
}
- if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT,
+ /* curlx_verify_windows_version must be called during init at least once
+ because it has its own initialization routine. */
+ if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
Curl_isVistaOrGreater = TRUE;
}
diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c
index aae997d..f8c6844 100644
--- a/Utilities/cmcurl/lib/tftp.c
+++ b/Utilities/cmcurl/lib/tftp.c
@@ -186,7 +186,7 @@ const struct Curl_handler Curl_handler_tftp = {
PORT_TFTP, /* defport */
CURLPROTO_TFTP, /* protocol */
CURLPROTO_TFTP, /* family */
- PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
+ PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
};
/**********************************************************
@@ -1304,9 +1304,9 @@ static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
/**********************************************************
*
- * tftp_peform
+ * tftp_perform
*
- * Entry point for transfer from tftp_do, sarts state mach
+ * Entry point for transfer from tftp_do, starts state mach
*
**********************************************************/
static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index 05fec79..22704fa 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -1631,7 +1631,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
if((type != FOLLOW_RETRY) &&
(data->req.httpcode != 401) && (data->req.httpcode != 407) &&
- Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN))
+ Curl_is_absolute_url(newurl, NULL, 0))
/* If this is not redirect due to a 401 or 407 response and an absolute
URL: don't allow a custom port number */
disallowport = TRUE;
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index 37b6c0e..9f10135 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -137,6 +137,15 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "curl_memory.h"
#include "memdebug.h"
+/* Count of the backend ssl objects to allocate */
+#ifdef USE_SSL
+# ifndef CURL_DISABLE_PROXY
+# define SSL_BACKEND_CNT 4
+# else
+# define SSL_BACKEND_CNT 2
+# endif
+#endif
+
static void conn_free(struct connectdata *conn);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
@@ -354,9 +363,7 @@ static void up_free(struct Curl_easy *data)
* This is the internal function curl_easy_cleanup() calls. This should
* cleanup and free all resources associated with this sessionhandle.
*
- * NOTE: if we ever add something that attempts to write to a socket or
- * similar here, we must ignore SIGPIPE first. It is currently only done
- * when curl_easy_perform() is invoked.
+ * We ignore SIGPIPE when this is called from curl_easy_cleanup.
*/
CURLcode Curl_close(struct Curl_easy **datap)
@@ -542,8 +549,10 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
* libcurl 7.10 introduced SSL verification *by default*! This needs to be
* switched off unless wanted.
*/
+#ifndef CURL_DISABLE_DOH
set->doh_verifyhost = TRUE;
set->doh_verifypeer = TRUE;
+#endif
set->ssl.primary.verifypeer = TRUE;
set->ssl.primary.verifyhost = TRUE;
#ifdef USE_TLS_SRP
@@ -622,6 +631,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
set->maxage_conn = 118;
+ set->maxlifetime_conn = 0;
set->http09_allowed = FALSE;
set->httpwant =
#ifdef USE_NGHTTP2
@@ -844,7 +854,7 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
return CURLE_OK;
}
- if(conn->dns_entry != NULL) {
+ if(conn->dns_entry) {
Curl_resolv_unlock(data, conn->dns_entry);
conn->dns_entry = NULL;
}
@@ -962,21 +972,36 @@ socks_proxy_info_matches(const struct proxy_info *data,
#define socks_proxy_info_matches(x,y) FALSE
#endif
-/* A connection has to have been idle for a shorter time than 'maxage_conn' to
- be subject for reuse. The success rate is just too low after this. */
+/* A connection has to have been idle for a shorter time than 'maxage_conn'
+ (the success rate is just too low after this), or created less than
+ 'maxlifetime_conn' ago, to be subject for reuse. */
static bool conn_maxage(struct Curl_easy *data,
struct connectdata *conn,
struct curltime now)
{
- timediff_t idletime = Curl_timediff(now, conn->lastused);
+ timediff_t idletime, lifetime;
+
+ idletime = Curl_timediff(now, conn->lastused);
idletime /= 1000; /* integer seconds is fine */
if(idletime > data->set.maxage_conn) {
- infof(data, "Too old connection (%ld seconds), disconnect it",
+ infof(data, "Too old connection (%ld seconds idle), disconnect it",
idletime);
return TRUE;
}
+
+ lifetime = Curl_timediff(now, conn->created);
+ lifetime /= 1000; /* integer seconds is fine */
+
+ if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) {
+ infof(data,
+ "Too old connection (%ld seconds since creation), disconnect it",
+ lifetime);
+ return TRUE;
+ }
+
+
return FALSE;
}
@@ -1284,13 +1309,12 @@ ConnectionExists(struct Curl_easy *data,
if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete)
continue;
}
- else {
- if(!Curl_ssl_config_matches(&needle->ssl_config,
- &check->ssl_config))
- continue;
- if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete)
- continue;
- }
+
+ if(!Curl_ssl_config_matches(&needle->ssl_config,
+ &check->ssl_config))
+ continue;
+ if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete)
+ continue;
}
}
#endif
@@ -1667,7 +1691,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
data becomes proxy backend data). */
{
size_t sslsize = Curl_ssl->sizeof_ssl_backend_data;
- char *ssl = calloc(4, sslsize);
+ char *ssl = calloc(SSL_BACKEND_CNT, sslsize);
if(!ssl) {
free(conn);
return NULL;
@@ -1934,7 +1958,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
- !Curl_is_absolute_url(data->state.url, NULL, MAX_SCHEME_LEN)) {
+ !Curl_is_absolute_url(data->state.url, NULL, 0)) {
char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
data->state.url);
if(!url)
@@ -1954,7 +1978,8 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
CURLU_DISALLOW_USER : 0) |
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
if(uc) {
- DEBUGF(infof(data, "curl_url_set rejected %s", data->state.url));
+ DEBUGF(infof(data, "curl_url_set rejected %s: %s", data->state.url,
+ curl_url_strerror(uc)));
return Curl_uc_to_curlcode(uc);
}
@@ -2380,6 +2405,11 @@ static CURLcode parse_proxy(struct Curl_easy *data,
CURLcode result = CURLE_OK;
char *scheme = NULL;
+ if(!uhp) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+
/* When parsing the proxy, allowing non-supported schemes since we have
these made up ones for proxies. Guess scheme for URLs without it. */
uc = curl_url_set(uhp, CURLUPART_URL, proxy,
@@ -2571,7 +2601,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
if(data->set.str[STRING_PROXY]) {
proxy = strdup(data->set.str[STRING_PROXY]);
/* if global proxy is set, this is it */
- if(NULL == proxy) {
+ if(!proxy) {
failf(data, "memory shortage");
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -2581,7 +2611,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
if(data->set.str[STRING_PRE_PROXY]) {
socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
/* if global socks proxy is set, this is it */
- if(NULL == socksproxy) {
+ if(!socksproxy) {
failf(data, "memory shortage");
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -2763,7 +2793,7 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
size_t plen;
size_t olen;
- /* the input length check is because this is called directcly from setopt
+ /* the input length check is because this is called directly from setopt
and isn't going through the regular string length check */
size_t llen = strlen(login);
if(llen > CURL_MAX_INPUT_LENGTH)
@@ -4093,7 +4123,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
/* init the single-transfer specific data */
Curl_free_request_state(data);
memset(&data->req, 0, sizeof(struct SingleRequest));
- data->req.maxdownload = -1;
+ data->req.size = data->req.maxdownload = -1;
/* call the stuff that needs to be called */
result = create_conn(data, &conn, asyncp);
diff --git a/Utilities/cmcurl/lib/urlapi-int.h b/Utilities/cmcurl/lib/urlapi-int.h
index 4257233..bd6b601 100644
--- a/Utilities/cmcurl/lib/urlapi-int.h
+++ b/Utilities/cmcurl/lib/urlapi-int.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,8 +22,6 @@
*
***************************************************************************/
#include "curl_setup.h"
-/* scheme is not URL encoded, the longest libcurl supported ones are... */
-#define MAX_SCHEME_LEN 40
bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen);
diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index 7f03862..d29aeb2 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/urlapi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -30,6 +30,7 @@
#include "escape.h"
#include "curl_ctype.h"
#include "inet_pton.h"
+#include "inet_ntop.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -50,6 +51,9 @@
((str)[1] == ':' || (str)[1] == '|') && \
((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0))
+/* scheme is not URL encoded, the longest libcurl supported ones are... */
+#define MAX_SCHEME_LEN 40
+
/* Internal representation of CURLU. Point to URL-encoded strings. */
struct Curl_URL {
char *scheme;
@@ -157,23 +161,23 @@ static size_t strlen_url(const char *url, bool relative)
continue;
}
- switch(*ptr) {
- case '?':
- left = FALSE;
- /* FALLTHROUGH */
- default:
- if(urlchar_needs_escaping(*ptr))
- newlen += 2;
- newlen++;
- break;
- case ' ':
+ if(*ptr == ' ') {
if(left)
newlen += 3;
else
newlen++;
- break;
+ continue;
}
+
+ if (*ptr == '?')
+ left = FALSE;
+
+ if(urlchar_needs_escaping(*ptr))
+ newlen += 2;
+
+ newlen++;
}
+
return newlen;
}
@@ -202,19 +206,7 @@ static void strcpy_url(char *output, const char *url, bool relative)
continue;
}
- switch(*iptr) {
- case '?':
- left = FALSE;
- /* FALLTHROUGH */
- default:
- if(urlchar_needs_escaping(*iptr)) {
- msnprintf(optr, 4, "%%%02x", *iptr);
- optr += 3;
- }
- else
- *optr++=*iptr;
- break;
- case ' ':
+ if(*iptr == ' ') {
if(left) {
*optr++='%'; /* add a '%' */
*optr++='2'; /* add a '2' */
@@ -222,41 +214,58 @@ static void strcpy_url(char *output, const char *url, bool relative)
}
else
*optr++='+'; /* add a '+' here */
- break;
+ continue;
}
+
+ if(*iptr == '?')
+ left = FALSE;
+
+ if(urlchar_needs_escaping(*iptr)) {
+ msnprintf(optr, 4, "%%%02x", *iptr);
+ optr += 3;
+ }
+ else
+ *optr++ = *iptr;
}
*optr = 0; /* null-terminate output buffer */
}
/*
- * Returns true if the given URL is absolute (as opposed to relative) within
- * the buffer size. Returns the scheme in the buffer if TRUE and 'buf' is
- * non-NULL.
+ * Returns true if the given URL is absolute (as opposed to relative). Returns
+ * the scheme in the buffer if TRUE and 'buf' is non-NULL. The buflen must
+ * be larger than MAX_SCHEME_LEN if buf is set.
*/
bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen)
{
size_t i;
+ DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN));
+ (void)buflen; /* only used in debug-builds */
+ if(buf)
+ buf[0] = 0; /* always leave a defined value in buf */
#ifdef WIN32
if(STARTS_WITH_DRIVE_PREFIX(url))
return FALSE;
#endif
- for(i = 0; i < buflen && url[i]; ++i) {
+ for(i = 0; i < MAX_SCHEME_LEN; ++i) {
char s = url[i];
- if((s == ':') && (url[i + 1] == '/')) {
- if(buf)
- buf[i] = 0;
- return TRUE;
- }
- /* RFC 3986 3.1 explains:
- scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
- */
- else if(ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') ) {
- if(buf)
- buf[i] = (char)TOLOWER(s);
+ if(s && (ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') )) {
+ /* RFC 3986 3.1 explains:
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ */
}
- else
+ else {
break;
+ }
+ }
+ if(i && (url[i] == ':') && (url[i + 1] == '/')) {
+ if(buf) {
+ buf[i] = 0;
+ while(i--) {
+ buf[i] = (char)TOLOWER(url[i]);
+ }
+ }
+ return TRUE;
}
return FALSE;
}
@@ -420,6 +429,29 @@ static char *concat_url(const char *base, const char *relurl)
return newest;
}
+/* scan for byte values < 31 or 127 */
+static bool junkscan(const char *part, unsigned int flags)
+{
+ if(part) {
+ static const char badbytes[]={
+ /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x7f, 0x00 /* null-terminate */
+ };
+ size_t n = strlen(part);
+ size_t nfine = strcspn(part, badbytes);
+ if(nfine != n)
+ /* since we don't know which part is scanned, return a generic error
+ code */
+ return TRUE;
+ if(!(flags & CURLU_ALLOW_SPACE) && strchr(part, ' '))
+ return TRUE;
+ }
+ return FALSE;
+}
+
/*
* parse_hostname_login()
*
@@ -467,7 +499,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
(h && (h->flags & PROTOPT_URLOPTIONS)) ?
&optionsp:NULL);
if(ccode) {
- result = CURLUE_MALFORMED_INPUT;
+ result = CURLUE_BAD_LOGIN;
goto out;
}
@@ -477,15 +509,28 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
result = CURLUE_USER_NOT_ALLOWED;
goto out;
}
-
+ if(junkscan(userp, flags)) {
+ result = CURLUE_BAD_USER;
+ goto out;
+ }
u->user = userp;
}
- if(passwdp)
+ if(passwdp) {
+ if(junkscan(passwdp, flags)) {
+ result = CURLUE_BAD_PASSWORD;
+ goto out;
+ }
u->password = passwdp;
+ }
- if(optionsp)
+ if(optionsp) {
+ if(junkscan(optionsp, flags)) {
+ result = CURLUE_BAD_LOGIN;
+ goto out;
+ }
u->options = optionsp;
+ }
return CURLUE_OK;
out:
@@ -493,6 +538,9 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
free(userp);
free(passwdp);
free(optionsp);
+ u->user = NULL;
+ u->password = NULL;
+ u->options = NULL;
return result;
}
@@ -516,19 +564,19 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
int zonelen = len;
if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) {
if(']' != endbracket)
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_IPV6;
portptr = &hostname[--zonelen + len + 1];
}
else
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_IPV6;
}
else
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_IPV6;
/* this is a RFC2732-style specified IP-address */
if(portptr && *portptr) {
if(*portptr != ':')
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_IPV6;
}
else
portptr = NULL;
@@ -558,9 +606,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */
- if((port <= 0) || (port > 0xffff))
- /* Single unix standard says port numbers are 16 bits long, but we don't
- treat port zero as OK. */
+ if(port > 0xffff)
return CURLUE_BAD_PORT_NUMBER;
if(rest[0])
@@ -579,46 +625,20 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
return CURLUE_OK;
}
-/* scan for byte values < 31 or 127 */
-static bool junkscan(const char *part, unsigned int flags)
-{
- if(part) {
- static const char badbytes[]={
- /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x7f, 0x00 /* null-terminate */
- };
- size_t n = strlen(part);
- size_t nfine = strcspn(part, badbytes);
- if(nfine != n)
- /* since we don't know which part is scanned, return a generic error
- code */
- return TRUE;
- if(!(flags & CURLU_ALLOW_SPACE) && strchr(part, ' '))
- return TRUE;
- }
- return FALSE;
-}
-
static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
{
size_t len;
size_t hlen = strlen(hostname);
if(hostname[0] == '[') {
-#ifdef ENABLE_IPV6
- char dest[16]; /* fits a binary IPv6 address */
-#endif
const char *l = "0123456789abcdefABCDEF:.";
if(hlen < 4) /* '[::]' is the shortest possible valid string */
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_IPV6;
hostname++;
hlen -= 2;
if(hostname[hlen] != ']')
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_IPV6;
/* only valid letters are ok */
len = strspn(hostname, l);
@@ -635,6 +655,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
while(*h && (*h != ']') && (i < 15))
zoneid[i++] = *h++;
if(!i || (']' != *h))
+ /* impossible to reach? */
return CURLUE_MALFORMED_INPUT;
zoneid[i] = 0;
u->zoneid = strdup(zoneid);
@@ -644,22 +665,34 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
hostname[len + 1] = 0; /* terminate the hostname */
}
else
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_IPV6;
/* hostname is fine */
}
#ifdef ENABLE_IPV6
- hostname[hlen] = 0; /* end the address there */
- if(1 != Curl_inet_pton(AF_INET6, hostname, dest))
- return CURLUE_MALFORMED_INPUT;
- hostname[hlen] = ']'; /* restore ending bracket */
+ {
+ char dest[16]; /* fits a binary IPv6 address */
+ char norm[MAX_IPADR_LEN];
+ hostname[hlen] = 0; /* end the address there */
+ if(1 != Curl_inet_pton(AF_INET6, hostname, dest))
+ return CURLUE_BAD_IPV6;
+
+ /* check if it can be done shorter */
+ if(Curl_inet_ntop(AF_INET6, dest, norm, sizeof(norm)) &&
+ (strlen(norm) < hlen)) {
+ strcpy(hostname, norm);
+ hlen = strlen(norm);
+ hostname[hlen + 1] = 0;
+ }
+ hostname[hlen] = ']'; /* restore ending bracket */
+ }
#endif
}
else {
/* letters from the second string is not ok */
- len = strcspn(hostname, " ");
+ len = strcspn(hostname, " \r\n");
if(hlen != len)
/* hostname with bad content */
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_HOSTNAME;
}
if(!hostname[0])
return CURLUE_NO_HOST;
@@ -756,10 +789,35 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
return TRUE;
}
+/* return strdup'ed version in 'outp', possibly percent decoded */
+static CURLUcode decode_host(char *hostname, char **outp)
+{
+ char *per = NULL;
+ if(hostname[0] != '[')
+ /* only decode if not an ipv6 numerical */
+ per = strchr(hostname, '%');
+ if(!per) {
+ *outp = strdup(hostname);
+ if(!*outp)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ else {
+ /* might be encoded */
+ size_t dlen;
+ CURLcode result = Curl_urldecode(NULL, hostname, 0,
+ outp, &dlen, REJECT_CTRL);
+ if(result)
+ return CURLUE_BAD_HOSTNAME;
+ }
+
+ return CURLUE_OK;
+}
+
static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
{
char *path;
bool path_alloced = FALSE;
+ bool uncpath = FALSE;
char *hostname;
char *query = NULL;
char *fragment = NULL;
@@ -794,11 +852,14 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
}
/* handle the file: scheme */
- if(url_has_scheme && strcasecompare(schemebuf, "file")) {
+ if(url_has_scheme && !strcmp(schemebuf, "file")) {
+ if(urllen <= 6)
+ /* file:/ is not enough to actually be a complete file: URL */
+ return CURLUE_BAD_FILE_URL;
+
/* path has been allocated large enough to hold this */
strcpy(path, &url[5]);
- hostname = NULL; /* no host for file: URLs */
u->scheme = strdup("file");
if(!u->scheme)
return CURLUE_OUT_OF_MEMORY;
@@ -820,10 +881,13 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
*
* o the hostname matches "localhost" (case-insensitively), or
*
- * o the hostname is a FQDN that resolves to this machine.
+ * o the hostname is a FQDN that resolves to this machine, or
+ *
+ * o it is an UNC String transformed to an URI (Windows only, RFC 8089
+ * Appendix E.3).
*
* For brevity, we only consider URLs with empty, "localhost", or
- * "127.0.0.1" hostnames as local.
+ * "127.0.0.1" hostnames as local, otherwise as an UNC String.
*
* Additionally, there is an exception for URLs with a Windows drive
* letter in the authority (which was accidentally omitted from RFC 8089
@@ -832,25 +896,50 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
/* the URL includes a host name, it must match "localhost" or
"127.0.0.1" to be valid */
- if(!checkprefix("localhost/", ptr) &&
- !checkprefix("127.0.0.1/", ptr)) {
+ if(checkprefix("localhost/", ptr) ||
+ checkprefix("127.0.0.1/", ptr)) {
+ ptr += 9; /* now points to the slash after the host */
+ }
+ else {
+#if defined(WIN32)
+ size_t len;
+
+ /* the host name, NetBIOS computer name, can not contain disallowed
+ chars, and the delimiting slash character must be appended to the
+ host name */
+ path = strpbrk(ptr, "/\\:*?\"<>|");
+ if(!path || *path != '/')
+ return CURLUE_BAD_FILE_URL;
+
+ len = path - ptr;
+ if(len) {
+ memcpy(hostname, ptr, len);
+ hostname[len] = 0;
+ uncpath = TRUE;
+ }
+
+ ptr -= 2; /* now points to the // before the host in UNC */
+#else
/* Invalid file://hostname/, expected localhost or 127.0.0.1 or
none */
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_FILE_URL;
+#endif
}
- ptr += 9; /* now points to the slash after the host */
}
path = ptr;
}
+ if(!uncpath)
+ hostname = NULL; /* no host for file: URLs by default */
+
#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
/* Don't allow Windows drive letters when not in Windows.
* This catches both "file:/c:" and "file:c:" */
if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
STARTS_WITH_URL_DRIVE_PREFIX(path)) {
/* File drive letters are only accepted in MSDOS/Windows */
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_FILE_URL;
}
#else
/* If the path starts with a slash and a drive letter, ditch the slash */
@@ -877,7 +966,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
}
if((i < 1) || (i>3))
/* less than one or more than three slashes */
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_SLASHES;
schemep = schemebuf;
if(!Curl_builtin_scheme(schemep) &&
@@ -885,13 +974,13 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
return CURLUE_UNSUPPORTED_SCHEME;
if(junkscan(schemep, flags))
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_SCHEME;
}
else {
/* no scheme! */
if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME)))
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_SCHEME;
if(flags & CURLU_DEFAULT_SCHEME)
schemep = DEFAULT_SCHEME;
@@ -902,7 +991,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
}
hostp = p; /* host name starts here */
- while(*p && !HOSTNAME_END(*p)) /* find end of host name */
+ /* find the end of the host name + port number */
+ while(*p && !HOSTNAME_END(*p))
p++;
len = p - hostp;
@@ -912,7 +1002,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
}
else {
if(!(flags & CURLU_NO_AUTHORITY))
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_NO_HOST;
}
len = strlen(p);
@@ -926,9 +1016,6 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
}
}
- if(junkscan(path, flags))
- return CURLUE_MALFORMED_INPUT;
-
if((flags & CURLU_URLENCODE) && path[0]) {
/* worst case output length is 3x the original! */
char *newp = malloc(strlen(path) * 3);
@@ -942,6 +1029,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
fragment = strchr(path, '#');
if(fragment) {
*fragment++ = 0;
+ if(junkscan(fragment, flags))
+ return CURLUE_BAD_FRAGMENT;
if(fragment[0]) {
u->fragment = strdup(fragment);
if(!u->fragment)
@@ -952,12 +1041,17 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
query = strchr(path, '?');
if(query) {
*query++ = 0;
+ if(junkscan(query, flags))
+ return CURLUE_BAD_QUERY;
/* done even if the query part is a blank string */
u->query = strdup(query);
if(!u->query)
return CURLUE_OUT_OF_MEMORY;
}
+ if(junkscan(path, flags))
+ return CURLUE_BAD_PATH;
+
if(!path[0])
/* if there's no path left set, unset */
path = NULL;
@@ -987,12 +1081,10 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(hostname) {
char normalized_ipv4[sizeof("255.255.255.255") + 1];
+
/*
* Parse the login details and strip them out of the host name.
*/
- if(junkscan(hostname, flags))
- return CURLUE_MALFORMED_INPUT;
-
result = parse_hostname_login(u, &hostname, flags);
if(result)
return result;
@@ -1001,22 +1093,27 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(result)
return result;
+ if(junkscan(hostname, flags))
+ return CURLUE_BAD_HOSTNAME;
+
if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) {
/* Skip hostname check, it's allowed to be empty. */
+ u->host = strdup("");
}
else {
- result = hostname_check(u, hostname);
- if(result)
- return result;
+ if(ipv4_normalize(hostname, normalized_ipv4, sizeof(normalized_ipv4)))
+ u->host = strdup(normalized_ipv4);
+ else {
+ result = decode_host(hostname, &u->host);
+ if(result)
+ return result;
+ result = hostname_check(u, u->host);
+ if(result)
+ return result;
+ }
}
-
- if(ipv4_normalize(hostname, normalized_ipv4, sizeof(normalized_ipv4)))
- u->host = strdup(normalized_ipv4);
- else
- u->host = strdup(hostname);
if(!u->host)
return CURLUE_OUT_OF_MEMORY;
-
if((flags & CURLU_GUESS_SCHEME) && !schemep) {
/* legacy curl-style guess based on host name */
if(checkprefix("ftp.", hostname))
@@ -1111,6 +1208,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
char portbuf[7];
bool urldecode = (flags & CURLU_URLDECODE)?1:0;
+ bool urlencode = (flags & CURLU_URLENCODE)?1:0;
bool plusdecode = FALSE;
(void)flags;
if(!u)
@@ -1143,6 +1241,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
break;
case CURLUPART_ZONEID:
ptr = u->zoneid;
+ ifmissing = CURLUE_NO_ZONEID;
break;
case CURLUPART_PORT:
ptr = u->port;
@@ -1228,16 +1327,54 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
if(h && !(h->flags & PROTOPT_URLOPTIONS))
options = NULL;
- if((u->host[0] == '[') && u->zoneid) {
- /* make it '[ host %25 zoneid ]' */
- size_t hostlen = strlen(u->host);
- size_t alen = hostlen + 3 + strlen(u->zoneid) + 1;
- allochost = malloc(alen);
+ if(u->host[0] == '[') {
+ if(u->zoneid) {
+ /* make it '[ host %25 zoneid ]' */
+ size_t hostlen = strlen(u->host);
+ size_t alen = hostlen + 3 + strlen(u->zoneid) + 1;
+ allochost = malloc(alen);
+ if(!allochost)
+ return CURLUE_OUT_OF_MEMORY;
+ memcpy(allochost, u->host, hostlen - 1);
+ msnprintf(&allochost[hostlen - 1], alen - hostlen + 1,
+ "%%25%s]", u->zoneid);
+ }
+ }
+ else if(urlencode) {
+ allochost = curl_easy_escape(NULL, u->host, 0);
if(!allochost)
return CURLUE_OUT_OF_MEMORY;
- memcpy(allochost, u->host, hostlen - 1);
- msnprintf(&allochost[hostlen - 1], alen - hostlen + 1,
- "%%25%s]", u->zoneid);
+ }
+ else {
+ /* only encode '%' in output host name */
+ char *host = u->host;
+ size_t pcount = 0;
+ /* first, count number of percents present in the name */
+ while(*host) {
+ if(*host == '%')
+ pcount++;
+ host++;
+ }
+ /* if there were percents, encode the host name */
+ if(pcount) {
+ size_t hostlen = strlen(u->host);
+ size_t alen = hostlen + 2 * pcount + 1;
+ char *o = allochost = malloc(alen);
+ if(!allochost)
+ return CURLUE_OUT_OF_MEMORY;
+
+ host = u->host;
+ while(*host) {
+ if(*host == '%') {
+ memcpy(o, "%25", 3);
+ o += 3;
+ host++;
+ continue;
+ }
+ *o++ = *host++;
+ }
+ *o = '\0';
+ }
}
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
@@ -1362,7 +1499,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
case CURLUPART_SCHEME:
if(strlen(part) > MAX_SCHEME_LEN)
/* too long */
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_SCHEME;
if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
/* verify that it is a fine scheme */
!Curl_builtin_scheme(part))
@@ -1379,10 +1516,15 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
case CURLUPART_OPTIONS:
storep = &u->options;
break;
- case CURLUPART_HOST:
+ case CURLUPART_HOST: {
+ size_t len = strcspn(part, " \r\n");
+ if(strlen(part) != len)
+ /* hostname with bad content */
+ return CURLUE_BAD_HOSTNAME;
storep = &u->host;
Curl_safefree(u->zoneid);
break;
+ }
case CURLUPART_ZONEID:
storep = &u->zoneid;
break;
@@ -1395,7 +1537,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
return CURLUE_BAD_PORT_NUMBER;
if(*endp)
/* weirdly provided number, not good! */
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_PORT_NUMBER;
storep = &u->port;
}
break;
@@ -1424,7 +1566,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
char *redired_url;
CURLU *handle2;
- if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN + 1)) {
+ if(Curl_is_absolute_url(part, NULL, 0)) {
handle2 = curl_url();
if(!handle2)
return CURLUE_OUT_OF_MEMORY;
@@ -1559,7 +1701,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
else {
if(hostname_check(u, (char *)newp)) {
free((char *)newp);
- return CURLUE_MALFORMED_INPUT;
+ return CURLUE_BAD_HOSTNAME;
}
}
}
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index 6ffd976..cc9c888 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -330,7 +330,7 @@ struct digestdata {
char *opaque;
char *qop;
char *algorithm;
- int nc; /* nounce count */
+ int nc; /* nonce count */
BIT(stale); /* set true for re-negotiation */
BIT(userhash);
#endif
@@ -518,7 +518,9 @@ struct ConnectBits {
BIT(tls_enable_npn); /* TLS NPN extension? */
BIT(tls_enable_alpn); /* TLS ALPN extension? */
BIT(connect_only);
+#ifndef CURL_DISABLE_DOH
BIT(doh);
+#endif
#ifdef USE_UNIX_SOCKETS
BIT(abstract_unix_socket);
#endif
@@ -835,6 +837,7 @@ struct Curl_handler {
#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
#define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in
user name and password */
+#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol can't proxy over TCP */
#define CONNCHECK_NONE 0 /* No checks */
#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */
@@ -1554,6 +1557,7 @@ enum dupstring {
STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
+ STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */
STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */
STRING_PROXY_SERVICE_NAME, /* Proxy service name */
STRING_SERVICE_NAME, /* Service name */
@@ -1651,6 +1655,8 @@ struct UserDefined {
curl_closesocket_callback fclosesocket; /* function for closing the
socket */
void *closesocket_client;
+ curl_prereq_callback fprereq; /* pre-initial request callback */
+ void *prereq_userp; /* pre-initial request user data */
void *seek_client; /* pointer to pass to the seek callback */
/* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
@@ -1675,6 +1681,8 @@ struct UserDefined {
long server_response_timeout; /* in milliseconds, 0 means no timeout */
long maxage_conn; /* in seconds, max idle time to allow a connection that
is to be reused */
+ long maxlifetime_conn; /* in seconds, max time since creation to allow a
+ connection that is to be reused */
long tftp_blksize; /* in bytes, 0 means use default */
curl_off_t filesize; /* size of file to upload, -1 means unknown */
long low_speed_limit; /* bytes/second */
@@ -1744,6 +1752,7 @@ struct UserDefined {
unsigned int scope_id; /* Scope id for IPv6 */
long allowed_protocols;
long redir_protocols;
+ long mime_options; /* Mime option flags. */
struct curl_slist *mail_rcpt; /* linked list of mail recipients */
/* Common RTSP header options */
Curl_RtspReq rtspreq; /* RTSP request type */
@@ -1851,11 +1860,12 @@ struct UserDefined {
header */
BIT(abstract_unix_socket);
BIT(disallow_username_in_url); /* disallow username in url */
+#ifndef CURL_DISABLE_DOH
BIT(doh); /* DNS-over-HTTPS enabled */
- BIT(doh_get); /* use GET for DoH requests, instead of POST */
BIT(doh_verifypeer); /* DoH certificate peer verification */
BIT(doh_verifyhost); /* DoH certificate hostname verification */
BIT(doh_verifystatus); /* DoH certificate status verification */
+#endif
BIT(http09_allowed); /* allow HTTP/0.9 responses */
BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
recipients */
diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
index a04ffab..d8aac66 100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/vauth/digest.c
@@ -230,7 +230,7 @@ static CURLcode auth_digest_get_qop_values(const char *options, int *value)
return CURLE_OUT_OF_MEMORY;
token = strtok_r(tmp, ",", &tok_buf);
- while(token != NULL) {
+ while(token) {
if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
*value |= DIGEST_QOP_VALUE_AUTH;
else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
@@ -556,7 +556,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
return CURLE_OUT_OF_MEMORY;
token = strtok_r(tmp, ",", &tok_buf);
- while(token != NULL) {
+ while(token) {
if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
foundAuth = TRUE;
}
@@ -666,8 +666,8 @@ static CURLcode auth_create_digest_http_message(
struct digestdata *digest,
char **outptr, size_t *outlen,
void (*convert_to_ascii)(unsigned char *, unsigned char *),
- void (*hash)(unsigned char *, const unsigned char *,
- const size_t))
+ CURLcode (*hash)(unsigned char *, const unsigned char *,
+ const size_t))
{
CURLcode result;
unsigned char hashbuf[32]; /* 32 bytes/256 bits */
@@ -722,8 +722,7 @@ static CURLcode auth_create_digest_http_message(
unq(nonce-value) ":" unq(cnonce-value)
*/
- hashthis = aprintf("%s:%s:%s", digest->userhash ? userh : userp,
- digest->realm, passwdp);
+ hashthis = aprintf("%s:%s:%s", userp, digest->realm, passwdp);
if(!hashthis)
return CURLE_OUT_OF_MEMORY;
diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c
index 0aa3f1c..04f6590 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm.c
@@ -603,7 +603,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
memcpy(tmp, &ntlm->nonce[0], 8);
memcpy(tmp + 8, entropy, 8);
- Curl_md5it(md5sum, tmp, 16);
+ result = Curl_md5it(md5sum, tmp, 16);
+ if(result)
+ return result;
/* We shall only use the first 8 bytes of md5sum, but the des code in
Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
diff --git a/Utilities/cmcurl/lib/version_win32.c b/Utilities/cmcurl/lib/version_win32.c
index b8157e9..79a2aa6 100644
--- a/Utilities/cmcurl/lib/version_win32.c
+++ b/Utilities/cmcurl/lib/version_win32.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2016 - 2020, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2016 - 2021, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,11 +26,28 @@
#include <curl/curl.h>
#include "version_win32.h"
+#include "warnless.h"
/* The last #include files should be: */
#include "curl_memory.h"
#include "memdebug.h"
+/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
+ and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
+struct OUR_OSVERSIONINFOEXW {
+ ULONG dwOSVersionInfoSize;
+ ULONG dwMajorVersion;
+ ULONG dwMinorVersion;
+ ULONG dwBuildNumber;
+ ULONG dwPlatformId;
+ WCHAR szCSDVersion[128];
+ USHORT wServicePackMajor;
+ USHORT wServicePackMinor;
+ USHORT wSuiteMask;
+ UCHAR wProductType;
+ UCHAR wReserved;
+};
+
/*
* curlx_verify_windows_version()
*
@@ -40,6 +57,8 @@
*
* majorVersion [in] - The major version number.
* minorVersion [in] - The minor version number.
+ * buildVersion [in] - The build version number. If 0, this parameter is
+ * ignored.
* platform [in] - The optional platform identifier.
* condition [in] - The test condition used to specifier whether we are
* checking a version less then, equal to or greater than
@@ -50,6 +69,7 @@
*/
bool curlx_verify_windows_version(const unsigned int majorVersion,
const unsigned int minorVersion,
+ const unsigned int buildVersion,
const PlatformIdentifier platform,
const VersionCondition condition)
{
@@ -101,34 +121,52 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_LESS_THAN:
if(osver.dwMajorVersion < majorVersion ||
(osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion < minorVersion))
+ osver.dwMinorVersion < minorVersion) ||
+ (buildVersion != 0 &&
+ (osver.dwMajorVersion == majorVersion &&
+ osver.dwMinorVersion == minorVersion &&
+ osver.dwBuildNumber < buildVersion)))
matched = TRUE;
break;
case VERSION_LESS_THAN_EQUAL:
if(osver.dwMajorVersion < majorVersion ||
(osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion <= minorVersion))
+ osver.dwMinorVersion < minorVersion) ||
+ (osver.dwMajorVersion == majorVersion &&
+ osver.dwMinorVersion == minorVersion &&
+ (buildVersion == 0 ||
+ osver.dwBuildNumber <= buildVersion)))
matched = TRUE;
break;
case VERSION_EQUAL:
if(osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion == minorVersion)
+ osver.dwMinorVersion == minorVersion &&
+ (buildVersion == 0 ||
+ osver.dwBuildNumber == buildVersion))
matched = TRUE;
break;
case VERSION_GREATER_THAN_EQUAL:
if(osver.dwMajorVersion > majorVersion ||
(osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion >= minorVersion))
+ osver.dwMinorVersion > minorVersion) ||
+ (osver.dwMajorVersion == majorVersion &&
+ osver.dwMinorVersion == minorVersion &&
+ (buildVersion == 0 ||
+ osver.dwBuildNumber >= buildVersion)))
matched = TRUE;
break;
case VERSION_GREATER_THAN:
if(osver.dwMajorVersion > majorVersion ||
(osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion > minorVersion))
+ osver.dwMinorVersion > minorVersion) ||
+ (buildVersion != 0 &&
+ (osver.dwMajorVersion == majorVersion &&
+ osver.dwMinorVersion == minorVersion &&
+ osver.dwBuildNumber > buildVersion)))
matched = TRUE;
break;
}
@@ -144,6 +182,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case PLATFORM_WINNT:
if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
matched = FALSE;
+ break;
default: /* like platform == PLATFORM_DONT_CARE */
break;
@@ -152,16 +191,31 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
}
#else
ULONGLONG cm = 0;
- OSVERSIONINFOEX osver;
+ struct OUR_OSVERSIONINFOEXW osver;
BYTE majorCondition;
BYTE minorCondition;
+ BYTE buildCondition;
BYTE spMajorCondition;
BYTE spMinorCondition;
+ DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
+
+ typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
+ (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
+ static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo;
+ static bool onetime = true; /* safe because first call is during init */
+
+ if(onetime) {
+ pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN,
+ (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo")));
+ onetime = false;
+ }
switch(condition) {
case VERSION_LESS_THAN:
majorCondition = VER_LESS;
minorCondition = VER_LESS;
+ buildCondition = VER_LESS;
spMajorCondition = VER_LESS_EQUAL;
spMinorCondition = VER_LESS_EQUAL;
break;
@@ -169,6 +223,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_LESS_THAN_EQUAL:
majorCondition = VER_LESS_EQUAL;
minorCondition = VER_LESS_EQUAL;
+ buildCondition = VER_LESS_EQUAL;
spMajorCondition = VER_LESS_EQUAL;
spMinorCondition = VER_LESS_EQUAL;
break;
@@ -176,6 +231,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_EQUAL:
majorCondition = VER_EQUAL;
minorCondition = VER_EQUAL;
+ buildCondition = VER_EQUAL;
spMajorCondition = VER_GREATER_EQUAL;
spMinorCondition = VER_GREATER_EQUAL;
break;
@@ -183,6 +239,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_GREATER_THAN_EQUAL:
majorCondition = VER_GREATER_EQUAL;
minorCondition = VER_GREATER_EQUAL;
+ buildCondition = VER_GREATER_EQUAL;
spMajorCondition = VER_GREATER_EQUAL;
spMinorCondition = VER_GREATER_EQUAL;
break;
@@ -190,6 +247,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_GREATER_THAN:
majorCondition = VER_GREATER;
minorCondition = VER_GREATER;
+ buildCondition = VER_GREATER;
spMajorCondition = VER_GREATER_EQUAL;
spMinorCondition = VER_GREATER_EQUAL;
break;
@@ -202,6 +260,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
osver.dwOSVersionInfoSize = sizeof(osver);
osver.dwMajorVersion = majorVersion;
osver.dwMinorVersion = minorVersion;
+ osver.dwBuildNumber = buildVersion;
if(platform == PLATFORM_WINDOWS)
osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
else if(platform == PLATFORM_WINNT)
@@ -211,13 +270,43 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
- if(platform != PLATFORM_DONT_CARE)
+
+ if(platform != PLATFORM_DONT_CARE) {
cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
+ dwTypeMask |= VER_PLATFORMID;
+ }
+
+ /* Later versions of Windows have version functions that may not return the
+ real version of Windows unless the application is so manifested. We prefer
+ the real version always, so we use the Rtl variant of the function when
+ possible. Note though the function signatures have underlying fundamental
+ types that are the same, the return values are different. */
+ if(pRtlVerifyVersionInfo)
+ matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
+ else
+ matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm);
+
+ /* Compare the build number separately. VerifyVersionInfo normally compares
+ major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not
+ do the same for build (eg 1.9 build 222 is not less than 2.0 build 111).
+ Build comparison is only needed when build numbers are equal (eg 1.9 is
+ always less than 2.0 so build comparison is not needed). */
+ if(matched && buildVersion &&
+ (condition == VERSION_EQUAL ||
+ ((condition == VERSION_GREATER_THAN_EQUAL ||
+ condition == VERSION_LESS_THAN_EQUAL) &&
+ curlx_verify_windows_version(majorVersion, minorVersion, 0,
+ platform, VERSION_EQUAL)))) {
+
+ cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition);
+ dwTypeMask = VER_BUILDNUMBER;
+ if(pRtlVerifyVersionInfo)
+ matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
+ else
+ matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
+ dwTypeMask, cm);
+ }
- if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
- VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
- cm))
- matched = TRUE;
#endif
return matched;
diff --git a/Utilities/cmcurl/lib/version_win32.h b/Utilities/cmcurl/lib/version_win32.h
index 9b1bd88..38af87f 100644
--- a/Utilities/cmcurl/lib/version_win32.h
+++ b/Utilities/cmcurl/lib/version_win32.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2016 - 2020, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2016 - 2021, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -45,6 +45,7 @@ typedef enum {
/* This is used to verify if we are running on a specific windows version */
bool curlx_verify_windows_version(const unsigned int majorVersion,
const unsigned int minorVersion,
+ const unsigned int buildVersion,
const PlatformIdentifier platform,
const VersionCondition condition);
diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.c b/Utilities/cmcurl/lib/vquic/ngtcp2.c
index 9fcfe81..1596049 100644
--- a/Utilities/cmcurl/lib/vquic/ngtcp2.c
+++ b/Utilities/cmcurl/lib/vquic/ngtcp2.c
@@ -29,8 +29,10 @@
#ifdef USE_OPENSSL
#include <openssl/err.h>
#include <ngtcp2/ngtcp2_crypto_openssl.h>
+#include "vtls/openssl.h"
#elif defined(USE_GNUTLS)
#include <ngtcp2/ngtcp2_crypto_gnutls.h>
+#include "vtls/gtls.h"
#endif
#include "urldata.h"
#include "sendf.h"
@@ -61,6 +63,7 @@
#endif
#define H3_ALPN_H3_29 "\x5h3-29"
+#define H3_ALPN_H3 "\x2h3"
/*
* This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked.
@@ -286,6 +289,27 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
}
+ {
+ struct connectdata *conn = data->conn;
+ const char * const ssl_cafile = conn->ssl_config.CAfile;
+ const char * const ssl_capath = conn->ssl_config.CApath;
+
+ if(conn->ssl_config.verifypeer) {
+ SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
+ /* tell OpenSSL where to find CA certificates that are used to verify
+ the server's certificate. */
+ if(!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:"
+ " CAfile: %s CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return NULL;
+ }
+ infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+ infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+ }
+ }
return ssl_ctx;
}
@@ -303,9 +327,10 @@ static int quic_init_ssl(struct quicsocket *qs)
SSL_set_app_data(qs->ssl, qs);
SSL_set_connect_state(qs->ssl);
+ SSL_set_quic_use_legacy_codepoint(qs->ssl, 0);
- alpn = (const uint8_t *)H3_ALPN_H3_29;
- alpnlen = sizeof(H3_ALPN_H3_29) - 1;
+ alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
+ alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
if(alpn)
SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
@@ -417,7 +442,7 @@ static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata)
static int quic_init_ssl(struct quicsocket *qs)
{
- gnutls_datum_t alpn = {NULL, 0};
+ gnutls_datum_t alpn[2];
/* this will need some attention when HTTPS proxy over QUIC get fixed */
const char * const hostname = qs->conn->host.name;
int rc;
@@ -439,12 +464,10 @@ static int quic_init_ssl(struct quicsocket *qs)
gnutls_alert_set_read_function(qs->ssl, alert_read_func);
rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters",
- 0xffa5, GNUTLS_EXT_TLS,
- tp_recv_func, tp_send_func,
- NULL, NULL, NULL,
- GNUTLS_EXT_FLAG_TLS |
- GNUTLS_EXT_FLAG_CLIENT_HELLO |
- GNUTLS_EXT_FLAG_EE);
+ NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1, GNUTLS_EXT_TLS,
+ tp_recv_func, tp_send_func, NULL, NULL, NULL,
+ GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO |
+ GNUTLS_EXT_FLAG_EE);
if(rc < 0) {
H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
gnutls_strerror(rc)));
@@ -484,10 +507,12 @@ static int quic_init_ssl(struct quicsocket *qs)
}
/* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
- alpn.data = (unsigned char *)H3_ALPN_H3_29 + 1;
- alpn.size = sizeof(H3_ALPN_H3_29) - 2;
- if(alpn.data)
- gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0);
+ alpn[0].data = (unsigned char *)H3_ALPN_H3_29 + 1;
+ alpn[0].size = sizeof(H3_ALPN_H3_29) - 2;
+ alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1;
+ alpn[1].size = sizeof(H3_ALPN_H3) - 2;
+
+ gnutls_alpn_set_protocols(qs->ssl, alpn, 2, GNUTLS_ALPN_MANDATORY);
/* set SNI */
gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname));
@@ -648,6 +673,20 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
return 0;
}
+static void cb_rand(uint8_t *dest, size_t destlen,
+ const ngtcp2_rand_ctx *rand_ctx)
+{
+ CURLcode result;
+ (void)rand_ctx;
+
+ result = Curl_rand(NULL, dest, destlen);
+ if(result) {
+ /* cb_rand is only used for non-cryptographic context. If Curl_rand
+ failed, just fill 0 and call it *random*. */
+ memset(dest, 0, destlen);
+ }
+}
+
static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
uint8_t *token, size_t cidlen,
void *user_data)
@@ -685,7 +724,7 @@ static ngtcp2_callbacks ng_callbacks = {
ngtcp2_crypto_recv_retry_cb,
cb_extend_max_local_streams_bidi,
NULL, /* extend_max_local_streams_uni */
- NULL, /* rand */
+ cb_rand,
cb_get_new_connection_id,
NULL, /* remove_connection_id */
ngtcp2_crypto_update_key_cb, /* update_key */
@@ -703,7 +742,7 @@ static ngtcp2_callbacks ng_callbacks = {
NULL, /* recv_datagram */
NULL, /* ack_datagram */
NULL, /* lost_datagram */
- NULL, /* get_path_challenge_data */
+ ngtcp2_crypto_get_path_challenge_data_cb,
cb_stream_stop_sending
};
@@ -776,7 +815,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
ngtcp2_addr_init(&path.remote, addr, addrlen);
rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path,
- NGTCP2_PROTO_VER_MIN, &ng_callbacks,
+ NGTCP2_PROTO_VER_V1, &ng_callbacks,
&qs->settings, &qs->transport_params, NULL, qs);
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
@@ -792,7 +831,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
void Curl_quic_ver(char *p, size_t len)
{
const ngtcp2_info *ng2 = ngtcp2_version(0);
- nghttp3_info *ht3 = nghttp3_version(0);
+ const nghttp3_info *ht3 = nghttp3_version(0);
(void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
ng2->version_str, ht3->version_str);
}
@@ -1622,8 +1661,10 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
return sent;
}
-static void ng_has_connected(struct connectdata *conn, int tempindex)
+static CURLcode ng_has_connected(struct Curl_easy *data,
+ struct connectdata *conn, int tempindex)
{
+ CURLcode result = CURLE_OK;
conn->recv[FIRSTSOCKET] = ngh3_stream_recv;
conn->send[FIRSTSOCKET] = ngh3_stream_send;
conn->handler = &Curl_handler_http3;
@@ -1631,6 +1672,27 @@ static void ng_has_connected(struct connectdata *conn, int tempindex)
conn->httpversion = 30;
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
conn->quic = &conn->hequic[tempindex];
+
+ if(conn->ssl_config.verifyhost) {
+#ifdef USE_OPENSSL
+ X509 *server_cert;
+ CURLcode result;
+ server_cert = SSL_get_peer_certificate(conn->quic->ssl);
+ if(!server_cert) {
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ result = Curl_ossl_verifyhost(data, conn, server_cert);
+ X509_free(server_cert);
+ if(result)
+ return result;
+ infof(data, "Verified certificate just fine");
+#else
+ result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET);
+#endif
+ }
+ else
+ infof(data, "Skipped certificate verification");
+ return result;
}
/*
@@ -1654,8 +1716,9 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data,
goto error;
if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
- *done = TRUE;
- ng_has_connected(conn, sockindex);
+ result = ng_has_connected(data, conn, sockindex);
+ if(!result)
+ *done = TRUE;
}
return result;
@@ -1702,6 +1765,10 @@ static CURLcode ng_process_ingress(struct Curl_easy *data,
rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts);
if(rv) {
/* TODO Send CONNECTION_CLOSE if possible */
+ if(rv == NGTCP2_ERR_CRYPTO)
+ /* this is a "TLS problem", but a failed certificate verification
+ is a common reason for this */
+ return CURLE_PEER_FAILED_VERIFICATION;
return CURLE_RECV_ERROR;
}
}
diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index a772f1f..581bc1b 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/vssh/libssh2.c
@@ -81,6 +81,11 @@
#include "select.h"
#include "warnless.h"
#include "curl_path.h"
+#include "strcase.h"
+
+#include <curl_base64.h> /* for base64 encoding/decoding */
+#include <curl_sha256.h>
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -615,40 +620,141 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
- char md5buffer[33];
+ const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256];
+
+ infof(data, "SSH MD5 public key: %s",
+ pubkey_md5 != NULL ? pubkey_md5 : "NULL");
+ infof(data, "SSH SHA256 public key: %s",
+ pubkey_sha256 != NULL ? pubkey_sha256 : "NULL");
- const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
- LIBSSH2_HOSTKEY_HASH_MD5);
+ if(pubkey_sha256) {
+ const char *fingerprint = NULL;
+ char *fingerprint_b64 = NULL;
+ size_t fingerprint_b64_len;
+ size_t pub_pos = 0;
+ size_t b64_pos = 0;
- if(fingerprint) {
+#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
/* The fingerprint points to static storage (!), don't free() it. */
- int i;
- for(i = 0; i < 16; i++)
- msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
- infof(data, "SSH MD5 fingerprint: %s", md5buffer);
- }
+ fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+ LIBSSH2_HOSTKEY_HASH_SHA256);
+#else
+ const char *hostkey;
+ size_t len = 0;
+ unsigned char hash[32];
+
+ hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL);
+ if(hostkey) {
+ if(!Curl_sha256it(hash, (const unsigned char *) hostkey, len))
+ fingerprint = (char *) hash;
+ }
+#endif
- /* Before we authenticate we check the hostkey's MD5 fingerprint
- * against a known fingerprint, if available.
- */
- if(pubkey_md5 && strlen(pubkey_md5) == 32) {
- if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
- if(fingerprint)
- failf(data,
- "Denied establishing ssh session: mismatch md5 fingerprint. "
- "Remote %s is not equal to %s", md5buffer, pubkey_md5);
- else
- failf(data,
- "Denied establishing ssh session: md5 fingerprint not available");
+ if(!fingerprint) {
+ failf(data,
+ "Denied establishing ssh session: sha256 fingerprint "
+ "not available");
+ state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+
+ /* The length of fingerprint is 32 bytes for SHA256.
+ * See libssh2_hostkey_hash documentation. */
+ if(Curl_base64_encode(data, fingerprint, 32, &fingerprint_b64,
+ &fingerprint_b64_len) != CURLE_OK) {
+ state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+
+ if(!fingerprint_b64) {
+ failf(data, "sha256 fingerprint could not be encoded");
+ state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+
+ infof(data, "SSH SHA256 fingerprint: %s", fingerprint_b64);
+
+ /* Find the position of any = padding characters in the public key */
+ while((pubkey_sha256[pub_pos] != '=') && pubkey_sha256[pub_pos]) {
+ pub_pos++;
+ }
+
+ /* Find the position of any = padding characters in the base64 coded
+ * hostkey fingerprint */
+ while((fingerprint_b64[b64_pos] != '=') && fingerprint_b64[b64_pos]) {
+ b64_pos++;
+ }
+
+ /* Before we authenticate we check the hostkey's sha256 fingerprint
+ * against a known fingerprint, if available.
+ */
+ if((pub_pos != b64_pos) ||
+ Curl_strncasecompare(fingerprint_b64, pubkey_sha256, pub_pos) != 1) {
+ free(fingerprint_b64);
+
+ failf(data,
+ "Denied establishing ssh session: mismatch sha256 fingerprint. "
+ "Remote %s is not equal to %s", fingerprint_b64, pubkey_sha256);
state(data, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
- infof(data, "MD5 checksum match!");
+
+ free(fingerprint_b64);
+
+ infof(data, "SHA256 checksum match!");
+ }
+
+ if(pubkey_md5) {
+ char md5buffer[33];
+ const char *fingerprint = NULL;
+
+ fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+ LIBSSH2_HOSTKEY_HASH_MD5);
+
+ if(fingerprint) {
+ /* The fingerprint points to static storage (!), don't free() it. */
+ int i;
+ for(i = 0; i < 16; i++) {
+ msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
+ }
+
+ infof(data, "SSH MD5 fingerprint: %s", md5buffer);
+ }
+
+ /* Before we authenticate we check the hostkey's MD5 fingerprint
+ * against a known fingerprint, if available.
+ */
+ if(pubkey_md5 && strlen(pubkey_md5) == 32) {
+ if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
+ if(fingerprint) {
+ failf(data,
+ "Denied establishing ssh session: mismatch md5 fingerprint. "
+ "Remote %s is not equal to %s", md5buffer, pubkey_md5);
+ }
+ else {
+ failf(data,
+ "Denied establishing ssh session: md5 fingerprint "
+ "not available");
+ }
+ state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+ infof(data, "MD5 checksum match!");
+ }
+ }
+
+ if(!pubkey_md5 && !pubkey_sha256) {
+ return ssh_knownhost(data);
+ }
+ else {
/* as we already matched, we skip the check for known hosts */
return CURLE_OK;
}
- return ssh_knownhost(data);
}
/*
@@ -3610,7 +3716,7 @@ void Curl_ssh_cleanup(void)
void Curl_ssh_version(char *buffer, size_t buflen)
{
- (void)msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION);
+ (void)msnprintf(buffer, buflen, "libssh2/%s", CURL_LIBSSH2_VERSION);
}
/* The SSH session is associated with the *CONNECTION* but the callback user
diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c
index 4b1e2ec..5b4cde9 100644
--- a/Utilities/cmcurl/lib/vssh/wolfssh.c
+++ b/Utilities/cmcurl/lib/vssh/wolfssh.c
@@ -449,7 +449,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
switch(sshc->state) {
case SSH_INIT:
state(data, SSH_S_STARTUP);
- /* FALLTHROUGH */
+ break;
+
case SSH_S_STARTUP:
rc = wolfSSH_connect(sshc->ssh_session);
if(rc != WS_SUCCESS)
@@ -838,7 +839,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
state(data, SSH_SFTP_READDIR);
- /* FALLTHROUGH */
+ break;
+
case SSH_SFTP_READDIR:
name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path);
if(!name)
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c
index e87649e..9b772d0 100644
--- a/Utilities/cmcurl/lib/vtls/bearssl.c
+++ b/Utilities/cmcurl/lib/vtls/bearssl.c
@@ -608,6 +608,7 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
+ bool added = FALSE;
void *oldsession;
br_ssl_session_parameters *session;
@@ -623,10 +624,11 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
Curl_ssl_delsessionid(data, oldsession);
ret = Curl_ssl_addsessionid(data, conn,
SSL_IS_PROXY() ? TRUE : FALSE,
- session, 0, sockindex);
+ session, 0, sockindex, &added);
Curl_ssl_sessionid_unlock(data);
- if(ret) {
+ if(!added)
free(session);
+ if(ret) {
return CURLE_OUT_OF_MEMORY;
}
}
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index 1b145d8..18864aa 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -404,6 +404,7 @@ gtls_connect_step1(struct Curl_easy *data,
const char * const hostname = SSL_HOST_NAME();
long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
const char *tls13support;
+ CURLcode result;
if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
@@ -496,6 +497,7 @@ gtls_connect_step1(struct Curl_easy *data,
/* use system ca certificate store as fallback */
if(SSL_CONN_CONFIG(verifypeer) &&
!(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
+ /* this ignores errors on purpose */
gnutls_certificate_set_x509_system_trust(backend->cred);
}
#endif
@@ -557,31 +559,25 @@ gtls_connect_step1(struct Curl_easy *data,
/* Ensure +SRP comes at the *end* of all relevant strings so that it can be
* removed if a run-time error indicates that SRP is not supported by this
* GnuTLS version */
- switch(SSL_CONN_CONFIG(version)) {
- case CURL_SSLVERSION_TLSv1_3:
- if(!tls13support) {
- failf(data, "This GnuTLS installation does not support TLS 1.3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* FALLTHROUGH */
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2: {
- CURLcode result = set_ssl_version_min_max(data, &prioritylist,
- tls13support);
- if(result)
- return result;
- break;
- }
- case CURL_SSLVERSION_SSLv2:
- case CURL_SSLVERSION_SSLv3:
- default:
- failf(data, "GnuTLS does not support SSLv2 or SSLv3");
+
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2 ||
+ SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) {
+ failf(data, "GnuTLS does not support SSLv2 or SSLv3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_TLSv1_3) {
+ if(!tls13support) {
+ failf(data, "This GnuTLS installation does not support TLS 1.3");
return CURLE_SSL_CONNECT_ERROR;
+ }
}
+ /* At this point we know we have a supported TLS version, so set it */
+ result = set_ssl_version_min_max(data, &prioritylist, tls13support);
+ if(result)
+ return result;
+
#ifdef HAVE_GNUTLS_SRP
/* Only add SRP to the cipher list if SRP is requested. Otherwise
* GnuTLS will disable TLS 1.3 support. */
@@ -636,7 +632,10 @@ gtls_connect_step1(struct Curl_easy *data,
cur++;
infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
- gnutls_alpn_set_protocols(session, protocols, cur, 0);
+ if(gnutls_alpn_set_protocols(session, protocols, cur, 0)) {
+ failf(data, "failed setting ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
if(SSL_SET_OPTION(primary.clientcert)) {
@@ -762,10 +761,10 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
/* if a path wasn't specified, don't pin */
- if(NULL == pinnedpubkey)
+ if(!pinnedpubkey)
return CURLE_OK;
- if(NULL == cert)
+ if(!cert)
return result;
do {
@@ -783,7 +782,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
break; /* failed */
buff1 = malloc(len1);
- if(NULL == buff1)
+ if(!buff1)
break; /* failed */
len2 = len1;
@@ -798,7 +797,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
} while(0);
- if(NULL != key)
+ if(key)
gnutls_pubkey_deinit(key);
Curl_safefree(buff1);
@@ -809,10 +808,11 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
static Curl_recv gtls_recv;
static Curl_send gtls_send;
-static CURLcode
-gtls_connect_step3(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
+CURLcode
+Curl_gtls_verifyserver(struct Curl_easy *data,
+ struct connectdata *conn,
+ gnutls_session_t session,
+ int sockindex)
{
unsigned int cert_list_size;
const gnutls_datum_t *chainp;
@@ -824,9 +824,6 @@ gtls_connect_step3(struct Curl_easy *data,
size_t size;
time_t certclock;
const char *ptr;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct ssl_backend_data *backend = connssl->backend;
- gnutls_session_t session = backend->session;
int rc;
gnutls_datum_t proto;
CURLcode result = CURLE_OK;
@@ -1270,8 +1267,6 @@ gtls_connect_step3(struct Curl_easy *data,
}
conn->ssl[sockindex].state = ssl_connection_complete;
- conn->recv[sockindex] = gtls_recv;
- conn->send[sockindex] = gtls_send;
if(SSL_SET_OPTION(primary.sessionid)) {
/* we always unconditionally get the session id here, as even if we
@@ -1287,6 +1282,7 @@ gtls_connect_step3(struct Curl_easy *data,
if(connect_sessionid) {
bool incache;
+ bool added = FALSE;
void *ssl_sessionid;
/* extract session ID to the allocated buffer */
@@ -1306,10 +1302,11 @@ gtls_connect_step3(struct Curl_easy *data,
result = Curl_ssl_addsessionid(data, conn,
SSL_IS_PROXY() ? TRUE : FALSE,
connect_sessionid, connect_idsize,
- sockindex);
+ sockindex, &added);
Curl_ssl_sessionid_unlock(data);
- if(result) {
+ if(!added)
free(connect_sessionid);
+ if(result) {
result = CURLE_OUT_OF_MEMORY;
}
}
@@ -1354,9 +1351,13 @@ gtls_connect_common(struct Curl_easy *data,
/* Finish connecting once the handshake is done */
if(ssl_connect_1 == connssl->connecting_state) {
- rc = gtls_connect_step3(data, conn, sockindex);
+ struct ssl_backend_data *backend = connssl->backend;
+ gnutls_session_t session = backend->session;
+ rc = Curl_gtls_verifyserver(data, conn, session, sockindex);
if(rc)
return rc;
+ conn->recv[sockindex] = gtls_recv;
+ conn->send[sockindex] = gtls_send;
}
*done = ssl_connect_1 == connssl->connecting_state;
diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
index 1a146a3..642d5f0 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.h
+++ b/Utilities/cmcurl/lib/vtls/gtls.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -27,7 +27,11 @@
#ifdef USE_GNUTLS
#include "urldata.h"
-
+#include <gnutls/gnutls.h>
+CURLcode
+Curl_gtls_verifyserver(struct Curl_easy *data, struct connectdata *conn,
+ gnutls_session_t session,
+ int sockindex);
extern const struct Curl_ssl Curl_ssl_gnutls;
#endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index 780d13e..1d209b2 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* This software is licensed as described in the file COPYING, which
@@ -270,7 +270,10 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
- const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ const char * const ssl_cafile =
+ /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+ (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
@@ -316,16 +319,34 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* Load the trusted CA */
mbedtls_x509_crt_init(&backend->cacert);
- if(ssl_cafile) {
+ if(ca_info_blob && verifypeer) {
+ /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
+ terminated even when provided the exact length, forcing us to waste
+ extra memory here. */
+ unsigned char *newblob = malloc(ca_info_blob->len + 1);
+ if(!newblob)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(newblob, ca_info_blob->data, ca_info_blob->len);
+ newblob[ca_info_blob->len] = 0; /* null terminate */
+ ret = mbedtls_x509_crt_parse(&backend->cacert, newblob,
+ ca_info_blob->len + 1);
+ free(newblob);
+ if(ret<0) {
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "Error importing ca cert blob - mbedTLS: (-0x%04X) %s",
+ -ret, errorbuf);
+ return ret;
+ }
+ }
+
+ if(ssl_cafile && verifypeer) {
ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile);
if(ret<0) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
ssl_cafile, -ret, errorbuf);
-
- if(verifypeer)
- return CURLE_SSL_CACERT_BADFILE;
+ return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -358,10 +379,17 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
if(ssl_cert_blob) {
- const unsigned char *blob_data =
- (const unsigned char *)ssl_cert_blob->data;
- ret = mbedtls_x509_crt_parse(&backend->clicert, blob_data,
+ /* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
+ terminated even when provided the exact length, forcing us to waste
+ extra memory here. */
+ unsigned char *newblob = malloc(ssl_cert_blob->len + 1);
+ if(!newblob)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(newblob, ssl_cert_blob->data, ssl_cert_blob->len);
+ newblob[ssl_cert_blob->len] = 0; /* null terminate */
+ ret = mbedtls_x509_crt_parse(&backend->clicert, newblob,
ssl_cert_blob->len);
+ free(newblob);
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
@@ -671,7 +699,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
mbedtls_x509_crt *p = NULL;
unsigned char *pubkey = NULL;
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) ||
!peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) {
#else
@@ -698,7 +726,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
needs a non-const key, for now.
https://github.com/ARMmbed/mbedtls/issues/396 */
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
if(mbedtls_x509_crt_parse_der(p,
peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p),
peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) {
@@ -710,7 +738,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
goto pinnedpubkey_error;
}
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#if MBEDTLS_VERSION_NUMBER == 0x03000000
size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey,
PUB_DER_MAX_BYTES);
#else
@@ -784,6 +812,7 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
+ bool added = FALSE;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
@@ -807,11 +836,13 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
Curl_ssl_delsessionid(data, old_ssl_sessionid);
retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
- 0, sockindex);
+ 0, sockindex, &added);
Curl_ssl_sessionid_unlock(data);
- if(retcode) {
+ if(!added) {
mbedtls_ssl_session_free(our_ssl_sessionid);
free(our_ssl_sessionid);
+ }
+ if(retcode) {
failf(data, "failed to store ssl session");
return retcode;
}
@@ -1151,6 +1182,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
{ CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
SSLSUPP_CA_PATH |
+ SSLSUPP_CAINFO_BLOB |
SSLSUPP_PINNEDPUBKEY |
SSLSUPP_SSL_CTX,
diff --git a/Utilities/cmcurl/lib/vtls/mesalink.c b/Utilities/cmcurl/lib/vtls/mesalink.c
index 3db9184..35a9165 100644
--- a/Utilities/cmcurl/lib/vtls/mesalink.c
+++ b/Utilities/cmcurl/lib/vtls/mesalink.c
@@ -68,8 +68,6 @@ struct ssl_backend_data
SSL *handle;
};
-#define BACKEND connssl->backend
-
static Curl_recv mesalink_recv;
static Curl_send mesalink_send;
@@ -100,9 +98,9 @@ mesalink_connect_step1(struct Curl_easy *data,
#endif
const char * const hostname = SSL_HOST_NAME();
size_t hostname_len = strlen(hostname);
-
SSL_METHOD *req_method = NULL;
curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
if(connssl->state == ssl_connection_complete)
return CURLE_OK;
@@ -139,22 +137,22 @@ mesalink_connect_step1(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- if(BACKEND->ctx)
- SSL_CTX_free(BACKEND->ctx);
- BACKEND->ctx = SSL_CTX_new(req_method);
+ if(backend->ctx)
+ SSL_CTX_free(backend->ctx);
+ backend->ctx = SSL_CTX_new(req_method);
- if(!BACKEND->ctx) {
+ if(!backend->ctx) {
failf(data, "SSL: couldn't create a context!");
return CURLE_OUT_OF_MEMORY;
}
SSL_CTX_set_verify(
- BACKEND->ctx, SSL_CONN_CONFIG(verifypeer) ?
+ backend->ctx, SSL_CONN_CONFIG(verifypeer) ?
SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath)) {
- if(!SSL_CTX_load_verify_locations(BACKEND->ctx, SSL_CONN_CONFIG(CAfile),
- SSL_CONN_CONFIG(CApath))) {
+ if(!SSL_CTX_load_verify_locations(backend->ctx, SSL_CONN_CONFIG(CAfile),
+ SSL_CONN_CONFIG(CApath))) {
if(SSL_CONN_CONFIG(verifypeer)) {
failf(data,
"error setting certificate verify locations: "
@@ -181,7 +179,7 @@ mesalink_connect_step1(struct Curl_easy *data,
if(SSL_SET_OPTION(primary.clientcert) && SSL_SET_OPTION(key)) {
int file_type = do_file_type(SSL_SET_OPTION(cert_type));
- if(SSL_CTX_use_certificate_chain_file(BACKEND->ctx,
+ if(SSL_CTX_use_certificate_chain_file(backend->ctx,
SSL_SET_OPTION(primary.clientcert),
file_type) != 1) {
failf(data, "unable to use client certificate (no key or wrong pass"
@@ -190,8 +188,8 @@ mesalink_connect_step1(struct Curl_easy *data,
}
file_type = do_file_type(SSL_SET_OPTION(key_type));
- if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key),
- file_type) != 1) {
+ if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key),
+ file_type) != 1) {
failf(data, "unable to set private key");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -204,7 +202,7 @@ mesalink_connect_step1(struct Curl_easy *data,
ciphers = SSL_CONN_CONFIG(cipher_list);
if(ciphers) {
#ifdef MESALINK_HAVE_CIPHER
- if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
+ if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
}
@@ -212,10 +210,10 @@ mesalink_connect_step1(struct Curl_easy *data,
infof(data, "Cipher selection: %s", ciphers);
}
- if(BACKEND->handle)
- SSL_free(BACKEND->handle);
- BACKEND->handle = SSL_new(BACKEND->ctx);
- if(!BACKEND->handle) {
+ if(backend->handle)
+ SSL_free(backend->handle);
+ backend->handle = SSL_new(backend->ctx);
+ if(!backend->handle) {
failf(data, "SSL: couldn't create a context (handle)!");
return CURLE_OUT_OF_MEMORY;
}
@@ -227,7 +225,7 @@ mesalink_connect_step1(struct Curl_easy *data,
#endif
) {
/* hostname is not a valid IP address */
- if(SSL_set_tlsext_host_name(BACKEND->handle, hostname) != SSL_SUCCESS) {
+ if(SSL_set_tlsext_host_name(backend->handle, hostname) != SSL_SUCCESS) {
failf(data,
"WARNING: failed to configure server name indication (SNI) "
"TLS extension\n");
@@ -244,7 +242,7 @@ mesalink_connect_step1(struct Curl_easy *data,
|| strncmp(hostname, "[::1]", 5) == 0
#endif
) {
- SSL_set_tlsext_host_name(BACKEND->handle, "localhost");
+ SSL_set_tlsext_host_name(backend->handle, "localhost");
}
else
#endif
@@ -264,12 +262,12 @@ mesalink_connect_step1(struct Curl_easy *data,
SSL_IS_PROXY() ? TRUE : FALSE,
&ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
- if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
+ if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(data);
failf(
data,
"SSL: SSL_set_session failed: %s",
- ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer));
+ ERR_error_string(SSL_get_error(backend->handle, 0), error_buffer));
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
@@ -279,7 +277,7 @@ mesalink_connect_step1(struct Curl_easy *data,
}
#endif /* MESALINK_HAVE_SESSION */
- if(SSL_set_fd(BACKEND->handle, (int)sockfd) != SSL_SUCCESS) {
+ if(SSL_set_fd(backend->handle, (int)sockfd) != SSL_SUCCESS) {
failf(data, "SSL: SSL_set_fd failed");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -294,13 +292,14 @@ mesalink_connect_step2(struct Curl_easy *data,
{
int ret = -1;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
conn->recv[sockindex] = mesalink_recv;
conn->send[sockindex] = mesalink_send;
- ret = SSL_connect(BACKEND->handle);
+ ret = SSL_connect(backend->handle);
if(ret != SSL_SUCCESS) {
- int detail = SSL_get_error(BACKEND->handle, ret);
+ int detail = SSL_get_error(backend->handle, ret);
if(SSL_ERROR_WANT_CONNECT == detail || SSL_ERROR_WANT_READ == detail) {
connssl->connecting_state = ssl_connect_2_reading;
@@ -327,8 +326,8 @@ mesalink_connect_step2(struct Curl_easy *data,
connssl->connecting_state = ssl_connect_3;
infof(data,
"SSL connection using %s / %s",
- SSL_get_version(BACKEND->handle),
- SSL_get_cipher_name(BACKEND->handle));
+ SSL_get_version(backend->handle),
+ SSL_get_cipher_name(backend->handle));
return CURLE_OK;
}
@@ -347,8 +346,9 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
SSL_SESSION *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
+ struct ssl_backend_data *backend = connssl->backend;
- our_ssl_sessionid = SSL_get_session(BACKEND->handle);
+ our_ssl_sessionid = SSL_get_session(backend->handle);
Curl_ssl_sessionid_lock(data);
incache =
@@ -365,7 +365,7 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
if(!incache) {
result =
Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, 0,
- sockindex);
+ sockindex, NULL);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "failed to store ssl session");
@@ -387,12 +387,13 @@ mesalink_send(struct Curl_easy *data, int sockindex, const void *mem,
{
struct connectdata *conn = data->conn;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
char error_buffer[MESALINK_MAX_ERROR_SZ];
int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- int rc = SSL_write(BACKEND->handle, mem, memlen);
+ int rc = SSL_write(backend->handle, mem, memlen);
if(rc < 0) {
- int err = SSL_get_error(BACKEND->handle, rc);
+ int err = SSL_get_error(backend->handle, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
@@ -415,17 +416,18 @@ static void
mesalink_close(struct Curl_easy *data, struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
(void) data;
- if(BACKEND->handle) {
- (void)SSL_shutdown(BACKEND->handle);
- SSL_free(BACKEND->handle);
- BACKEND->handle = NULL;
+ if(backend->handle) {
+ (void)SSL_shutdown(backend->handle);
+ SSL_free(backend->handle);
+ backend->handle = NULL;
}
- if(BACKEND->ctx) {
- SSL_CTX_free(BACKEND->ctx);
- BACKEND->ctx = NULL;
+ if(backend->ctx) {
+ SSL_CTX_free(backend->ctx);
+ backend->ctx = NULL;
}
}
@@ -435,12 +437,13 @@ mesalink_recv(struct Curl_easy *data, int num, char *buf, size_t buffersize,
{
struct connectdata *conn = data->conn;
struct ssl_connect_data *connssl = &conn->ssl[num];
+ struct ssl_backend_data *backend = connssl->backend;
char error_buffer[MESALINK_MAX_ERROR_SZ];
int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- int nread = SSL_read(BACKEND->handle, buf, buffsize);
+ int nread = SSL_read(backend->handle, buf, buffsize);
if(nread <= 0) {
- int err = SSL_get_error(BACKEND->handle, nread);
+ int err = SSL_get_error(backend->handle, nread);
switch(err) {
case SSL_ERROR_ZERO_RETURN: /* no more data */
@@ -485,12 +488,13 @@ mesalink_shutdown(struct Curl_easy *data,
{
int retval = 0;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
(void) data;
- if(BACKEND->handle) {
- SSL_free(BACKEND->handle);
- BACKEND->handle = NULL;
+ if(backend->handle) {
+ SSL_free(backend->handle);
+ backend->handle = NULL;
}
return retval;
}
@@ -636,8 +640,9 @@ static void *
mesalink_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
{
+ struct ssl_backend_data *backend = connssl->backend;
(void)info;
- return BACKEND->handle;
+ return backend->handle;
}
const struct Curl_ssl Curl_ssl_mesalink = {
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index cf65789..2b44f05 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -304,13 +304,14 @@ static char *nss_sslver_to_name(PRUint16 nssver)
}
}
-static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
- char *cipher_list)
+/* the longest cipher name this supports */
+#define MAX_CIPHER_LENGTH 128
+
+static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc *model,
+ const char *cipher_list)
{
unsigned int i;
- PRBool cipher_state[NUM_OF_CIPHERS];
- PRBool found;
- char *cipher;
+ const char *cipher;
/* use accessors to avoid dynamic linking issues after an update of NSS */
const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
@@ -326,51 +327,52 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE);
}
- /* Set every entry in our list to false */
- for(i = 0; i < NUM_OF_CIPHERS; i++) {
- cipher_state[i] = PR_FALSE;
- }
-
cipher = cipher_list;
- while(cipher_list && (cipher_list[0])) {
+ while(cipher && cipher[0]) {
+ const char *end;
+ char name[MAX_CIPHER_LENGTH + 1];
+ size_t len;
+ bool found = FALSE;
while((*cipher) && (ISSPACE(*cipher)))
++cipher;
- cipher_list = strpbrk(cipher, ":, ");
- if(cipher_list) {
- *cipher_list++ = '\0';
- }
-
- found = PR_FALSE;
-
- for(i = 0; i<NUM_OF_CIPHERS; i++) {
- if(strcasecompare(cipher, cipherlist[i].name)) {
- cipher_state[i] = PR_TRUE;
- found = PR_TRUE;
- break;
- }
- }
+ end = strpbrk(cipher, ":, ");
+ if(end)
+ len = end - cipher;
+ else
+ len = strlen(cipher);
- if(found == PR_FALSE) {
- failf(data, "Unknown cipher in list: %s", cipher);
+ if(len > MAX_CIPHER_LENGTH) {
+ failf(data, "Bad cipher list");
return SECFailure;
}
-
- if(cipher_list) {
- cipher = cipher_list;
+ else if(len) {
+ memcpy(name, cipher, len);
+ name[len] = 0;
+
+ for(i = 0; i<NUM_OF_CIPHERS; i++) {
+ if(strcasecompare(name, cipherlist[i].name)) {
+ /* Enable the selected cipher */
+ if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) !=
+ SECSuccess) {
+ failf(data, "cipher-suite not supported by NSS: %s", name);
+ return SECFailure;
+ }
+ found = TRUE;
+ break;
+ }
+ }
}
- }
-
- /* Finally actually enable the selected ciphers */
- for(i = 0; i<NUM_OF_CIPHERS; i++) {
- if(!cipher_state[i])
- continue;
- if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) {
- failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
+ if(!found && len) {
+ failf(data, "Unknown cipher: %s", name);
return SECFailure;
}
+ if(end)
+ cipher = ++end;
+ else
+ break;
}
return SECSuccess;
@@ -782,7 +784,7 @@ static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
{
(void)slot; /* unused */
- if(retry || NULL == arg)
+ if(retry || !arg)
return NULL;
else
return (char *)PORT_Strdup((char *)arg);
@@ -955,7 +957,7 @@ static void display_cert_info(struct Curl_easy *data,
subject = CERT_NameToAscii(&cert->subject);
issuer = CERT_NameToAscii(&cert->issuer);
common_name = CERT_GetCommonName(&cert->subject);
- infof(data, "subject: %s\n", subject);
+ infof(data, "subject: %s", subject);
CERT_GetCertTimes(cert, &notBefore, &notAfter);
PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
@@ -1168,7 +1170,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
struct SECKEYPrivateKeyStr *key;
PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
- if(NULL == slot) {
+ if(!slot) {
failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
return SECFailure;
}
@@ -1182,7 +1184,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
SECITEM_FreeItem(&cert_der, PR_FALSE);
- if(NULL == cert) {
+ if(!cert) {
failf(data, "NSS: client certificate from file not found");
PK11_FreeSlot(slot);
return SECFailure;
@@ -1190,7 +1192,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
PK11_FreeSlot(slot);
- if(NULL == key) {
+ if(!key) {
failf(data, "NSS: private key from file not found");
CERT_DestroyCertificate(cert);
return SECFailure;
@@ -1207,9 +1209,9 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
/* use the default NSS hook */
if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
pRetCert, pRetKey)
- || NULL == *pRetCert) {
+ || !*pRetCert) {
- if(NULL == nickname)
+ if(!nickname)
failf(data, "NSS: client certificate not found (nickname not "
"specified)");
else
@@ -1220,7 +1222,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
/* get certificate nickname if any */
nickname = (*pRetCert)->nickname;
- if(NULL == nickname)
+ if(!nickname)
nickname = "[unknown]";
if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
@@ -1229,7 +1231,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
return SECFailure;
}
- if(NULL == *pRetKey) {
+ if(!*pRetKey) {
failf(data, "NSS: private key not found for certificate: %s", nickname);
return SECFailure;
}
@@ -1344,7 +1346,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
PRErrorCode err;
const char *err_name;
- if(nss_context != NULL)
+ if(nss_context)
return CURLE_OK;
memset((void *) &initparams, '\0', sizeof(initparams));
@@ -1360,7 +1362,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
free(certpath);
- if(nss_context != NULL)
+ if(nss_context)
return CURLE_OK;
err = PR_GetError();
@@ -1372,7 +1374,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
| NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
| NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
- if(nss_context != NULL)
+ if(nss_context)
return CURLE_OK;
err = PR_GetError();
@@ -2250,10 +2252,11 @@ static CURLcode nss_connect_common(struct Curl_easy *data,
case CURLE_OK:
break;
case CURLE_AGAIN:
+ /* CURLE_AGAIN in non-blocking mode is not an error */
if(!blocking)
- /* CURLE_AGAIN in non-blocking mode is not an error */
return CURLE_OK;
- /* FALLTHROUGH */
+ else
+ return result;
default:
return result;
}
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 87f4b02..f836c63 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -171,6 +171,21 @@
#define OPENSSL_load_builtin_modules(x)
#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+#define HAVE_EVP_PKEY_GET_PARAMS 1
+#else
+#define SSL_get1_peer_certificate SSL_get_peer_certificate
+#endif
+
+#ifdef HAVE_EVP_PKEY_GET_PARAMS
+#include <openssl/core_names.h>
+#define DECLARE_PKEY_PARAM_BIGNUM(name) BIGNUM *name = NULL
+#define FREE_PKEY_PARAM_BIGNUM(name) BN_clear_free(name)
+#else
+#define DECLARE_PKEY_PARAM_BIGNUM(name) const BIGNUM *name
+#define FREE_PKEY_PARAM_BIGNUM(name)
+#endif
+
/*
* Whether SSL_CTX_set_keylog_callback is available.
* OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
@@ -227,6 +242,17 @@
#endif
#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+#define HAVE_RANDOM_INIT_BY_DEFAULT 1
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
+ !(defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x2070100fL) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+#define HAVE_OPENSSL_VERSION
+#endif
+
struct ssl_backend_data {
struct Curl_easy *logger; /* transfer handle to pass trace logs to, only
using sockindex 0 */
@@ -435,18 +461,21 @@ static bool rand_enough(void)
static CURLcode ossl_seed(struct Curl_easy *data)
{
- char fname[256];
-
/* This might get called before it has been added to a multi handle */
if(data->multi && data->multi->ssl_seeded)
return CURLE_OK;
if(rand_enough()) {
- /* OpenSSL 1.1.0+ will return here */
+ /* OpenSSL 1.1.0+ should return here */
if(data->multi)
data->multi->ssl_seeded = TRUE;
return CURLE_OK;
}
+#ifdef HAVE_RANDOM_INIT_BY_DEFAULT
+ /* with OpenSSL 1.1.0+, a failed RAND_status is a showstopper */
+ failf(data, "Insufficient randomness");
+ return CURLE_SSL_CONNECT_ERROR;
+#else
#ifndef RANDOM_FILE
/* if RANDOM_FILE isn't defined, we only perform this if an option tells
@@ -507,19 +536,23 @@ static CURLcode ossl_seed(struct Curl_easy *data)
RAND_add(randb, (int)len, (double)len/2);
} while(!rand_enough());
- /* generates a default path for the random seed file */
- fname[0] = 0; /* blank it first */
- RAND_file_name(fname, sizeof(fname));
- if(fname[0]) {
- /* we got a file name to try */
- RAND_load_file(fname, RAND_LOAD_LENGTH);
- if(rand_enough())
- return CURLE_OK;
+ {
+ /* generates a default path for the random seed file */
+ char fname[256];
+ fname[0] = 0; /* blank it first */
+ RAND_file_name(fname, sizeof(fname));
+ if(fname[0]) {
+ /* we got a file name to try */
+ RAND_load_file(fname, RAND_LOAD_LENGTH);
+ if(rand_enough())
+ return CURLE_OK;
+ }
}
infof(data, "libcurl is now using a weak random seed!");
return (rand_enough() ? CURLE_OK :
- CURLE_SSL_CONNECT_ERROR /* confusing error code */);
+ CURLE_SSL_CONNECT_ERROR /* confusing error code */);
+#endif
}
#ifndef SSL_FILETYPE_ENGINE
@@ -1088,7 +1121,8 @@ int cert_stuff(struct Curl_easy *data,
EVP_PKEY_free(pktmp);
}
-#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL)
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) && \
+ !defined(OPENSSL_NO_DEPRECATED_3_0)
{
/* If RSA is used, don't check the private key if its flags indicate
* it doesn't support it. */
@@ -1401,6 +1435,12 @@ static void ossl_closeone(struct Curl_easy *data,
if(backend->handle) {
char buf[32];
set_logger(conn, data);
+ /*
+ * The conn->sock[0] socket is passed to openssl with SSL_set_fd(). Make
+ * sure the socket is not closed before calling OpenSSL functions that
+ * will use it.
+ */
+ DEBUGASSERT(conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD);
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
@@ -1639,9 +1679,10 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
hostname. In this case, the iPAddress subjectAltName must be present
in the certificate and must exactly match the IP in the URI.
+ This function is now used from ngtcp2 (QUIC) as well.
*/
-static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
- X509 *server_cert)
+CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+ X509 *server_cert)
{
bool matched = FALSE;
int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
@@ -1926,7 +1967,7 @@ static CURLcode verifystatus(struct Curl_easy *data,
}
/* Compute the certificate's ID */
- cert = SSL_get_peer_certificate(backend->handle);
+ cert = SSL_get1_peer_certificate(backend->handle);
if(!cert) {
failf(data, "Error getting peer certificate");
result = CURLE_SSL_INVALIDCERTSTATUS;
@@ -2493,6 +2534,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
+ bool added = FALSE;
void *old_ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
@@ -2511,9 +2553,11 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
if(!incache) {
if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
- 0 /* unknown size */, sockindex)) {
- /* the session has been put into the session cache */
- res = 1;
+ 0 /* unknown size */, sockindex, &added)) {
+ if(added) {
+ /* the session has been put into the session cache */
+ res = 1;
+ }
}
else
failf(data, "failed to store ssl session");
@@ -2936,7 +2980,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
NULL, cert_name, sizeof(cert_name))) {
strcpy(cert_name, "Unknown");
}
- infof(data, "SSL: Checking cert %s\"\n", cert_name);
+ infof(data, "SSL: Checking cert \"%s\"", cert_name);
#endif
encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
@@ -3052,60 +3096,36 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
}
}
+ if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) {
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
- {
- if(ssl_cafile) {
- if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
- if(verifypeer && !imported_native_ca) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate file: %s", ssl_cafile);
- return CURLE_SSL_CACERT_BADFILE;
- }
- /* Continue with warning if certificate verification isn't required. */
- infof(data, "error setting certificate file, continuing anyway");
- }
- infof(data, " CAfile: %s", ssl_cafile);
+ if(ssl_cafile &&
+ !SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate file: %s", ssl_cafile);
+ return CURLE_SSL_CACERT_BADFILE;
}
- if(ssl_capath) {
- if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
- if(verifypeer && !imported_native_ca) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate path: %s", ssl_capath);
- return CURLE_SSL_CACERT_BADFILE;
- }
- /* Continue with warning if certificate verification isn't required. */
- infof(data, "error setting certificate path, continuing anyway");
- }
- infof(data, " CApath: %s", ssl_capath);
+ if(ssl_capath &&
+ !SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate path: %s", ssl_capath);
+ return CURLE_SSL_CACERT_BADFILE;
}
- }
#else
- if(ssl_cafile || ssl_capath) {
- /* tell SSL where to find CA certificates that are used to verify
- the server's certificate. */
+ /* tell OpenSSL where to find CA certificates that are used to verify the
+ server's certificate. */
if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) {
- if(verifypeer && !imported_native_ca) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate verify locations:"
- " CAfile: %s CApath: %s",
- ssl_cafile ? ssl_cafile : "none",
- ssl_capath ? ssl_capath : "none");
- return CURLE_SSL_CACERT_BADFILE;
- }
- /* Just continue with a warning if no strict certificate verification
- is required. */
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:");
- }
- else {
- /* Everything is fine. */
- infof(data, "successfully set certificate verify locations:");
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:"
+ " CAfile: %s CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return CURLE_SSL_CACERT_BADFILE;
}
+#endif
infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
}
-#endif
#ifdef CURL_CA_FALLBACK
if(verifypeer &&
@@ -3476,10 +3496,7 @@ static void pubkey_show(struct Curl_easy *data,
int num,
const char *type,
const char *name,
-#ifdef HAVE_OPAQUE_RSA_DSA_DH
- const
-#endif
- BIGNUM *bn)
+ const BIGNUM *bn)
{
char *ptr;
char namebuf[32];
@@ -3544,12 +3561,6 @@ typedef size_t numcert_t;
typedef int numcert_t;
#endif
-#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
-#define OSSL3_CONST const
-#else
-#define OSSL3_CONST
-#endif
-
static CURLcode get_cert_chain(struct Curl_easy *data,
struct ssl_connect_data *connssl)
{
@@ -3573,6 +3584,9 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
}
mem = BIO_new(BIO_s_mem());
+ if(!mem) {
+ return CURLE_OUT_OF_MEMORY;
+ }
for(i = 0; i < (int)numcerts; i++) {
ASN1_INTEGER *num;
@@ -3657,92 +3671,115 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
switch(pktype) {
case EVP_PKEY_RSA:
{
- OSSL3_CONST RSA *rsa;
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+ RSA *rsa;
#ifdef HAVE_OPAQUE_EVP_PKEY
rsa = EVP_PKEY_get0_RSA(pubkey);
#else
rsa = pubkey->pkey.rsa;
-#endif
+#endif /* HAVE_OPAQUE_EVP_PKEY */
+#endif /* !HAVE_EVP_PKEY_GET_PARAMS */
-#ifdef HAVE_OPAQUE_RSA_DSA_DH
{
- const BIGNUM *n;
- const BIGNUM *e;
-
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+ DECLARE_PKEY_PARAM_BIGNUM(n);
+ DECLARE_PKEY_PARAM_BIGNUM(e);
+#ifdef HAVE_EVP_PKEY_GET_PARAMS
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n);
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e);
+#else
RSA_get0_key(rsa, &n, &e, NULL);
+#endif /* HAVE_EVP_PKEY_GET_PARAMS */
BIO_printf(mem, "%d", BN_num_bits(n));
+#else
+ BIO_printf(mem, "%d", BN_num_bits(rsa->n));
+#endif /* HAVE_OPAQUE_RSA_DSA_DH */
push_certinfo("RSA Public Key", i);
print_pubkey_BN(rsa, n, i);
print_pubkey_BN(rsa, e, i);
+ FREE_PKEY_PARAM_BIGNUM(n);
+ FREE_PKEY_PARAM_BIGNUM(e);
}
-#else
- BIO_printf(mem, "%d", BN_num_bits(rsa->n));
- push_certinfo("RSA Public Key", i);
- print_pubkey_BN(rsa, n, i);
- print_pubkey_BN(rsa, e, i);
-#endif
break;
}
case EVP_PKEY_DSA:
{
#ifndef OPENSSL_NO_DSA
- OSSL3_CONST DSA *dsa;
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+ DSA *dsa;
#ifdef HAVE_OPAQUE_EVP_PKEY
dsa = EVP_PKEY_get0_DSA(pubkey);
#else
dsa = pubkey->pkey.dsa;
-#endif
-#ifdef HAVE_OPAQUE_RSA_DSA_DH
+#endif /* HAVE_OPAQUE_EVP_PKEY */
+#endif /* !HAVE_EVP_PKEY_GET_PARAMS */
{
- const BIGNUM *p;
- const BIGNUM *q;
- const BIGNUM *g;
- const BIGNUM *pub_key;
-
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+ DECLARE_PKEY_PARAM_BIGNUM(p);
+ DECLARE_PKEY_PARAM_BIGNUM(q);
+ DECLARE_PKEY_PARAM_BIGNUM(g);
+ DECLARE_PKEY_PARAM_BIGNUM(pub_key);
+#ifdef HAVE_EVP_PKEY_GET_PARAMS
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p);
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q);
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g);
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key);
+#else
DSA_get0_pqg(dsa, &p, &q, &g);
DSA_get0_key(dsa, &pub_key, NULL);
-
+#endif /* HAVE_EVP_PKEY_GET_PARAMS */
+#endif /* HAVE_OPAQUE_RSA_DSA_DH */
print_pubkey_BN(dsa, p, i);
print_pubkey_BN(dsa, q, i);
print_pubkey_BN(dsa, g, i);
print_pubkey_BN(dsa, pub_key, i);
+ FREE_PKEY_PARAM_BIGNUM(p);
+ FREE_PKEY_PARAM_BIGNUM(q);
+ FREE_PKEY_PARAM_BIGNUM(g);
+ FREE_PKEY_PARAM_BIGNUM(pub_key);
}
-#else
- print_pubkey_BN(dsa, p, i);
- print_pubkey_BN(dsa, q, i);
- print_pubkey_BN(dsa, g, i);
- print_pubkey_BN(dsa, pub_key, i);
-#endif
#endif /* !OPENSSL_NO_DSA */
break;
}
case EVP_PKEY_DH:
{
- OSSL3_CONST DH *dh;
+#ifndef HAVE_EVP_PKEY_GET_PARAMS
+ DH *dh;
#ifdef HAVE_OPAQUE_EVP_PKEY
dh = EVP_PKEY_get0_DH(pubkey);
#else
dh = pubkey->pkey.dh;
-#endif
-#ifdef HAVE_OPAQUE_RSA_DSA_DH
+#endif /* HAVE_OPAQUE_EVP_PKEY */
+#endif /* !HAVE_EVP_PKEY_GET_PARAMS */
{
- const BIGNUM *p;
- const BIGNUM *q;
- const BIGNUM *g;
- const BIGNUM *pub_key;
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+ DECLARE_PKEY_PARAM_BIGNUM(p);
+ DECLARE_PKEY_PARAM_BIGNUM(q);
+ DECLARE_PKEY_PARAM_BIGNUM(g);
+ DECLARE_PKEY_PARAM_BIGNUM(pub_key);
+#ifdef HAVE_EVP_PKEY_GET_PARAMS
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p);
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q);
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g);
+ EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key);
+#else
DH_get0_pqg(dh, &p, &q, &g);
DH_get0_key(dh, &pub_key, NULL);
+#endif /* HAVE_EVP_PKEY_GET_PARAMS */
print_pubkey_BN(dh, p, i);
print_pubkey_BN(dh, q, i);
print_pubkey_BN(dh, g, i);
+#else
+ print_pubkey_BN(dh, p, i);
+ print_pubkey_BN(dh, g, i);
+#endif /* HAVE_OPAQUE_RSA_DSA_DH */
print_pubkey_BN(dh, pub_key, i);
+ FREE_PKEY_PARAM_BIGNUM(p);
+ FREE_PKEY_PARAM_BIGNUM(q);
+ FREE_PKEY_PARAM_BIGNUM(g);
+ FREE_PKEY_PARAM_BIGNUM(pub_key);
}
-#else
- print_pubkey_BN(dh, p, i);
- print_pubkey_BN(dh, g, i);
- print_pubkey_BN(dh, pub_key, i);
-#endif
break;
}
}
@@ -3846,11 +3883,20 @@ static CURLcode servercert(struct Curl_easy *data,
BIO *mem = BIO_new(BIO_s_mem());
struct ssl_backend_data *backend = connssl->backend;
+ if(!mem) {
+ failf(data,
+ "BIO_new return NULL, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ return CURLE_OUT_OF_MEMORY;
+ }
+
if(data->set.ssl.certinfo)
/* we've been asked to gather certificate info! */
(void)get_cert_chain(data, connssl);
- backend->server_cert = SSL_get_peer_certificate(backend->handle);
+ backend->server_cert = SSL_get1_peer_certificate(backend->handle);
if(!backend->server_cert) {
BIO_free(mem);
if(!strict)
@@ -3884,7 +3930,7 @@ static CURLcode servercert(struct Curl_easy *data,
BIO_free(mem);
if(SSL_CONN_CONFIG(verifyhost)) {
- result = verifyhost(data, conn, backend->server_cert);
+ result = Curl_ossl_verifyhost(data, conn, backend->server_cert);
if(result) {
X509_free(backend->server_cert);
backend->server_cert = NULL;
@@ -4364,13 +4410,7 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
static size_t ossl_version(char *buffer, size_t size)
{
#ifdef LIBRESSL_VERSION_NUMBER
-#if LIBRESSL_VERSION_NUMBER < 0x2070100fL
- return msnprintf(buffer, size, "%s/%lx.%lx.%lx",
- OSSL_PACKAGE,
- (LIBRESSL_VERSION_NUMBER>>28)&0xf,
- (LIBRESSL_VERSION_NUMBER>>20)&0xff,
- (LIBRESSL_VERSION_NUMBER>>12)&0xff);
-#else /* OpenSSL_version() first appeared in LibreSSL 2.7.1 */
+#ifdef HAVE_OPENSSL_VERSION
char *p;
int count;
const char *ver = OpenSSL_version(OPENSSL_VERSION);
@@ -4384,6 +4424,12 @@ static size_t ossl_version(char *buffer, size_t size)
*p = '_';
}
return count;
+#else
+ return msnprintf(buffer, size, "%s/%lx.%lx.%lx",
+ OSSL_PACKAGE,
+ (LIBRESSL_VERSION_NUMBER>>28)&0xf,
+ (LIBRESSL_VERSION_NUMBER>>20)&0xff,
+ (LIBRESSL_VERSION_NUMBER>>12)&0xff);
#endif
#elif defined(OPENSSL_IS_BORINGSSL)
return msnprintf(buffer, size, OSSL_PACKAGE);
diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h
index 2f6e1b2..2805845 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.h
+++ b/Utilities/cmcurl/lib/vtls/openssl.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,11 +26,15 @@
#ifdef USE_OPENSSL
/*
- * This header should only be needed to get included by vtls.c and openssl.c
+ * This header should only be needed to get included by vtls.c, openssl.c
+ * and ngtcp2.c
*/
+#include <openssl/x509v3.h>
#include "urldata.h"
+CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+ X509 *server_cert);
extern const struct Curl_ssl Curl_ssl_openssl;
#endif /* USE_OPENSSL */
diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c
index 2ac97ce..6dbb1ef 100644
--- a/Utilities/cmcurl/lib/vtls/rustls.c
+++ b/Utilities/cmcurl/lib/vtls/rustls.c
@@ -27,7 +27,7 @@
#include "curl_printf.h"
#include <errno.h>
-#include <crustls.h>
+#include <rustls.h>
#include "inet_pton.h"
#include "urldata.h"
@@ -138,11 +138,6 @@ cr_recv(struct Curl_easy *data, int sockindex,
*err = CURLE_READ_ERROR;
return -1;
}
- else if(tls_bytes_read == 0) {
- failf(data, "connection closed without TLS close_notify alert");
- *err = CURLE_READ_ERROR;
- return -1;
- }
infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read);
@@ -161,22 +156,21 @@ cr_recv(struct Curl_easy *data, int sockindex,
(uint8_t *)plainbuf + plain_bytes_copied,
plainlen - plain_bytes_copied,
&n);
- if(rresult == RUSTLS_RESULT_ALERT_CLOSE_NOTIFY) {
- *err = CURLE_OK;
- return 0;
+ if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
+ infof(data, "cr_recv got PLAINTEXT_EMPTY. will try again later.");
+ backend->data_pending = FALSE;
+ break;
}
else if(rresult != RUSTLS_RESULT_OK) {
- failf(data, "error in rustls_connection_read");
+ /* n always equals 0 in this case, don't need to check it */
+ failf(data, "error in rustls_connection_read: %d", rresult);
*err = CURLE_READ_ERROR;
return -1;
}
else if(n == 0) {
- /* rustls returns 0 from connection_read to mean "all currently
- available data has been read." If we bring in more ciphertext with
- read_tls, more plaintext will become available. So don't tell curl
- this is an EOF. Instead, say "come back later." */
- infof(data, "cr_recv got 0 bytes of plaintext");
- backend->data_pending = FALSE;
+ /* n == 0 indicates clean EOF, but we may have read some other
+ plaintext bytes before we reached this. Break out of the loop
+ so we can figure out whether to return success or EOF. */
break;
}
else {
@@ -185,15 +179,23 @@ cr_recv(struct Curl_easy *data, int sockindex,
}
}
- /* If we wrote out 0 plaintext bytes, it might just mean we haven't yet
- read a full TLS record. Return CURLE_AGAIN so curl doesn't treat this
- as EOF. */
- if(plain_bytes_copied == 0) {
+ if(plain_bytes_copied) {
+ *err = CURLE_OK;
+ return plain_bytes_copied;
+ }
+
+ /* If we wrote out 0 plaintext bytes, that means either we hit a clean EOF,
+ OR we got a RUSTLS_RESULT_PLAINTEXT_EMPTY.
+ If the latter, return CURLE_AGAIN so curl doesn't treat this as EOF. */
+ if(!backend->data_pending) {
*err = CURLE_AGAIN;
return -1;
}
- return plain_bytes_copied;
+ /* Zero bytes read, and no RUSTLS_RESULT_PLAINTEXT_EMPTY, means the TCP
+ connection was cleanly closed (with a close_notify alert). */
+ *err = CURLE_OK;
+ return 0;
}
/*
@@ -309,10 +311,10 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
config_builder = rustls_client_config_builder_new();
#ifdef USE_HTTP2
infof(data, "offering ALPN for HTTP/1.1 and HTTP/2");
- rustls_client_config_builder_set_protocols(config_builder, alpn, 2);
+ rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 2);
#else
infof(data, "offering ALPN for HTTP/1.1 only");
- rustls_client_config_builder_set_protocols(config_builder, alpn, 1);
+ rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 1);
#endif
if(!verifypeer) {
rustls_client_config_builder_dangerous_set_certificate_verifier(
@@ -358,7 +360,7 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
size_t len = 0;
rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
- if(NULL == protocol) {
+ if(!protocol) {
infof(data, "ALPN, server did not agree to a protocol");
return;
}
@@ -414,9 +416,6 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
/*
* Connection has been established according to rustls. Set send/recv
* handlers, and update the state machine.
- * This check has to come last because is_handshaking starts out false,
- * then becomes true when we first write data, then becomes false again
- * once the handshake is done.
*/
if(!rustls_connection_is_handshaking(rconn)) {
infof(data, "Done handshaking");
@@ -543,6 +542,12 @@ cr_close(struct Curl_easy *data, struct connectdata *conn,
}
}
+static size_t cr_version(char *buffer, size_t size)
+{
+ struct rustls_str ver = rustls_version();
+ return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
+}
+
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_TLS13_CIPHERSUITES, /* supports */
@@ -550,7 +555,7 @@ const struct Curl_ssl Curl_ssl_rustls = {
Curl_none_init, /* init */
Curl_none_cleanup, /* cleanup */
- rustls_version, /* version */
+ cr_version, /* version */
Curl_none_check_cxn, /* check_cxn */
Curl_none_shutdown, /* shutdown */
cr_data_pending, /* data_pending */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index 722a937..0a8e606 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -147,8 +147,6 @@
#define ALG_CLASS_DHASH ALG_CLASS_HASH
#endif
-#define BACKEND connssl->backend
-
static Curl_recv schannel_recv;
static Curl_send schannel_send;
@@ -423,6 +421,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
PCCERT_CONTEXT client_certs[1] = { NULL };
SECURITY_STATUS sspi_status = SEC_E_OK;
CURLcode result;
+ struct ssl_backend_data *backend = connssl->backend;
/* setup Schannel API options */
memset(&schannel_cred, 0, sizeof(schannel_cred));
@@ -430,7 +429,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
if(conn->ssl_config.verifypeer) {
#ifdef HAS_MANUAL_VERIFY_API
- if(BACKEND->use_manual_cred_validation)
+ if(backend->use_manual_cred_validation)
schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
else
#endif
@@ -503,7 +502,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
if(SSL_CONN_CONFIG(cipher_list)) {
result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
- BACKEND->algIds);
+ backend->algIds);
if(CURLE_OK != result) {
failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
return result;
@@ -600,7 +599,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
datablob.pbData = (BYTE*)certdata;
datablob.cbData = (DWORD)certsize;
- if(data->set.ssl.key_passwd != NULL)
+ if(data->set.ssl.key_passwd)
pwd_len = strlen(data->set.ssl.key_passwd);
pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
if(pszPassword) {
@@ -704,9 +703,9 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
#endif
/* allocate memory for the re-usable credential handle */
- BACKEND->cred = (struct Curl_schannel_cred *)
+ backend->cred = (struct Curl_schannel_cred *)
calloc(1, sizeof(struct Curl_schannel_cred));
- if(!BACKEND->cred) {
+ if(!backend->cred) {
failf(data, "schannel: unable to allocate memory");
if(client_certs[0])
@@ -714,16 +713,14 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- BACKEND->cred->refcount = 1;
+ backend->cred->refcount = 1;
- /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
- */
sspi_status =
s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL,
&schannel_cred, NULL, NULL,
- &BACKEND->cred->cred_handle,
- &BACKEND->cred->time_stamp);
+ &backend->cred->cred_handle,
+ &backend->cred->time_stamp);
if(client_certs[0])
CertFreeCertificateContext(client_certs[0]);
@@ -732,7 +729,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data,
char buffer[STRERROR_LEN];
failf(data, "schannel: AcquireCredentialsHandle failed: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
- Curl_safefree(BACKEND->cred);
+ Curl_safefree(backend->cred);
switch(sspi_status) {
case SEC_E_INSUFFICIENT_MEMORY:
return CURLE_OUT_OF_MEMORY;
@@ -771,12 +768,13 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
TCHAR *host_name;
CURLcode result;
char * const hostname = SSL_HOST_NAME();
+ struct ssl_backend_data *backend = connssl->backend;
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %hu (step 1/3)",
hostname, conn->remote_port));
- if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT,
+ if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
/* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
algorithms that may not be supported by all servers. */
@@ -787,29 +785,29 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
Also it doesn't seem to be supported for Wine, see curl bug #983. */
- BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
+ backend->use_alpn = conn->bits.tls_enable_alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") &&
- curlx_verify_windows_version(6, 3, PLATFORM_WINNT,
+ curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL);
#else
- BACKEND->use_alpn = false;
+ backend->use_alpn = false;
#endif
#ifdef _WIN32_WCE
#ifdef HAS_MANUAL_VERIFY_API
/* certificate validation on CE doesn't seem to work right; we'll
* do it following a more manual process. */
- BACKEND->use_manual_cred_validation = true;
+ backend->use_manual_cred_validation = true;
#else
#error "compiler too old to support requisite manual cert verify for Win CE"
#endif
#else
#ifdef HAS_MANUAL_VERIFY_API
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
- if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT,
+ if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
- BACKEND->use_manual_cred_validation = true;
+ backend->use_manual_cred_validation = true;
}
else {
failf(data, "schannel: this version of Windows is too old to support "
@@ -818,7 +816,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
}
else
- BACKEND->use_manual_cred_validation = false;
+ backend->use_manual_cred_validation = false;
#else
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
failf(data, "schannel: CA cert support not built in");
@@ -827,7 +825,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
#endif
- BACKEND->cred = NULL;
+ backend->cred = NULL;
/* check for an existing re-usable credential handle */
if(SSL_SET_OPTION(primary.sessionid)) {
@@ -835,19 +833,19 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(!Curl_ssl_getsessionid(data, conn,
SSL_IS_PROXY() ? TRUE : FALSE,
(void **)&old_cred, NULL, sockindex)) {
- BACKEND->cred = old_cred;
+ backend->cred = old_cred;
DEBUGF(infof(data, "schannel: re-using existing credential handle"));
/* increment the reference counter of the credential/session handle */
- BACKEND->cred->refcount++;
+ backend->cred->refcount++;
DEBUGF(infof(data,
"schannel: incremented credential handle refcount = %d",
- BACKEND->cred->refcount));
+ backend->cred->refcount));
}
Curl_ssl_sessionid_unlock(data);
}
- if(!BACKEND->cred) {
+ if(!backend->cred) {
result = schannel_acquire_credential_handle(data, conn, sockindex);
if(result != CURLE_OK) {
return result;
@@ -864,7 +862,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAS_ALPN
- if(BACKEND->use_alpn) {
+ if(backend->use_alpn) {
int cur = 0;
int list_start_index = 0;
unsigned int *extension_len = NULL;
@@ -922,18 +920,18 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
/* security request flags */
- BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
+ backend->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
if(!SSL_SET_OPTION(auto_client_cert)) {
- BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
+ backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
}
/* allocate memory for the security context handle */
- BACKEND->ctxt = (struct Curl_schannel_ctxt *)
+ backend->ctxt = (struct Curl_schannel_ctxt *)
calloc(1, sizeof(struct Curl_schannel_ctxt));
- if(!BACKEND->ctxt) {
+ if(!backend->ctxt) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
@@ -950,16 +948,16 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
us problems with inbuf regardless. https://github.com/curl/curl/issues/983
*/
sspi_status = s_pSecFn->InitializeSecurityContext(
- &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
- (BACKEND->use_alpn ? &inbuf_desc : NULL),
- 0, &BACKEND->ctxt->ctxt_handle,
- &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
+ &backend->cred->cred_handle, NULL, host_name, backend->req_flags, 0, 0,
+ (backend->use_alpn ? &inbuf_desc : NULL),
+ 0, &backend->ctxt->ctxt_handle,
+ &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
curlx_unicodefree(host_name);
if(sspi_status != SEC_I_CONTINUE_NEEDED) {
char buffer[STRERROR_LEN];
- Curl_safefree(BACKEND->ctxt);
+ Curl_safefree(backend->ctxt);
switch(sspi_status) {
case SEC_E_INSUFFICIENT_MEMORY:
failf(data, "schannel: initial InitializeSecurityContext failed: %s",
@@ -1003,10 +1001,10 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
DEBUGF(infof(data, "schannel: sent initial handshake data: "
"sent %zd bytes", written));
- BACKEND->recv_unrecoverable_err = CURLE_OK;
- BACKEND->recv_sspi_close_notify = false;
- BACKEND->recv_connection_closed = false;
- BACKEND->encdata_is_incomplete = false;
+ backend->recv_unrecoverable_err = CURLE_OK;
+ backend->recv_sspi_close_notify = false;
+ backend->recv_connection_closed = false;
+ backend->encdata_is_incomplete = false;
/* continue to second handshake step */
connssl->connecting_state = ssl_connect_2;
@@ -1031,6 +1029,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
bool doread;
char * const hostname = SSL_HOST_NAME();
const char *pubkey_ptr;
+ struct ssl_backend_data *backend = connssl->backend;
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
@@ -1038,39 +1037,39 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
"schannel: SSL/TLS connection with %s port %hu (step 2/3)",
hostname, conn->remote_port));
- if(!BACKEND->cred || !BACKEND->ctxt)
+ if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
/* buffer to store previously received and decrypted data */
- if(!BACKEND->decdata_buffer) {
- BACKEND->decdata_offset = 0;
- BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
- BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
- if(!BACKEND->decdata_buffer) {
+ if(!backend->decdata_buffer) {
+ backend->decdata_offset = 0;
+ backend->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+ backend->decdata_buffer = malloc(backend->decdata_length);
+ if(!backend->decdata_buffer) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
}
/* buffer to store previously received and encrypted data */
- if(!BACKEND->encdata_buffer) {
- BACKEND->encdata_is_incomplete = false;
- BACKEND->encdata_offset = 0;
- BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
- BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
- if(!BACKEND->encdata_buffer) {
+ if(!backend->encdata_buffer) {
+ backend->encdata_is_incomplete = false;
+ backend->encdata_offset = 0;
+ backend->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+ backend->encdata_buffer = malloc(backend->encdata_length);
+ if(!backend->encdata_buffer) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
}
/* if we need a bigger buffer to read a full message, increase buffer now */
- if(BACKEND->encdata_length - BACKEND->encdata_offset <
+ if(backend->encdata_length - backend->encdata_offset <
CURL_SCHANNEL_BUFFER_FREE_SIZE) {
/* increase internal encrypted data buffer */
- size_t reallocated_length = BACKEND->encdata_offset +
+ size_t reallocated_length = backend->encdata_offset +
CURL_SCHANNEL_BUFFER_FREE_SIZE;
- reallocated_buffer = realloc(BACKEND->encdata_buffer,
+ reallocated_buffer = realloc(backend->encdata_buffer,
reallocated_length);
if(!reallocated_buffer) {
@@ -1078,8 +1077,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
}
else {
- BACKEND->encdata_buffer = reallocated_buffer;
- BACKEND->encdata_length = reallocated_length;
+ backend->encdata_buffer = reallocated_buffer;
+ backend->encdata_length = reallocated_length;
}
}
@@ -1088,10 +1087,10 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
if(doread) {
/* read encrypted handshake data from socket */
result = Curl_read_plain(conn->sock[sockindex],
- (char *) (BACKEND->encdata_buffer +
- BACKEND->encdata_offset),
- BACKEND->encdata_length -
- BACKEND->encdata_offset,
+ (char *) (backend->encdata_buffer +
+ backend->encdata_offset),
+ backend->encdata_length -
+ backend->encdata_offset,
&nread);
if(result == CURLE_AGAIN) {
if(connssl->connecting_state != ssl_connect_2_writing)
@@ -1107,18 +1106,18 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
/* increase encrypted data buffer offset */
- BACKEND->encdata_offset += nread;
- BACKEND->encdata_is_incomplete = false;
+ backend->encdata_offset += nread;
+ backend->encdata_is_incomplete = false;
DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
}
DEBUGF(infof(data,
"schannel: encrypted data buffer: offset %zu length %zu",
- BACKEND->encdata_offset, BACKEND->encdata_length));
+ backend->encdata_offset, backend->encdata_length));
/* setup input buffers */
- InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
- curlx_uztoul(BACKEND->encdata_offset));
+ InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(backend->encdata_offset),
+ curlx_uztoul(backend->encdata_offset));
InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&inbuf_desc, inbuf, 2);
@@ -1134,19 +1133,17 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
/* copy received handshake data into input buffer */
- memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
- BACKEND->encdata_offset);
+ memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
+ backend->encdata_offset);
host_name = curlx_convert_UTF8_to_tchar(hostname);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
- /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
- */
sspi_status = s_pSecFn->InitializeSecurityContext(
- &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
- host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
- &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
+ &backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
+ host_name, backend->req_flags, 0, 0, &inbuf_desc, 0, NULL,
+ &outbuf_desc, &backend->ret_flags, &backend->ctxt->time_stamp);
curlx_unicodefree(host_name);
@@ -1155,7 +1152,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* check if the handshake was incomplete */
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
- BACKEND->encdata_is_incomplete = true;
+ backend->encdata_is_incomplete = true;
connssl->connecting_state = ssl_connect_2_reading;
DEBUGF(infof(data,
"schannel: received incomplete message, need more data"));
@@ -1166,8 +1163,8 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
the handshake without one. This will allow connections to servers which
request a client certificate but do not require it. */
if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
- !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
- BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
+ !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
+ backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
connssl->connecting_state = ssl_connect_2_writing;
DEBUGF(infof(data,
"schannel: a client certificate has been requested"));
@@ -1195,7 +1192,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
/* free obsolete buffer */
- if(outbuf[i].pvBuffer != NULL) {
+ if(outbuf[i].pvBuffer) {
s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
}
}
@@ -1249,11 +1246,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
*/
/* check if the remaining data is less than the total amount
and therefore begins after the already processed data */
- if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
- memmove(BACKEND->encdata_buffer,
- (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
+ if(backend->encdata_offset > inbuf[1].cbBuffer) {
+ memmove(backend->encdata_buffer,
+ (backend->encdata_buffer + backend->encdata_offset) -
inbuf[1].cbBuffer, inbuf[1].cbBuffer);
- BACKEND->encdata_offset = inbuf[1].cbBuffer;
+ backend->encdata_offset = inbuf[1].cbBuffer;
if(sspi_status == SEC_I_CONTINUE_NEEDED) {
doread = FALSE;
continue;
@@ -1261,7 +1258,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
}
else {
- BACKEND->encdata_offset = 0;
+ backend->encdata_offset = 0;
}
break;
}
@@ -1288,7 +1285,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
#ifdef HAS_MANUAL_VERIFY_API
- if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
+ if(conn->ssl_config.verifypeer && backend->use_manual_cred_validation) {
return Curl_verify_certificate(data, conn, sockindex);
}
#endif
@@ -1370,6 +1367,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAS_ALPN
SecPkgContext_ApplicationProtocol alpn_result;
#endif
+ struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
@@ -1377,28 +1375,28 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
"schannel: SSL/TLS connection with %s port %hu (step 3/3)",
hostname, conn->remote_port));
- if(!BACKEND->cred)
+ if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR;
/* check if the required context attributes are met */
- if(BACKEND->ret_flags != BACKEND->req_flags) {
- if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
+ if(backend->ret_flags != backend->req_flags) {
+ if(!(backend->ret_flags & ISC_RET_SEQUENCE_DETECT))
failf(data, "schannel: failed to setup sequence detection");
- if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
+ if(!(backend->ret_flags & ISC_RET_REPLAY_DETECT))
failf(data, "schannel: failed to setup replay detection");
- if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
+ if(!(backend->ret_flags & ISC_RET_CONFIDENTIALITY))
failf(data, "schannel: failed to setup confidentiality");
- if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
+ if(!(backend->ret_flags & ISC_RET_ALLOCATED_MEMORY))
failf(data, "schannel: failed to setup memory allocation");
- if(!(BACKEND->ret_flags & ISC_RET_STREAM))
+ if(!(backend->ret_flags & ISC_RET_STREAM))
failf(data, "schannel: failed to setup stream orientation");
return CURLE_SSL_CONNECT_ERROR;
}
#ifdef HAS_ALPN
- if(BACKEND->use_alpn) {
+ if(backend->use_alpn) {
sspi_status =
- s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_APPLICATION_PROTOCOL,
&alpn_result);
@@ -1436,13 +1434,14 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
/* save the current session data for possible re-use */
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
+ bool added = FALSE;
struct Curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(data);
incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred,
NULL, sockindex));
if(incache) {
- if(old_cred != BACKEND->cred) {
+ if(old_cred != backend->cred) {
DEBUGF(infof(data,
"schannel: old credential handle is stale, removing"));
/* we're not taking old_cred ownership here, no refcount++ is needed */
@@ -1451,17 +1450,17 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
}
if(!incache) {
- result = Curl_ssl_addsessionid(data, conn, isproxy, BACKEND->cred,
+ result = Curl_ssl_addsessionid(data, conn, isproxy, backend->cred,
sizeof(struct Curl_schannel_cred),
- sockindex);
+ sockindex, &added);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "schannel: failed to store credential handle");
return result;
}
- else {
+ else if(added) {
/* this cred session is now also referenced by sessionid cache */
- BACKEND->cred->refcount++;
+ backend->cred->refcount++;
DEBUGF(infof(data,
"schannel: stored credential handle in session cache"));
}
@@ -1472,7 +1471,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
if(data->set.ssl.certinfo) {
int certs_count = 0;
sspi_status =
- s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&ccert_context);
@@ -1609,7 +1608,10 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn,
* binding to pass the IIS extended protection checks.
* Available on Windows 7 or later.
*/
- conn->sslContext = &BACKEND->ctxt->ctxt_handle;
+ {
+ struct ssl_backend_data *backend = connssl->backend;
+ conn->sslContext = &backend->ctxt->ctxt_handle;
+ }
#endif
*done = TRUE;
@@ -1636,13 +1638,14 @@ schannel_send(struct Curl_easy *data, int sockindex,
SecBufferDesc outbuf_desc;
SECURITY_STATUS sspi_status = SEC_E_OK;
CURLcode result;
+ struct ssl_backend_data *backend = connssl->backend;
/* check if the maximum stream sizes were queried */
- if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
+ if(backend->stream_sizes.cbMaximumMessage == 0) {
sspi_status = s_pSecFn->QueryContextAttributes(
- &BACKEND->ctxt->ctxt_handle,
+ &backend->ctxt->ctxt_handle,
SECPKG_ATTR_STREAM_SIZES,
- &BACKEND->stream_sizes);
+ &backend->stream_sizes);
if(sspi_status != SEC_E_OK) {
*err = CURLE_SEND_ERROR;
return -1;
@@ -1650,13 +1653,13 @@ schannel_send(struct Curl_easy *data, int sockindex,
}
/* check if the buffer is longer than the maximum message length */
- if(len > BACKEND->stream_sizes.cbMaximumMessage) {
- len = BACKEND->stream_sizes.cbMaximumMessage;
+ if(len > backend->stream_sizes.cbMaximumMessage) {
+ len = backend->stream_sizes.cbMaximumMessage;
}
/* calculate the complete message length and allocate a buffer for it */
- data_len = BACKEND->stream_sizes.cbHeader + len +
- BACKEND->stream_sizes.cbTrailer;
+ data_len = backend->stream_sizes.cbHeader + len +
+ backend->stream_sizes.cbTrailer;
ptr = (unsigned char *) malloc(data_len);
if(!ptr) {
*err = CURLE_OUT_OF_MEMORY;
@@ -1665,12 +1668,12 @@ schannel_send(struct Curl_easy *data, int sockindex,
/* setup output buffers (header, data, trailer, empty) */
InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
- ptr, BACKEND->stream_sizes.cbHeader);
+ ptr, backend->stream_sizes.cbHeader);
InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
- ptr + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
+ ptr + backend->stream_sizes.cbHeader, curlx_uztoul(len));
InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
- ptr + BACKEND->stream_sizes.cbHeader + len,
- BACKEND->stream_sizes.cbTrailer);
+ ptr + backend->stream_sizes.cbHeader + len,
+ backend->stream_sizes.cbTrailer);
InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&outbuf_desc, outbuf, 4);
@@ -1678,7 +1681,7 @@ schannel_send(struct Curl_easy *data, int sockindex,
memcpy(outbuf[1].pvBuffer, buf, len);
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
- sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
+ sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
&outbuf_desc, 0);
/* check if the message was encrypted */
@@ -1783,9 +1786,10 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* we want the length of the encrypted buffer to be at least large enough
that it can hold all the bytes requested and some TLS record overhead. */
size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
+ struct ssl_backend_data *backend = connssl->backend;
/****************************************************************************
- * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
+ * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
* The pattern for return error is set *err, optional infof, goto cleanup.
*
* Our priority is to always return as much decrypted data to the caller as
@@ -1797,16 +1801,16 @@ schannel_recv(struct Curl_easy *data, int sockindex,
DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
*err = CURLE_OK;
- if(len && len <= BACKEND->decdata_offset) {
+ if(len && len <= backend->decdata_offset) {
infof(data, "schannel: enough decrypted data is already available");
goto cleanup;
}
- else if(BACKEND->recv_unrecoverable_err) {
- *err = BACKEND->recv_unrecoverable_err;
+ else if(backend->recv_unrecoverable_err) {
+ *err = backend->recv_unrecoverable_err;
infof(data, "schannel: an unrecoverable error occurred in a prior call");
goto cleanup;
}
- else if(BACKEND->recv_sspi_close_notify) {
+ else if(backend->recv_sspi_close_notify) {
/* once a server has indicated shutdown there is no more encrypted data */
infof(data, "schannel: server indicated shutdown in a prior call");
goto cleanup;
@@ -1816,17 +1820,17 @@ schannel_recv(struct Curl_easy *data, int sockindex,
immediately because there may be data to decrypt (in the case we want to
decrypt all encrypted cached data) so handle !len later in cleanup.
*/
- else if(len && !BACKEND->recv_connection_closed) {
+ else if(len && !backend->recv_connection_closed) {
/* increase enc buffer in order to fit the requested amount of data */
- size = BACKEND->encdata_length - BACKEND->encdata_offset;
+ size = backend->encdata_length - backend->encdata_offset;
if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
- BACKEND->encdata_length < min_encdata_length) {
- reallocated_length = BACKEND->encdata_offset +
+ backend->encdata_length < min_encdata_length) {
+ reallocated_length = backend->encdata_offset +
CURL_SCHANNEL_BUFFER_FREE_SIZE;
if(reallocated_length < min_encdata_length) {
reallocated_length = min_encdata_length;
}
- reallocated_buffer = realloc(BACKEND->encdata_buffer,
+ reallocated_buffer = realloc(backend->encdata_buffer,
reallocated_length);
if(!reallocated_buffer) {
*err = CURLE_OUT_OF_MEMORY;
@@ -1834,21 +1838,21 @@ schannel_recv(struct Curl_easy *data, int sockindex,
goto cleanup;
}
- BACKEND->encdata_buffer = reallocated_buffer;
- BACKEND->encdata_length = reallocated_length;
- size = BACKEND->encdata_length - BACKEND->encdata_offset;
+ backend->encdata_buffer = reallocated_buffer;
+ backend->encdata_length = reallocated_length;
+ size = backend->encdata_length - backend->encdata_offset;
DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
- BACKEND->encdata_length));
+ backend->encdata_length));
}
DEBUGF(infof(data,
"schannel: encrypted data buffer: offset %zu length %zu",
- BACKEND->encdata_offset, BACKEND->encdata_length));
+ backend->encdata_offset, backend->encdata_length));
/* read encrypted data from socket */
*err = Curl_read_plain(conn->sock[sockindex],
- (char *)(BACKEND->encdata_buffer +
- BACKEND->encdata_offset),
+ (char *)(backend->encdata_buffer +
+ backend->encdata_offset),
size, &nread);
if(*err) {
nread = -1;
@@ -1861,27 +1865,27 @@ schannel_recv(struct Curl_easy *data, int sockindex,
infof(data, "schannel: Curl_read_plain returned error %d", *err);
}
else if(nread == 0) {
- BACKEND->recv_connection_closed = true;
+ backend->recv_connection_closed = true;
DEBUGF(infof(data, "schannel: server closed the connection"));
}
else if(nread > 0) {
- BACKEND->encdata_offset += (size_t)nread;
- BACKEND->encdata_is_incomplete = false;
+ backend->encdata_offset += (size_t)nread;
+ backend->encdata_is_incomplete = false;
DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
}
}
DEBUGF(infof(data,
"schannel: encrypted data buffer: offset %zu length %zu",
- BACKEND->encdata_offset, BACKEND->encdata_length));
+ backend->encdata_offset, backend->encdata_length));
/* decrypt loop */
- while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
- (!len || BACKEND->decdata_offset < len ||
- BACKEND->recv_connection_closed)) {
+ while(backend->encdata_offset > 0 && sspi_status == SEC_E_OK &&
+ (!len || backend->decdata_offset < len ||
+ backend->recv_connection_closed)) {
/* prepare data buffer for DecryptMessage call */
- InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
- curlx_uztoul(BACKEND->encdata_offset));
+ InitSecBuffer(&inbuf[0], SECBUFFER_DATA, backend->encdata_buffer,
+ curlx_uztoul(backend->encdata_offset));
/* we need 3 more empty input buffers for possible output */
InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
@@ -1891,7 +1895,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
*/
- sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
+ sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
&inbuf_desc, 0, NULL);
/* check if everything went fine (server may want to renegotiate
@@ -1907,37 +1911,37 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* increase buffer in order to fit the received amount of data */
size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
- if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
- BACKEND->decdata_length < len) {
+ if(backend->decdata_length - backend->decdata_offset < size ||
+ backend->decdata_length < len) {
/* increase internal decrypted data buffer */
- reallocated_length = BACKEND->decdata_offset + size;
+ reallocated_length = backend->decdata_offset + size;
/* make sure that the requested amount of data fits */
if(reallocated_length < len) {
reallocated_length = len;
}
- reallocated_buffer = realloc(BACKEND->decdata_buffer,
+ reallocated_buffer = realloc(backend->decdata_buffer,
reallocated_length);
if(!reallocated_buffer) {
*err = CURLE_OUT_OF_MEMORY;
failf(data, "schannel: unable to re-allocate memory");
goto cleanup;
}
- BACKEND->decdata_buffer = reallocated_buffer;
- BACKEND->decdata_length = reallocated_length;
+ backend->decdata_buffer = reallocated_buffer;
+ backend->decdata_length = reallocated_length;
}
/* copy decrypted data to internal buffer */
size = inbuf[1].cbBuffer;
if(size) {
- memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
+ memcpy(backend->decdata_buffer + backend->decdata_offset,
inbuf[1].pvBuffer, size);
- BACKEND->decdata_offset += size;
+ backend->decdata_offset += size;
}
DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
DEBUGF(infof(data,
"schannel: decrypted cached: offset %zu length %zu",
- BACKEND->decdata_offset, BACKEND->decdata_length));
+ backend->decdata_offset, backend->decdata_length));
}
/* check for remaining encrypted data */
@@ -1948,34 +1952,34 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* check if the remaining data is less than the total amount
* and therefore begins after the already processed data
*/
- if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
+ if(backend->encdata_offset > inbuf[3].cbBuffer) {
/* move remaining encrypted data forward to the beginning of
buffer */
- memmove(BACKEND->encdata_buffer,
- (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
+ memmove(backend->encdata_buffer,
+ (backend->encdata_buffer + backend->encdata_offset) -
inbuf[3].cbBuffer, inbuf[3].cbBuffer);
- BACKEND->encdata_offset = inbuf[3].cbBuffer;
+ backend->encdata_offset = inbuf[3].cbBuffer;
}
DEBUGF(infof(data,
"schannel: encrypted cached: offset %zu length %zu",
- BACKEND->encdata_offset, BACKEND->encdata_length));
+ backend->encdata_offset, backend->encdata_length));
}
else {
/* reset encrypted buffer offset, because there is no data remaining */
- BACKEND->encdata_offset = 0;
+ backend->encdata_offset = 0;
}
/* check if server wants to renegotiate the connection context */
if(sspi_status == SEC_I_RENEGOTIATE) {
infof(data, "schannel: remote party requests renegotiation");
if(*err && *err != CURLE_AGAIN) {
- infof(data, "schannel: can't renogotiate, an error is pending");
+ infof(data, "schannel: can't renegotiate, an error is pending");
goto cleanup;
}
- if(BACKEND->encdata_offset) {
+ if(backend->encdata_offset) {
*err = CURLE_RECV_ERROR;
- infof(data, "schannel: can't renogotiate, "
+ infof(data, "schannel: can't renegotiate, "
"encrypted data available");
goto cleanup;
}
@@ -1997,16 +2001,16 @@ schannel_recv(struct Curl_easy *data, int sockindex,
else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
/* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
returned so we have to work around that in cleanup. */
- BACKEND->recv_sspi_close_notify = true;
- if(!BACKEND->recv_connection_closed) {
- BACKEND->recv_connection_closed = true;
+ backend->recv_sspi_close_notify = true;
+ if(!backend->recv_connection_closed) {
+ backend->recv_connection_closed = true;
infof(data, "schannel: server closed the connection");
}
goto cleanup;
}
}
else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
- BACKEND->encdata_is_incomplete = true;
+ backend->encdata_is_incomplete = true;
if(!*err)
*err = CURLE_AGAIN;
infof(data, "schannel: failed to decrypt data, need more data");
@@ -2025,11 +2029,11 @@ schannel_recv(struct Curl_easy *data, int sockindex,
DEBUGF(infof(data,
"schannel: encrypted data buffer: offset %zu length %zu",
- BACKEND->encdata_offset, BACKEND->encdata_length));
+ backend->encdata_offset, backend->encdata_length));
DEBUGF(infof(data,
"schannel: decrypted data buffer: offset %zu length %zu",
- BACKEND->decdata_offset, BACKEND->decdata_length));
+ backend->decdata_offset, backend->decdata_length));
cleanup:
/* Warning- there is no guarantee the encdata state is valid at this point */
@@ -2046,13 +2050,13 @@ schannel_recv(struct Curl_easy *data, int sockindex,
assume it was graceful (close_notify) since there doesn't seem to be a
way to tell.
*/
- if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
- !BACKEND->recv_sspi_close_notify) {
- bool isWin2k = curlx_verify_windows_version(5, 0, PLATFORM_WINNT,
+ if(len && !backend->decdata_offset && backend->recv_connection_closed &&
+ !backend->recv_sspi_close_notify) {
+ bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
VERSION_EQUAL);
if(isWin2k && sspi_status == SEC_E_OK)
- BACKEND->recv_sspi_close_notify = true;
+ backend->recv_sspi_close_notify = true;
else {
*err = CURLE_RECV_ERROR;
infof(data, "schannel: server closed abruptly (missing close_notify)");
@@ -2061,23 +2065,23 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* Any error other than CURLE_AGAIN is an unrecoverable error. */
if(*err && *err != CURLE_AGAIN)
- BACKEND->recv_unrecoverable_err = *err;
+ backend->recv_unrecoverable_err = *err;
- size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
+ size = len < backend->decdata_offset ? len : backend->decdata_offset;
if(size) {
- memcpy(buf, BACKEND->decdata_buffer, size);
- memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
- BACKEND->decdata_offset - size);
- BACKEND->decdata_offset -= size;
+ memcpy(buf, backend->decdata_buffer, size);
+ memmove(backend->decdata_buffer, backend->decdata_buffer + size,
+ backend->decdata_offset - size);
+ backend->decdata_offset -= size;
DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
DEBUGF(infof(data,
"schannel: decrypted data buffer: offset %zu length %zu",
- BACKEND->decdata_offset, BACKEND->decdata_length));
+ backend->decdata_offset, backend->decdata_length));
*err = CURLE_OK;
return (ssize_t)size;
}
- if(!*err && !BACKEND->recv_connection_closed)
+ if(!*err && !backend->recv_connection_closed)
*err = CURLE_AGAIN;
/* It's debatable what to return when !len. We could return whatever error
@@ -2116,34 +2120,32 @@ static bool schannel_data_pending(const struct connectdata *conn,
int sockindex)
{
const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
if(connssl->use) /* SSL/TLS is in use */
- return (BACKEND->decdata_offset > 0 ||
- (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
+ return (backend->decdata_offset > 0 ||
+ (backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
else
return FALSE;
}
-static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
- int sockindex)
-{
- if(conn->ssl[sockindex].use)
- /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
- Curl_ssl_shutdown(data, conn, sockindex);
-}
-
static void schannel_session_free(void *ptr)
{
/* this is expected to be called under sessionid lock */
struct Curl_schannel_cred *cred = ptr;
- cred->refcount--;
- if(cred->refcount == 0) {
- s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
- Curl_safefree(cred);
+ if(cred) {
+ cred->refcount--;
+ if(cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ Curl_safefree(cred);
+ }
}
}
+/* shut down the SSL connection and clean up related memory.
+ this function can be called multiple times on the same connection including
+ if the SSL connection failed (eg connection made but failed handshake). */
static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
int sockindex)
{
@@ -2152,13 +2154,16 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
*/
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
char * const hostname = SSL_HOST_NAME();
+ struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(data);
- infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
- hostname, conn->remote_port);
+ if(connssl->use) {
+ infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
+ hostname, conn->remote_port);
+ }
- if(BACKEND->cred && BACKEND->ctxt) {
+ if(connssl->use && backend->cred && backend->ctxt) {
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_status;
@@ -2171,7 +2176,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
InitSecBufferDesc(&BuffDesc, &Buffer, 1);
- sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
+ sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
&BuffDesc);
if(sspi_status != SEC_E_OK) {
@@ -2189,18 +2194,18 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
sspi_status = s_pSecFn->InitializeSecurityContext(
- &BACKEND->cred->cred_handle,
- &BACKEND->ctxt->ctxt_handle,
+ &backend->cred->cred_handle,
+ &backend->ctxt->ctxt_handle,
host_name,
- BACKEND->req_flags,
+ backend->req_flags,
0,
0,
NULL,
0,
- &BACKEND->ctxt->ctxt_handle,
+ &backend->ctxt->ctxt_handle,
&outbuf_desc,
- &BACKEND->ret_flags,
- &BACKEND->ctxt->time_stamp);
+ &backend->ret_flags,
+ &backend->ctxt->time_stamp);
curlx_unicodefree(host_name);
@@ -2219,38 +2224,48 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
}
/* free SSPI Schannel API security context handle */
- if(BACKEND->ctxt) {
+ if(backend->ctxt) {
DEBUGF(infof(data, "schannel: clear security context handle"));
- s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
- Curl_safefree(BACKEND->ctxt);
+ s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
+ Curl_safefree(backend->ctxt);
}
/* free SSPI Schannel API credential handle */
- if(BACKEND->cred) {
+ if(backend->cred) {
Curl_ssl_sessionid_lock(data);
- schannel_session_free(BACKEND->cred);
+ schannel_session_free(backend->cred);
Curl_ssl_sessionid_unlock(data);
- BACKEND->cred = NULL;
+ backend->cred = NULL;
}
/* free internal buffer for received encrypted data */
- if(BACKEND->encdata_buffer != NULL) {
- Curl_safefree(BACKEND->encdata_buffer);
- BACKEND->encdata_length = 0;
- BACKEND->encdata_offset = 0;
- BACKEND->encdata_is_incomplete = false;
+ if(backend->encdata_buffer) {
+ Curl_safefree(backend->encdata_buffer);
+ backend->encdata_length = 0;
+ backend->encdata_offset = 0;
+ backend->encdata_is_incomplete = false;
}
/* free internal buffer for received decrypted data */
- if(BACKEND->decdata_buffer != NULL) {
- Curl_safefree(BACKEND->decdata_buffer);
- BACKEND->decdata_length = 0;
- BACKEND->decdata_offset = 0;
+ if(backend->decdata_buffer) {
+ Curl_safefree(backend->decdata_buffer);
+ backend->decdata_length = 0;
+ backend->decdata_offset = 0;
}
return CURLE_OK;
}
+static void schannel_close(struct Curl_easy *data, struct connectdata *conn,
+ int sockindex)
+{
+ if(conn->ssl[sockindex].use)
+ /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */
+ Curl_ssl_shutdown(data, conn, sockindex);
+ else
+ schannel_shutdown(data, conn, sockindex);
+}
+
static int schannel_init(void)
{
return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
@@ -2293,6 +2308,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
const char *pinnedpubkey)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
CERT_CONTEXT *pCertContextServer = NULL;
/* Result is returned to caller */
@@ -2310,7 +2326,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
struct Curl_asn1Element *pubkey;
sspi_status =
- s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer);
@@ -2416,8 +2432,9 @@ static CURLcode schannel_sha256sum(const unsigned char *input,
static void *schannel_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
{
+ struct ssl_backend_data *backend = connssl->backend;
(void)info;
- return &BACKEND->ctxt->ctxt_handle;
+ return &backend->ctxt->ctxt_handle;
}
const struct Curl_ssl Curl_ssl_schannel = {
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index 1b283d0..4966cd4 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -355,7 +355,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
DWORD i;
/* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
- if(curlx_verify_windows_version(6, 2, PLATFORM_WINNT,
+ if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
/* CertGetNameString will provide the 8-bit character string without
@@ -597,7 +597,8 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
* trusted certificates. This is only supported on Windows 7+.
*/
- if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) {
+ if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
+ VERSION_LESS_THAN)) {
failf(data, "schannel: this version of Windows is too old to support "
"certificate verification via CA bundle file.");
result = CURLE_SSL_CACERT_BADFILE;
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index 1e6ed5f..f7a20b2 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ b/Utilities/cmcurl/lib/vtls/sectransp.c
@@ -997,14 +997,14 @@ CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
#else
#if CURL_BUILD_MAC_10_7
/* Lion & later: Get the long description if we can. */
- if(SecCertificateCopyLongDescription != NULL)
+ if(SecCertificateCopyLongDescription)
server_cert_summary =
SecCertificateCopyLongDescription(NULL, cert, NULL);
else
#endif /* CURL_BUILD_MAC_10_7 */
#if CURL_BUILD_MAC_10_6
/* Snow Leopard: Get the certificate summary. */
- if(SecCertificateCopySubjectSummary != NULL)
+ if(SecCertificateCopySubjectSummary)
server_cert_summary = SecCertificateCopySubjectSummary(cert);
else
#endif /* CURL_BUILD_MAC_10_6 */
@@ -1118,7 +1118,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
/* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
kSecClassIdentity was introduced in Lion. If both exist, let's use them
to find the certificate. */
- if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
+ if(SecItemCopyMatching && kSecClassIdentity) {
CFTypeRef keys[5];
CFTypeRef values[5];
CFDictionaryRef query_dict;
@@ -1248,7 +1248,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
password ? 1L : 0L, NULL, NULL);
- if(options != NULL) {
+ if(options) {
status = SecPKCS12Import(pkcs_data, options, &items);
CFRelease(options);
}
@@ -1406,7 +1406,7 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
}
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLSetProtocolVersionMax != NULL) {
+ if(SSLSetProtocolVersionMax) {
SSLProtocol darwin_ver_min = kTLSProtocol1;
SSLProtocol darwin_ver_max = kTLSProtocol1;
CURLcode result = sectransp_version_from_curl(&darwin_ver_min,
@@ -1608,7 +1608,7 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
if(tls_name) {
table_cipher_name = ciphertable[i].name;
}
- else if(ciphertable[i].alias_name != NULL) {
+ else if(ciphertable[i].alias_name) {
table_cipher_name = ciphertable[i].alias_name;
}
else {
@@ -1688,7 +1688,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#endif /* CURL_BUILD_MAC */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLCreateContext != NULL) { /* use the newer API if available */
+ if(SSLCreateContext) { /* use the newer API if available */
if(backend->ssl_ctx)
CFRelease(backend->ssl_ctx);
backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
@@ -1722,7 +1722,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
/* check to see if we've been told to use an explicit SSL/TLS version */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLSetProtocolVersionMax != NULL) {
+ if(SSLSetProtocolVersionMax) {
switch(conn->ssl_config.version) {
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
@@ -1980,9 +1980,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
Darwin 15.x.x is El Capitan (10.11)
*/
#if CURL_BUILD_MAC
- if(SSLSetSessionOption != NULL && darwinver_maj >= 13) {
+ if(SSLSetSessionOption && darwinver_maj >= 13) {
#else
- if(SSLSetSessionOption != NULL) {
+ if(SSLSetSessionOption) {
#endif /* CURL_BUILD_MAC */
bool break_on_auth = !conn->ssl_config.verifypeer ||
ssl_cafile || ssl_cablob;
@@ -2065,7 +2065,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
/* We want to enable 1/n-1 when using a CBC cipher unless the user
specifically doesn't want us doing that: */
- if(SSLSetSessionOption != NULL) {
+ if(SSLSetSessionOption) {
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
!SSL_SET_OPTION(enable_beast));
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
@@ -2109,7 +2109,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
}
result = Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
- ssl_sessionid_len, sockindex);
+ ssl_sessionid_len, sockindex, NULL);
Curl_ssl_sessionid_unlock(data);
if(result) {
failf(data, "failed to store ssl session");
@@ -2521,7 +2521,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
} while(0);
Curl_safefree(realpubkey);
- if(publicKeyBits != NULL)
+ if(publicKeyBits)
CFRelease(publicKeyBits);
return result;
@@ -2947,7 +2947,7 @@ collect_server_cert(struct Curl_easy *data,
private API and doesn't work as expected. So we have to look for
a different symbol to make sure this code is only executed under
Lion or later. */
- if(SecTrustEvaluateAsync != NULL) {
+ if(SecTrustEvaluateAsync) {
#pragma unused(server_certs)
err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
/* For some reason, SSLCopyPeerTrust() can return noErr and yet return
@@ -3165,7 +3165,7 @@ static void sectransp_close(struct Curl_easy *data, struct connectdata *conn,
if(backend->ssl_ctx) {
(void)SSLClose(backend->ssl_ctx);
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(SSLCreateContext != NULL)
+ if(SSLCreateContext)
CFRelease(backend->ssl_ctx);
#if CURL_SUPPORT_MAC_10_8
else
@@ -3329,7 +3329,7 @@ static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
static bool sectransp_false_start(void)
{
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- if(SSLSetSessionOption != NULL)
+ if(SSLSetSessionOption)
return TRUE;
#endif
return FALSE;
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index e5bbe1f..6007bbb 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -516,7 +516,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
const bool isProxy,
void *ssl_sessionid,
size_t idsize,
- int sockindex)
+ int sockindex,
+ bool *added)
{
size_t i;
struct Curl_ssl_session *store;
@@ -536,6 +537,10 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
const char *hostname = conn->host.name;
#endif
(void)sockindex;
+
+ if(added)
+ *added = FALSE;
+
if(!data->state.session)
return CURLE_OK;
@@ -609,6 +614,9 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
+ if(added)
+ *added = TRUE;
+
DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
store->scheme, store->name, store->remote_port,
isProxy ? "PROXY" : "server"));
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index beaa83d..c7bbba0 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -261,7 +261,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
const bool isProxy,
void *ssl_sessionid,
size_t idsize,
- int sockindex);
+ int sockindex,
+ bool *added);
/* Kill a single session ID entry in the cache
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
* This will call engine-specific curlssl_session_free function, which must
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index 16fbb89..8c5b915 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -202,6 +202,43 @@ static int do_file_type(const char *type)
return -1;
}
+#ifdef HAVE_LIBOQS
+struct group_name_map {
+ const word16 group;
+ const char *name;
+};
+
+static const struct group_name_map gnm[] = {
+ { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" },
+ { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" },
+ { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" },
+ { WOLFSSL_NTRU_HPS_LEVEL1, "NTRU_HPS_LEVEL1" },
+ { WOLFSSL_NTRU_HPS_LEVEL3, "NTRU_HPS_LEVEL3" },
+ { WOLFSSL_NTRU_HPS_LEVEL5, "NTRU_HPS_LEVEL5" },
+ { WOLFSSL_NTRU_HRSS_LEVEL3, "NTRU_HRSS_LEVEL3" },
+ { WOLFSSL_SABER_LEVEL1, "SABER_LEVEL1" },
+ { WOLFSSL_SABER_LEVEL3, "SABER_LEVEL3" },
+ { WOLFSSL_SABER_LEVEL5, "SABER_LEVEL5" },
+ { WOLFSSL_KYBER_90S_LEVEL1, "KYBER_90S_LEVEL1" },
+ { WOLFSSL_KYBER_90S_LEVEL3, "KYBER_90S_LEVEL3" },
+ { WOLFSSL_KYBER_90S_LEVEL5, "KYBER_90S_LEVEL5" },
+ { WOLFSSL_P256_NTRU_HPS_LEVEL1, "P256_NTRU_HPS_LEVEL1" },
+ { WOLFSSL_P384_NTRU_HPS_LEVEL3, "P384_NTRU_HPS_LEVEL3" },
+ { WOLFSSL_P521_NTRU_HPS_LEVEL5, "P521_NTRU_HPS_LEVEL5" },
+ { WOLFSSL_P384_NTRU_HRSS_LEVEL3, "P384_NTRU_HRSS_LEVEL3" },
+ { WOLFSSL_P256_SABER_LEVEL1, "P256_SABER_LEVEL1" },
+ { WOLFSSL_P384_SABER_LEVEL3, "P384_SABER_LEVEL3" },
+ { WOLFSSL_P521_SABER_LEVEL5, "P521_SABER_LEVEL5" },
+ { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" },
+ { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" },
+ { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" },
+ { WOLFSSL_P256_KYBER_90S_LEVEL1, "P256_KYBER_90S_LEVEL1" },
+ { WOLFSSL_P384_KYBER_90S_LEVEL3, "P384_KYBER_90S_LEVEL3" },
+ { WOLFSSL_P521_KYBER_90S_LEVEL5, "P521_KYBER_90S_LEVEL5" },
+ { 0, NULL }
+};
+#endif
+
/*
* This function loads all the client/CA certificates and CRLs. Setup the TLS
* layer and do all necessary magic.
@@ -210,11 +247,15 @@ static CURLcode
wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
int sockindex)
{
- char *ciphers;
+ char *ciphers, *curves;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
SSL_METHOD* req_method = NULL;
curl_socket_t sockfd = conn->sock[sockindex];
+#ifdef HAVE_LIBOQS
+ word16 oqsAlg = 0;
+ size_t idx = 0;
+#endif
#ifdef HAVE_SNI
bool sni = FALSE;
#define use_sni(x) sni = (x)
@@ -327,6 +368,26 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
infof(data, "Cipher selection: %s", ciphers);
}
+ curves = SSL_CONN_CONFIG(curves);
+ if(curves) {
+
+#ifdef HAVE_LIBOQS
+ for(idx = 0; gnm[idx].name != NULL; idx++) {
+ if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
+ oqsAlg = gnm[idx].group;
+ break;
+ }
+ }
+
+ if(oqsAlg == 0)
+#endif
+ {
+ if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
+ failf(data, "failed setting curves list: '%s'", curves);
+ return CURLE_SSL_CIPHER;
+ }
+ }
+ }
#ifndef NO_FILESYSTEM
/* load trusted cacert */
if(SSL_CONN_CONFIG(CAfile)) {
@@ -439,6 +500,14 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
}
+#ifdef HAVE_LIBOQS
+ if(oqsAlg) {
+ if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
+ failf(data, "unable to use oqs KEM");
+ }
+ }
+#endif
+
#ifdef HAVE_ALPN
if(conn->bits.tls_enable_alpn) {
char protocols[128];
@@ -495,7 +564,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_delsessionid(data, ssl_sessionid);
- infof(data, "Can't use session ID, going on without\n");
+ infof(data, "Can't use session ID, going on without");
}
else
infof(data, "SSL re-using session ID");
@@ -749,7 +818,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
if(!incache) {
result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
- 0, sockindex);
+ 0, sockindex, NULL);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "failed to store ssl session");
diff --git a/Utilities/cmcurl/lib/x509asn1.c b/Utilities/cmcurl/lib/x509asn1.c
index 1bdaead..0341543 100644
--- a/Utilities/cmcurl/lib/x509asn1.c
+++ b/Utilities/cmcurl/lib/x509asn1.c
@@ -608,7 +608,10 @@ static const char *ASN1tostr(struct Curl_asn1Element *elem, int type)
/*
* ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at
- * `buf'. Return the total string length, even if larger than `buflen'.
+ * `buf'.
+ *
+ * Returns the total string length, even if larger than `buflen' or -1 on
+ * error.
*/
static ssize_t encodeDN(char *buf, size_t buflen, struct Curl_asn1Element *dn)
{
@@ -692,7 +695,10 @@ static const char *DNtostr(struct Curl_asn1Element *dn)
if(buflen >= 0) {
buf = malloc(buflen + 1);
if(buf) {
- encodeDN(buf, buflen + 1, dn);
+ if(encodeDN(buf, buflen + 1, dn) == -1) {
+ free(buf);
+ return NULL;
+ }
buf[buflen] = '\0';
}
}
@@ -855,26 +861,30 @@ static const char *dumpAlgo(struct Curl_asn1Element *param,
return OID2str(oid.beg, oid.end, TRUE);
}
-static void do_pubkey_field(struct Curl_easy *data, int certnum,
- const char *label, struct Curl_asn1Element *elem)
+/* return 0 on success, 1 on error */
+static int do_pubkey_field(struct Curl_easy *data, int certnum,
+ const char *label, struct Curl_asn1Element *elem)
{
const char *output;
+ CURLcode result = CURLE_OK;
/* Generate a certificate information record for the public key. */
output = ASN1tostr(elem, 0);
if(output) {
if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, label, output);
- if(!certnum)
+ result = Curl_ssl_push_certinfo(data, certnum, label, output);
+ if(!certnum && !result)
infof(data, " %s: %s", label, output);
free((char *) output);
}
+ return result ? 1 : 0;
}
-static void do_pubkey(struct Curl_easy *data, int certnum,
- const char *algo, struct Curl_asn1Element *param,
- struct Curl_asn1Element *pubkey)
+/* return 0 on success, 1 on error */
+static int do_pubkey(struct Curl_easy *data, int certnum,
+ const char *algo, struct Curl_asn1Element *param,
+ struct Curl_asn1Element *pubkey)
{
struct Curl_asn1Element elem;
struct Curl_asn1Element pk;
@@ -884,7 +894,7 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
/* Get the public key (single element). */
if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
- return;
+ return 1;
if(strcasecompare(algo, "rsaEncryption")) {
const char *q;
@@ -892,7 +902,7 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
p = getASN1Element(&elem, pk.beg, pk.end);
if(!p)
- return;
+ return 1;
/* Compute key length. */
for(q = elem.beg; !*q && q < elem.end; q++)
@@ -910,26 +920,35 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
if(data->set.ssl.certinfo) {
q = curl_maprintf("%lu", len);
if(q) {
- Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
+ CURLcode result =
+ Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
free((char *) q);
+ if(result)
+ return 1;
}
}
/* Generate coefficients. */
- do_pubkey_field(data, certnum, "rsa(n)", &elem);
+ if(do_pubkey_field(data, certnum, "rsa(n)", &elem))
+ return 1;
if(!getASN1Element(&elem, p, pk.end))
- return;
- do_pubkey_field(data, certnum, "rsa(e)", &elem);
+ return 1;
+ if(do_pubkey_field(data, certnum, "rsa(e)", &elem))
+ return 1;
}
else if(strcasecompare(algo, "dsa")) {
p = getASN1Element(&elem, param->beg, param->end);
if(p) {
- do_pubkey_field(data, certnum, "dsa(p)", &elem);
+ if(do_pubkey_field(data, certnum, "dsa(p)", &elem))
+ return 1;
p = getASN1Element(&elem, p, param->end);
if(p) {
- do_pubkey_field(data, certnum, "dsa(q)", &elem);
+ if(do_pubkey_field(data, certnum, "dsa(q)", &elem))
+ return 1;
if(getASN1Element(&elem, p, param->end)) {
- do_pubkey_field(data, certnum, "dsa(g)", &elem);
- do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
+ if(do_pubkey_field(data, certnum, "dsa(g)", &elem))
+ return 1;
+ if(do_pubkey_field(data, certnum, "dsa(pub_key)", &pk))
+ return 1;
}
}
}
@@ -937,13 +956,17 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
else if(strcasecompare(algo, "dhpublicnumber")) {
p = getASN1Element(&elem, param->beg, param->end);
if(p) {
- do_pubkey_field(data, certnum, "dh(p)", &elem);
+ if(do_pubkey_field(data, certnum, "dh(p)", &elem))
+ return 1;
if(getASN1Element(&elem, param->beg, param->end)) {
- do_pubkey_field(data, certnum, "dh(g)", &elem);
- do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
+ if(do_pubkey_field(data, certnum, "dh(g)", &elem))
+ return 1;
+ if(do_pubkey_field(data, certnum, "dh(pub_key)", &pk))
+ return 1;
}
}
}
+ return 0;
}
CURLcode Curl_extract_certinfo(struct Curl_easy *data,
@@ -957,7 +980,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
char *cp1;
size_t cl1;
char *cp2;
- CURLcode result;
+ CURLcode result = CURLE_OK;
unsigned long version;
size_t i;
size_t j;
@@ -976,8 +999,11 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
ccp = DNtostr(&cert.subject);
if(!ccp)
return CURLE_OUT_OF_MEMORY;
- if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
+ if(data->set.ssl.certinfo) {
+ result = Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
+ if(result)
+ return result;
+ }
if(!certnum)
infof(data, "%2d Subject: %s", certnum, ccp);
free((char *) ccp);
@@ -986,11 +1012,14 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
ccp = DNtostr(&cert.issuer);
if(!ccp)
return CURLE_OUT_OF_MEMORY;
- if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
+ if(data->set.ssl.certinfo) {
+ result = Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
+ }
if(!certnum)
infof(data, " Issuer: %s", ccp);
free((char *) ccp);
+ if(result)
+ return result;
/* Version (always fits in less than 32 bits). */
version = 0;
@@ -1000,8 +1029,10 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
ccp = curl_maprintf("%lx", version);
if(!ccp)
return CURLE_OUT_OF_MEMORY;
- Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
+ result = Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
free((char *) ccp);
+ if(result)
+ return result;
}
if(!certnum)
infof(data, " Version: %lu (0x%lx)", version + 1, version);
@@ -1011,10 +1042,12 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(!ccp)
return CURLE_OUT_OF_MEMORY;
if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
+ result = Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
if(!certnum)
infof(data, " Serial Number: %s", ccp);
free((char *) ccp);
+ if(result)
+ return result;
/* Signature algorithm .*/
ccp = dumpAlgo(&param, cert.signatureAlgorithm.beg,
@@ -1022,30 +1055,36 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(!ccp)
return CURLE_OUT_OF_MEMORY;
if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
+ result = Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
if(!certnum)
infof(data, " Signature Algorithm: %s", ccp);
free((char *) ccp);
+ if(result)
+ return result;
/* Start Date. */
ccp = ASN1tostr(&cert.notBefore, 0);
if(!ccp)
return CURLE_OUT_OF_MEMORY;
if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
+ result = Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
if(!certnum)
infof(data, " Start Date: %s", ccp);
free((char *) ccp);
+ if(result)
+ return result;
/* Expire Date. */
ccp = ASN1tostr(&cert.notAfter, 0);
if(!ccp)
return CURLE_OUT_OF_MEMORY;
if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
+ result = Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
if(!certnum)
infof(data, " Expire Date: %s", ccp);
free((char *) ccp);
+ if(result)
+ return result;
/* Public Key Algorithm. */
ccp = dumpAlgo(&param, cert.subjectPublicKeyAlgorithm.beg,
@@ -1053,21 +1092,31 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(!ccp)
return CURLE_OUT_OF_MEMORY;
if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
- if(!certnum)
- infof(data, " Public Key Algorithm: %s", ccp);
- do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
+ result = Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm",
+ ccp);
+ if(!result) {
+ int ret;
+ if(!certnum)
+ infof(data, " Public Key Algorithm: %s", ccp);
+ ret = do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
+ if(ret)
+ result = CURLE_OUT_OF_MEMORY; /* the most likely error */
+ }
free((char *) ccp);
+ if(result)
+ return result;
/* Signature. */
ccp = ASN1tostr(&cert.signature, 0);
if(!ccp)
return CURLE_OUT_OF_MEMORY;
if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
+ result = Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
if(!certnum)
infof(data, " Signature: %s", ccp);
free((char *) ccp);
+ if(result)
+ return result;
/* Generate PEM certificate. */
result = Curl_base64_encode(data, cert.certificate.beg,
@@ -1097,11 +1146,11 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
cp2[i] = '\0';
free(cp1);
if(data->set.ssl.certinfo)
- Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
+ result = Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
if(!certnum)
infof(data, "%s", cp2);
free(cp2);
- return CURLE_OK;
+ return result;
}
#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
diff --git a/Utilities/cmexpat/CMakeLists.txt b/Utilities/cmexpat/CMakeLists.txt
index ce72927..9a62b79 100644
--- a/Utilities/cmexpat/CMakeLists.txt
+++ b/Utilities/cmexpat/CMakeLists.txt
@@ -1,6 +1,6 @@
# Disable warnings to avoid changing 3rd party code.
IF(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmexpat/ConfigureChecks.cmake b/Utilities/cmexpat/ConfigureChecks.cmake
index 4da252c..341bab7 100644
--- a/Utilities/cmexpat/ConfigureChecks.cmake
+++ b/Utilities/cmexpat/ConfigureChecks.cmake
@@ -2,6 +2,7 @@ include(CheckCCompilerFlag)
include(CheckCSourceCompiles)
include(CheckIncludeFile)
include(CheckIncludeFiles)
+include(CheckLibraryExists)
include(CheckSymbolExists)
include(TestBigEndian)
diff --git a/Utilities/cmexpat/README.md b/Utilities/cmexpat/README.md
index 251dc8a..959c4a6 100644
--- a/Utilities/cmexpat/README.md
+++ b/Utilities/cmexpat/README.md
@@ -5,7 +5,7 @@
[![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases)
-# Expat, Release 2.4.1
+# Expat, Release 2.4.6
This is Expat, a C library for parsing XML, started by
[James Clark](https://en.wikipedia.org/wiki/James_Clark_%28programmer%29) in 1997.
diff --git a/Utilities/cmexpat/lib/expat.h b/Utilities/cmexpat/lib/expat.h
index b7d6d35..46a0e1b 100644
--- a/Utilities/cmexpat/lib/expat.h
+++ b/Utilities/cmexpat/lib/expat.h
@@ -11,7 +11,7 @@
Copyright (c) 2000-2005 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
- Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016 Cristian Rodríguez <crrodriguez@opensuse.org>
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
@@ -1041,7 +1041,7 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(
*/
#define XML_MAJOR_VERSION 2
#define XML_MINOR_VERSION 4
-#define XML_MICRO_VERSION 1
+#define XML_MICRO_VERSION 6
#ifdef __cplusplus
}
diff --git a/Utilities/cmexpat/lib/xmlparse.c b/Utilities/cmexpat/lib/xmlparse.c
index 5ba56eae..7db28d0 100644
--- a/Utilities/cmexpat/lib/xmlparse.c
+++ b/Utilities/cmexpat/lib/xmlparse.c
@@ -1,4 +1,4 @@
-/* 8539b9040d9d901366a62560a064af7cb99811335784b363abc039c5b0ebc416 (2.4.1+)
+/* a30d2613dcfdef81475a9d1a349134d2d42722172fdaa7d5bb12ed2aa74b9596 (2.4.6+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -11,9 +11,9 @@
Copyright (c) 2000-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
- Copyright (c) 2005-2009 Steven Solie <ssolie@users.sourceforge.net>
+ Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
Copyright (c) 2016 Eric Rahm <erahm@mozilla.com>
- Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016 Gaurav <g.gupta@samsung.com>
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
Copyright (c) 2016 Gustavo Grieco <gustavo.grieco@imag.fr>
@@ -32,6 +32,8 @@
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
Copyright (c) 2019-2020 Ben Wagner <bungeman@chromium.org>
Copyright (c) 2019 Vadim Zeitlin <vadim@zeitlins.org>
+ Copyright (c) 2021 Dong-hee Na <donghee.na@python.org>
+ Copyright (c) 2022 Samanta Navarro <ferivoz@riseup.net>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -54,6 +56,10 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#define XML_BUILDING_EXPAT 1
+
+#include <expat_config.h>
+
#if ! defined(_GNU_SOURCE)
# define _GNU_SOURCE 1 /* syscall prototype */
#endif
@@ -84,14 +90,10 @@
# include <errno.h>
#endif
-#define XML_BUILDING_EXPAT 1
-
#ifdef _WIN32
# include "winconfig.h"
#endif
-#include <expat_config.h>
-
#include "ascii.h"
#include "expat.h"
#include "siphash.h"
@@ -716,8 +718,7 @@ XML_ParserCreate(const XML_Char *encodingName) {
XML_Parser XMLCALL
XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
- XML_Char tmp[2];
- *tmp = nsSep;
+ XML_Char tmp[2] = {nsSep, 0};
return XML_ParserCreate_MM(encodingName, NULL, tmp);
}
@@ -973,7 +974,7 @@ parserCreate(const XML_Char *encodingName,
if (memsuite) {
XML_Memory_Handling_Suite *mtemp;
- parser = (XML_Parser)memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
+ parser = memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
if (parser != NULL) {
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
mtemp->malloc_fcn = memsuite->malloc_fcn;
@@ -1342,8 +1343,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
would be otherwise.
*/
if (parser->m_ns) {
- XML_Char tmp[2];
- *tmp = parser->m_namespaceSeparator;
+ XML_Char tmp[2] = {parser->m_namespaceSeparator, 0};
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
} else {
parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
@@ -2066,6 +2066,11 @@ XML_GetBuffer(XML_Parser parser, int len) {
keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
if (keep > XML_CONTEXT_BYTES)
keep = XML_CONTEXT_BYTES;
+ /* Detect and prevent integer overflow */
+ if (keep > INT_MAX - neededSize) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
neededSize += keep;
#endif /* defined XML_CONTEXT_BYTES */
if (neededSize
@@ -2556,6 +2561,7 @@ storeRawNames(XML_Parser parser) {
while (tag) {
int bufSize;
int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
+ size_t rawNameLen;
char *rawNameBuf = tag->buf + nameLen;
/* Stop if already stored. Since m_tagStack is a stack, we can stop
at the first entry that has already been copied; everything
@@ -2567,7 +2573,11 @@ storeRawNames(XML_Parser parser) {
/* For re-use purposes we need to ensure that the
size of tag->buf is a multiple of sizeof(XML_Char).
*/
- bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+ rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+ /* Detect and prevent integer overflow. */
+ if (rawNameLen > (size_t)INT_MAX - nameLen)
+ return XML_FALSE;
+ bufSize = nameLen + (int)rawNameLen;
if (bufSize > tag->bufEnd - tag->buf) {
char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
if (temp == NULL)
@@ -3260,13 +3270,38 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
/* get the attributes from the tokenizer */
n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
+
+ /* Detect and prevent integer overflow */
+ if (n > INT_MAX - nDefaultAtts) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
if (n + nDefaultAtts > parser->m_attsSize) {
int oldAttsSize = parser->m_attsSize;
ATTRIBUTE *temp;
#ifdef XML_ATTR_INFO
XML_AttrInfo *temp2;
#endif
+
+ /* Detect and prevent integer overflow */
+ if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE)
+ || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) {
+ parser->m_attsSize = oldAttsSize;
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts,
parser->m_attsSize * sizeof(ATTRIBUTE));
if (temp == NULL) {
@@ -3275,6 +3310,17 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
}
parser->m_atts = temp;
#ifdef XML_ATTR_INFO
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+# if UINT_MAX >= SIZE_MAX
+ if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) {
+ parser->m_attsSize = oldAttsSize;
+ return XML_ERROR_NO_MEMORY;
+ }
+# endif
+
temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo,
parser->m_attsSize * sizeof(XML_AttrInfo));
if (temp2 == NULL) {
@@ -3413,7 +3459,13 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
if (nPrefixes) {
int j; /* hash table index */
unsigned long version = parser->m_nsAttsVersion;
- int nsAttsSize = (int)1 << parser->m_nsAttsPower;
+
+ /* Detect and prevent invalid shift */
+ if (parser->m_nsAttsPower >= sizeof(unsigned int) * 8 /* bits per byte */) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ unsigned int nsAttsSize = 1u << parser->m_nsAttsPower;
unsigned char oldNsAttsPower = parser->m_nsAttsPower;
/* size of hash table must be at least 2 * (# of prefixed attributes) */
if ((nPrefixes << 1)
@@ -3424,7 +3476,28 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
;
if (parser->m_nsAttsPower < 3)
parser->m_nsAttsPower = 3;
- nsAttsSize = (int)1 << parser->m_nsAttsPower;
+
+ /* Detect and prevent invalid shift */
+ if (parser->m_nsAttsPower >= sizeof(nsAttsSize) * 8 /* bits per byte */) {
+ /* Restore actual size of memory in m_nsAtts */
+ parser->m_nsAttsPower = oldNsAttsPower;
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ nsAttsSize = 1u << parser->m_nsAttsPower;
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) {
+ /* Restore actual size of memory in m_nsAtts */
+ parser->m_nsAttsPower = oldNsAttsPower;
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts,
nsAttsSize * sizeof(NS_ATT));
if (! temp) {
@@ -3582,9 +3655,31 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
tagNamePtr->prefixLen = prefixLen;
for (i = 0; localPart[i++];)
; /* i includes null terminator */
+
+ /* Detect and prevent integer overflow */
+ if (binding->uriLen > INT_MAX - prefixLen
+ || i > INT_MAX - (binding->uriLen + prefixLen)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
n = i + binding->uriLen + prefixLen;
if (n > binding->uriAlloc) {
TAG *p;
+
+ /* Detect and prevent integer overflow */
+ if (n > INT_MAX - EXPAND_SPARE) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
if (! uri)
return XML_ERROR_NO_MEMORY;
@@ -3664,6 +3759,17 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
if (! mustBeXML && isXMLNS
&& (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
isXMLNS = XML_FALSE;
+
+ // NOTE: While Expat does not validate namespace URIs against RFC 3986,
+ // we have to at least make sure that the XML processor on top of
+ // Expat (that is splitting tag names by namespace separator into
+ // 2- or 3-tuples (uri-local or uri-local-prefix)) cannot be confused
+ // by an attacker putting additional namespace separator characters
+ // into namespace declarations. That would be ambiguous and not to
+ // be expected.
+ if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)) {
+ return XML_ERROR_SYNTAX;
+ }
}
isXML = isXML && len == xmlLen;
isXMLNS = isXMLNS && len == xmlnsLen;
@@ -3680,6 +3786,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
if (parser->m_freeBindingList) {
b = parser->m_freeBindingList;
if (len > b->uriAlloc) {
+ /* Detect and prevent integer overflow */
+ if (len > INT_MAX - EXPAND_SPARE) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
XML_Char *temp = (XML_Char *)REALLOC(
parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (temp == NULL)
@@ -3692,6 +3813,21 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
b = (BINDING *)MALLOC(parser, sizeof(BINDING));
if (! b)
return XML_ERROR_NO_MEMORY;
+
+ /* Detect and prevent integer overflow */
+ if (len > INT_MAX - EXPAND_SPARE) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
b->uri
= (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (! b->uri) {
@@ -3976,7 +4112,7 @@ initializeEncoding(XML_Parser parser) {
const char *s;
#ifdef XML_UNICODE
char encodingBuf[128];
- /* See comments abount `protoclEncodingName` in parserInit() */
+ /* See comments about `protocolEncodingName` in parserInit() */
if (! parser->m_protocolEncodingName)
s = NULL;
else {
@@ -5018,6 +5154,11 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
if (parser->m_prologState.level >= parser->m_groupSize) {
if (parser->m_groupSize) {
{
+ /* Detect and prevent integer overflow */
+ if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
char *const new_connector = (char *)REALLOC(
parser, parser->m_groupConnector, parser->m_groupSize *= 2);
if (new_connector == NULL) {
@@ -5028,6 +5169,16 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
}
if (dtd->scaffIndex) {
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+#endif
+
int *const new_scaff_index = (int *)REALLOC(
parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
if (new_scaff_index == NULL)
@@ -5236,7 +5387,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
if (dtd->in_eldecl) {
ELEMENT_TYPE *el;
const XML_Char *name;
- int nameLen;
+ size_t nameLen;
const char *nxt
= (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar);
int myindex = nextScaffoldPart(parser);
@@ -5252,7 +5403,13 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
nameLen = 0;
for (; name[nameLen++];)
;
- dtd->contentStringLen += nameLen;
+
+ /* Detect and prevent integer overflow */
+ if (nameLen > UINT_MAX - dtd->contentStringLen) {
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ dtd->contentStringLen += (unsigned)nameLen;
if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
@@ -6098,7 +6255,24 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
}
} else {
DEFAULT_ATTRIBUTE *temp;
+
+ /* Detect and prevent integer overflow */
+ if (type->allocDefaultAtts > INT_MAX / 2) {
+ return 0;
+ }
+
int count = type->allocDefaultAtts * 2;
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) {
+ return 0;
+ }
+#endif
+
temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts,
(count * sizeof(DEFAULT_ATTRIBUTE)));
if (temp == NULL)
@@ -6388,7 +6562,7 @@ normalizePublicId(XML_Char *publicId) {
static DTD *
dtdCreate(const XML_Memory_Handling_Suite *ms) {
- DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
+ DTD *p = ms->malloc_fcn(sizeof(DTD));
if (p == NULL)
return p;
poolInit(&(p->pool), ms);
@@ -6561,8 +6735,8 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
if (! newE)
return 0;
if (oldE->nDefaultAtts) {
- newE->defaultAtts = (DEFAULT_ATTRIBUTE *)ms->malloc_fcn(
- oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+ newE->defaultAtts
+ = ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
if (! newE->defaultAtts) {
return 0;
}
@@ -6724,7 +6898,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
/* table->size is a power of 2 */
table->size = (size_t)1 << INIT_POWER;
tsize = table->size * sizeof(NAMED *);
- table->v = (NAMED **)table->mem->malloc_fcn(tsize);
+ table->v = table->mem->malloc_fcn(tsize);
if (! table->v) {
table->size = 0;
return NULL;
@@ -6749,10 +6923,22 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
/* check for overflow (table is half full) */
if (table->used >> (table->power - 1)) {
unsigned char newPower = table->power + 1;
+
+ /* Detect and prevent invalid shift */
+ if (newPower >= sizeof(unsigned long) * 8 /* bits per byte */) {
+ return NULL;
+ }
+
size_t newSize = (size_t)1 << newPower;
unsigned long newMask = (unsigned long)newSize - 1;
+
+ /* Detect and prevent integer overflow */
+ if (newSize > (size_t)(-1) / sizeof(NAMED *)) {
+ return NULL;
+ }
+
size_t tsize = newSize * sizeof(NAMED *);
- NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
+ NAMED **newV = table->mem->malloc_fcn(tsize);
if (! newV)
return NULL;
memset(newV, 0, tsize);
@@ -6781,7 +6967,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
}
}
}
- table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
+ table->v[i] = table->mem->malloc_fcn(createSize);
if (! table->v[i])
return NULL;
memset(table->v[i], 0, createSize);
@@ -7069,7 +7255,7 @@ poolGrow(STRING_POOL *pool) {
if (bytesToAllocate == 0)
return XML_FALSE;
- tem = (BLOCK *)pool->mem->malloc_fcn(bytesToAllocate);
+ tem = pool->mem->malloc_fcn(bytesToAllocate);
if (! tem)
return XML_FALSE;
tem->size = blockSize;
@@ -7100,6 +7286,20 @@ nextScaffoldPart(XML_Parser parser) {
if (dtd->scaffCount >= dtd->scaffSize) {
CONTENT_SCAFFOLD *temp;
if (dtd->scaffold) {
+ /* Detect and prevent integer overflow */
+ if (dtd->scaffSize > UINT_MAX / 2u) {
+ return -1;
+ }
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) {
+ return -1;
+ }
+#endif
+
temp = (CONTENT_SCAFFOLD *)REALLOC(
parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
if (temp == NULL)
@@ -7131,55 +7331,130 @@ nextScaffoldPart(XML_Parser parser) {
return next;
}
-static void
-build_node(XML_Parser parser, int src_node, XML_Content *dest,
- XML_Content **contpos, XML_Char **strpos) {
- DTD *const dtd = parser->m_dtd; /* save one level of indirection */
- dest->type = dtd->scaffold[src_node].type;
- dest->quant = dtd->scaffold[src_node].quant;
- if (dest->type == XML_CTYPE_NAME) {
- const XML_Char *src;
- dest->name = *strpos;
- src = dtd->scaffold[src_node].name;
- for (;;) {
- *(*strpos)++ = *src;
- if (! *src)
- break;
- src++;
- }
- dest->numchildren = 0;
- dest->children = NULL;
- } else {
- unsigned int i;
- int cn;
- dest->numchildren = dtd->scaffold[src_node].childcnt;
- dest->children = *contpos;
- *contpos += dest->numchildren;
- for (i = 0, cn = dtd->scaffold[src_node].firstchild; i < dest->numchildren;
- i++, cn = dtd->scaffold[cn].nextsib) {
- build_node(parser, cn, &(dest->children[i]), contpos, strpos);
- }
- dest->name = NULL;
- }
-}
-
static XML_Content *
build_model(XML_Parser parser) {
+ /* Function build_model transforms the existing parser->m_dtd->scaffold
+ * array of CONTENT_SCAFFOLD tree nodes into a new array of
+ * XML_Content tree nodes followed by a gapless list of zero-terminated
+ * strings. */
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
XML_Content *ret;
- XML_Content *cpos;
- XML_Char *str;
- int allocsize = (dtd->scaffCount * sizeof(XML_Content)
- + (dtd->contentStringLen * sizeof(XML_Char)));
+ XML_Char *str; /* the current string writing location */
+
+ /* Detect and prevent integer overflow.
+ * The preprocessor guard addresses the "always false" warning
+ * from -Wtype-limits on platforms where
+ * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
+#if UINT_MAX >= SIZE_MAX
+ if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) {
+ return NULL;
+ }
+ if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) {
+ return NULL;
+ }
+#endif
+ if (dtd->scaffCount * sizeof(XML_Content)
+ > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) {
+ return NULL;
+ }
+
+ const size_t allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ + (dtd->contentStringLen * sizeof(XML_Char)));
ret = (XML_Content *)MALLOC(parser, allocsize);
if (! ret)
return NULL;
- str = (XML_Char *)(&ret[dtd->scaffCount]);
- cpos = &ret[1];
+ /* What follows is an iterative implementation (of what was previously done
+ * recursively in a dedicated function called "build_node". The old recursive
+ * build_node could be forced into stack exhaustion from input as small as a
+ * few megabyte, and so that was a security issue. Hence, a function call
+ * stack is avoided now by resolving recursion.)
+ *
+ * The iterative approach works as follows:
+ *
+ * - We have two writing pointers, both walking up the result array; one does
+ * the work, the other creates "jobs" for its colleague to do, and leads
+ * the way:
+ *
+ * - The faster one, pointer jobDest, always leads and writes "what job
+ * to do" by the other, once they reach that place in the
+ * array: leader "jobDest" stores the source node array index (relative
+ * to array dtd->scaffold) in field "numchildren".
+ *
+ * - The slower one, pointer dest, looks at the value stored in the
+ * "numchildren" field (which actually holds a source node array index
+ * at that time) and puts the real data from dtd->scaffold in.
+ *
+ * - Before the loop starts, jobDest writes source array index 0
+ * (where the root node is located) so that dest will have something to do
+ * when it starts operation.
+ *
+ * - Whenever nodes with children are encountered, jobDest appends
+ * them as new jobs, in order. As a result, tree node siblings are
+ * adjacent in the resulting array, for example:
+ *
+ * [0] root, has two children
+ * [1] first child of 0, has three children
+ * [3] first child of 1, does not have children
+ * [4] second child of 1, does not have children
+ * [5] third child of 1, does not have children
+ * [2] second child of 0, does not have children
+ *
+ * Or (the same data) presented in flat array view:
+ *
+ * [0] root, has two children
+ *
+ * [1] first child of 0, has three children
+ * [2] second child of 0, does not have children
+ *
+ * [3] first child of 1, does not have children
+ * [4] second child of 1, does not have children
+ * [5] third child of 1, does not have children
+ *
+ * - The algorithm repeats until all target array indices have been processed.
+ */
+ XML_Content *dest = ret; /* tree node writing location, moves upwards */
+ XML_Content *const destLimit = &ret[dtd->scaffCount];
+ XML_Content *jobDest = ret; /* next free writing location in target array */
+ str = (XML_Char *)&ret[dtd->scaffCount];
+
+ /* Add the starting job, the root node (index 0) of the source tree */
+ (jobDest++)->numchildren = 0;
+
+ for (; dest < destLimit; dest++) {
+ /* Retrieve source tree array index from job storage */
+ const int src_node = (int)dest->numchildren;
+
+ /* Convert item */
+ dest->type = dtd->scaffold[src_node].type;
+ dest->quant = dtd->scaffold[src_node].quant;
+ if (dest->type == XML_CTYPE_NAME) {
+ const XML_Char *src;
+ dest->name = str;
+ src = dtd->scaffold[src_node].name;
+ for (;;) {
+ *str++ = *src;
+ if (! *src)
+ break;
+ src++;
+ }
+ dest->numchildren = 0;
+ dest->children = NULL;
+ } else {
+ unsigned int i;
+ int cn;
+ dest->name = NULL;
+ dest->numchildren = dtd->scaffold[src_node].childcnt;
+ dest->children = jobDest;
+
+ /* Append scaffold indices of children to array */
+ for (i = 0, cn = dtd->scaffold[src_node].firstchild;
+ i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib)
+ (jobDest++)->numchildren = (unsigned int)cn;
+ }
+ }
- build_node(parser, 0, ret, &cpos, &str);
return ret;
}
@@ -7208,7 +7483,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
static XML_Char *
copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
- int charsRequired = 0;
+ size_t charsRequired = 0;
XML_Char *result;
/* First determine how long the string is */
diff --git a/Utilities/cmexpat/lib/xmlrole.c b/Utilities/cmexpat/lib/xmlrole.c
index 08173b0..3f0f5c1 100644
--- a/Utilities/cmexpat/lib/xmlrole.c
+++ b/Utilities/cmexpat/lib/xmlrole.c
@@ -11,10 +11,11 @@
Copyright (c) 2002 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2002-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
- Copyright (c) 2005-2009 Steven Solie <ssolie@users.sourceforge.net>
+ Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2021 Dong-hee Na <donghee.na@python.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -37,14 +38,14 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <expat_config.h>
+
#include <stddef.h>
#ifdef _WIN32
# include "winconfig.h"
#endif
-#include <expat_config.h>
-
#include "expat_external.h"
#include "internal.h"
#include "xmlrole.h"
diff --git a/Utilities/cmexpat/lib/xmltok.c b/Utilities/cmexpat/lib/xmltok.c
index f2b6b40..c659983 100644
--- a/Utilities/cmexpat/lib/xmltok.c
+++ b/Utilities/cmexpat/lib/xmltok.c
@@ -11,8 +11,8 @@
Copyright (c) 2001-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2002 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
- Copyright (c) 2005-2009 Steven Solie <ssolie@users.sourceforge.net>
- Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016 Pascal Cuoq <cuoq@trust-in-soft.com>
Copyright (c) 2016 Don Lewis <truckman@apache.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
@@ -20,6 +20,7 @@
Copyright (c) 2017 Benbuck Nason <bnason@netflix.com>
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
+ Copyright (c) 2021 Dong-hee Na <donghee.na@python.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -42,6 +43,8 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <expat_config.h>
+
#include <stddef.h>
#include <string.h> /* memcpy */
#include <stdbool.h>
@@ -50,8 +53,6 @@
# include "winconfig.h"
#endif
-#include <expat_config.h>
-
#include "expat_external.h"
#include "internal.h"
#include "xmltok.h"
@@ -97,11 +98,6 @@
+ ((((byte)[1]) & 3) << 1) + ((((byte)[2]) >> 5) & 1)] \
& (1u << (((byte)[2]) & 0x1F)))
-#define UTF8_GET_NAMING(pages, p, n) \
- ((n) == 2 \
- ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
- : ((n) == 3 ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) : 0))
-
/* Detection of invalid UTF-8 sequences is based on Table 3.1B
of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
with the additional restriction of not allowing the Unicode
diff --git a/Utilities/cmexpat/lib/xmltok_impl.c b/Utilities/cmexpat/lib/xmltok_impl.c
index 0430591..4072b06 100644
--- a/Utilities/cmexpat/lib/xmltok_impl.c
+++ b/Utilities/cmexpat/lib/xmltok_impl.c
@@ -10,7 +10,7 @@
Copyright (c) 2000 Clark Cooper <coopercc@users.sourceforge.net>
Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
- Copyright (c) 2016-2021 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016-2022 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2018 Benjamin Peterson <benjamin@python.org>
Copyright (c) 2018 Anton Maklakov <antmak.pub@gmail.com>
@@ -69,7 +69,7 @@
case BT_LEAD##n: \
if (end - ptr < n) \
return XML_TOK_PARTIAL_CHAR; \
- if (! IS_NAME_CHAR(enc, ptr, n)) { \
+ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NAME_CHAR(enc, ptr, n)) { \
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
@@ -98,7 +98,7 @@
case BT_LEAD##n: \
if (end - ptr < n) \
return XML_TOK_PARTIAL_CHAR; \
- if (! IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) { \
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
@@ -1142,6 +1142,10 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
case BT_LEAD##n: \
if (end - ptr < n) \
return XML_TOK_PARTIAL_CHAR; \
+ if (IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
ptr += n; \
tok = XML_TOK_NAME; \
@@ -1270,7 +1274,7 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end,
switch (BYTE_TYPE(enc, ptr)) {
# define LEAD_CASE(n) \
case BT_LEAD##n: \
- ptr += n; \
+ ptr += n; /* NOTE: The encoding has already been validated. */ \
break;
LEAD_CASE(2)
LEAD_CASE(3)
@@ -1339,7 +1343,7 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end,
switch (BYTE_TYPE(enc, ptr)) {
# define LEAD_CASE(n) \
case BT_LEAD##n: \
- ptr += n; \
+ ptr += n; /* NOTE: The encoding has already been validated. */ \
break;
LEAD_CASE(2)
LEAD_CASE(3)
@@ -1518,7 +1522,7 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
state = inName; \
}
# define LEAD_CASE(n) \
- case BT_LEAD##n: \
+ case BT_LEAD##n: /* NOTE: The encoding has already been validated. */ \
START_NAME ptr += (n - MINBPC(enc)); \
break;
LEAD_CASE(2)
@@ -1730,7 +1734,7 @@ PREFIX(nameLength)(const ENCODING *enc, const char *ptr) {
switch (BYTE_TYPE(enc, ptr)) {
# define LEAD_CASE(n) \
case BT_LEAD##n: \
- ptr += n; \
+ ptr += n; /* NOTE: The encoding has already been validated. */ \
break;
LEAD_CASE(2)
LEAD_CASE(3)
@@ -1775,7 +1779,7 @@ PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end,
switch (BYTE_TYPE(enc, ptr)) {
# define LEAD_CASE(n) \
case BT_LEAD##n: \
- ptr += n; \
+ ptr += n; /* NOTE: The encoding has already been validated. */ \
pos->columnNumber++; \
break;
LEAD_CASE(2)
diff --git a/Utilities/cmexpat/lib/xmltok_ns.c b/Utilities/cmexpat/lib/xmltok_ns.c
index 5fd8392..fbdd3e3 100644
--- a/Utilities/cmexpat/lib/xmltok_ns.c
+++ b/Utilities/cmexpat/lib/xmltok_ns.c
@@ -11,7 +11,7 @@
Copyright (c) 2002 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2002 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
- Copyright (c) 2017 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2017-2021 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -93,7 +93,7 @@ NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
static const ENCODING *
NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) {
# define ENCODING_MAX 128
- char buf[ENCODING_MAX];
+ char buf[ENCODING_MAX] = "";
char *p = buf;
int i;
XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
diff --git a/Utilities/cmjsoncpp/CMakeLists.txt b/Utilities/cmjsoncpp/CMakeLists.txt
index 029ae86..c384f4e 100644
--- a/Utilities/cmjsoncpp/CMakeLists.txt
+++ b/Utilities/cmjsoncpp/CMakeLists.txt
@@ -2,7 +2,7 @@ project(JsonCpp CXX)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_CXX_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -woffall")
diff --git a/Utilities/cmjsoncpp/LICENSE b/Utilities/cmjsoncpp/LICENSE
index 89280a6..c41a1d1 100644
--- a/Utilities/cmjsoncpp/LICENSE
+++ b/Utilities/cmjsoncpp/LICENSE
@@ -1,25 +1,25 @@
-The JsonCpp library's source code, including accompanying documentation,
+The JsonCpp library's source code, including accompanying documentation,
tests and demonstration applications, are licensed under the following
conditions...
-Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
-jurisdictions which recognize such a disclaimer. In such jurisdictions,
+Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
this software is released into the Public Domain.
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
-In jurisdictions which recognize Public Domain property, the user of this
-software may choose to accept it either as 1) Public Domain, 2) under the
-conditions of the MIT License (see below), or 3) under the terms of dual
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
Public Domain/MIT License conditions described here, as they choose.
The MIT License is about as close to Public Domain as a license can get, and is
described in clear, concise terms at:
http://en.wikipedia.org/wiki/MIT_License
-
+
The full text of the MIT License follows:
========================================================================
diff --git a/Utilities/cmjsoncpp/README-CMake.txt b/Utilities/cmjsoncpp/README-CMake.txt
deleted file mode 100644
index bf74094..0000000
--- a/Utilities/cmjsoncpp/README-CMake.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-The Utilities/cmjsoncpp directory contains a reduced distribution
-of the jsoncpp source tree with only the library source code and
-CMake build system. It is not a submodule; the actual content is part
-of our source tree and changes can be made and committed directly.
-
-We update from upstream using Git's "subtree" merge strategy. A
-special branch contains commits of upstream jsoncpp snapshots and
-nothing else. No Git ref points explicitly to the head of this
-branch, but it is merged into our history.
-
-Update jsoncpp from upstream as follows. Create a local branch to
-explicitly reference the upstream snapshot branch head:
-
- git branch jsoncpp-upstream 53f6ccb0
-
-Use a temporary directory to checkout the branch:
-
- mkdir jsoncpp-tmp
- cd jsoncpp-tmp
- git init
- git pull .. jsoncpp-upstream
- rm -rf *
-
-Now place the (reduced) jsoncpp content in this directory. See
-instructions shown by
-
- git log 53f6ccb0
-
-for help extracting the content from the upstream svn repo. Then run
-the following commands to commit the new version. Substitute the
-appropriate date and version number:
-
- git add --all
-
- GIT_AUTHOR_NAME='JsonCpp Upstream' \
- GIT_AUTHOR_EMAIL='kwrobot@kitware.com' \
- GIT_AUTHOR_DATE='Thu Nov 20 08:45:58 2014 -0600' \
- git commit -m 'JsonCpp 1.0.0 (reduced)' &&
- git commit --amend
-
-Edit the commit message to describe the procedure used to obtain the
-content. Then push the changes back up to the main local repository:
-
- git push .. HEAD:jsoncpp-upstream
- cd ..
- rm -rf jsoncpp-tmp
-
-Create a topic in the main repository on which to perform the update:
-
- git checkout -b update-jsoncpp master
-
-Merge the jsoncpp-upstream branch as a subtree:
-
- git merge -s recursive -X subtree=Utilities/cmjsoncpp \
- jsoncpp-upstream
-
-If there are conflicts, resolve them and commit. Build and test the
-tree. Commit any additional changes needed to succeed.
-
-Finally, run
-
- git rev-parse --short=8 jsoncpp-upstream
-
-to get the commit from which the jsoncpp-upstream branch must be started
-on the next update. Edit the "git branch jsoncpp-upstream" line above to
-record it, and commit this file.
diff --git a/Utilities/cmjsoncpp/include/json/allocator.h b/Utilities/cmjsoncpp/include/json/allocator.h
index a685da1..3718df1 100644
--- a/Utilities/cmjsoncpp/include/json/allocator.h
+++ b/Utilities/cmjsoncpp/include/json/allocator.h
@@ -10,7 +10,8 @@
#include <memory>
#if !defined(__SUNPRO_CC)
-#pragma pack(push, 8)
+#pragma pack(push)
+#pragma pack()
#endif
namespace Json {
@@ -37,11 +38,10 @@ public:
* Release memory which was allocated for N items at pointer P.
*
* The memory block is filled with zeroes before being released.
- * The pointer argument is tagged as "volatile" to prevent the
- * compiler optimizing out this critical step.
*/
- void deallocate(volatile pointer p, size_type n) {
- std::memset(p, 0, n * sizeof(T));
+ void deallocate(pointer p, size_type n) {
+ // memset_s is used because memset may be optimized away by the compiler
+ memset_s(p, n * sizeof(T), 0, n * sizeof(T));
// free using "global operator delete"
::operator delete(p);
}
diff --git a/Utilities/cmjsoncpp/include/json/json_features.h b/Utilities/cmjsoncpp/include/json/json_features.h
index 6b99b4d..e1fc983 100644
--- a/Utilities/cmjsoncpp/include/json/json_features.h
+++ b/Utilities/cmjsoncpp/include/json/json_features.h
@@ -11,7 +11,8 @@
#endif // if !defined(JSON_IS_AMALGAMATION)
#if !defined(__SUNPRO_CC)
-#pragma pack(push, 8)
+#pragma pack(push)
+#pragma pack()
#endif
namespace Json {
diff --git a/Utilities/cmjsoncpp/include/json/reader.h b/Utilities/cmjsoncpp/include/json/reader.h
index 7ad0be6..0d444ad 100644
--- a/Utilities/cmjsoncpp/include/json/reader.h
+++ b/Utilities/cmjsoncpp/include/json/reader.h
@@ -24,7 +24,8 @@
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#if !defined(__SUNPRO_CC)
-#pragma pack(push, 8)
+#pragma pack(push)
+#pragma pack()
#endif
namespace Json {
@@ -35,8 +36,7 @@ namespace Json {
* deprecated Use CharReader and CharReaderBuilder.
*/
-class JSONCPP_DEPRECATED(
- "Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
+class JSON_API Reader {
public:
using Char = char;
using Location = const Char*;
@@ -53,13 +53,13 @@ public:
};
/** \brief Constructs a Reader allowing all features for parsing.
+ * deprecated Use CharReader and CharReaderBuilder.
*/
- JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
Reader();
/** \brief Constructs a Reader allowing the specified feature set for parsing.
+ * deprecated Use CharReader and CharReaderBuilder.
*/
- JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead")
Reader(const Features& features);
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
@@ -326,6 +326,9 @@ public:
* - `"allowSpecialFloats": false or true`
* - If true, special float values (NaNs and infinities) are allowed and
* their values are lossfree restorable.
+ * - `"skipBom": false or true`
+ * - If true, if the input starts with the Unicode byte order mark (BOM),
+ * it is skipped.
*
* You can examine 'settings_` yourself to see the defaults. You can also
* write and read them just like any JSON Value.
diff --git a/Utilities/cmjsoncpp/include/json/value.h b/Utilities/cmjsoncpp/include/json/value.h
index 952d423..f6ac9e3 100644
--- a/Utilities/cmjsoncpp/include/json/value.h
+++ b/Utilities/cmjsoncpp/include/json/value.h
@@ -50,11 +50,12 @@
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
-#pragma warning(disable : 4251)
+#pragma warning(disable : 4251 4275)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#if !defined(__SUNPRO_CC)
-#pragma pack(push, 8)
+#pragma pack(push)
+#pragma pack()
#endif
/** \brief JSON (JavaScript Object Notation).
@@ -265,10 +266,10 @@ private:
CZString(ArrayIndex index);
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
CZString(CZString const& other);
- CZString(CZString&& other);
+ CZString(CZString&& other) noexcept;
~CZString();
CZString& operator=(const CZString& other);
- CZString& operator=(CZString&& other);
+ CZString& operator=(CZString&& other) noexcept;
bool operator<(CZString const& other) const;
bool operator==(CZString const& other) const;
@@ -346,13 +347,13 @@ public:
Value(bool value);
Value(std::nullptr_t ptr) = delete;
Value(const Value& other);
- Value(Value&& other);
+ Value(Value&& other) noexcept;
~Value();
/// \note Overwrite existing comments. To preserve comments, use
/// #swapPayload().
Value& operator=(const Value& other);
- Value& operator=(Value&& other);
+ Value& operator=(Value&& other) noexcept;
/// Swap everything.
void swap(Value& other);
@@ -637,9 +638,9 @@ private:
public:
Comments() = default;
Comments(const Comments& that);
- Comments(Comments&& that);
+ Comments(Comments&& that) noexcept;
Comments& operator=(const Comments& that);
- Comments& operator=(Comments&& that);
+ Comments& operator=(Comments&& that) noexcept;
bool has(CommentPlacement slot) const;
String get(CommentPlacement slot) const;
void set(CommentPlacement slot, String comment);
@@ -920,8 +921,8 @@ public:
* because the returned references/pointers can be used
* to change state of the base class.
*/
- reference operator*() { return deref(); }
- pointer operator->() { return &deref(); }
+ reference operator*() const { return const_cast<reference>(deref()); }
+ pointer operator->() const { return const_cast<pointer>(&deref()); }
};
inline void swap(Value& a, Value& b) { a.swap(b); }
diff --git a/Utilities/cmjsoncpp/include/json/version.h b/Utilities/cmjsoncpp/include/json/version.h
index 5b9783d..e931d03 100644
--- a/Utilities/cmjsoncpp/include/json/version.h
+++ b/Utilities/cmjsoncpp/include/json/version.h
@@ -9,10 +9,10 @@
// 3. /CMakeLists.txt
// IMPORTANT: also update the SOVERSION!!
-#define JSONCPP_VERSION_STRING "1.9.4"
+#define JSONCPP_VERSION_STRING "1.9.5"
#define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 9
-#define JSONCPP_VERSION_PATCH 3
+#define JSONCPP_VERSION_PATCH 5
#define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
diff --git a/Utilities/cmjsoncpp/include/json/writer.h b/Utilities/cmjsoncpp/include/json/writer.h
index cc6b78c..2a47d5e 100644
--- a/Utilities/cmjsoncpp/include/json/writer.h
+++ b/Utilities/cmjsoncpp/include/json/writer.h
@@ -21,7 +21,8 @@
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#if !defined(__SUNPRO_CC)
-#pragma pack(push, 8)
+#pragma pack(push)
+#pragma pack()
#endif
namespace Json {
@@ -112,6 +113,8 @@ public:
* - Number of precision digits for formatting of real values.
* - "precisionType": "significant"(default) or "decimal"
* - Type of precision for formatting of real values.
+ * - "emitUTF8": false or true
+ * - If true, outputs raw UTF8 strings instead of escaping them.
* You can examine 'settings_` yourself
* to see the defaults. You can also write and read them just like any
@@ -147,7 +150,7 @@ public:
/** \brief Abstract class for writers.
* deprecated Use StreamWriter. (And really, this is an implementation detail.)
*/
-class JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer {
+class JSON_API Writer {
public:
virtual ~Writer();
@@ -167,7 +170,7 @@ public:
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
-class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter
+class JSON_API FastWriter
: public Writer {
public:
FastWriter();
@@ -217,7 +220,7 @@ private:
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
- * If the Value have comments then they are outputed according to their
+ * If the Value have comments then they are outputted according to their
*#CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
@@ -227,7 +230,7 @@ private:
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
-class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
+class JSON_API
StyledWriter : public Writer {
public:
StyledWriter();
@@ -286,7 +289,7 @@ private:
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
- * If the Value have comments then they are outputed according to their
+ * If the Value have comments then they are outputted according to their
#CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
@@ -296,7 +299,7 @@ private:
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
-class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API
+class JSON_API
StyledStreamWriter {
public:
/**
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp b/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
index e6caf40..5cc718d 100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
+++ b/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
@@ -12,6 +12,7 @@
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <algorithm>
#include <cassert>
+#include <cmath>
#include <cstring>
#include <iostream>
#include <istream>
@@ -104,8 +105,7 @@ bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
// Since String is reference-counted, this at least does not
// create an extra copy.
- String doc;
- std::getline(is, doc, static_cast<char> EOF);
+ String doc(std::istreambuf_iterator<char>(is), {});
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
}
@@ -601,9 +601,15 @@ bool Reader::decodeDouble(Token& token, Value& decoded) {
double value = 0;
String buffer(token.start_, token.end_);
IStringStream is(buffer);
- if (!(is >> value))
- return addError(
+ if (!(is >> value)) {
+ if (value == std::numeric_limits<double>::max())
+ value = std::numeric_limits<double>::infinity();
+ else if (value == std::numeric_limits<double>::lowest())
+ value = -std::numeric_limits<double>::infinity();
+ else if (!std::isinf(value))
+ return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token);
+ }
decoded = value;
return true;
}
@@ -1608,7 +1614,7 @@ bool OurReader::decodeNumber(Token& token, Value& decoded) {
const auto digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If
- // a) we've only just touched the limit, meaing value == threshold,
+ // a) we've only just touched the limit, meaning value == threshold,
// b) this is the last digit, or
// c) it's small enough to fit in that rounding delta, we're okay.
// Otherwise treat this number as a double to avoid overflow.
@@ -1648,7 +1654,12 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) {
const String buffer(token.start_, token.end_);
IStringStream is(buffer);
if (!(is >> value)) {
- return addError(
+ if (value == std::numeric_limits<double>::max())
+ value = std::numeric_limits<double>::infinity();
+ else if (value == std::numeric_limits<double>::lowest())
+ value = -std::numeric_limits<double>::infinity();
+ else if (!std::isinf(value))
+ return addError(
"'" + String(token.start_, token.end_) + "' is not a number.", token);
}
decoded = value;
@@ -1922,7 +1933,7 @@ bool CharReaderBuilder::validate(Json::Value* invalid) const {
if (valid_keys.count(key))
continue;
if (invalid)
- (*invalid)[std::move(key)] = *si;
+ (*invalid)[key] = *si;
else
return false;
}
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_tool.h b/Utilities/cmjsoncpp/src/lib_json/json_tool.h
index 2d7b7d9..b952c19 100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_tool.h
+++ b/Utilities/cmjsoncpp/src/lib_json/json_tool.h
@@ -116,14 +116,18 @@ template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
* Return iterator that would be the new end of the range [begin,end), if we
* were to delete zeros in the end of string, but not the last zero before '.'.
*/
-template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
+template <typename Iter>
+Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
for (; begin != end; --end) {
if (*(end - 1) != '0') {
return end;
}
// Don't delete the last zero before the decimal point.
- if (begin != (end - 1) && *(end - 2) == '.') {
- return end;
+ if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
+ if (precision) {
+ return end;
+ }
+ return end - 2;
}
}
return end;
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_value.cpp b/Utilities/cmjsoncpp/src/lib_json/json_value.cpp
index d59b7d9..b496ddf 100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_value.cpp
+++ b/Utilities/cmjsoncpp/src/lib_json/json_value.cpp
@@ -259,7 +259,7 @@ Value::CZString::CZString(const CZString& other) {
storage_.length_ = other.storage_.length_;
}
-Value::CZString::CZString(CZString&& other)
+Value::CZString::CZString(CZString&& other) noexcept
: cstr_(other.cstr_), index_(other.index_) {
other.cstr_ = nullptr;
}
@@ -285,7 +285,7 @@ Value::CZString& Value::CZString::operator=(const CZString& other) {
return *this;
}
-Value::CZString& Value::CZString::operator=(CZString&& other) {
+Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
cstr_ = other.cstr_;
index_ = other.index_;
other.cstr_ = nullptr;
@@ -433,7 +433,7 @@ Value::Value(const Value& other) {
dupMeta(other);
}
-Value::Value(Value&& other) {
+Value::Value(Value&& other) noexcept {
initBasic(nullValue);
swap(other);
}
@@ -448,7 +448,7 @@ Value& Value::operator=(const Value& other) {
return *this;
}
-Value& Value::operator=(Value&& other) {
+Value& Value::operator=(Value&& other) noexcept {
other.swap(*this);
return *this;
}
@@ -912,7 +912,8 @@ void Value::resize(ArrayIndex newSize) {
if (newSize == 0)
clear();
else if (newSize > oldSize)
- this->operator[](newSize - 1);
+ for (ArrayIndex i = oldSize; i < newSize; ++i)
+ (*this)[i];
else {
for (ArrayIndex index = newSize; index < oldSize; ++index) {
value_.map_->erase(index);
@@ -1373,14 +1374,15 @@ bool Value::isObject() const { return type() == objectValue; }
Value::Comments::Comments(const Comments& that)
: ptr_{cloneUnique(that.ptr_)} {}
-Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
+Value::Comments::Comments(Comments&& that) noexcept
+ : ptr_{std::move(that.ptr_)} {}
Value::Comments& Value::Comments::operator=(const Comments& that) {
ptr_ = cloneUnique(that.ptr_);
return *this;
}
-Value::Comments& Value::Comments::operator=(Comments&& that) {
+Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
ptr_ = std::move(that.ptr_);
return *this;
}
@@ -1396,13 +1398,11 @@ String Value::Comments::get(CommentPlacement slot) const {
}
void Value::Comments::set(CommentPlacement slot, String comment) {
- if (!ptr_) {
+ if (slot >= CommentPlacement::numberOfCommentPlacement)
+ return;
+ if (!ptr_)
ptr_ = std::unique_ptr<Array>(new Array());
- }
- // check comments array boundry.
- if (slot < CommentPlacement::numberOfCommentPlacement) {
- (*ptr_)[slot] = std::move(comment);
- }
+ (*ptr_)[slot] = std::move(comment);
}
void Value::setComment(String comment, CommentPlacement placement) {
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp b/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
index 8bf02db..0dd160e 100644
--- a/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
+++ b/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
@@ -68,7 +68,7 @@
#if !defined(isnan)
// IEEE standard states that NaN values will not compare to themselves
-#define isnan(x) (x != x)
+#define isnan(x) ((x) != (x))
#endif
#if !defined(__APPLE__)
@@ -154,16 +154,18 @@ String valueToString(double value, bool useSpecialFloats,
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
- // strip the zero padding from the right
- if (precisionType == PrecisionType::decimalPlaces) {
- buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
- }
-
// try to ensure we preserve the fact that this was given to us as a double on
// input
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
buffer += ".0";
}
+
+ // strip the zero padding from the right
+ if (precisionType == PrecisionType::decimalPlaces) {
+ buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision),
+ buffer.end());
+ }
+
return buffer;
}
} // namespace
@@ -270,7 +272,7 @@ static void appendHex(String& result, unsigned ch) {
result.append("\\u").append(toHex16Bit(ch));
}
-static String valueToQuotedStringN(const char* value, unsigned length,
+static String valueToQuotedStringN(const char* value, size_t length,
bool emitUTF8 = false) {
if (value == nullptr)
return "";
@@ -348,7 +350,7 @@ static String valueToQuotedStringN(const char* value, unsigned length,
}
String valueToQuotedString(const char* value) {
- return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
+ return valueToQuotedStringN(value, strlen(value));
}
// Class Writer
@@ -397,7 +399,7 @@ void FastWriter::writeValue(const Value& value) {
char const* end;
bool ok = value.getString(&str, &end);
if (ok)
- document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
+ document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
break;
}
case booleanValue:
@@ -420,8 +422,7 @@ void FastWriter::writeValue(const Value& value) {
const String& name = *it;
if (it != members.begin())
document_ += ',';
- document_ += valueToQuotedStringN(name.data(),
- static_cast<unsigned>(name.length()));
+ document_ += valueToQuotedStringN(name.data(), name.length());
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
writeValue(value[name]);
}
@@ -466,7 +467,7 @@ void StyledWriter::writeValue(const Value& value) {
char const* end;
bool ok = value.getString(&str, &end);
if (ok)
- pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+ pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
else
pushValue("");
break;
@@ -507,7 +508,7 @@ void StyledWriter::writeValue(const Value& value) {
}
void StyledWriter::writeArrayValue(const Value& value) {
- unsigned size = value.size();
+ size_t size = value.size();
if (size == 0)
pushValue("[]");
else {
@@ -516,7 +517,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
writeWithIndent("[");
indent();
bool hasChildValue = !childValues_.empty();
- unsigned index = 0;
+ ArrayIndex index = 0;
for (;;) {
const Value& childValue = value[index];
writeCommentBeforeValue(childValue);
@@ -539,7 +540,7 @@ void StyledWriter::writeArrayValue(const Value& value) {
{
assert(childValues_.size() == size);
document_ += "[ ";
- for (unsigned index = 0; index < size; ++index) {
+ for (size_t index = 0; index < size; ++index) {
if (index > 0)
document_ += ", ";
document_ += childValues_[index];
@@ -684,7 +685,7 @@ void StyledStreamWriter::writeValue(const Value& value) {
char const* end;
bool ok = value.getString(&str, &end);
if (ok)
- pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
+ pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
else
pushValue("");
break;
@@ -958,8 +959,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
char const* end;
bool ok = value.getString(&str, &end);
if (ok)
- pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str),
- emitUTF8_));
+ pushValue(
+ valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_));
else
pushValue("");
break;
@@ -982,8 +983,8 @@ void BuiltStyledStreamWriter::writeValue(Value const& value) {
String const& name = *it;
Value const& childValue = value[name];
writeCommentBeforeValue(childValue);
- writeWithIndent(valueToQuotedStringN(
- name.data(), static_cast<unsigned>(name.length()), emitUTF8_));
+ writeWithIndent(
+ valueToQuotedStringN(name.data(), name.length(), emitUTF8_));
*sout_ << colonSymbol_;
writeValue(childValue);
if (++it == members.end()) {
@@ -1217,7 +1218,7 @@ bool StreamWriterBuilder::validate(Json::Value* invalid) const {
if (valid_keys.count(key))
continue;
if (invalid)
- (*invalid)[std::move(key)] = *si;
+ (*invalid)[key] = *si;
else
return false;
}
diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index ba65470..2a788ff 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -94,7 +94,7 @@ SET(CMAKE_REQUIRED_FLAGS)
# Disable warnings to avoid changing 3rd party code.
IF(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -110,7 +110,7 @@ endif ()
# Especially for early development, we want to be a little
# aggressive about diagnosing build problems; this can get
# relaxed somewhat in final shipping versions.
-IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$")
+IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR CMAKE_C_COMPILER_ID MATCHES "^LCC$")
SET(CMAKE_REQUIRED_FLAGS "-Wall -Wformat -Wformat-security")
#################################################################
# Set compile flags for all build types.
@@ -126,7 +126,7 @@ IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wshadow")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wmissing-prototypes")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wcast-qual")
-ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$")
+ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR CMAKE_C_COMPILER_ID MATCHES "^LCC$")
IF (CMAKE_C_COMPILER_ID MATCHES "^Clang$")
SET(CMAKE_REQUIRED_FLAGS "-Wall -Wformat -Wformat-security")
#################################################################
@@ -863,6 +863,8 @@ MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
# crypto implementation is available on this platform.
SET(TRY_CRYPTO_REQUIRED_INCLUDES
"-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive;${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp")
+ LIST(APPEND TRY_CRYPTO_REQUIRED_INCLUDES "${CMake_SOURCE_DIR}/Utilities" "${CMake_BINARY_DIR}/Utilities") # for KWIML inside CMake
+
SET(TRY_CRYPTO_REQUIRED_LIBS)
IF ("${IMPLEMENTATION}" MATCHES "^OPENSSL$" AND OPENSSL_FOUND)
SET(TRY_CRYPTO_REQUIRED_INCLUDES
@@ -1038,7 +1040,7 @@ ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
IF(NOT HAVE_ICONV)
CMAKE_PUSH_CHECK_STATE() # Save the state of the variables
- IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
+ IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR CMAKE_C_COMPILER_ID MATCHES "^LCC$" OR
CMAKE_C_COMPILER_ID MATCHES "^Clang$")
#
# During checking iconv proto type, we should use -Werror to avoid the
@@ -1046,7 +1048,7 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
# detection. So this needs for all build mode(even it's a release mode).
#
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
- ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
+ ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR CMAKE_C_COMPILER_ID MATCHES "^LCC$" OR
CMAKE_C_COMPILER_ID MATCHES "^Clang$")
IF (CMAKE_C_COMPILER_ID MATCHES "^XL$")
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -qhalt=w -qflag=w:w")
@@ -1335,7 +1337,7 @@ ENDIF(NOT FOUND_POSIX_REGEX_LIB AND POSIX_REGEX_LIB MATCHES "^(AUTO|LIBPCREPOSIX
# Check functions
#
CMAKE_PUSH_CHECK_STATE() # Save the state of the variables
-IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
+IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR CMAKE_C_COMPILER_ID MATCHES "^LCC$" OR
CMAKE_C_COMPILER_ID MATCHES "^Clang$")
#
# During checking functions, we should use -fno-builtin to avoid the
@@ -1343,7 +1345,7 @@ IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
# types for built-in function" caused by using -Werror option.
#
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-builtin")
-ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
+ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR CMAKE_C_COMPILER_ID MATCHES "^LCC$" OR
CMAKE_C_COMPILER_ID MATCHES "^Clang$")
CHECK_SYMBOL_EXISTS(_CrtSetReportMode "crtdbg.h" HAVE__CrtSetReportMode)
CHECK_FUNCTION_EXISTS_GLIBC(arc4random_buf HAVE_ARC4RANDOM_BUF)
diff --git a/Utilities/cmliblzma/CMakeLists.txt b/Utilities/cmliblzma/CMakeLists.txt
index 4820a8f..0de1e97 100644
--- a/Utilities/cmliblzma/CMakeLists.txt
+++ b/Utilities/cmliblzma/CMakeLists.txt
@@ -160,7 +160,7 @@ INCLUDE_DIRECTORIES(
# Disable warnings to avoid changing 3rd party code.
IF(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -172,7 +172,7 @@ IF(CMAKE_C_COMPILER_ID STREQUAL "XL")
# Disable the XL compiler optimizer because it causes crashes
# and other bad behavior in liblzma code.
SET_PROPERTY(TARGET cmliblzma PROPERTY COMPILE_FLAGS "-qnooptimize")
-ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
+ELSEIF((CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "LCC") AND
CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
# Disable the old GNU compiler optimizer.
SET_PROPERTY(TARGET cmliblzma PROPERTY COMPILE_FLAGS "-O0")
diff --git a/Utilities/cmlibrhash/CMakeLists.txt b/Utilities/cmlibrhash/CMakeLists.txt
index 1a01165..9f532ad 100644
--- a/Utilities/cmlibrhash/CMakeLists.txt
+++ b/Utilities/cmlibrhash/CMakeLists.txt
@@ -2,7 +2,7 @@ project(librhash C)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt
index 086345c..b815a5c 100644
--- a/Utilities/cmlibuv/CMakeLists.txt
+++ b/Utilities/cmlibuv/CMakeLists.txt
@@ -2,7 +2,7 @@ project(libuv C)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
@@ -202,6 +202,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
)
list(APPEND uv_defines _GNU_SOURCE)
list(APPEND uv_sources
+ src/unix/epoll.c
src/unix/linux-core.c
src/unix/linux-inotify.c
src/unix/linux-syscalls.c
diff --git a/Utilities/cmlibuv/LICENSE b/Utilities/cmlibuv/LICENSE
index 28f1733..eb126da 100644
--- a/Utilities/cmlibuv/LICENSE
+++ b/Utilities/cmlibuv/LICENSE
@@ -64,7 +64,3 @@ The externally maintained libraries used by libuv are:
- pthread-fixes.c, copyright Google Inc. and Sony Mobile Communications AB.
Three clause BSD license.
-
- - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
- Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement
- n° 289016). Three clause BSD license.
diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h
index 11891df..747095f 100644
--- a/Utilities/cmlibuv/include/uv.h
+++ b/Utilities/cmlibuv/include/uv.h
@@ -49,6 +49,8 @@ extern "C" {
# endif
#elif __GNUC__ >= 4
# define UV_EXTERN __attribute__((visibility("default")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) /* Sun Studio >= 8 */
+# define UV_EXTERN __global
#else
# define UV_EXTERN /* nothing */
#endif
@@ -130,6 +132,7 @@ extern "C" {
XX(ENOTEMPTY, "directory not empty") \
XX(ENOTSOCK, "socket operation on non-socket") \
XX(ENOTSUP, "operation not supported on socket") \
+ XX(EOVERFLOW, "value too large for defined data type") \
XX(EPERM, "operation not permitted") \
XX(EPIPE, "broken pipe") \
XX(EPROTO, "protocol error") \
@@ -152,6 +155,7 @@ extern "C" {
XX(ENOTTY, "inappropriate ioctl for device") \
XX(EFTYPE, "inappropriate file type or format") \
XX(EILSEQ, "illegal byte sequence") \
+ XX(ESOCKTNOSUPPORT, "socket type not supported") \
#define UV_HANDLE_TYPE_MAP(XX) \
XX(ASYNC, async) \
@@ -479,6 +483,12 @@ UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
+UV_EXTERN int uv_pipe(uv_file fds[2], int read_flags, int write_flags);
+UV_EXTERN int uv_socketpair(int type,
+ int protocol,
+ uv_os_sock_t socket_vector[2],
+ int flags0,
+ int flags1);
#define UV_STREAM_FIELDS \
/* number of bytes queued for writing */ \
@@ -524,6 +534,10 @@ UV_EXTERN int uv_write2(uv_write_t* req,
UV_EXTERN int uv_try_write(uv_stream_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs);
+UV_EXTERN int uv_try_write2(uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle);
/* uv_write_t is a subclass of uv_req_t. */
struct uv_write_s {
@@ -624,7 +638,14 @@ enum uv_udp_flags {
* in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL.
*/
UV_UDP_MMSG_FREE = 16,
-
+ /*
+ * Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle.
+ * This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on
+ * Linux. This stops the Linux kernel from suppressing some ICMP error
+ * messages and enables full ICMP error reporting for faster failover.
+ * This flag is no-op on platforms other than Linux.
+ */
+ UV_UDP_LINUX_RECVERR = 32,
/*
* Indicates that recvmmsg should be used, if available.
*/
@@ -937,10 +958,13 @@ typedef enum {
UV_WRITABLE_PIPE = 0x20,
/*
- * Open the child pipe handle in overlapped mode on Windows.
- * On Unix it is silently ignored.
+ * When UV_CREATE_PIPE is specified, specifying UV_NONBLOCK_PIPE opens the
+ * handle in non-blocking mode in the child. This may cause loss of data,
+ * if the child is not designed to handle to encounter this mode,
+ * but can also be significantly more efficient.
*/
- UV_OVERLAPPED_PIPE = 0x40
+ UV_NONBLOCK_PIPE = 0x40,
+ UV_OVERLAPPED_PIPE = 0x40 /* old name, for compatibility */
} uv_stdio_flags;
typedef struct uv_stdio_container_s {
@@ -1654,6 +1678,7 @@ UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr);
UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size);
UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size);
+UV_EXTERN int uv_ip_name(const struct sockaddr* src, char* dst, size_t size);
UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
diff --git a/Utilities/cmlibuv/include/uv/android-ifaddrs.h b/Utilities/cmlibuv/include/uv/android-ifaddrs.h
deleted file mode 100644
index 9cd19fe..0000000
--- a/Utilities/cmlibuv/include/uv/android-ifaddrs.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 1995, 1999
- * Berkeley Software Design, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
- */
-
-#ifndef _IFADDRS_H_
-#define _IFADDRS_H_
-
-struct ifaddrs {
- struct ifaddrs *ifa_next;
- char *ifa_name;
- unsigned int ifa_flags;
- struct sockaddr *ifa_addr;
- struct sockaddr *ifa_netmask;
- struct sockaddr *ifa_dstaddr;
- void *ifa_data;
-};
-
-/*
- * This may have been defined in <net/if.h>. Note that if <net/if.h> is
- * to be included it must be included before this header file.
- */
-#ifndef ifa_broadaddr
-#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
-#endif
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-extern int getifaddrs(struct ifaddrs **ifap);
-extern void freeifaddrs(struct ifaddrs *ifa);
-__END_DECLS
-
-#endif
diff --git a/Utilities/cmlibuv/include/uv/errno.h b/Utilities/cmlibuv/include/uv/errno.h
index 8d4d768..71906b3 100644
--- a/Utilities/cmlibuv/include/uv/errno.h
+++ b/Utilities/cmlibuv/include/uv/errno.h
@@ -317,7 +317,7 @@
#if defined(EPROTO) && !defined(_WIN32)
# define UV__EPROTO UV__ERR(EPROTO)
#else
-# define UV__EPROTO UV__ERR(-4046)
+# define UV__EPROTO (-4046)
#endif
#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
@@ -445,4 +445,16 @@
# define UV__EILSEQ (-4027)
#endif
+#if defined(EOVERFLOW) && !defined(_WIN32)
+# define UV__EOVERFLOW UV__ERR(EOVERFLOW)
+#else
+# define UV__EOVERFLOW (-4026)
+#endif
+
+#if defined(ESOCKTNOSUPPORT) && !defined(_WIN32)
+# define UV__ESOCKTNOSUPPORT UV__ERR(ESOCKTNOSUPPORT)
+#else
+# define UV__ESOCKTNOSUPPORT (-4025)
+#endif
+
#endif /* UV_ERRNO_H_ */
diff --git a/Utilities/cmlibuv/include/uv/tree.h b/Utilities/cmlibuv/include/uv/tree.h
index f936416..2b28835 100644
--- a/Utilities/cmlibuv/include/uv/tree.h
+++ b/Utilities/cmlibuv/include/uv/tree.h
@@ -251,7 +251,7 @@ void name##_SPLAY_MINMAX(struct name *head, int __comp) \
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
__left = __right = &__node; \
\
- while (1) { \
+ for (;;) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
diff --git a/Utilities/cmlibuv/include/uv/unix.h b/Utilities/cmlibuv/include/uv/unix.h
index a59192f..7a5a3cb 100644
--- a/Utilities/cmlibuv/include/uv/unix.h
+++ b/Utilities/cmlibuv/include/uv/unix.h
@@ -72,12 +72,10 @@
# include "bsd.h"
#elif defined(__CYGWIN__) || \
defined(__MSYS__) || \
+ defined(__HAIKU__) || \
+ defined(__QNX__) || \
defined(__GNU__)
# include "posix.h"
-#elif defined(__HAIKU__)
-# include "posix.h"
-#elif defined(__QNX__)
-# include "posix.h"
#endif
#ifndef NI_MAXHOST
diff --git a/Utilities/cmlibuv/include/uv/version.h b/Utilities/cmlibuv/include/uv/version.h
index 96c1c13..1934f39 100644
--- a/Utilities/cmlibuv/include/uv/version.h
+++ b/Utilities/cmlibuv/include/uv/version.h
@@ -31,7 +31,7 @@
*/
#define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 39
+#define UV_VERSION_MINOR 43
#define UV_VERSION_PATCH 1
#define UV_VERSION_IS_RELEASE 0
#define UV_VERSION_SUFFIX "dev"
diff --git a/Utilities/cmlibuv/include/uv/win.h b/Utilities/cmlibuv/include/uv/win.h
index 9b5d5dc..e3fe37d 100644
--- a/Utilities/cmlibuv/include/uv/win.h
+++ b/Utilities/cmlibuv/include/uv/win.h
@@ -274,21 +274,14 @@ typedef union {
} unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
} uv_cond_t;
-typedef union {
- struct {
- unsigned int num_readers_;
- CRITICAL_SECTION num_readers_lock_;
- HANDLE write_semaphore_;
- } state_;
- /* TODO: remove me in v2.x. */
- struct {
- SRWLOCK unused_;
- } unused1_;
- /* TODO: remove me in v2.x. */
- struct {
- uv_mutex_t unused1_;
- uv_mutex_t unused2_;
- } unused2_;
+typedef struct {
+ SRWLOCK read_write_lock_;
+ /* TODO: retained for ABI compatibility; remove me in v2.x */
+#ifdef _WIN64
+ unsigned char padding_[72];
+#else
+ unsigned char padding_[44];
+#endif
} uv_rwlock_t;
typedef struct {
diff --git a/Utilities/cmlibuv/src/idna.c b/Utilities/cmlibuv/src/idna.c
index 13ffac6..b44cb16 100644
--- a/Utilities/cmlibuv/src/idna.c
+++ b/Utilities/cmlibuv/src/idna.c
@@ -19,6 +19,7 @@
#include "uv.h"
#include "idna.h"
+#include <assert.h>
#include <string.h>
static unsigned uv__utf8_decode1_slow(const char** p,
@@ -32,7 +33,7 @@ static unsigned uv__utf8_decode1_slow(const char** p,
if (a > 0xF7)
return -1;
- switch (*p - pe) {
+ switch (pe - *p) {
default:
if (a > 0xEF) {
min = 0x10000;
@@ -62,6 +63,8 @@ static unsigned uv__utf8_decode1_slow(const char** p,
a = 0;
break;
}
+ /* Fall through. */
+ case 0:
return -1; /* Invalid continuation byte. */
}
@@ -88,6 +91,8 @@ static unsigned uv__utf8_decode1_slow(const char** p,
unsigned uv__utf8_decode1(const char** p, const char* pe) {
unsigned a;
+ assert(*p < pe);
+
a = (unsigned char) *(*p)++;
if (a < 128)
@@ -96,9 +101,6 @@ unsigned uv__utf8_decode1(const char** p, const char* pe) {
return uv__utf8_decode1_slow(p, pe, a);
}
-#define foreach_codepoint(c, p, pe) \
- for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;)
-
static int uv__idna_toascii_label(const char* s, const char* se,
char** d, char* de) {
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
@@ -121,15 +123,22 @@ static int uv__idna_toascii_label(const char* s, const char* se,
ss = s;
todo = 0;
- foreach_codepoint(c, &s, se) {
+ /* Note: after this loop we've visited all UTF-8 characters and know
+ * they're legal so we no longer need to check for decode errors.
+ */
+ while (s < se) {
+ c = uv__utf8_decode1(&s, se);
+
+ if (c == -1u)
+ return UV_EINVAL;
+
if (c < 128)
h++;
- else if (c == (unsigned) -1)
- return UV_EINVAL;
else
todo++;
}
+ /* Only write "xn--" when there are non-ASCII characters. */
if (todo > 0) {
if (*d < de) *(*d)++ = 'x';
if (*d < de) *(*d)++ = 'n';
@@ -137,9 +146,13 @@ static int uv__idna_toascii_label(const char* s, const char* se,
if (*d < de) *(*d)++ = '-';
}
+ /* Write ASCII characters. */
x = 0;
s = ss;
- foreach_codepoint(c, &s, se) {
+ while (s < se) {
+ c = uv__utf8_decode1(&s, se);
+ assert(c != -1u);
+
if (c > 127)
continue;
@@ -166,10 +179,15 @@ static int uv__idna_toascii_label(const char* s, const char* se,
while (todo > 0) {
m = -1;
s = ss;
- foreach_codepoint(c, &s, se)
+
+ while (s < se) {
+ c = uv__utf8_decode1(&s, se);
+ assert(c != -1u);
+
if (c >= n)
if (c < m)
m = c;
+ }
x = m - n;
y = h + 1;
@@ -181,7 +199,10 @@ static int uv__idna_toascii_label(const char* s, const char* se,
n = m;
s = ss;
- foreach_codepoint(c, &s, se) {
+ while (s < se) {
+ c = uv__utf8_decode1(&s, se);
+ assert(c != -1u);
+
if (c < n)
if (++delta == 0)
return UV_E2BIG; /* Overflow. */
@@ -245,8 +266,6 @@ static int uv__idna_toascii_label(const char* s, const char* se,
return 0;
}
-#undef foreach_codepoint
-
long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
const char* si;
const char* st;
@@ -256,10 +275,14 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
ds = d;
- for (si = s; si < se; /* empty */) {
+ si = s;
+ while (si < se) {
st = si;
c = uv__utf8_decode1(&si, se);
+ if (c == -1u)
+ return UV_EINVAL;
+
if (c != '.')
if (c != 0x3002) /* 。 */
if (c != 0xFF0E) /* . */
diff --git a/Utilities/cmlibuv/src/inet.c b/Utilities/cmlibuv/src/inet.c
index 58238dc..384c0f7 100644
--- a/Utilities/cmlibuv/src/inet.c
+++ b/Utilities/cmlibuv/src/inet.c
@@ -141,8 +141,9 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
*tp++ = ':';
*tp++ = '\0';
- if (UV_E2BIG == uv__strscpy(dst, tmp, size))
+ if ((size_t) (tp - tmp) > size)
return UV_ENOSPC;
+ uv__strscpy(dst, tmp, size);
return 0;
}
diff --git a/Utilities/cmlibuv/src/threadpool.c b/Utilities/cmlibuv/src/threadpool.c
index 0998938..e804c7c 100644
--- a/Utilities/cmlibuv/src/threadpool.c
+++ b/Utilities/cmlibuv/src/threadpool.c
@@ -160,14 +160,20 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
}
+#ifdef __MVS__
+/* TODO(itodorov) - zos: revisit when Woz compiler is available. */
+__attribute__((destructor))
+#endif
void uv__threadpool_cleanup(void) {
-#ifndef _WIN32
unsigned int i;
if (nthreads == 0)
return;
+#ifndef __MVS__
+ /* TODO(gabylb) - zos: revisit when Woz compiler is available. */
post(&exit_message, UV__WORK_CPU);
+#endif
for (i = 0; i < nthreads; i++)
if (uv_thread_join(threads + i))
@@ -181,7 +187,6 @@ void uv__threadpool_cleanup(void) {
threads = NULL;
nthreads = 0;
-#endif
}
diff --git a/Utilities/cmlibuv/src/timer.c b/Utilities/cmlibuv/src/timer.c
index 1bea2a8..bc680e7 100644
--- a/Utilities/cmlibuv/src/timer.c
+++ b/Utilities/cmlibuv/src/timer.c
@@ -58,6 +58,7 @@ static int timer_less_than(const struct heap_node* ha,
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
handle->timer_cb = NULL;
+ handle->timeout = 0;
handle->repeat = 0;
return 0;
}
diff --git a/Utilities/cmlibuv/src/unix/android-ifaddrs.c b/Utilities/cmlibuv/src/unix/android-ifaddrs.c
deleted file mode 100644
index 4765cc0..0000000
--- a/Utilities/cmlibuv/src/unix/android-ifaddrs.c
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
-Copyright (c) 2013, Kenneth MacKay
-Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "uv/android-ifaddrs.h"
-#include "uv-common.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/if_packet.h>
-
-typedef struct NetlinkList
-{
- struct NetlinkList *m_next;
- struct nlmsghdr *m_data;
- unsigned int m_size;
-} NetlinkList;
-
-static int netlink_socket(pid_t *p_pid)
-{
- struct sockaddr_nl l_addr;
- socklen_t l_len;
-
- int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if(l_socket < 0)
- {
- return -1;
- }
-
- memset(&l_addr, 0, sizeof(l_addr));
- l_addr.nl_family = AF_NETLINK;
- if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
- {
- close(l_socket);
- return -1;
- }
-
- l_len = sizeof(l_addr);
- if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
- {
- close(l_socket);
- return -1;
- }
- *p_pid = l_addr.nl_pid;
-
- return l_socket;
-}
-
-static int netlink_send(int p_socket, int p_request)
-{
- char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
-
- struct nlmsghdr *l_hdr;
- struct rtgenmsg *l_msg;
- struct sockaddr_nl l_addr;
-
- memset(l_buffer, 0, sizeof(l_buffer));
-
- l_hdr = (struct nlmsghdr *)l_buffer;
- l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
-
- l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
- l_hdr->nlmsg_type = p_request;
- l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
- l_hdr->nlmsg_pid = 0;
- l_hdr->nlmsg_seq = p_socket;
- l_msg->rtgen_family = AF_UNSPEC;
-
- memset(&l_addr, 0, sizeof(l_addr));
- l_addr.nl_family = AF_NETLINK;
- return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
-}
-
-static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
-{
- struct sockaddr_nl l_addr;
- struct msghdr l_msg;
-
- struct iovec l_iov;
- l_iov.iov_base = p_buffer;
- l_iov.iov_len = p_len;
-
- for(;;)
- {
- int l_result;
- l_msg.msg_name = (void *)&l_addr;
- l_msg.msg_namelen = sizeof(l_addr);
- l_msg.msg_iov = &l_iov;
- l_msg.msg_iovlen = 1;
- l_msg.msg_control = NULL;
- l_msg.msg_controllen = 0;
- l_msg.msg_flags = 0;
- l_result = recvmsg(p_socket, &l_msg, 0);
-
- if(l_result < 0)
- {
- if(errno == EINTR)
- {
- continue;
- }
- return -2;
- }
-
- /* Buffer was too small */
- if(l_msg.msg_flags & MSG_TRUNC)
- {
- return -1;
- }
- return l_result;
- }
-}
-
-static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
-{
- size_t l_size = 4096;
- void *l_buffer = NULL;
-
- for(;;)
- {
- int l_read;
-
- uv__free(l_buffer);
- l_buffer = uv__malloc(l_size);
- if (l_buffer == NULL)
- {
- return NULL;
- }
-
- l_read = netlink_recv(p_socket, l_buffer, l_size);
- *p_size = l_read;
- if(l_read == -2)
- {
- uv__free(l_buffer);
- return NULL;
- }
- if(l_read >= 0)
- {
- struct nlmsghdr *l_hdr;
- for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
- {
- if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
- {
- continue;
- }
-
- if(l_hdr->nlmsg_type == NLMSG_DONE)
- {
- *p_done = 1;
- break;
- }
-
- if(l_hdr->nlmsg_type == NLMSG_ERROR)
- {
- uv__free(l_buffer);
- return NULL;
- }
- }
- return l_buffer;
- }
-
- l_size *= 2;
- }
-}
-
-static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
-{
- NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
- if (l_item == NULL)
- {
- return NULL;
- }
-
- l_item->m_next = NULL;
- l_item->m_data = p_data;
- l_item->m_size = p_size;
- return l_item;
-}
-
-static void freeResultList(NetlinkList *p_list)
-{
- NetlinkList *l_cur;
- while(p_list)
- {
- l_cur = p_list;
- p_list = p_list->m_next;
- uv__free(l_cur->m_data);
- uv__free(l_cur);
- }
-}
-
-static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
-{
- int l_size;
- int l_done;
- NetlinkList *l_list;
- NetlinkList *l_end;
-
- if(netlink_send(p_socket, p_request) < 0)
- {
- return NULL;
- }
-
- l_list = NULL;
- l_end = NULL;
-
- l_done = 0;
- while(!l_done)
- {
- NetlinkList *l_item;
-
- struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
- /* Error */
- if(!l_hdr)
- {
- freeResultList(l_list);
- return NULL;
- }
-
- l_item = newListItem(l_hdr, l_size);
- if (!l_item)
- {
- freeResultList(l_list);
- return NULL;
- }
- if(!l_list)
- {
- l_list = l_item;
- }
- else
- {
- l_end->m_next = l_item;
- }
- l_end = l_item;
- }
- return l_list;
-}
-
-static size_t maxSize(size_t a, size_t b)
-{
- return (a > b ? a : b);
-}
-
-static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
-{
- switch(p_family)
- {
- case AF_INET:
- return sizeof(struct sockaddr_in);
- case AF_INET6:
- return sizeof(struct sockaddr_in6);
- case AF_PACKET:
- return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
- default:
- return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
- }
-}
-
-static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
-{
- switch(p_family)
- {
- case AF_INET:
- memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
- break;
- case AF_INET6:
- memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
- break;
- case AF_PACKET:
- memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
- ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
- break;
- default:
- memcpy(p_dest->sa_data, p_data, p_size);
- break;
- }
- p_dest->sa_family = p_family;
-}
-
-static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
-{
- if(!*p_resultList)
- {
- *p_resultList = p_entry;
- }
- else
- {
- struct ifaddrs *l_cur = *p_resultList;
- while(l_cur->ifa_next)
- {
- l_cur = l_cur->ifa_next;
- }
- l_cur->ifa_next = p_entry;
- }
-}
-
-static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
-{
- struct ifaddrs *l_entry;
-
- char *l_index;
- char *l_name;
- char *l_addr;
- char *l_data;
-
- struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
-
- size_t l_nameSize = 0;
- size_t l_addrSize = 0;
- size_t l_dataSize = 0;
-
- size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
- struct rtattr *l_rta;
- for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
- {
- size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
- switch(l_rta->rta_type)
- {
- case IFLA_ADDRESS:
- case IFLA_BROADCAST:
- l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
- break;
- case IFLA_IFNAME:
- l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
- break;
- case IFLA_STATS:
- l_dataSize += NLMSG_ALIGN(l_rtaSize);
- break;
- default:
- break;
- }
- }
-
- l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
- if (l_entry == NULL)
- {
- return -1;
- }
- memset(l_entry, 0, sizeof(struct ifaddrs));
- l_entry->ifa_name = "";
-
- l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
- l_name = l_index + sizeof(int);
- l_addr = l_name + l_nameSize;
- l_data = l_addr + l_addrSize;
-
- /* Save the interface index so we can look it up when handling the
- * addresses.
- */
- memcpy(l_index, &l_info->ifi_index, sizeof(int));
-
- l_entry->ifa_flags = l_info->ifi_flags;
-
- l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
- for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
- {
- void *l_rtaData = RTA_DATA(l_rta);
- size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
- switch(l_rta->rta_type)
- {
- case IFLA_ADDRESS:
- case IFLA_BROADCAST:
- {
- size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
- makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
- ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
- ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
- if(l_rta->rta_type == IFLA_ADDRESS)
- {
- l_entry->ifa_addr = (struct sockaddr *)l_addr;
- }
- else
- {
- l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
- }
- l_addr += NLMSG_ALIGN(l_addrLen);
- break;
- }
- case IFLA_IFNAME:
- strncpy(l_name, l_rtaData, l_rtaDataSize);
- l_name[l_rtaDataSize] = '\0';
- l_entry->ifa_name = l_name;
- break;
- case IFLA_STATS:
- memcpy(l_data, l_rtaData, l_rtaDataSize);
- l_entry->ifa_data = l_data;
- break;
- default:
- break;
- }
- }
-
- addToEnd(p_resultList, l_entry);
- return 0;
-}
-
-static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
-{
- int l_num = 0;
- struct ifaddrs *l_cur = *p_links;
- while(l_cur && l_num < p_numLinks)
- {
- char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
- int l_index;
- memcpy(&l_index, l_indexPtr, sizeof(int));
- if(l_index == p_index)
- {
- return l_cur;
- }
-
- l_cur = l_cur->ifa_next;
- ++l_num;
- }
- return NULL;
-}
-
-static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
-{
- struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
- struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
-
- size_t l_nameSize = 0;
- size_t l_addrSize = 0;
-
- int l_addedNetmask = 0;
-
- size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
- struct rtattr *l_rta;
- struct ifaddrs *l_entry;
-
- char *l_name;
- char *l_addr;
-
- for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
- {
- size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
- if(l_info->ifa_family == AF_PACKET)
- {
- continue;
- }
-
- switch(l_rta->rta_type)
- {
- case IFA_ADDRESS:
- case IFA_LOCAL:
- l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
- if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
- {
- /* Make room for netmask */
- l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
- l_addedNetmask = 1;
- }
- break;
- case IFA_BROADCAST:
- l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
- break;
- case IFA_LABEL:
- l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
- break;
- default:
- break;
- }
- }
-
- l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
- if (l_entry == NULL)
- {
- return -1;
- }
- memset(l_entry, 0, sizeof(struct ifaddrs));
- l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
-
- l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
- l_addr = l_name + l_nameSize;
-
- l_entry->ifa_flags = l_info->ifa_flags;
- if(l_interface)
- {
- l_entry->ifa_flags |= l_interface->ifa_flags;
- }
-
- l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
- for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
- {
- void *l_rtaData = RTA_DATA(l_rta);
- size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
- switch(l_rta->rta_type)
- {
- case IFA_ADDRESS:
- case IFA_BROADCAST:
- case IFA_LOCAL:
- {
- size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
- makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
- if(l_info->ifa_family == AF_INET6)
- {
- if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
- {
- ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
- }
- }
-
- /* Apparently in a point-to-point network IFA_ADDRESS contains
- * the dest address and IFA_LOCAL contains the local address
- */
- if(l_rta->rta_type == IFA_ADDRESS)
- {
- if(l_entry->ifa_addr)
- {
- l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
- }
- else
- {
- l_entry->ifa_addr = (struct sockaddr *)l_addr;
- }
- }
- else if(l_rta->rta_type == IFA_LOCAL)
- {
- if(l_entry->ifa_addr)
- {
- l_entry->ifa_dstaddr = l_entry->ifa_addr;
- }
- l_entry->ifa_addr = (struct sockaddr *)l_addr;
- }
- else
- {
- l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
- }
- l_addr += NLMSG_ALIGN(l_addrLen);
- break;
- }
- case IFA_LABEL:
- strncpy(l_name, l_rtaData, l_rtaDataSize);
- l_name[l_rtaDataSize] = '\0';
- l_entry->ifa_name = l_name;
- break;
- default:
- break;
- }
- }
-
- if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
- {
- unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
- unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
- unsigned char l_mask[16] = {0};
- unsigned i;
- for(i=0; i<(l_prefix/8); ++i)
- {
- l_mask[i] = 0xff;
- }
- if(l_prefix % 8)
- {
- l_mask[i] = 0xff << (8 - (l_prefix % 8));
- }
-
- makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
- l_entry->ifa_netmask = (struct sockaddr *)l_addr;
- }
-
- addToEnd(p_resultList, l_entry);
- return 0;
-}
-
-static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
-{
-
- int l_numLinks = 0;
- for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
- {
- unsigned int l_nlsize = p_netlinkList->m_size;
- struct nlmsghdr *l_hdr;
- for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
- {
- if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
- {
- continue;
- }
-
- if(l_hdr->nlmsg_type == NLMSG_DONE)
- {
- break;
- }
-
- if(l_hdr->nlmsg_type == RTM_NEWLINK)
- {
- if(interpretLink(l_hdr, p_resultList) == -1)
- {
- return -1;
- }
- ++l_numLinks;
- }
- }
- }
- return l_numLinks;
-}
-
-static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
-{
- for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
- {
- unsigned int l_nlsize = p_netlinkList->m_size;
- struct nlmsghdr *l_hdr;
- for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
- {
- if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
- {
- continue;
- }
-
- if(l_hdr->nlmsg_type == NLMSG_DONE)
- {
- break;
- }
-
- if(l_hdr->nlmsg_type == RTM_NEWADDR)
- {
- if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
- {
- return -1;
- }
- }
- }
- }
- return 0;
-}
-
-int getifaddrs(struct ifaddrs **ifap)
-{
- int l_socket;
- int l_result;
- int l_numLinks;
- pid_t l_pid;
- NetlinkList *l_linkResults;
- NetlinkList *l_addrResults;
-
- if(!ifap)
- {
- return -1;
- }
- *ifap = NULL;
-
- l_socket = netlink_socket(&l_pid);
- if(l_socket < 0)
- {
- return -1;
- }
-
- l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
- if(!l_linkResults)
- {
- close(l_socket);
- return -1;
- }
-
- l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
- if(!l_addrResults)
- {
- close(l_socket);
- freeResultList(l_linkResults);
- return -1;
- }
-
- l_result = 0;
- l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
- if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
- {
- l_result = -1;
- }
-
- freeResultList(l_linkResults);
- freeResultList(l_addrResults);
- close(l_socket);
- return l_result;
-}
-
-void freeifaddrs(struct ifaddrs *ifa)
-{
- struct ifaddrs *l_cur;
- while(ifa)
- {
- l_cur = ifa;
- ifa = ifa->ifa_next;
- uv__free(l_cur);
- }
-}
diff --git a/Utilities/cmlibuv/src/unix/async.c b/Utilities/cmlibuv/src/unix/async.c
index 5f58fb8..e1805c3 100644
--- a/Utilities/cmlibuv/src/unix/async.c
+++ b/Utilities/cmlibuv/src/unix/async.c
@@ -214,7 +214,7 @@ static int uv__async_start(uv_loop_t* loop) {
pipefd[0] = err;
pipefd[1] = -1;
#else
- err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
+ err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
if (err < 0)
return err;
#endif
diff --git a/Utilities/cmlibuv/src/unix/atomic-ops.h b/Utilities/cmlibuv/src/unix/atomic-ops.h
index 2518a06..63d8268 100644
--- a/Utilities/cmlibuv/src/unix/atomic-ops.h
+++ b/Utilities/cmlibuv/src/unix/atomic-ops.h
@@ -58,9 +58,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
UV_UNUSED(static void cpu_relax(void)) {
#if defined(__i386__) || defined(__x86_64__)
- __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
+ __asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
- __asm__ volatile("yield");
+ __asm__ __volatile__ ("yield" ::: "memory");
+#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
+ __asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
#endif
}
diff --git a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
index 5223ab4..e48934b 100644
--- a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
+++ b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
@@ -42,8 +42,8 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
return 1;
#if !defined(__CYGWIN__) && !defined(__MSYS__)
/*
- * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
- * equals to `AF_LINK` or not. Otherwise, the result depends on the operation
+ * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family`
+ * equals `AF_LINK`. Otherwise, the result depends on the operating
* system with `AF_LINK` or `PF_INET`.
*/
if (exclude_type == UV__EXCLUDE_IFPHYS)
@@ -53,7 +53,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
defined(__HAIKU__)
/*
* On BSD getifaddrs returns information related to the raw underlying
- * devices. We're not interested in this information.
+ * devices. We're not interested in this information.
*/
if (ent->ifa_addr->sa_family == AF_LINK)
return 1;
diff --git a/Utilities/cmlibuv/src/unix/bsd-proctitle.c b/Utilities/cmlibuv/src/unix/bsd-proctitle.c
index 723b81c..4f4e9e5 100644
--- a/Utilities/cmlibuv/src/unix/bsd-proctitle.c
+++ b/Utilities/cmlibuv/src/unix/bsd-proctitle.c
@@ -38,9 +38,7 @@ static void init_process_title_mutex_once(void) {
void uv__process_title_cleanup(void) {
- /* TODO(bnoordhuis) uv_mutex_destroy(&process_title_mutex)
- * and reset process_title_mutex_once?
- */
+ uv_mutex_destroy(&process_title_mutex);
}
diff --git a/Utilities/cmlibuv/src/unix/cmake-bootstrap.c b/Utilities/cmlibuv/src/unix/cmake-bootstrap.c
index 054775e..0f279d5 100644
--- a/Utilities/cmlibuv/src/unix/cmake-bootstrap.c
+++ b/Utilities/cmlibuv/src/unix/cmake-bootstrap.c
@@ -7,27 +7,10 @@ void uv__process_title_cleanup(void) {
void uv__threadpool_cleanup(void) {
}
-int uv__tcp_nodelay(int fd, int on) {
- errno = EINVAL;
- return -1;
-}
-
-int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
- errno = EINVAL;
- return -1;
-}
-
-int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
- return -EINVAL;
-}
-
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
return -EINVAL;
}
-void uv__tcp_close(uv_tcp_t* handle) {
-}
-
void uv__udp_close(uv_udp_t* handle) {
}
@@ -153,8 +136,8 @@ int uv__statx(int dirfd,
return -1;
}
-ssize_t uv__fs_copy_file_range(int fd_in, ssize_t* off_in,
- int fd_out, ssize_t* off_out,
+ssize_t uv__fs_copy_file_range(int fd_in, off_t* off_in,
+ int fd_out, off_t* off_out,
size_t len, unsigned int flags)
{
errno = ENOSYS;
diff --git a/Utilities/cmlibuv/src/unix/core.c b/Utilities/cmlibuv/src/unix/core.c
index 4245e02..0793922 100644
--- a/Utilities/cmlibuv/src/unix/core.c
+++ b/Utilities/cmlibuv/src/unix/core.c
@@ -94,13 +94,17 @@ extern char** environ;
# define uv__accept4 accept4
#endif
+#if defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
+# include <sanitizer/linux_syscall_hooks.h>
+#endif
+
static int uv__run_pending(uv_loop_t* loop);
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
-STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) ==
+STATIC_ASSERT(sizeof(((uv_buf_t*) 0)->base) ==
sizeof(((struct iovec*) 0)->iov_base));
-STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) ==
+STATIC_ASSERT(sizeof(((uv_buf_t*) 0)->len) ==
sizeof(((struct iovec*) 0)->iov_len));
STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
@@ -545,7 +549,13 @@ int uv__close_nocancel(int fd) {
return close$NOCANCEL$UNIX2003(fd);
#endif
#pragma GCC diagnostic pop
-#elif defined(__linux__)
+#elif defined(__linux__) && defined(__SANITIZE_THREAD__) && defined(__clang__)
+ long rc;
+ __sanitizer_syscall_pre_close(fd);
+ rc = syscall(SYS_close, fd);
+ __sanitizer_syscall_post_close(rc, fd);
+ return rc;
+#elif defined(__linux__) && !defined(__SANITIZE_THREAD__)
return syscall(SYS_close, fd);
#else
return close(fd);
@@ -580,7 +590,7 @@ int uv__close(int fd) {
return uv__close_nocheckstdio(fd);
}
-
+#if UV__NONBLOCK_IS_IOCTL
int uv__nonblock_ioctl(int fd, int set) {
int r;
@@ -595,7 +605,6 @@ int uv__nonblock_ioctl(int fd, int set) {
}
-#if !defined(__hpux) && !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__HAIKU__)
int uv__cloexec_ioctl(int fd, int set) {
int r;
@@ -931,13 +940,12 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
if (w->pevents == 0) {
QUEUE_REMOVE(&w->watcher_queue);
QUEUE_INIT(&w->watcher_queue);
+ w->events = 0;
- if (loop->watchers[w->fd] != NULL) {
- assert(loop->watchers[w->fd] == w);
+ if (w == loop->watchers[w->fd]) {
assert(loop->nfds > 0);
loop->watchers[w->fd] = NULL;
loop->nfds--;
- w->events = 0;
}
}
else if (QUEUE_EMPTY(&w->watcher_queue))
@@ -1181,7 +1189,9 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (buf == NULL)
return UV_ENOMEM;
- r = getpwuid_r(uid, &pw, buf, bufsize, &result);
+ do
+ r = getpwuid_r(uid, &pw, buf, bufsize, &result);
+ while (r == EINTR);
if (r != ERANGE)
break;
@@ -1191,7 +1201,7 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
if (r != 0) {
uv__free(buf);
- return -r;
+ return UV__ERR(r);
}
if (result == NULL) {
@@ -1586,7 +1596,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
buf[*buflen] = '\0';
return 0;
- }
+ }
/* Case iii). Search PATH environment variable */
cloned_path = NULL;
diff --git a/Utilities/cmlibuv/src/unix/darwin.c b/Utilities/cmlibuv/src/unix/darwin.c
index d0ecd45..62f04d3 100644
--- a/Utilities/cmlibuv/src/unix/darwin.c
+++ b/Utilities/cmlibuv/src/unix/darwin.c
@@ -33,9 +33,7 @@
#include <sys/sysctl.h>
#include <unistd.h> /* sysconf */
-#if !TARGET_OS_IPHONE
#include "darwin-stub.h"
-#endif
static uv_once_t once = UV_ONCE_INIT;
static uint64_t (*time_func)(void);
@@ -223,10 +221,10 @@ static int uv__get_cpu_speed(uint64_t* speed) {
err = UV_ENOENT;
core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/"
- "Versions/A/CoreFoundation",
+ "CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);
iokit_handle = dlopen("/System/Library/Frameworks/IOKit.framework/"
- "Versions/A/IOKit",
+ "IOKit",
RTLD_LAZY | RTLD_LOCAL);
if (core_foundation_handle == NULL || iokit_handle == NULL)
@@ -282,14 +280,18 @@ static int uv__get_cpu_speed(uint64_t* speed) {
NULL,
0);
if (freq_ref) {
- uint32_t freq;
+ const UInt8* freq_ref_ptr = pCFDataGetBytePtr(freq_ref);
CFIndex len = pCFDataGetLength(freq_ref);
- CFRange range;
- range.location = 0;
- range.length = len;
+ if (len == 8)
+ memcpy(speed, freq_ref_ptr, 8);
+ else if (len == 4) {
+ uint32_t v;
+ memcpy(&v, freq_ref_ptr, 4);
+ *speed = v;
+ } else {
+ *speed = 0;
+ }
- pCFDataGetBytes(freq_ref, range, (UInt8*)&freq);
- *speed = freq;
pCFRelease(freq_ref);
pCFRelease(data);
break;
@@ -304,6 +306,12 @@ static int uv__get_cpu_speed(uint64_t* speed) {
pIOObjectRelease(it);
err = 0;
+
+ if (device_type_str != NULL)
+ pCFRelease(device_type_str);
+ if (clock_frequency_str != NULL)
+ pCFRelease(clock_frequency_str);
+
out:
if (core_foundation_handle != NULL)
dlclose(core_foundation_handle);
diff --git a/Utilities/cmlibuv/src/unix/dl.c b/Utilities/cmlibuv/src/unix/dl.c
index fc1c052..80b3333 100644
--- a/Utilities/cmlibuv/src/unix/dl.c
+++ b/Utilities/cmlibuv/src/unix/dl.c
@@ -53,7 +53,7 @@ void uv_dlclose(uv_lib_t* lib) {
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
dlerror(); /* Reset error status. */
*ptr = dlsym(lib->handle, name);
- return uv__dlerror(lib);
+ return *ptr ? 0 : uv__dlerror(lib);
}
diff --git a/Utilities/cmlibuv/src/unix/epoll.c b/Utilities/cmlibuv/src/unix/epoll.c
new file mode 100644
index 0000000..97348e2
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/epoll.c
@@ -0,0 +1,422 @@
+/* Copyright libuv contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include <errno.h>
+#include <sys/epoll.h>
+
+int uv__epoll_init(uv_loop_t* loop) {
+ int fd;
+ fd = epoll_create1(O_CLOEXEC);
+
+ /* epoll_create1() can fail either because it's not implemented (old kernel)
+ * or because it doesn't understand the O_CLOEXEC flag.
+ */
+ if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
+ fd = epoll_create(256);
+
+ if (fd != -1)
+ uv__cloexec(fd, 1);
+ }
+
+ loop->backend_fd = fd;
+ if (fd == -1)
+ return UV__ERR(errno);
+
+ return 0;
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct epoll_event* events;
+ struct epoll_event dummy;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+ assert(fd >= 0);
+
+ events = (struct epoll_event*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events != NULL)
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if (events[i].data.fd == fd)
+ events[i].data.fd = -1;
+
+ /* Remove the file descriptor from the epoll.
+ * This avoids a problem where the same file description remains open
+ * in another process, causing repeated junk epoll events.
+ *
+ * We pass in a dummy epoll_event, to work around a bug in old kernels.
+ */
+ if (loop->backend_fd >= 0) {
+ /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
+ * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
+ */
+ memset(&dummy, 0, sizeof(dummy));
+ epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
+ }
+}
+
+
+int uv__io_check_fd(uv_loop_t* loop, int fd) {
+ struct epoll_event e;
+ int rc;
+
+ memset(&e, 0, sizeof(e));
+ e.events = POLLIN;
+ e.data.fd = -1;
+
+ rc = 0;
+ if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
+ if (errno != EEXIST)
+ rc = UV__ERR(errno);
+
+ if (rc == 0)
+ if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
+ abort();
+
+ return rc;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
+ * effectively infinite on 32 bits architectures. To avoid blocking
+ * indefinitely, we cap the timeout and poll again if necessary.
+ *
+ * Note that "30 minutes" is a simplification because it depends on
+ * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
+ * that being the largest value I have seen in the wild (and only once.)
+ */
+ static const int max_safe_timeout = 1789569;
+ static int no_epoll_pwait_cached;
+ static int no_epoll_wait_cached;
+ int no_epoll_pwait;
+ int no_epoll_wait;
+ struct epoll_event events[1024];
+ struct epoll_event* pe;
+ struct epoll_event e;
+ int real_timeout;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t sigset;
+ uint64_t sigmask;
+ uint64_t base;
+ int have_signals;
+ int nevents;
+ int count;
+ int nfds;
+ int fd;
+ int op;
+ int i;
+ int user_timeout;
+ int reset_timeout;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ memset(&e, 0, sizeof(e));
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ e.events = w->pevents;
+ e.data.fd = w->fd;
+
+ if (w->events == 0)
+ op = EPOLL_CTL_ADD;
+ else
+ op = EPOLL_CTL_MOD;
+
+ /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
+ * events, skip the syscall and squelch the events after epoll_wait().
+ */
+ if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
+ if (errno != EEXIST)
+ abort();
+
+ assert(op == EPOLL_CTL_ADD);
+
+ /* We've reactivated a file descriptor that's been watched before. */
+ if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
+ abort();
+ }
+
+ w->events = w->pevents;
+ }
+
+ sigmask = 0;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGPROF);
+ sigmask |= 1 << (SIGPROF - 1);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+ real_timeout = timeout;
+
+ if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
+ reset_timeout = 1;
+ user_timeout = timeout;
+ timeout = 0;
+ } else {
+ reset_timeout = 0;
+ user_timeout = 0;
+ }
+
+ /* You could argue there is a dependency between these two but
+ * ultimately we don't care about their ordering with respect
+ * to one another. Worst case, we make a few system calls that
+ * could have been avoided because another thread already knows
+ * they fail with ENOSYS. Hardly the end of the world.
+ */
+ no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached);
+ no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached);
+
+ for (;;) {
+ /* Only need to set the provider_entry_time if timeout != 0. The function
+ * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
+ */
+ if (timeout != 0)
+ uv__metrics_set_provider_entry_time(loop);
+
+ /* See the comment for max_safe_timeout for an explanation of why
+ * this is necessary. Executive summary: kernel bug workaround.
+ */
+ if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
+ timeout = max_safe_timeout;
+
+ if (sigmask != 0 && no_epoll_pwait != 0)
+ if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
+ abort();
+
+ if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
+ nfds = epoll_pwait(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout,
+ &sigset);
+ if (nfds == -1 && errno == ENOSYS) {
+ uv__store_relaxed(&no_epoll_pwait_cached, 1);
+ no_epoll_pwait = 1;
+ }
+ } else {
+ nfds = epoll_wait(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout);
+ if (nfds == -1 && errno == ENOSYS) {
+ uv__store_relaxed(&no_epoll_wait_cached, 1);
+ no_epoll_wait = 1;
+ }
+ }
+
+ if (sigmask != 0 && no_epoll_pwait != 0)
+ if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
+ abort();
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+
+ if (reset_timeout != 0) {
+ timeout = user_timeout;
+ reset_timeout = 0;
+ }
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* We may have been inside the system call for longer than |timeout|
+ * milliseconds so we need to update the timestamp to avoid drift.
+ */
+ goto update_timeout;
+ }
+
+ if (nfds == -1) {
+ if (errno == ENOSYS) {
+ /* epoll_wait() or epoll_pwait() failed, try the other system call. */
+ assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
+ continue;
+ }
+
+ if (errno != EINTR)
+ abort();
+
+ if (reset_timeout != 0) {
+ timeout = user_timeout;
+ reset_timeout = 0;
+ }
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ have_signals = 0;
+ nevents = 0;
+
+ {
+ /* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */
+ union {
+ struct epoll_event* events;
+ uv__io_t* watchers;
+ } x;
+
+ x.events = events;
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = x.watchers;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ }
+
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ fd = pe->data.fd;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it.
+ *
+ * Ignore all errors because we may be racing with another thread
+ * when the file descriptor is closed.
+ */
+ epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
+ continue;
+ }
+
+ /* Give users only events they're interested in. Prevents spurious
+ * callbacks when previous callback invocation in this loop has stopped
+ * the current watcher. Also, filters out events that users has not
+ * requested us to watch.
+ */
+ pe->events &= w->pevents | POLLERR | POLLHUP;
+
+ /* Work around an epoll quirk where it sometimes reports just the
+ * EPOLLERR or EPOLLHUP event. In order to force the event loop to
+ * move forward, we merge in the read/write events that the watcher
+ * is interested in; uv__read() and uv__write() will then deal with
+ * the error or hangup in the usual fashion.
+ *
+ * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
+ * reads the available data, calls uv_read_stop(), then sometime later
+ * calls uv_read_start() again. By then, libuv has forgotten about the
+ * hangup and the kernel won't report EPOLLIN again because there's
+ * nothing left to read. If anything, libuv is to blame here. The
+ * current hack is just a quick bandaid; to properly fix it, libuv
+ * needs to remember the error/hangup event. We should get that for
+ * free when we switch over to edge-triggered I/O.
+ */
+ if (pe->events == POLLERR || pe->events == POLLHUP)
+ pe->events |=
+ w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
+
+ if (pe->events != 0) {
+ /* Run signal watchers last. This also affects child process watchers
+ * because those are implemented in terms of signal watchers.
+ */
+ if (w == &loop->signal_io_watcher) {
+ have_signals = 1;
+ } else {
+ uv__metrics_update_idle_time(loop);
+ w->cb(loop, w, pe->events);
+ }
+
+ nevents++;
+ }
+ }
+
+ if (reset_timeout != 0) {
+ timeout = user_timeout;
+ reset_timeout = 0;
+ }
+
+ if (have_signals != 0) {
+ uv__metrics_update_idle_time(loop);
+ loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
+ }
+
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (have_signals != 0)
+ return; /* Event loop should cycle now so don't poll again. */
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ real_timeout -= (loop->time - base);
+ if (real_timeout <= 0)
+ return;
+
+ timeout = real_timeout;
+ }
+}
+
diff --git a/Utilities/cmlibuv/src/unix/freebsd.c b/Utilities/cmlibuv/src/unix/freebsd.c
index fe795a0..170b897 100644
--- a/Utilities/cmlibuv/src/unix/freebsd.c
+++ b/Utilities/cmlibuv/src/unix/freebsd.c
@@ -265,8 +265,11 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
-#if __FreeBSD__ >= 11
- return sendmmsg(fd, mmsg, vlen, /* flags */ 0);
+#if __FreeBSD__ >= 11 && !defined(__DragonFly__)
+ return sendmmsg(fd,
+ (struct mmsghdr*) mmsg,
+ vlen,
+ 0 /* flags */);
#else
return errno = ENOSYS, -1;
#endif
@@ -274,8 +277,12 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
-#if __FreeBSD__ >= 11
- return recvmmsg(fd, mmsg, vlen, 0 /* flags */, NULL /* timeout */);
+#if __FreeBSD__ >= 11 && !defined(__DragonFly__)
+ return recvmmsg(fd,
+ (struct mmsghdr*) mmsg,
+ vlen,
+ 0 /* flags */,
+ NULL /* timeout */);
#else
return errno = ENOSYS, -1;
#endif
diff --git a/Utilities/cmlibuv/src/unix/fs.c b/Utilities/cmlibuv/src/unix/fs.c
index 6d57cee..40448f1 100644
--- a/Utilities/cmlibuv/src/unix/fs.c
+++ b/Utilities/cmlibuv/src/unix/fs.c
@@ -56,8 +56,13 @@
# define HAVE_PREADV 0
#endif
+#if defined(__linux__)
+# include "sys/utsname.h"
+#endif
+
#if defined(__linux__) || defined(__sun)
# include <sys/sendfile.h>
+# include <sys/sysmacros.h>
#endif
#if defined(__APPLE__)
@@ -212,14 +217,30 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
struct timespec ts;
ts.tv_sec = time;
- ts.tv_nsec = (uint64_t)(time * 1000000) % 1000000 * 1000;
+ ts.tv_nsec = (time - ts.tv_sec) * 1e9;
+
+ /* TODO(bnoordhuis) Remove this. utimesat() has nanosecond resolution but we
+ * stick to microsecond resolution for the sake of consistency with other
+ * platforms. I'm the original author of this compatibility hack but I'm
+ * less convinced it's useful nowadays.
+ */
+ ts.tv_nsec -= ts.tv_nsec % 1000;
+
+ if (ts.tv_nsec < 0) {
+ ts.tv_nsec += 1e9;
+ ts.tv_sec -= 1;
+ }
return ts;
}
UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
struct timeval tv;
tv.tv_sec = time;
- tv.tv_usec = (uint64_t)(time * 1000000) % 1000000;
+ tv.tv_usec = (time - tv.tv_sec) * 1e6;
+ if (tv.tv_usec < 0) {
+ tv.tv_usec += 1e6;
+ tv.tv_sec -= 1;
+ }
return tv;
}
@@ -227,9 +248,6 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__) \
|| defined(_AIX71) \
|| defined(__HAIKU__)
- /* utimesat() has nanosecond resolution but we stick to microseconds
- * for the sake of consistency with other platforms.
- */
struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);
@@ -897,6 +915,115 @@ out:
}
+#ifdef __linux__
+static unsigned uv__kernel_version(void) {
+ static unsigned cached_version;
+ struct utsname u;
+ unsigned version;
+ unsigned major;
+ unsigned minor;
+ unsigned patch;
+
+ version = uv__load_relaxed(&cached_version);
+ if (version != 0)
+ return version;
+
+ if (-1 == uname(&u))
+ return 0;
+
+ if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch))
+ return 0;
+
+ version = major * 65536 + minor * 256 + patch;
+ uv__store_relaxed(&cached_version, version);
+
+ return version;
+}
+
+
+/* Pre-4.20 kernels have a bug where CephFS uses the RADOS copy-from command
+ * in copy_file_range() when it shouldn't. There is no workaround except to
+ * fall back to a regular copy.
+ */
+static int uv__is_buggy_cephfs(int fd) {
+ struct statfs s;
+
+ if (-1 == fstatfs(fd, &s))
+ return 0;
+
+ if (s.f_type != /* CephFS */ 0xC36400)
+ return 0;
+
+ return uv__kernel_version() < /* 4.20.0 */ 0x041400;
+}
+
+
+static int uv__is_cifs_or_smb(int fd) {
+ struct statfs s;
+
+ if (-1 == fstatfs(fd, &s))
+ return 0;
+
+ switch ((unsigned) s.f_type) {
+ case 0x0000517Bu: /* SMB */
+ case 0xFE534D42u: /* SMB2 */
+ case 0xFF534D42u: /* CIFS */
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static ssize_t uv__fs_try_copy_file_range(int in_fd, off_t* off,
+ int out_fd, size_t len) {
+ static int no_copy_file_range_support;
+ ssize_t r;
+
+ if (uv__load_relaxed(&no_copy_file_range_support)) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ r = uv__fs_copy_file_range(in_fd, off, out_fd, NULL, len, 0);
+
+ if (r != -1)
+ return r;
+
+ switch (errno) {
+ case EACCES:
+ /* Pre-4.20 kernels have a bug where CephFS uses the RADOS
+ * copy-from command when it shouldn't.
+ */
+ if (uv__is_buggy_cephfs(in_fd))
+ errno = ENOSYS; /* Use fallback. */
+ break;
+ case ENOSYS:
+ uv__store_relaxed(&no_copy_file_range_support, 1);
+ break;
+ case EPERM:
+ /* It's been reported that CIFS spuriously fails.
+ * Consider it a transient error.
+ */
+ if (uv__is_cifs_or_smb(out_fd))
+ errno = ENOSYS; /* Use fallback. */
+ break;
+ case ENOTSUP:
+ case EXDEV:
+ /* ENOTSUP - it could work on another file system type.
+ * EXDEV - it will not work when in_fd and out_fd are not on the same
+ * mounted filesystem (pre Linux 5.3)
+ */
+ errno = ENOSYS; /* Use fallback. */
+ break;
+ }
+
+ return -1;
+}
+
+#endif /* __linux__ */
+
+
static ssize_t uv__fs_sendfile(uv_fs_t* req) {
int in_fd;
int out_fd;
@@ -908,29 +1035,22 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
{
off_t off;
ssize_t r;
+ size_t len;
+ int try_sendfile;
off = req->off;
+ len = req->bufsml[0].len;
#ifdef __linux__
- {
- static int copy_file_range_support = 1;
-
- if (copy_file_range_support) {
- r = uv__fs_copy_file_range(in_fd, NULL, out_fd, &off, req->bufsml[0].len, 0);
-
- if (r == -1 && errno == ENOSYS) {
- errno = 0;
- copy_file_range_support = 0;
- } else {
- goto ok;
- }
- }
- }
+ r = uv__fs_try_copy_file_range(in_fd, &off, out_fd, len);
+ try_sendfile = (r == -1 && errno == ENOSYS);
+#else
+ try_sendfile = 1;
#endif
- r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
+ if (try_sendfile)
+ r = sendfile(out_fd, in_fd, &off, len);
-ok:
/* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
* it still writes out data. Fortunately, we can detect it by checking if
* the offset has been updated.
@@ -1020,9 +1140,6 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|| defined(_AIX71) \
|| defined(__sun) \
|| defined(__HAIKU__)
- /* utimesat() has nanosecond resolution but we stick to microseconds
- * for the sake of consistency with other platforms.
- */
struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime);
@@ -1217,22 +1334,15 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
err = UV__ERR(errno);
#ifdef __linux__
+ /* fchmod() on CIFS shares always fails with EPERM unless the share is
+ * mounted with "noperm". As fchmod() is a meaningless operation on such
+ * shares anyway, detect that condition and squelch the error.
+ */
if (err != UV_EPERM)
goto out;
- {
- struct statfs s;
-
- /* fchmod() on CIFS shares always fails with EPERM unless the share is
- * mounted with "noperm". As fchmod() is a meaningless operation on such
- * shares anyway, detect that condition and squelch the error.
- */
- if (fstatfs(dstfd, &s) == -1)
- goto out;
-
- if (s.f_type != /* CIFS */ 0xFF534D42u)
- goto out;
- }
+ if (!uv__is_cifs_or_smb(dstfd))
+ goto out;
err = 0;
#else /* !__linux__ */
@@ -1350,7 +1460,8 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
dst->st_birthtim.tv_nsec = src->st_ctimensec;
dst->st_flags = 0;
dst->st_gen = 0;
-#elif !defined(_AIX) && ( \
+#elif !defined(_AIX) && \
+ !defined(__MVS__) && ( \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__OpenBSD__) || \
@@ -1430,8 +1541,9 @@ static int uv__fs_statx(int fd,
case -1:
/* EPERM happens when a seccomp filter rejects the system call.
* Has been observed with libseccomp < 2.3.3 and docker < 18.04.
+ * EOPNOTSUPP is used on DVS exported filesystems
*/
- if (errno != EINVAL && errno != EPERM && errno != ENOSYS)
+ if (errno != EINVAL && errno != EPERM && errno != ENOSYS && errno != EOPNOTSUPP)
return -1;
/* Fall through. */
default:
@@ -1444,12 +1556,12 @@ static int uv__fs_statx(int fd,
return UV_ENOSYS;
}
- buf->st_dev = 256 * statxbuf.stx_dev_major + statxbuf.stx_dev_minor;
+ buf->st_dev = makedev(statxbuf.stx_dev_major, statxbuf.stx_dev_minor);
buf->st_mode = statxbuf.stx_mode;
buf->st_nlink = statxbuf.stx_nlink;
buf->st_uid = statxbuf.stx_uid;
buf->st_gid = statxbuf.stx_gid;
- buf->st_rdev = statxbuf.stx_rdev_major;
+ buf->st_rdev = makedev(statxbuf.stx_rdev_major, statxbuf.stx_rdev_minor);
buf->st_ino = statxbuf.stx_ino;
buf->st_size = statxbuf.stx_size;
buf->st_blksize = statxbuf.stx_blksize;
diff --git a/Utilities/cmlibuv/src/unix/fsevents.c b/Utilities/cmlibuv/src/unix/fsevents.c
index a51f29b..bf4f1f6 100644
--- a/Utilities/cmlibuv/src/unix/fsevents.c
+++ b/Utilities/cmlibuv/src/unix/fsevents.c
@@ -595,8 +595,7 @@ out:
static int uv__fsevents_loop_init(uv_loop_t* loop) {
CFRunLoopSourceContext ctx;
uv__cf_loop_state_t* state;
- pthread_attr_t attr_storage;
- pthread_attr_t* attr;
+ pthread_attr_t attr;
int err;
if (loop->cf_state != NULL)
@@ -641,25 +640,19 @@ static int uv__fsevents_loop_init(uv_loop_t* loop) {
goto fail_signal_source_create;
}
- /* In the unlikely event that pthread_attr_init() fails, create the thread
- * with the default stack size. We'll use a little more address space but
- * that in itself is not a fatal error.
- */
- attr = &attr_storage;
- if (pthread_attr_init(attr))
- attr = NULL;
+ if (pthread_attr_init(&attr))
+ abort();
- if (attr != NULL)
- if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
- abort();
+ if (pthread_attr_setstacksize(&attr, uv__thread_stack_size()))
+ abort();
loop->cf_state = state;
/* uv_thread_t is an alias for pthread_t. */
- err = UV__ERR(pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop));
+ err = UV__ERR(pthread_create(&loop->cf_thread, &attr, uv__cf_loop_runner, loop));
- if (attr != NULL)
- pthread_attr_destroy(attr);
+ if (pthread_attr_destroy(&attr))
+ abort();
if (err)
goto fail_thread_create;
diff --git a/Utilities/cmlibuv/src/unix/getaddrinfo.c b/Utilities/cmlibuv/src/unix/getaddrinfo.c
index d7ca7d1..77337ac 100644
--- a/Utilities/cmlibuv/src/unix/getaddrinfo.c
+++ b/Utilities/cmlibuv/src/unix/getaddrinfo.c
@@ -21,9 +21,6 @@
/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
* include any headers.
*/
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-#endif
#include "uv.h"
#include "internal.h"
diff --git a/Utilities/cmlibuv/src/unix/ibmi.c b/Utilities/cmlibuv/src/unix/ibmi.c
index 73ab02a..580ea1f 100644
--- a/Utilities/cmlibuv/src/unix/ibmi.c
+++ b/Utilities/cmlibuv/src/unix/ibmi.c
@@ -26,7 +26,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <assert.h>
#include <errno.h>
#include <sys/types.h>
@@ -166,7 +165,7 @@ static void iconv_a2e(const char* src, unsigned char dst[], size_t length) {
srclen = strlen(src);
if (srclen > length)
- abort();
+ srclen = length;
for (i = 0; i < srclen; i++)
dst[i] = a2e[src[i]];
/* padding the remaining part with spaces */
@@ -360,6 +359,10 @@ static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
if (rc != 0)
return rc;
+ if (err.bytes_available > 0) {
+ return -1;
+ }
+
/* convert ebcdic loca_adapter_address to ascii first */
iconv_e2a(rcvr.loca_adapter_address, mac_addr,
sizeof(rcvr.loca_adapter_address));
@@ -443,9 +446,42 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0;
if (!address->is_internal) {
- int rc = get_ibmi_physical_address(address->name, &address->phys_addr);
- if (rc != 0)
- r = rc;
+ int rc = -1;
+ size_t name_len = strlen(address->name);
+ /* To get the associated MAC address, we must convert the address to a
+ * line description. Normally, the name field contains the line
+ * description name, but for VLANs it has the VLAN appended with a
+ * period. Since object names can also contain periods and numbers, there
+ * is no way to know if a returned name is for a VLAN or not. eg.
+ * *LIND ETH1.1 and *LIND ETH1, VLAN 1 both have the same name: ETH1.1
+ *
+ * Instead, we apply the same heuristic used by some of the XPF ioctls:
+ * - names > 10 *must* contain a VLAN
+ * - assume names <= 10 do not contain a VLAN and try directly
+ * - if >10 or QDCRLIND returned an error, try to strip off a VLAN
+ * and try again
+ * - if we still get an error or couldn't find a period, leave the MAC as
+ * 00:00:00:00:00:00
+ */
+ if (name_len <= 10) {
+ /* Assume name does not contain a VLAN ID */
+ rc = get_ibmi_physical_address(address->name, &address->phys_addr);
+ }
+
+ if (name_len > 10 || rc != 0) {
+ /* The interface name must contain a VLAN ID suffix. Attempt to strip
+ * it off so we can get the line description to pass to QDCRLIND.
+ */
+ char* temp_name = uv__strdup(address->name);
+ char* dot = strrchr(temp_name, '.');
+ if (dot != NULL) {
+ *dot = '\0';
+ if (strlen(temp_name) <= 10) {
+ rc = get_ibmi_physical_address(temp_name, &address->phys_addr);
+ }
+ }
+ uv__free(temp_name);
+ }
}
address++;
@@ -499,3 +535,4 @@ int uv_get_process_title(char* buffer, size_t size) {
void uv__process_title_cleanup(void) {
}
+
diff --git a/Utilities/cmlibuv/src/unix/internal.h b/Utilities/cmlibuv/src/unix/internal.h
index 444dc85..586ae39 100644
--- a/Utilities/cmlibuv/src/unix/internal.h
+++ b/Utilities/cmlibuv/src/unix/internal.h
@@ -62,6 +62,17 @@
# include <AvailabilityMacros.h>
#endif
+/*
+ * Define common detection for active Thread Sanitizer
+ * - clang uses __has_feature(thread_sanitizer)
+ * - gcc-7+ uses __SANITIZE_THREAD__
+ */
+#if defined(__has_feature)
+# if __has_feature(thread_sanitizer)
+# define __SANITIZE_THREAD__ 1
+# endif
+#endif
+
#if defined(PATH_MAX)
# define UV__PATH_MAX PATH_MAX
#else
@@ -175,9 +186,11 @@ struct uv__stream_queued_fds_s {
defined(__NetBSD__)
#define uv__cloexec uv__cloexec_ioctl
#define uv__nonblock uv__nonblock_ioctl
+#define UV__NONBLOCK_IS_IOCTL 1
#else
#define uv__cloexec uv__cloexec_fcntl
#define uv__nonblock uv__nonblock_fcntl
+#define UV__NONBLOCK_IS_IOCTL 0
#endif
/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute
@@ -256,6 +269,7 @@ int uv__signal_loop_fork(uv_loop_t* loop);
/* platform specific */
uint64_t uv__hrtime(uv_clocktype_t type);
int uv__kqueue_init(uv_loop_t* loop);
+int uv__epoll_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop);
void uv__platform_loop_delete(uv_loop_t* loop);
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
@@ -271,6 +285,7 @@ void uv__prepare_close(uv_prepare_t* handle);
void uv__process_close(uv_process_t* handle);
void uv__stream_close(uv_stream_t* handle);
void uv__tcp_close(uv_tcp_t* handle);
+size_t uv__thread_stack_size(void);
void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
uv_handle_type uv__handle_type(int fd);
@@ -292,12 +307,6 @@ int uv___stream_fd(const uv_stream_t* handle);
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
#endif /* defined(__APPLE__) */
-#ifdef O_NONBLOCK
-# define UV__F_NONBLOCK O_NONBLOCK
-#else
-# define UV__F_NONBLOCK 1
-#endif
-
int uv__make_pipe(int fds[2], int flags);
#if defined(__APPLE__)
@@ -337,7 +346,8 @@ int uv__getsockpeername(const uv_handle_t* handle,
#if defined(__linux__) || \
defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__)
+ defined(__FreeBSD_kernel__) || \
+ defined(__DragonFly__)
#define HAVE_MMSG 1
struct uv__mmsghdr {
struct msghdr msg_hdr;
@@ -350,5 +360,11 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen);
#define HAVE_MMSG 0
#endif
+#if defined(__sun)
+#if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
+size_t strnlen(const char* s, size_t maxlen);
+#endif
+#endif
+
#endif /* UV_UNIX_INTERNAL_H_ */
diff --git a/Utilities/cmlibuv/src/unix/kqueue.c b/Utilities/cmlibuv/src/unix/kqueue.c
index bf183d5..75e9110 100644
--- a/Utilities/cmlibuv/src/unix/kqueue.c
+++ b/Utilities/cmlibuv/src/unix/kqueue.c
@@ -326,6 +326,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (errno != ENOENT)
abort();
}
+ if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
+ revents |= UV__POLLRDHUP;
}
if (ev->filter == EV_OOBAND) {
@@ -359,9 +361,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (ev->flags & EV_ERROR)
revents |= POLLERR;
- if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
- revents |= UV__POLLRDHUP;
-
if (revents == 0)
continue;
diff --git a/Utilities/cmlibuv/src/unix/linux-core.c b/Utilities/cmlibuv/src/unix/linux-core.c
index 4db2f05..7b041e6 100644
--- a/Utilities/cmlibuv/src/unix/linux-core.c
+++ b/Utilities/cmlibuv/src/unix/linux-core.c
@@ -45,6 +45,10 @@
#define HAVE_IFADDRS_H 1
+# if defined(__ANDROID_API__) && __ANDROID_API__ < 24
+# undef HAVE_IFADDRS_H
+#endif
+
#ifdef __UCLIBC__
# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
# undef HAVE_IFADDRS_H
@@ -52,11 +56,7 @@
#endif
#ifdef HAVE_IFADDRS_H
-# if defined(__ANDROID__)
-# include "uv/android-ifaddrs.h"
-# else
-# include <ifaddrs.h>
-# endif
+# include <ifaddrs.h>
# include <sys/socket.h>
# include <net/ethernet.h>
# include <netpacket/packet.h>
@@ -82,29 +82,12 @@ static int read_times(FILE* statfile_fp,
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
static uint64_t read_cpufreq(unsigned int cpunum);
-
int uv__platform_loop_init(uv_loop_t* loop) {
- int fd;
- fd = epoll_create1(O_CLOEXEC);
-
- /* epoll_create1() can fail either because it's not implemented (old kernel)
- * or because it doesn't understand the O_CLOEXEC flag.
- */
- if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
- fd = epoll_create(256);
-
- if (fd != -1)
- uv__cloexec(fd, 1);
- }
-
- loop->backend_fd = fd;
+
loop->inotify_fd = -1;
loop->inotify_watchers = NULL;
- if (fd == -1)
- return UV__ERR(errno);
-
- return 0;
+ return uv__epoll_init(loop);
}
@@ -134,380 +117,6 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
-void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
- struct epoll_event* events;
- struct epoll_event dummy;
- uintptr_t i;
- uintptr_t nfds;
-
- assert(loop->watchers != NULL);
- assert(fd >= 0);
-
- events = (struct epoll_event*) loop->watchers[loop->nwatchers];
- nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
- if (events != NULL)
- /* Invalidate events with same file descriptor */
- for (i = 0; i < nfds; i++)
- if (events[i].data.fd == fd)
- events[i].data.fd = -1;
-
- /* Remove the file descriptor from the epoll.
- * This avoids a problem where the same file description remains open
- * in another process, causing repeated junk epoll events.
- *
- * We pass in a dummy epoll_event, to work around a bug in old kernels.
- */
- if (loop->backend_fd >= 0) {
- /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
- * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
- */
- memset(&dummy, 0, sizeof(dummy));
- epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
- }
-}
-
-
-int uv__io_check_fd(uv_loop_t* loop, int fd) {
- struct epoll_event e;
- int rc;
-
- memset(&e, 0, sizeof(e));
- e.events = POLLIN;
- e.data.fd = -1;
-
- rc = 0;
- if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
- if (errno != EEXIST)
- rc = UV__ERR(errno);
-
- if (rc == 0)
- if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
- abort();
-
- return rc;
-}
-
-
-void uv__io_poll(uv_loop_t* loop, int timeout) {
- /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
- * effectively infinite on 32 bits architectures. To avoid blocking
- * indefinitely, we cap the timeout and poll again if necessary.
- *
- * Note that "30 minutes" is a simplification because it depends on
- * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
- * that being the largest value I have seen in the wild (and only once.)
- */
- static const int max_safe_timeout = 1789569;
- static int no_epoll_pwait_cached;
- static int no_epoll_wait_cached;
- int no_epoll_pwait;
- int no_epoll_wait;
- struct epoll_event events[1024];
- struct epoll_event* pe;
- struct epoll_event e;
- int real_timeout;
- QUEUE* q;
- uv__io_t* w;
- sigset_t sigset;
- uint64_t sigmask;
- uint64_t base;
- int have_signals;
- int nevents;
- int count;
- int nfds;
- int fd;
- int op;
- int i;
- int user_timeout;
- int reset_timeout;
-
- if (loop->nfds == 0) {
- assert(QUEUE_EMPTY(&loop->watcher_queue));
- return;
- }
-
- memset(&e, 0, sizeof(e));
-
- while (!QUEUE_EMPTY(&loop->watcher_queue)) {
- q = QUEUE_HEAD(&loop->watcher_queue);
- QUEUE_REMOVE(q);
- QUEUE_INIT(q);
-
- w = QUEUE_DATA(q, uv__io_t, watcher_queue);
- assert(w->pevents != 0);
- assert(w->fd >= 0);
- assert(w->fd < (int) loop->nwatchers);
-
- e.events = w->pevents;
- e.data.fd = w->fd;
-
- if (w->events == 0)
- op = EPOLL_CTL_ADD;
- else
- op = EPOLL_CTL_MOD;
-
- /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
- * events, skip the syscall and squelch the events after epoll_wait().
- */
- if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
- if (errno != EEXIST)
- abort();
-
- assert(op == EPOLL_CTL_ADD);
-
- /* We've reactivated a file descriptor that's been watched before. */
- if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
- abort();
- }
-
- w->events = w->pevents;
- }
-
- sigmask = 0;
- if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGPROF);
- sigmask |= 1 << (SIGPROF - 1);
- }
-
- assert(timeout >= -1);
- base = loop->time;
- count = 48; /* Benchmarks suggest this gives the best throughput. */
- real_timeout = timeout;
-
- if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
- reset_timeout = 1;
- user_timeout = timeout;
- timeout = 0;
- } else {
- reset_timeout = 0;
- user_timeout = 0;
- }
-
- /* You could argue there is a dependency between these two but
- * ultimately we don't care about their ordering with respect
- * to one another. Worst case, we make a few system calls that
- * could have been avoided because another thread already knows
- * they fail with ENOSYS. Hardly the end of the world.
- */
- no_epoll_pwait = uv__load_relaxed(&no_epoll_pwait_cached);
- no_epoll_wait = uv__load_relaxed(&no_epoll_wait_cached);
-
- for (;;) {
- /* Only need to set the provider_entry_time if timeout != 0. The function
- * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
- */
- if (timeout != 0)
- uv__metrics_set_provider_entry_time(loop);
-
- /* See the comment for max_safe_timeout for an explanation of why
- * this is necessary. Executive summary: kernel bug workaround.
- */
- if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
- timeout = max_safe_timeout;
-
- if (sigmask != 0 && no_epoll_pwait != 0)
- if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
- abort();
-
- if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
- nfds = epoll_pwait(loop->backend_fd,
- events,
- ARRAY_SIZE(events),
- timeout,
- &sigset);
- if (nfds == -1 && errno == ENOSYS) {
- uv__store_relaxed(&no_epoll_pwait_cached, 1);
- no_epoll_pwait = 1;
- }
- } else {
- nfds = epoll_wait(loop->backend_fd,
- events,
- ARRAY_SIZE(events),
- timeout);
- if (nfds == -1 && errno == ENOSYS) {
- uv__store_relaxed(&no_epoll_wait_cached, 1);
- no_epoll_wait = 1;
- }
- }
-
- if (sigmask != 0 && no_epoll_pwait != 0)
- if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
- abort();
-
- /* Update loop->time unconditionally. It's tempting to skip the update when
- * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
- * operating system didn't reschedule our process while in the syscall.
- */
- SAVE_ERRNO(uv__update_time(loop));
-
- if (nfds == 0) {
- assert(timeout != -1);
-
- if (reset_timeout != 0) {
- timeout = user_timeout;
- reset_timeout = 0;
- }
-
- if (timeout == -1)
- continue;
-
- if (timeout == 0)
- return;
-
- /* We may have been inside the system call for longer than |timeout|
- * milliseconds so we need to update the timestamp to avoid drift.
- */
- goto update_timeout;
- }
-
- if (nfds == -1) {
- if (errno == ENOSYS) {
- /* epoll_wait() or epoll_pwait() failed, try the other system call. */
- assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
- continue;
- }
-
- if (errno != EINTR)
- abort();
-
- if (reset_timeout != 0) {
- timeout = user_timeout;
- reset_timeout = 0;
- }
-
- if (timeout == -1)
- continue;
-
- if (timeout == 0)
- return;
-
- /* Interrupted by a signal. Update timeout and poll again. */
- goto update_timeout;
- }
-
- have_signals = 0;
- nevents = 0;
-
- {
- /* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */
- union {
- struct epoll_event* events;
- uv__io_t* watchers;
- } x;
-
- x.events = events;
- assert(loop->watchers != NULL);
- loop->watchers[loop->nwatchers] = x.watchers;
- loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
- }
-
- for (i = 0; i < nfds; i++) {
- pe = events + i;
- fd = pe->data.fd;
-
- /* Skip invalidated events, see uv__platform_invalidate_fd */
- if (fd == -1)
- continue;
-
- assert(fd >= 0);
- assert((unsigned) fd < loop->nwatchers);
-
- w = loop->watchers[fd];
-
- if (w == NULL) {
- /* File descriptor that we've stopped watching, disarm it.
- *
- * Ignore all errors because we may be racing with another thread
- * when the file descriptor is closed.
- */
- epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
- continue;
- }
-
- /* Give users only events they're interested in. Prevents spurious
- * callbacks when previous callback invocation in this loop has stopped
- * the current watcher. Also, filters out events that users has not
- * requested us to watch.
- */
- pe->events &= w->pevents | POLLERR | POLLHUP;
-
- /* Work around an epoll quirk where it sometimes reports just the
- * EPOLLERR or EPOLLHUP event. In order to force the event loop to
- * move forward, we merge in the read/write events that the watcher
- * is interested in; uv__read() and uv__write() will then deal with
- * the error or hangup in the usual fashion.
- *
- * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
- * reads the available data, calls uv_read_stop(), then sometime later
- * calls uv_read_start() again. By then, libuv has forgotten about the
- * hangup and the kernel won't report EPOLLIN again because there's
- * nothing left to read. If anything, libuv is to blame here. The
- * current hack is just a quick bandaid; to properly fix it, libuv
- * needs to remember the error/hangup event. We should get that for
- * free when we switch over to edge-triggered I/O.
- */
- if (pe->events == POLLERR || pe->events == POLLHUP)
- pe->events |=
- w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
-
- if (pe->events != 0) {
- /* Run signal watchers last. This also affects child process watchers
- * because those are implemented in terms of signal watchers.
- */
- if (w == &loop->signal_io_watcher) {
- have_signals = 1;
- } else {
- uv__metrics_update_idle_time(loop);
- w->cb(loop, w, pe->events);
- }
-
- nevents++;
- }
- }
-
- if (reset_timeout != 0) {
- timeout = user_timeout;
- reset_timeout = 0;
- }
-
- if (have_signals != 0) {
- uv__metrics_update_idle_time(loop);
- loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
- }
-
- loop->watchers[loop->nwatchers] = NULL;
- loop->watchers[loop->nwatchers + 1] = NULL;
-
- if (have_signals != 0)
- return; /* Event loop should cycle now so don't poll again. */
-
- if (nevents != 0) {
- if (nfds == ARRAY_SIZE(events) && --count != 0) {
- /* Poll for more events but don't block this time. */
- timeout = 0;
- continue;
- }
- return;
- }
-
- if (timeout == 0)
- return;
-
- if (timeout == -1)
- continue;
-
-update_timeout:
- assert(timeout > 0);
-
- real_timeout -= (loop->time - base);
- if (real_timeout <= 0)
- return;
-
- timeout = real_timeout;
- }
-}
-
uint64_t uv__hrtime(uv_clocktype_t type) {
static clock_t fast_clock_id = -1;
@@ -602,22 +211,53 @@ err:
return UV_EINVAL;
}
+static int uv__slurp(const char* filename, char* buf, size_t len) {
+ ssize_t n;
+ int fd;
+
+ assert(len > 0);
+
+ fd = uv__open_cloexec(filename, O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ do
+ n = read(fd, buf, len - 1);
+ while (n == -1 && errno == EINTR);
+
+ if (uv__close_nocheckstdio(fd))
+ abort();
+
+ if (n < 0)
+ return UV__ERR(errno);
+
+ buf[n] = '\0';
+
+ return 0;
+}
int uv_uptime(double* uptime) {
static volatile int no_clock_boottime;
+ char buf[128];
struct timespec now;
int r;
+ /* Try /proc/uptime first, then fallback to clock_gettime(). */
+
+ if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
+ if (1 == sscanf(buf, "%lf", uptime))
+ return 0;
+
/* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
* (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
* is suspended.
*/
if (no_clock_boottime) {
- retry: r = clock_gettime(CLOCK_MONOTONIC, &now);
+ retry_clock_gettime: r = clock_gettime(CLOCK_MONOTONIC, &now);
}
else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
no_clock_boottime = 1;
- goto retry;
+ goto retry_clock_gettime;
}
if (r)
@@ -709,35 +349,47 @@ static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
}
-/* Also reads the CPU frequency on x86. The other architectures only have
- * a BogoMIPS field, which may not be very accurate.
+/* Also reads the CPU frequency on ppc and x86. The other architectures only
+ * have a BogoMIPS field, which may not be very accurate.
*
* Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
*/
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
+#if defined(__PPC__)
+ static const char model_marker[] = "cpu\t\t: ";
+ static const char speed_marker[] = "clock\t\t: ";
+#else
static const char model_marker[] = "model name\t: ";
static const char speed_marker[] = "cpu MHz\t\t: ";
+#endif
const char* inferred_model;
unsigned int model_idx;
unsigned int speed_idx;
+ unsigned int part_idx;
char buf[1024];
char* model;
FILE* fp;
+ int model_id;
/* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
(void) &model_marker;
(void) &speed_marker;
(void) &speed_idx;
+ (void) &part_idx;
(void) &model;
(void) &buf;
(void) &fp;
+ (void) &model_id;
model_idx = 0;
speed_idx = 0;
+ part_idx = 0;
#if defined(__arm__) || \
defined(__i386__) || \
defined(__mips__) || \
+ defined(__aarch64__) || \
+ defined(__PPC__) || \
defined(__x86_64__)
fp = uv__open_file("/proc/cpuinfo");
if (fp == NULL)
@@ -756,11 +408,96 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
continue;
}
}
-#if defined(__arm__) || defined(__mips__)
+#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
if (model_idx < numcpus) {
#if defined(__arm__)
/* Fallback for pre-3.8 kernels. */
static const char model_marker[] = "Processor\t: ";
+#elif defined(__aarch64__)
+ static const char part_marker[] = "CPU part\t: ";
+
+ /* Adapted from: https://github.com/karelzak/util-linux */
+ struct vendor_part {
+ const int id;
+ const char* name;
+ };
+
+ static const struct vendor_part arm_chips[] = {
+ { 0x811, "ARM810" },
+ { 0x920, "ARM920" },
+ { 0x922, "ARM922" },
+ { 0x926, "ARM926" },
+ { 0x940, "ARM940" },
+ { 0x946, "ARM946" },
+ { 0x966, "ARM966" },
+ { 0xa20, "ARM1020" },
+ { 0xa22, "ARM1022" },
+ { 0xa26, "ARM1026" },
+ { 0xb02, "ARM11 MPCore" },
+ { 0xb36, "ARM1136" },
+ { 0xb56, "ARM1156" },
+ { 0xb76, "ARM1176" },
+ { 0xc05, "Cortex-A5" },
+ { 0xc07, "Cortex-A7" },
+ { 0xc08, "Cortex-A8" },
+ { 0xc09, "Cortex-A9" },
+ { 0xc0d, "Cortex-A17" }, /* Originally A12 */
+ { 0xc0f, "Cortex-A15" },
+ { 0xc0e, "Cortex-A17" },
+ { 0xc14, "Cortex-R4" },
+ { 0xc15, "Cortex-R5" },
+ { 0xc17, "Cortex-R7" },
+ { 0xc18, "Cortex-R8" },
+ { 0xc20, "Cortex-M0" },
+ { 0xc21, "Cortex-M1" },
+ { 0xc23, "Cortex-M3" },
+ { 0xc24, "Cortex-M4" },
+ { 0xc27, "Cortex-M7" },
+ { 0xc60, "Cortex-M0+" },
+ { 0xd01, "Cortex-A32" },
+ { 0xd03, "Cortex-A53" },
+ { 0xd04, "Cortex-A35" },
+ { 0xd05, "Cortex-A55" },
+ { 0xd06, "Cortex-A65" },
+ { 0xd07, "Cortex-A57" },
+ { 0xd08, "Cortex-A72" },
+ { 0xd09, "Cortex-A73" },
+ { 0xd0a, "Cortex-A75" },
+ { 0xd0b, "Cortex-A76" },
+ { 0xd0c, "Neoverse-N1" },
+ { 0xd0d, "Cortex-A77" },
+ { 0xd0e, "Cortex-A76AE" },
+ { 0xd13, "Cortex-R52" },
+ { 0xd20, "Cortex-M23" },
+ { 0xd21, "Cortex-M33" },
+ { 0xd41, "Cortex-A78" },
+ { 0xd42, "Cortex-A78AE" },
+ { 0xd4a, "Neoverse-E1" },
+ { 0xd4b, "Cortex-A78C" },
+ };
+
+ if (strncmp(buf, part_marker, sizeof(part_marker) - 1) == 0) {
+ model = buf + sizeof(part_marker) - 1;
+
+ errno = 0;
+ model_id = strtol(model, NULL, 16);
+ if ((errno != 0) || model_id < 0) {
+ fclose(fp);
+ return UV_EINVAL;
+ }
+
+ for (part_idx = 0; part_idx < ARRAY_SIZE(arm_chips); part_idx++) {
+ if (model_id == arm_chips[part_idx].id) {
+ model = uv__strdup(arm_chips[part_idx].name);
+ if (model == NULL) {
+ fclose(fp);
+ return UV_ENOMEM;
+ }
+ ci[model_idx++].model = model;
+ break;
+ }
+ }
+ }
#else /* defined(__mips__) */
static const char model_marker[] = "cpu model\t\t: ";
#endif
@@ -775,18 +512,18 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
continue;
}
}
-#else /* !__arm__ && !__mips__ */
+#else /* !__arm__ && !__mips__ && !__aarch64__ */
if (speed_idx < numcpus) {
if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
continue;
}
}
-#endif /* __arm__ || __mips__ */
+#endif /* __arm__ || __mips__ || __aarch64__ */
}
fclose(fp);
-#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */
+#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ || __aarch__ */
/* Now we want to make sure that all the models contain *something* because
* it's not safe to leave them as null. Copy the last entry unless there
@@ -824,9 +561,9 @@ static int read_times(FILE* statfile_fp,
char buf[1024];
ticks = (unsigned int)sysconf(_SC_CLK_TCK);
- multiplier = ((uint64_t)1000L / ticks);
assert(ticks != (unsigned int) -1);
assert(ticks != 0);
+ multiplier = ((uint64_t)1000L / ticks);
rewind(statfile_fp);
@@ -1025,32 +762,6 @@ void uv__set_process_title(const char* title) {
}
-static int uv__slurp(const char* filename, char* buf, size_t len) {
- ssize_t n;
- int fd;
-
- assert(len > 0);
-
- fd = uv__open_cloexec(filename, O_RDONLY);
- if (fd < 0)
- return fd;
-
- do
- n = read(fd, buf, len - 1);
- while (n == -1 && errno == EINTR);
-
- if (uv__close_nocheckstdio(fd))
- abort();
-
- if (n < 0)
- return UV__ERR(errno);
-
- buf[n] = '\0';
-
- return 0;
-}
-
-
static uint64_t uv__read_proc_meminfo(const char* what) {
uint64_t rc;
char* p;
@@ -1077,7 +788,7 @@ uint64_t uv_get_free_memory(void) {
struct sysinfo info;
uint64_t rc;
- rc = uv__read_proc_meminfo("MemFree:");
+ rc = uv__read_proc_meminfo("MemAvailable:");
if (rc != 0)
return rc;
diff --git a/Utilities/cmlibuv/src/unix/linux-inotify.c b/Utilities/cmlibuv/src/unix/linux-inotify.c
index 42b601a..c1bd260 100644
--- a/Utilities/cmlibuv/src/unix/linux-inotify.c
+++ b/Utilities/cmlibuv/src/unix/linux-inotify.c
@@ -178,7 +178,7 @@ static void uv__inotify_read(uv_loop_t* loop,
/* needs to be large enough for sizeof(inotify_event) + strlen(path) */
char buf[4096];
- while (1) {
+ for (;;) {
do
size = read(loop->inotify_fd, buf, sizeof(buf));
while (size == -1 && errno == EINTR);
diff --git a/Utilities/cmlibuv/src/unix/linux-syscalls.c b/Utilities/cmlibuv/src/unix/linux-syscalls.c
index 44daaf1..5071cd5 100644
--- a/Utilities/cmlibuv/src/unix/linux-syscalls.c
+++ b/Utilities/cmlibuv/src/unix/linux-syscalls.c
@@ -194,37 +194,37 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
-#if defined(__NR_preadv)
- return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
-#else
+#if !defined(__NR_preadv) || defined(__ANDROID_API__) && __ANDROID_API__ < 24
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#endif
}
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
-#if defined(__NR_pwritev)
- return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
-#else
+#if !defined(__NR_pwritev) || defined(__ANDROID_API__) && __ANDROID_API__ < 24
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
#endif
}
int uv__dup3(int oldfd, int newfd, int flags) {
-#if defined(__NR_dup3)
- return syscall(__NR_dup3, oldfd, newfd, flags);
-#else
+#if !defined(__NR_dup3) || defined(__ANDROID_API__) && __ANDROID_API__ < 21
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_dup3, oldfd, newfd, flags);
#endif
}
ssize_t
uv__fs_copy_file_range(int fd_in,
- ssize_t* off_in,
+ off_t* off_in,
int fd_out,
- ssize_t* off_out,
+ off_t* off_out,
size_t len,
unsigned int flags)
{
@@ -247,21 +247,18 @@ int uv__statx(int dirfd,
int flags,
unsigned int mask,
struct uv__statx* statxbuf) {
- /* __NR_statx make Android box killed by SIGSYS.
- * That looks like a seccomp2 sandbox filter rejecting the system call.
- */
-#if defined(__NR_statx) && !defined(__ANDROID__)
- return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
-#else
+#if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
#endif
}
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
-#if defined(__NR_getrandom)
- return syscall(__NR_getrandom, buf, buflen, flags);
-#else
+#if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28
return errno = ENOSYS, -1;
+#else
+ return syscall(__NR_getrandom, buf, buflen, flags);
#endif
}
diff --git a/Utilities/cmlibuv/src/unix/linux-syscalls.h b/Utilities/cmlibuv/src/unix/linux-syscalls.h
index 761ff32..b4d9082 100644
--- a/Utilities/cmlibuv/src/unix/linux-syscalls.h
+++ b/Utilities/cmlibuv/src/unix/linux-syscalls.h
@@ -22,9 +22,6 @@
#ifndef UV_LINUX_SYSCALL_H_
#define UV_LINUX_SYSCALL_H_
-#undef _GNU_SOURCE
-#define _GNU_SOURCE
-
#include <stdint.h>
#include <signal.h>
#include <sys/types.h>
@@ -66,9 +63,9 @@ ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset)
int uv__dup3(int oldfd, int newfd, int flags);
ssize_t
uv__fs_copy_file_range(int fd_in,
- ssize_t* off_in,
+ off_t* off_in,
int fd_out,
- ssize_t* off_out,
+ off_t* off_out,
size_t len,
unsigned int flags);
int uv__statx(int dirfd,
diff --git a/Utilities/cmlibuv/src/unix/os390-proctitle.c b/Utilities/cmlibuv/src/unix/os390-proctitle.c
new file mode 100644
index 0000000..ccda97c
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/os390-proctitle.c
@@ -0,0 +1,136 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static uv_mutex_t process_title_mutex;
+static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
+static char* process_title = NULL;
+static void* args_mem = NULL;
+
+
+static void init_process_title_mutex_once(void) {
+ uv_mutex_init(&process_title_mutex);
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ char** new_argv;
+ size_t size;
+ char* s;
+ int i;
+
+ if (argc <= 0)
+ return argv;
+
+ /* Calculate how much memory we need for the argv strings. */
+ size = 0;
+ for (i = 0; i < argc; i++)
+ size += strlen(argv[i]) + 1;
+
+ /* Add space for the argv pointers. */
+ size += (argc + 1) * sizeof(char*);
+
+ new_argv = uv__malloc(size);
+ if (new_argv == NULL)
+ return argv;
+
+ /* Copy over the strings and set up the pointer table. */
+ s = (char*) &new_argv[argc + 1];
+ for (i = 0; i < argc; i++) {
+ size = strlen(argv[i]) + 1;
+ memcpy(s, argv[i], size);
+ new_argv[i] = s;
+ s += size;
+ }
+ new_argv[i] = NULL;
+
+ args_mem = new_argv;
+ process_title = uv__strdup(argv[0]);
+
+ return new_argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ char* new_title;
+
+ /* If uv_setup_args wasn't called or failed, we can't continue. */
+ if (args_mem == NULL)
+ return UV_ENOBUFS;
+
+ /* We cannot free this pointer when libuv shuts down,
+ * the process may still be using it.
+ */
+ new_title = uv__strdup(title);
+ if (new_title == NULL)
+ return UV_ENOMEM;
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ if (process_title != NULL)
+ uv__free(process_title);
+
+ process_title = new_title;
+
+ uv_mutex_unlock(&process_title_mutex);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ size_t len;
+
+ if (buffer == NULL || size == 0)
+ return UV_EINVAL;
+
+ /* If uv_setup_args wasn't called or failed, we can't continue. */
+ if (args_mem == NULL || process_title == NULL)
+ return UV_ENOBUFS;
+
+ uv_once(&process_title_mutex_once, init_process_title_mutex_once);
+ uv_mutex_lock(&process_title_mutex);
+
+ len = strlen(process_title);
+
+ if (size <= len) {
+ uv_mutex_unlock(&process_title_mutex);
+ return UV_ENOBUFS;
+ }
+
+ strcpy(buffer, process_title);
+
+ uv_mutex_unlock(&process_title_mutex);
+
+ return 0;
+}
+
+
+void uv__process_title_cleanup(void) {
+ uv__free(args_mem); /* Keep valgrind happy. */
+ args_mem = NULL;
+}
diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.c b/Utilities/cmlibuv/src/unix/os390-syscalls.c
index 491e950..a741127 100644
--- a/Utilities/cmlibuv/src/unix/os390-syscalls.c
+++ b/Utilities/cmlibuv/src/unix/os390-syscalls.c
@@ -27,12 +27,6 @@
#include <termios.h>
#include <sys/msg.h>
-#define CW_INTRPT 1
-#define CW_CONDVAR 32
-
-#pragma linkage(BPX4CTW, OS)
-#pragma linkage(BPX1CTW, OS)
-
static QUEUE global_epoll_queue;
static uv_mutex_t global_epoll_lock;
static uv_once_t once = UV_ONCE_INIT;
@@ -55,7 +49,7 @@ int scandir(const char* maindir, struct dirent*** namelist,
if (!mdir)
return -1;
- while (1) {
+ for (;;) {
dirent = readdir(mdir);
if (!dirent)
break;
@@ -142,6 +136,11 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
}
+void uv__os390_cleanup(void) {
+ msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, NULL);
+}
+
+
static void init_message_queue(uv__os390_epoll* lst) {
struct {
long int header;
@@ -381,46 +380,6 @@ void epoll_queue_close(uv__os390_epoll* lst) {
}
-int nanosleep(const struct timespec* req, struct timespec* rem) {
- unsigned nano;
- unsigned seconds;
- unsigned events;
- unsigned secrem;
- unsigned nanorem;
- int rv;
- int err;
- int rsn;
-
- nano = (int)req->tv_nsec;
- seconds = req->tv_sec;
- events = CW_CONDVAR | CW_INTRPT;
- secrem = 0;
- nanorem = 0;
-
-#if defined(_LP64)
- BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
-#else
- BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
-#endif
-
- /* Don't clobber errno unless BPX1CTW/BPX4CTW errored.
- * Don't leak EAGAIN, that just means the timeout expired.
- */
- if (rv == -1)
- if (err == EAGAIN)
- rv = 0;
- else
- errno = err;
-
- if (rem != NULL && (rv == 0 || err == EINTR)) {
- rem->tv_nsec = nanorem;
- rem->tv_sec = secrem;
- }
-
- return rv;
-}
-
-
char* mkdtemp(char* path) {
static const char* tempchars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@@ -550,15 +509,6 @@ ssize_t os390_readlink(const char* path, char* buf, size_t len) {
}
-size_t strnlen(const char* str, size_t maxlen) {
- char* p = memchr(str, 0, maxlen);
- if (p == NULL)
- return maxlen;
- else
- return p - str;
-}
-
-
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
UNREACHABLE();
}
diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.h b/Utilities/cmlibuv/src/unix/os390-syscalls.h
index 86416bb..9f50417 100644
--- a/Utilities/cmlibuv/src/unix/os390-syscalls.h
+++ b/Utilities/cmlibuv/src/unix/os390-syscalls.h
@@ -28,6 +28,7 @@
#include <dirent.h>
#include <poll.h>
#include <pthread.h>
+#include "zos-base.h"
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
@@ -57,7 +58,6 @@ int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, i
int epoll_file_close(int fd);
/* utility functions */
-int nanosleep(const struct timespec* req, struct timespec* rem);
int scandir(const char* maindir, struct dirent*** namelist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **,
@@ -70,5 +70,6 @@ int sem_destroy(UV_PLATFORM_SEM_T* semid);
int sem_post(UV_PLATFORM_SEM_T* semid);
int sem_trywait(UV_PLATFORM_SEM_T* semid);
int sem_wait(UV_PLATFORM_SEM_T* semid);
+void uv__os390_cleanup(void);
#endif /* UV_OS390_SYSCALL_H_ */
diff --git a/Utilities/cmlibuv/src/unix/os390.c b/Utilities/cmlibuv/src/unix/os390.c
index 3bb4426..bf0448b 100644
--- a/Utilities/cmlibuv/src/unix/os390.c
+++ b/Utilities/cmlibuv/src/unix/os390.c
@@ -28,6 +28,8 @@
#include <builtins.h>
#include <termios.h>
#include <sys/msg.h>
+#include <sys/resource.h>
+#include "zos-base.h"
#if defined(__clang__)
#include "csrsic.h"
#else
@@ -61,12 +63,6 @@
/* Address of the rsm control and enumeration area. */
#define CVTRCEP_OFFSET 0x490
-/*
- Number of frames currently available to system.
- Excluded are frames backing perm storage, frames offline, and bad frames.
-*/
-#define RCEPOOL_OFFSET 0x004
-
/* Total number of frames currently on all available frame queues. */
#define RCEAFC_OFFSET 0x088
@@ -144,102 +140,8 @@ uint64_t uv__hrtime(uv_clocktype_t type) {
}
-/*
- Get the exe path using the thread entry information
- in the address space.
-*/
-static int getexe(const int pid, char* buf, size_t len) {
- struct {
- int pid;
- int thid[2];
- char accesspid;
- char accessthid;
- char asid[2];
- char loginname[8];
- char flag;
- char len;
- } Input_data;
-
- union {
- struct {
- char gthb[4];
- int pid;
- int thid[2];
- char accesspid;
- char accessthid[3];
- int lenused;
- int offsetProcess;
- int offsetConTTY;
- int offsetPath;
- int offsetCommand;
- int offsetFileData;
- int offsetThread;
- } Output_data;
- char buf[2048];
- } Output_buf;
-
- struct Output_path_type {
- char gthe[4];
- short int len;
- char path[1024];
- };
-
- int Input_length;
- int Output_length;
- void* Input_address;
- void* Output_address;
- struct Output_path_type* Output_path;
- int rv;
- int rc;
- int rsn;
-
- Input_length = PGTH_LEN;
- Output_length = sizeof(Output_buf);
- Output_address = &Output_buf;
- Input_address = &Input_data;
- memset(&Input_data, 0, sizeof Input_data);
- Input_data.flag |= PGTHAPATH;
- Input_data.pid = pid;
- Input_data.accesspid = PGTH_CURRENT;
-
-#ifdef _LP64
- BPX4GTH(&Input_length,
- &Input_address,
- &Output_length,
- &Output_address,
- &rv,
- &rc,
- &rsn);
-#else
- BPX1GTH(&Input_length,
- &Input_address,
- &Output_length,
- &Output_address,
- &rv,
- &rc,
- &rsn);
-#endif
-
- if (rv == -1) {
- errno = rc;
- return -1;
- }
-
- /* Check highest byte to ensure data availability */
- assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
-
- /* Get the offset from the lowest 3 bytes */
- Output_path = (struct Output_path_type*) ((char*) (&Output_buf) +
- (Output_buf.Output_data.offsetPath & 0x00FFFFFF));
-
- if (Output_path->len >= len) {
- errno = ENOBUFS;
- return -1;
- }
-
- uv__strscpy(buf, Output_path->path, len);
-
- return 0;
+static int getexe(char* buf, size_t len) {
+ return uv__strscpy(buf, __getargv()[0], len);
}
@@ -259,8 +161,7 @@ int uv_exepath(char* buffer, size_t* size) {
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
- pid = getpid();
- res = getexe(pid, args, sizeof(args));
+ res = getexe(args, sizeof(args));
if (res < 0)
return UV_EINVAL;
@@ -275,25 +176,25 @@ uint64_t uv_get_free_memory(void) {
data_area_ptr rcep = {0};
cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
- freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4;
+ freeram = (uint64_t)*((uint32_t*)(rcep.deref + RCEAFC_OFFSET)) * 4096;
return freeram;
}
uint64_t uv_get_total_memory(void) {
- uint64_t totalram;
-
- data_area_ptr cvt = {0};
- data_area_ptr rcep = {0};
- cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
- rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
- totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4;
- return totalram;
+ /* Use CVTRLSTG to get the size of actual real storage online at IPL in K. */
+ return (uint64_t)((int)((char *__ptr32 *__ptr32 *)0)[4][214]) * 1024;
}
uint64_t uv_get_constrained_memory(void) {
- return 0; /* Memory constraints are unknown. */
+ struct rlimit rl;
+
+ /* RLIMIT_MEMLIMIT return value is in megabytes rather than bytes. */
+ if (getrlimit(RLIMIT_MEMLIMIT, &rl) == 0)
+ return rl.rlim_cur * 1024 * 1024;
+
+ return 0; /* There is no memory limit set. */
}
@@ -733,6 +634,10 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
/* Some event that we are not interested in. */
return 0;
+ /* `__rfim_utok` is treated as text when it should be treated as binary while
+ * running in ASCII mode, resulting in an unwanted autoconversion.
+ */
+ __a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok));
handle = *(uv_fs_event_t**)(msg.__rfim_utok);
handle->cb(handle, uv__basename_r(handle->path), events, 0);
return 1;
@@ -959,9 +864,6 @@ update_timeout:
}
}
-void uv__set_process_title(const char* title) {
- /* do nothing */
-}
int uv__io_fork(uv_loop_t* loop) {
/*
diff --git a/Utilities/cmlibuv/src/unix/pipe.c b/Utilities/cmlibuv/src/unix/pipe.c
index 52a8fd5..fc7c4ea 100644
--- a/Utilities/cmlibuv/src/unix/pipe.c
+++ b/Utilities/cmlibuv/src/unix/pipe.c
@@ -377,3 +377,57 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
return r != -1 ? 0 : UV__ERR(errno);
}
+
+
+int uv_pipe(uv_os_fd_t fds[2], int read_flags, int write_flags) {
+ uv_os_fd_t temp[2];
+ int err;
+#if defined(__FreeBSD__) || defined(__linux__)
+ int flags = O_CLOEXEC;
+
+ if ((read_flags & UV_NONBLOCK_PIPE) && (write_flags & UV_NONBLOCK_PIPE))
+ flags |= UV_FS_O_NONBLOCK;
+
+ if (pipe2(temp, flags))
+ return UV__ERR(errno);
+
+ if (flags & UV_FS_O_NONBLOCK) {
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+ }
+#else
+ if (pipe(temp))
+ return UV__ERR(errno);
+
+ if ((err = uv__cloexec(temp[0], 1)))
+ goto fail;
+
+ if ((err = uv__cloexec(temp[1], 1)))
+ goto fail;
+#endif
+
+ if (read_flags & UV_NONBLOCK_PIPE)
+ if ((err = uv__nonblock(temp[0], 1)))
+ goto fail;
+
+ if (write_flags & UV_NONBLOCK_PIPE)
+ if ((err = uv__nonblock(temp[1], 1)))
+ goto fail;
+
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+
+fail:
+ uv__close(temp[0]);
+ uv__close(temp[1]);
+ return err;
+}
+
+
+int uv__make_pipe(int fds[2], int flags) {
+ return uv_pipe(fds,
+ flags & UV_NONBLOCK_PIPE,
+ flags & UV_NONBLOCK_PIPE);
+}
diff --git a/Utilities/cmlibuv/src/unix/poll.c b/Utilities/cmlibuv/src/unix/poll.c
index 3d5022b..7a12e2d 100644
--- a/Utilities/cmlibuv/src/unix/poll.c
+++ b/Utilities/cmlibuv/src/unix/poll.c
@@ -79,9 +79,10 @@ int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
* Workaround for e.g. kqueue fds not supporting ioctls.
*/
err = uv__nonblock(fd, 1);
+#if UV__NONBLOCK_IS_IOCTL
if (err == UV_ENOTTY)
- if (uv__nonblock == uv__nonblock_ioctl)
- err = uv__nonblock_fcntl(fd, 1);
+ err = uv__nonblock_fcntl(fd, 1);
+#endif
if (err)
return err;
@@ -116,12 +117,21 @@ int uv_poll_stop(uv_poll_t* handle) {
int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
+ uv__io_t** watchers;
+ uv__io_t* w;
int events;
assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
UV_PRIORITIZED)) == 0);
assert(!uv__is_closing(handle));
+ watchers = handle->loop->watchers;
+ w = &handle->io_watcher;
+
+ if (uv__fd_exists(handle->loop, w->fd))
+ if (watchers[w->fd] != w)
+ return UV_EEXIST;
+
uv__poll_stop(handle);
if (pevents == 0)
diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c
index 08aa2f3..2af2088 100644
--- a/Utilities/cmlibuv/src/unix/process.c
+++ b/Utilities/cmlibuv/src/unix/process.c
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
+#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -45,6 +46,10 @@ extern char **environ;
# include <grp.h>
#endif
+#if defined(__MVS__)
+# include "zos-base.h"
+#endif
+
#ifndef CMAKE_BOOTSTRAP
#if defined(__linux__)
# define uv__cpu_set_t cpu_set_t
@@ -122,68 +127,6 @@ static void uv__chld(uv_signal_t* handle, int signum) {
assert(QUEUE_EMPTY(&pending));
}
-
-static int uv__make_socketpair(int fds[2]) {
-#if defined(__FreeBSD__) || defined(__linux__)
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds))
- return UV__ERR(errno);
-
- return 0;
-#else
- int err;
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
- return UV__ERR(errno);
-
- err = uv__cloexec(fds[0], 1);
- if (err == 0)
- err = uv__cloexec(fds[1], 1);
-
- if (err != 0) {
- uv__close(fds[0]);
- uv__close(fds[1]);
- return UV__ERR(errno);
- }
-
- return 0;
-#endif
-}
-
-
-int uv__make_pipe(int fds[2], int flags) {
-#if defined(__FreeBSD__) || defined(__linux__)
- if (pipe2(fds, flags | O_CLOEXEC))
- return UV__ERR(errno);
-
- return 0;
-#else
- if (pipe(fds))
- return UV__ERR(errno);
-
- if (uv__cloexec(fds[0], 1))
- goto fail;
-
- if (uv__cloexec(fds[1], 1))
- goto fail;
-
- if (flags & UV__F_NONBLOCK) {
- if (uv__nonblock(fds[0], 1))
- goto fail;
-
- if (uv__nonblock(fds[1], 1))
- goto fail;
- }
-
- return 0;
-
-fail:
- uv__close(fds[0]);
- uv__close(fds[1]);
- return UV__ERR(errno);
-#endif
-}
-
-
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success. See also the cleanup section in uv_spawn().
@@ -203,7 +146,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
if (container->data.stream->type != UV_NAMED_PIPE)
return UV_EINVAL;
else
- return uv__make_socketpair(fds);
+ return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0);
case UV_INHERIT_FD:
case UV_INHERIT_STREAM:
@@ -270,6 +213,12 @@ static void uv__write_int(int fd, int val) {
}
+static void uv__write_errno(int error_fd) {
+ uv__write_int(error_fd, UV__ERR(errno));
+ _exit(127);
+}
+
+
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
* avoided. Since this isn't called on those targets, the function
@@ -279,10 +228,9 @@ static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
- sigset_t set;
+ sigset_t signewset;
int close_fd;
int use_fd;
- int err;
int fd;
int n;
#ifndef CMAKE_BOOTSTRAP
@@ -294,6 +242,26 @@ static void uv__process_child_init(const uv_process_options_t* options,
#endif
#endif
+ /* Reset signal disposition first. Use a hard-coded limit because NSIG is not
+ * fixed on Linux: it's either 32, 34 or 64, depending on whether RT signals
+ * are enabled. We are not allowed to touch RT signal handlers, glibc uses
+ * them internally.
+ */
+ for (n = 1; n < 32; n += 1) {
+ if (n == SIGKILL || n == SIGSTOP)
+ continue; /* Can't be changed. */
+
+#if defined(__HAIKU__)
+ if (n == SIGKILLTHR)
+ continue; /* Can't be changed. */
+#endif
+
+ if (SIG_ERR != signal(n, SIG_DFL))
+ continue;
+
+ uv__write_errno(error_fd);
+ }
+
if (options->flags & UV_PROCESS_DETACHED)
setsid();
@@ -306,10 +274,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
if (use_fd < 0 || use_fd >= fd)
continue;
pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
- if (pipes[fd][1] == -1) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if (pipes[fd][1] == -1)
+ uv__write_errno(error_fd);
}
for (fd = 0; fd < stdio_count; fd++) {
@@ -326,10 +292,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
close_fd = use_fd;
- if (use_fd < 0) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if (use_fd < 0)
+ uv__write_errno(error_fd);
}
}
@@ -338,10 +302,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
else
fd = dup2(use_fd, fd);
- if (fd == -1) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if (fd == -1)
+ uv__write_errno(error_fd);
if (fd <= 2)
uv__nonblock_fcntl(fd, 0);
@@ -357,10 +319,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
uv__close(use_fd);
}
- if (options->cwd != NULL && chdir(options->cwd)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if (options->cwd != NULL && chdir(options->cwd))
+ uv__write_errno(error_fd);
if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
/* When dropping privileges from root, the `setgroups` call will
@@ -373,15 +333,11 @@ static void uv__process_child_init(const uv_process_options_t* options,
SAVE_ERRNO(setgroups(0, NULL));
}
- if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid))
+ uv__write_errno(error_fd);
- if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid))
+ uv__write_errno(error_fd);
#ifndef CMAKE_BOOTSTRAP
#if defined(__linux__) || defined(__FreeBSD__)
@@ -409,39 +365,19 @@ static void uv__process_child_init(const uv_process_options_t* options,
environ = options->env;
}
- /* Reset signal disposition. Use a hard-coded limit because NSIG
- * is not fixed on Linux: it's either 32, 34 or 64, depending on
- * whether RT signals are enabled. We are not allowed to touch
- * RT signal handlers, glibc uses them internally.
- */
- for (n = 1; n < 32; n += 1) {
- if (n == SIGKILL || n == SIGSTOP)
- continue; /* Can't be changed. */
+ /* Reset signal mask just before exec. */
+ sigemptyset(&signewset);
+ if (sigprocmask(SIG_SETMASK, &signewset, NULL) != 0)
+ abort();
-#if defined(__HAIKU__)
- if (n == SIGKILLTHR)
- continue; /* Can't be changed. */
+#ifdef __MVS__
+ execvpe(options->file, options->args, environ);
+#else
+ execvp(options->file, options->args);
#endif
- if (SIG_ERR != signal(n, SIG_DFL))
- continue;
-
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
-
- /* Reset signal mask. */
- sigemptyset(&set);
- err = pthread_sigmask(SIG_SETMASK, &set, NULL);
-
- if (err != 0) {
- uv__write_int(error_fd, UV__ERR(err));
- _exit(127);
- }
-
- execvp(options->file, options->args);
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
+ uv__write_errno(error_fd);
+ abort();
}
#endif
@@ -453,6 +389,8 @@ int uv_spawn(uv_loop_t* loop,
/* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
return UV_ENOSYS;
#else
+ sigset_t signewset;
+ sigset_t sigoldset;
int signal_pipe[2] = { -1, -1 };
int pipes_storage[8][2];
int (*pipes)[2];
@@ -541,25 +479,41 @@ int uv_spawn(uv_loop_t* loop,
/* Acquire write lock to prevent opening new fds in worker threads */
uv_rwlock_wrlock(&loop->cloexec_lock);
- pid = fork();
- if (pid == -1) {
+ /* Start the child with most signals blocked, to avoid any issues before we
+ * can reset them, but allow program failures to exit (and not hang). */
+ sigfillset(&signewset);
+ sigdelset(&signewset, SIGKILL);
+ sigdelset(&signewset, SIGSTOP);
+ sigdelset(&signewset, SIGTRAP);
+ sigdelset(&signewset, SIGSEGV);
+ sigdelset(&signewset, SIGBUS);
+ sigdelset(&signewset, SIGILL);
+ sigdelset(&signewset, SIGSYS);
+ sigdelset(&signewset, SIGABRT);
+ if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0)
+ abort();
+
+ pid = fork();
+ if (pid == -1)
err = UV__ERR(errno);
- uv_rwlock_wrunlock(&loop->cloexec_lock);
- uv__close(signal_pipe[0]);
- uv__close(signal_pipe[1]);
- goto error;
- }
- if (pid == 0) {
+ if (pid == 0)
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
+
+ if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0)
abort();
- }
/* Release lock in parent process */
uv_rwlock_wrunlock(&loop->cloexec_lock);
+
uv__close(signal_pipe[1]);
+ if (pid == -1) {
+ uv__close(signal_pipe[0]);
+ goto error;
+ }
+
process->status = 0;
exec_errorno = 0;
do
diff --git a/Utilities/cmlibuv/src/unix/proctitle.c b/Utilities/cmlibuv/src/unix/proctitle.c
index 9ffe5b6..9d1f00d 100644
--- a/Utilities/cmlibuv/src/unix/proctitle.c
+++ b/Utilities/cmlibuv/src/unix/proctitle.c
@@ -84,10 +84,7 @@ char** uv_setup_args(int argc, char** argv) {
}
new_argv[i] = NULL;
- /* argv is not adjacent on z/os, we use just argv[0] on that platform. */
-#ifndef __MVS__
pt.cap = argv[i - 1] + size - argv[0];
-#endif
args_mem = new_argv;
process_title = pt;
@@ -119,6 +116,7 @@ int uv_set_process_title(const char* title) {
memcpy(pt->str, title, len);
memset(pt->str + len, '\0', pt->cap - len);
pt->len = len;
+ uv__set_process_title(pt->str);
uv_mutex_unlock(&process_title_mutex);
diff --git a/Utilities/cmlibuv/src/unix/signal.c b/Utilities/cmlibuv/src/unix/signal.c
index f40a3e5..1133c73 100644
--- a/Utilities/cmlibuv/src/unix/signal.c
+++ b/Utilities/cmlibuv/src/unix/signal.c
@@ -265,7 +265,7 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) {
if (loop->signal_pipefd[0] != -1)
return 0;
- err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
+ err = uv__make_pipe(loop->signal_pipefd, UV_NONBLOCK_PIPE);
if (err)
return err;
diff --git a/Utilities/cmlibuv/src/unix/stream.c b/Utilities/cmlibuv/src/unix/stream.c
index 3b6da8d..52e2b9a 100644
--- a/Utilities/cmlibuv/src/unix/stream.c
+++ b/Utilities/cmlibuv/src/unix/stream.c
@@ -58,20 +58,6 @@ struct uv__stream_select_s {
fd_set* swrite;
size_t swrite_sz;
};
-
-/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
- * EPROTOTYPE can be returned while trying to write to a socket that is
- * shutting down. If we retry the write, we should get the expected EPIPE
- * instead.
- */
-# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE)
-# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
- (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \
- (errno == EMSGSIZE && send_handle != NULL))
-#else
-# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR)
-# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
- (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
#endif /* defined(__APPLE__) */
static void uv__stream_connect(uv_stream_t*);
@@ -164,7 +150,7 @@ static void uv__stream_osx_select(void* arg) {
else
max_fd = s->int_fd;
- while (1) {
+ for (;;) {
/* Terminate on semaphore */
if (uv_sem_trywait(&s->close_sem) == 0)
break;
@@ -195,7 +181,7 @@ static void uv__stream_osx_select(void* arg) {
/* Empty socketpair's buffer in case of interruption */
if (FD_ISSET(s->int_fd, s->sread))
- while (1) {
+ for (;;) {
r = read(s->int_fd, buf, sizeof(buf));
if (r == sizeof(buf))
@@ -799,33 +785,21 @@ static int uv__handle_fd(uv_handle_t* handle) {
}
}
-static void uv__write(uv_stream_t* stream) {
+static int uv__try_write(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle) {
struct iovec* iov;
- QUEUE* q;
- uv_write_t* req;
int iovmax;
int iovcnt;
ssize_t n;
- int err;
-
-start:
-
- assert(uv__stream_fd(stream) >= 0);
-
- if (QUEUE_EMPTY(&stream->write_queue))
- return;
-
- q = QUEUE_HEAD(&stream->write_queue);
- req = QUEUE_DATA(q, uv_write_t, queue);
- assert(req->handle == stream);
/*
* Cast to iovec. We had to have our own uv_buf_t instead of iovec
* because Windows's WSABUF is not an iovec.
*/
- assert(sizeof(uv_buf_t) == sizeof(struct iovec));
- iov = (struct iovec*) &(req->bufs[req->write_index]);
- iovcnt = req->nbufs - req->write_index;
+ iov = (struct iovec*) bufs;
+ iovcnt = nbufs;
iovmax = uv__getiovmax();
@@ -837,8 +811,7 @@ start:
* Now do the actual writev. Note that we've been updating the pointers
* inside the iov each time we write. So there is no need to offset it.
*/
-
- if (req->send_handle) {
+ if (send_handle != NULL) {
int fd_to_send;
struct msghdr msg;
struct cmsghdr *cmsg;
@@ -847,12 +820,10 @@ start:
struct cmsghdr alias;
} scratch;
- if (uv__is_closing(req->send_handle)) {
- err = UV_EBADF;
- goto error;
- }
+ if (uv__is_closing(send_handle))
+ return UV_EBADF;
- fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
+ fd_to_send = uv__handle_fd((uv_handle_t*) send_handle);
memset(&scratch, 0, sizeof(scratch));
@@ -881,45 +852,83 @@ start:
do
n = sendmsg(uv__stream_fd(stream), &msg, 0);
- while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
-
- /* Ensure the handle isn't sent again in case this is a partial write. */
- if (n >= 0)
- req->send_handle = NULL;
+ while (n == -1 && errno == EINTR);
} else {
do
n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
- while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
+ while (n == -1 && errno == EINTR);
}
- if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) {
- err = UV__ERR(errno);
- goto error;
- }
+ if (n >= 0)
+ return n;
- if (n >= 0 && uv__write_req_update(stream, req, n)) {
- uv__write_req_finish(req);
- return; /* TODO(bnoordhuis) Start trying to write the next request. */
- }
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
+ return UV_EAGAIN;
- /* If this is a blocking stream, try again. */
- if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
- goto start;
+#ifdef __APPLE__
+ /* macOS versions 10.10 and 10.15 - and presumbaly 10.11 to 10.14, too -
+ * have a bug where a race condition causes the kernel to return EPROTOTYPE
+ * because the socket isn't fully constructed. It's probably the result of
+ * the peer closing the connection and that is why libuv translates it to
+ * ECONNRESET. Previously, libuv retried until the EPROTOTYPE error went
+ * away but some VPN software causes the same behavior except the error is
+ * permanent, not transient, turning the retry mechanism into an infinite
+ * loop. See https://github.com/libuv/libuv/pull/482.
+ */
+ if (errno == EPROTOTYPE)
+ return UV_ECONNRESET;
+#endif /* __APPLE__ */
- /* We're not done. */
- uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
+ return UV__ERR(errno);
+}
- /* Notify select() thread about state change */
- uv__stream_osx_interrupt_select(stream);
+static void uv__write(uv_stream_t* stream) {
+ QUEUE* q;
+ uv_write_t* req;
+ ssize_t n;
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ for (;;) {
+ if (QUEUE_EMPTY(&stream->write_queue))
+ return;
- return;
+ q = QUEUE_HEAD(&stream->write_queue);
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ assert(req->handle == stream);
+
+ n = uv__try_write(stream,
+ &(req->bufs[req->write_index]),
+ req->nbufs - req->write_index,
+ req->send_handle);
+
+ /* Ensure the handle isn't sent again in case this is a partial write. */
+ if (n >= 0) {
+ req->send_handle = NULL;
+ if (uv__write_req_update(stream, req, n)) {
+ uv__write_req_finish(req);
+ return; /* TODO(bnoordhuis) Start trying to write the next request. */
+ }
+ } else if (n != UV_EAGAIN)
+ break;
+
+ /* If this is a blocking stream, try again. */
+ if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
+ continue;
+
+ /* We're not done. */
+ uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
-error:
- req->error = err;
+ /* Notify select() thread about state change */
+ uv__stream_osx_interrupt_select(stream);
+
+ return;
+ }
+
+ req->error = n;
+ /* XXX(jwn): this must call uv__stream_flush_write_queue(stream, n) here, since we won't generate any more events */
uv__write_req_finish(req);
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
- if (!uv__io_active(&stream->io_watcher, POLLIN))
- uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream);
}
@@ -1002,8 +1011,7 @@ static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
stream->flags |= UV_HANDLE_READ_EOF;
stream->flags &= ~UV_HANDLE_READING;
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
- if (!uv__io_active(&stream->io_watcher, POLLOUT))
- uv__handle_stop(stream);
+ uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream);
stream->read_cb(stream, UV_EOF, buf);
}
@@ -1188,12 +1196,12 @@ static void uv__read(uv_stream_t* stream) {
#endif
} else {
/* Error. User should call uv_close(). */
+ stream->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
stream->read_cb(stream, UV__ERR(errno), &buf);
if (stream->flags & UV_HANDLE_READING) {
stream->flags &= ~UV_HANDLE_READING;
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
- if (!uv__io_active(&stream->io_watcher, POLLOUT))
- uv__handle_stop(stream);
+ uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream);
}
}
@@ -1276,6 +1284,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
req->cb = cb;
stream->shutdown_req = req;
stream->flags |= UV_HANDLE_SHUTTING;
+ stream->flags &= ~UV_HANDLE_WRITABLE;
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream);
@@ -1390,14 +1399,9 @@ static void uv__stream_connect(uv_stream_t* stream) {
}
-int uv_write2(uv_write_t* req,
- uv_stream_t* stream,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_stream_t* send_handle,
- uv_write_cb cb) {
- int empty_queue;
-
+static int uv__check_before_write(uv_stream_t* stream,
+ unsigned int nbufs,
+ uv_stream_t* send_handle) {
assert(nbufs > 0);
assert((stream->type == UV_TCP ||
stream->type == UV_NAMED_PIPE ||
@@ -1410,7 +1414,7 @@ int uv_write2(uv_write_t* req,
if (!(stream->flags & UV_HANDLE_WRITABLE))
return UV_EPIPE;
- if (send_handle) {
+ if (send_handle != NULL) {
if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
return UV_EINVAL;
@@ -1430,6 +1434,22 @@ int uv_write2(uv_write_t* req,
#endif
}
+ return 0;
+}
+
+int uv_write2(uv_write_t* req,
+ uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ int empty_queue;
+ int err;
+
+ err = uv__check_before_write(stream, nbufs, send_handle);
+ if (err < 0)
+ return err;
+
/* It's legal for write_queue_size > 0 even when the write_queue is empty;
* it means there are error-state requests in the write_completed_queue that
* will touch up write_queue_size later, see also uv__write_req_finish().
@@ -1498,81 +1518,43 @@ int uv_write(uv_write_t* req,
}
-void uv_try_write_cb(uv_write_t* req, int status) {
- /* Should not be called */
- abort();
-}
-
-
int uv_try_write(uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs) {
- int r;
- int has_pollout;
- size_t written;
- size_t req_size;
- uv_write_t req;
+ return uv_try_write2(stream, bufs, nbufs, NULL);
+}
+
+
+int uv_try_write2(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle) {
+ int err;
/* Connecting or already writing some data */
if (stream->connect_req != NULL || stream->write_queue_size != 0)
return UV_EAGAIN;
- has_pollout = uv__io_active(&stream->io_watcher, POLLOUT);
-
- r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb);
- if (r != 0)
- return r;
+ err = uv__check_before_write(stream, nbufs, NULL);
+ if (err < 0)
+ return err;
- /* Remove not written bytes from write queue size */
- written = uv__count_bufs(bufs, nbufs);
- if (req.bufs != NULL)
- req_size = uv__write_req_size(&req);
- else
- req_size = 0;
- written -= req_size;
- stream->write_queue_size -= req_size;
-
- /* Unqueue request, regardless of immediateness */
- QUEUE_REMOVE(&req.queue);
- uv__req_unregister(stream->loop, &req);
- if (req.bufs != req.bufsml)
- uv__free(req.bufs);
- req.bufs = NULL;
-
- /* Do not poll for writable, if we wasn't before calling this */
- if (!has_pollout) {
- uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
- uv__stream_osx_interrupt_select(stream);
- }
-
- if (written == 0 && req_size != 0)
- return req.error < 0 ? req.error : UV_EAGAIN;
- else
- return written;
+ return uv__try_write(stream, bufs, nbufs, send_handle);
}
-int uv_read_start(uv_stream_t* stream,
- uv_alloc_cb alloc_cb,
- uv_read_cb read_cb) {
+int uv__read_start(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
stream->type == UV_TTY);
- if (stream->flags & UV_HANDLE_CLOSING)
- return UV_EINVAL;
-
- if (!(stream->flags & UV_HANDLE_READABLE))
- return UV_ENOTCONN;
-
- /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
- * expresses the desired state of the user.
- */
+ /* The UV_HANDLE_READING flag is irrelevant of the state of the stream - it
+ * just expresses the desired state of the user. */
stream->flags |= UV_HANDLE_READING;
+ stream->flags &= ~UV_HANDLE_READ_EOF;
/* TODO: try to do the read inline? */
- /* TODO: keep track of tcp state. If we've gotten a EOF then we should
- * not start the IO watcher.
- */
assert(uv__stream_fd(stream) >= 0);
assert(alloc_cb);
@@ -1593,8 +1575,7 @@ int uv_read_stop(uv_stream_t* stream) {
stream->flags &= ~UV_HANDLE_READING;
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
- if (!uv__io_active(&stream->io_watcher, POLLOUT))
- uv__handle_stop(stream);
+ uv__handle_stop(stream);
uv__stream_osx_interrupt_select(stream);
stream->read_cb = NULL;
diff --git a/Utilities/cmlibuv/src/unix/sunos.c b/Utilities/cmlibuv/src/unix/sunos.c
index 2166e8f..eab2e40 100644
--- a/Utilities/cmlibuv/src/unix/sunos.c
+++ b/Utilities/cmlibuv/src/unix/sunos.c
@@ -869,3 +869,14 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
uv__free(addresses);
}
+
+
+#if !defined(_POSIX_VERSION) || _POSIX_VERSION < 200809L
+size_t strnlen(const char* s, size_t maxlen) {
+ const char* end;
+ end = memchr(s, '\0', maxlen);
+ if (end == NULL)
+ return maxlen;
+ return end - s;
+}
+#endif
diff --git a/Utilities/cmlibuv/src/unix/tcp.c b/Utilities/cmlibuv/src/unix/tcp.c
index 18acd20..bc0fb66 100644
--- a/Utilities/cmlibuv/src/unix/tcp.c
+++ b/Utilities/cmlibuv/src/unix/tcp.c
@@ -214,14 +214,15 @@ int uv__tcp_connect(uv_connect_t* req,
if (handle->connect_req != NULL)
return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
+ if (handle->delayed_error != 0)
+ goto out;
+
err = maybe_new_socket(handle,
addr->sa_family,
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
if (err)
return err;
- handle->delayed_error = 0;
-
do {
errno = 0;
r = connect(uv__stream_fd(handle), addr, addrlen);
@@ -249,6 +250,8 @@ int uv__tcp_connect(uv_connect_t* req,
return UV__ERR(errno);
}
+out:
+
uv__req_init(handle->loop, req, UV_CONNECT);
req->cb = cb;
req->handle = (uv_stream_t*) handle;
@@ -459,3 +462,49 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
void uv__tcp_close(uv_tcp_t* handle) {
uv__stream_close((uv_stream_t*)handle);
}
+
+
+int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
+ uv_os_sock_t temp[2];
+ int err;
+#if defined(__FreeBSD__) || defined(__linux__)
+ int flags;
+
+ flags = type | SOCK_CLOEXEC;
+ if ((flags0 & UV_NONBLOCK_PIPE) && (flags1 & UV_NONBLOCK_PIPE))
+ flags |= SOCK_NONBLOCK;
+
+ if (socketpair(AF_UNIX, flags, protocol, temp))
+ return UV__ERR(errno);
+
+ if (flags & UV_FS_O_NONBLOCK) {
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+ }
+#else
+ if (socketpair(AF_UNIX, type, protocol, temp))
+ return UV__ERR(errno);
+
+ if ((err = uv__cloexec(temp[0], 1)))
+ goto fail;
+ if ((err = uv__cloexec(temp[1], 1)))
+ goto fail;
+#endif
+
+ if (flags0 & UV_NONBLOCK_PIPE)
+ if ((err = uv__nonblock(temp[0], 1)))
+ goto fail;
+ if (flags1 & UV_NONBLOCK_PIPE)
+ if ((err = uv__nonblock(temp[1], 1)))
+ goto fail;
+
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+
+fail:
+ uv__close(temp[0]);
+ uv__close(temp[1]);
+ return err;
+}
diff --git a/Utilities/cmlibuv/src/unix/thread.c b/Utilities/cmlibuv/src/unix/thread.c
index 8aeb0ca..cbddf17 100644
--- a/Utilities/cmlibuv/src/unix/thread.c
+++ b/Utilities/cmlibuv/src/unix/thread.c
@@ -107,8 +107,7 @@ int uv_barrier_wait(uv_barrier_t* barrier) {
}
last = (--b->out == 0);
- if (!last)
- uv_cond_signal(&b->cond); /* Not needed for last thread. */
+ uv_cond_signal(&b->cond);
uv_mutex_unlock(&b->mutex);
return last;
@@ -122,9 +121,10 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
uv_mutex_lock(&b->mutex);
assert(b->in == 0);
- assert(b->out == 0);
+ while (b->out != 0)
+ uv_cond_wait(&b->cond, &b->mutex);
- if (b->in != 0 || b->out != 0)
+ if (b->in != 0)
abort();
uv_mutex_unlock(&b->mutex);
@@ -168,7 +168,7 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
* On Linux, threads created by musl have a much smaller stack than threads
* created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
*/
-static size_t thread_stack_size(void) {
+size_t uv__thread_stack_size(void) {
#if defined(__APPLE__) || defined(__linux__)
struct rlimit lim;
@@ -234,7 +234,7 @@ int uv_thread_create_ex(uv_thread_t* tid,
attr = NULL;
if (stack_size == 0) {
- stack_size = thread_stack_size();
+ stack_size = uv__thread_stack_size();
} else {
pagesize = (size_t)getpagesize();
/* Round up to the nearest page boundary. */
diff --git a/Utilities/cmlibuv/src/unix/tty.c b/Utilities/cmlibuv/src/unix/tty.c
index 82cd723..8cefc15 100644
--- a/Utilities/cmlibuv/src/unix/tty.c
+++ b/Utilities/cmlibuv/src/unix/tty.c
@@ -239,6 +239,24 @@ static void uv__tty_make_raw(struct termios* tio) {
tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tio->c_cflag &= ~(CSIZE | PARENB);
tio->c_cflag |= CS8;
+
+ /*
+ * By default, most software expects a pending read to block until at
+ * least one byte becomes available. As per termio(7I), this requires
+ * setting the MIN and TIME parameters appropriately.
+ *
+ * As a somewhat unfortunate artifact of history, the MIN and TIME slots
+ * in the control character array overlap with the EOF and EOL slots used
+ * for canonical mode processing. Because the EOF character needs to be
+ * the ASCII EOT value (aka Control-D), it has the byte value 4. When
+ * switching to raw mode, this is interpreted as a MIN value of 4; i.e.,
+ * reads will block until at least four bytes have been input.
+ *
+ * Other platforms with a distinct MIN slot like Linux and FreeBSD appear
+ * to default to a MIN value of 1, so we'll force that value here:
+ */
+ tio->c_cc[VMIN] = 1;
+ tio->c_cc[VTIME] = 0;
#else
cfmakeraw(tio);
#endif /* #ifdef __sun */
diff --git a/Utilities/cmlibuv/src/unix/udp.c b/Utilities/cmlibuv/src/unix/udp.c
index 7d699a1..aee8d63 100644
--- a/Utilities/cmlibuv/src/unix/udp.c
+++ b/Utilities/cmlibuv/src/unix/udp.c
@@ -32,8 +32,6 @@
#endif
#include <sys/un.h>
-#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
-
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
#endif
@@ -377,8 +375,11 @@ write_queue_drain:
return;
}
+ /* Safety: npkts known to be >0 below. Hence cast from ssize_t
+ * to size_t safe.
+ */
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
- i < pkts && q != &handle->write_queue;
+ i < (size_t)npkts && q != &handle->write_queue;
++i, q = QUEUE_HEAD(&handle->write_queue)) {
assert(q != NULL);
req = QUEUE_DATA(q, uv_udp_send_t, queue);
@@ -504,6 +505,28 @@ static int uv__set_reuse(int fd) {
return 0;
}
+/*
+ * The Linux kernel suppresses some ICMP error messages by default for UDP
+ * sockets. Setting IP_RECVERR/IPV6_RECVERR on the socket enables full ICMP
+ * error reporting, hopefully resulting in faster failover to working name
+ * servers.
+ */
+static int uv__set_recverr(int fd, sa_family_t ss_family) {
+#if defined(__linux__)
+ int yes;
+
+ yes = 1;
+ if (ss_family == AF_INET) {
+ if (setsockopt(fd, IPPROTO_IP, IP_RECVERR, &yes, sizeof(yes)))
+ return UV__ERR(errno);
+ } else if (ss_family == AF_INET6) {
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVERR, &yes, sizeof(yes)))
+ return UV__ERR(errno);
+ }
+#endif
+ return 0;
+}
+
int uv__udp_bind(uv_udp_t* handle,
const struct sockaddr* addr,
@@ -514,7 +537,7 @@ int uv__udp_bind(uv_udp_t* handle,
int fd;
/* Check for bad flags. */
- if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
+ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR | UV_UDP_LINUX_RECVERR))
return UV_EINVAL;
/* Cannot set IPv6-only mode on non-IPv6 socket. */
@@ -530,6 +553,12 @@ int uv__udp_bind(uv_udp_t* handle,
handle->io_watcher.fd = fd;
}
+ if (flags & UV_UDP_LINUX_RECVERR) {
+ err = uv__set_recverr(fd, addr->sa_family);
+ if (err)
+ return err;
+ }
+
if (flags & UV_UDP_REUSEADDR) {
err = uv__set_reuse(fd);
if (err)
@@ -625,28 +654,71 @@ int uv__udp_connect(uv_udp_t* handle,
return 0;
}
-
+/* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html
+ * Any of uv supported UNIXs kernel should be standardized, but the kernel
+ * implementation logic not same, let's use pseudocode to explain the udp
+ * disconnect behaviors:
+ *
+ * Predefined stubs for pseudocode:
+ * 1. sodisconnect: The function to perform the real udp disconnect
+ * 2. pru_connect: The function to perform the real udp connect
+ * 3. so: The kernel object match with socket fd
+ * 4. addr: The sockaddr parameter from user space
+ *
+ * BSDs:
+ * if(sodisconnect(so) == 0) { // udp disconnect succeed
+ * if (addr->sa_len != so->addr->sa_len) return EINVAL;
+ * if (addr->sa_family != so->addr->sa_family) return EAFNOSUPPORT;
+ * pru_connect(so);
+ * }
+ * else return EISCONN;
+ *
+ * z/OS (same with Windows):
+ * if(addr->sa_len < so->addr->sa_len) return EINVAL;
+ * if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
+ *
+ * AIX:
+ * if(addr->sa_len != sizeof(struct sockaddr)) return EINVAL; // ignore ip proto version
+ * if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
+ *
+ * Linux,Others:
+ * if(addr->sa_len < sizeof(struct sockaddr)) return EINVAL;
+ * if (addr->sa_family == AF_UNSPEC) sodisconnect(so);
+ */
int uv__udp_disconnect(uv_udp_t* handle) {
int r;
+#if defined(__MVS__)
+ struct sockaddr_storage addr;
+#else
struct sockaddr addr;
+#endif
memset(&addr, 0, sizeof(addr));
-
+
+#if defined(__MVS__)
+ addr.ss_family = AF_UNSPEC;
+#else
addr.sa_family = AF_UNSPEC;
-
+#endif
+
do {
errno = 0;
- r = connect(handle->io_watcher.fd, &addr, sizeof(addr));
+ r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
} while (r == -1 && errno == EINTR);
- if (r == -1 && errno != EAFNOSUPPORT)
+ if (r == -1) {
+#if defined(BSD) /* The macro BSD is from sys/param.h */
+ if (errno != EAFNOSUPPORT && errno != EINVAL)
+ return UV__ERR(errno);
+#else
return UV__ERR(errno);
+#endif
+ }
handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
return 0;
}
-
int uv__udp_send(uv_udp_send_t* req,
uv_udp_t* handle,
const uv_buf_t bufs[],
@@ -854,7 +926,7 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
#if !defined(__OpenBSD__) && \
!defined(__NetBSD__) && \
!defined(__ANDROID__) && \
- !defined(__DragonFly__) & \
+ !defined(__DragonFly__) && \
!defined(__QNX__)
static int uv__udp_set_source_membership4(uv_udp_t* handle,
const struct sockaddr_in* multicast_addr,
diff --git a/Utilities/cmlibuv/src/uv-common.c b/Utilities/cmlibuv/src/uv-common.c
index f986d75..e88347a 100644
--- a/Utilities/cmlibuv/src/uv-common.c
+++ b/Utilities/cmlibuv/src/uv-common.c
@@ -275,6 +275,20 @@ int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
}
+int uv_ip_name(const struct sockaddr *src, char *dst, size_t size) {
+ switch (src->sa_family) {
+ case AF_INET:
+ return uv_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr,
+ dst, size);
+ case AF_INET6:
+ return uv_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr,
+ dst, size);
+ default:
+ return UV_EAFNOSUPPORT;
+ }
+}
+
+
int uv_tcp_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int flags) {
@@ -834,6 +848,25 @@ void uv_loop_delete(uv_loop_t* loop) {
}
+int uv_read_start(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ if (stream == NULL || alloc_cb == NULL || read_cb == NULL)
+ return UV_EINVAL;
+
+ if (stream->flags & UV_HANDLE_CLOSING)
+ return UV_EINVAL;
+
+ if (stream->flags & UV_HANDLE_READING)
+ return UV_EALREADY;
+
+ if (!(stream->flags & UV_HANDLE_READABLE))
+ return UV_ENOTCONN;
+
+ return uv__read_start(stream, alloc_cb, read_cb);
+}
+
+
void uv_os_free_environ(uv_env_item_t* envitems, int count) {
int i;
@@ -855,7 +888,11 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
}
-#ifdef __GNUC__ /* Also covers __clang__ and __INTEL_COMPILER. */
+/* Also covers __clang__ and __INTEL_COMPILER. Disabled on Windows because
+ * threads have already been forcibly terminated by the operating system
+ * by the time destructors run, ergo, it's not safe to try to clean them up.
+ */
+#if defined(__GNUC__) && !defined(_WIN32)
__attribute__((destructor))
#endif
void uv_library_shutdown(void) {
@@ -866,7 +903,12 @@ void uv_library_shutdown(void) {
uv__process_title_cleanup();
uv__signal_cleanup();
+#ifdef __MVS__
+ /* TODO(itodorov) - zos: revisit when Woz compiler is available. */
+ uv__os390_cleanup();
+#else
uv__threadpool_cleanup();
+#endif
uv__store_relaxed(&was_shutdown, 1);
}
diff --git a/Utilities/cmlibuv/src/uv-common.h b/Utilities/cmlibuv/src/uv-common.h
index e851291..8a190bf 100644
--- a/Utilities/cmlibuv/src/uv-common.h
+++ b/Utilities/cmlibuv/src/uv-common.h
@@ -68,6 +68,8 @@ extern int snprintf(char*, size_t, const char*, ...);
#define uv__store_relaxed(p, v) do *p = v; while (0)
#endif
+#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
+
/* Handle flags. Some flags are specific to Windows or UNIX. */
enum {
/* Used by all handles. */
@@ -106,8 +108,7 @@ enum {
UV_HANDLE_TCP_KEEPALIVE = 0x02000000,
UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000,
UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000,
- UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000,
- UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000,
+ UV_HANDLE_SHARED_TCP_SOCKET = 0x10000000,
/* Only used by uv_udp_t handles. */
UV_HANDLE_UDP_PROCESSING = 0x01000000,
@@ -136,6 +137,10 @@ int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
void uv__loop_close(uv_loop_t* loop);
+int uv__read_start(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+
int uv__tcp_bind(uv_tcp_t* tcp,
const struct sockaddr* addr,
unsigned int addrlen,
diff --git a/Utilities/cmlibuv/src/win/error.c b/Utilities/cmlibuv/src/win/error.c
index 3ec984c..3a269da 100644
--- a/Utilities/cmlibuv/src/win/error.c
+++ b/Utilities/cmlibuv/src/win/error.c
@@ -105,7 +105,6 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
case WSAEINVAL: return UV_EINVAL;
case WSAEPFNOSUPPORT: return UV_EINVAL;
- case WSAESOCKTNOSUPPORT: return UV_EINVAL;
case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
case ERROR_BUS_RESET: return UV_EIO;
case ERROR_CRC: return UV_EIO;
@@ -168,6 +167,7 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
case ERROR_INVALID_FUNCTION: return UV_EISDIR;
case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
+ case WSAESOCKTNOSUPPORT: return UV_ESOCKTNOSUPPORT;
default: return UV_UNKNOWN;
}
}
diff --git a/Utilities/cmlibuv/src/win/fs-event.c b/Utilities/cmlibuv/src/win/fs-event.c
index 0126c5e..76da077 100644
--- a/Utilities/cmlibuv/src/win/fs-event.c
+++ b/Utilities/cmlibuv/src/win/fs-event.c
@@ -574,10 +574,10 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
}
- if (!(handle->flags & UV_HANDLE_CLOSING)) {
- uv_fs_event_queue_readdirchanges(loop, handle);
- } else {
+ if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*)handle);
+ } else if (uv__is_active(handle)) {
+ uv_fs_event_queue_readdirchanges(loop, handle);
}
}
diff --git a/Utilities/cmlibuv/src/win/fs.c b/Utilities/cmlibuv/src/win/fs.c
index d6ff7ed..9037641 100644
--- a/Utilities/cmlibuv/src/win/fs.c
+++ b/Utilities/cmlibuv/src/win/fs.c
@@ -92,30 +92,24 @@
return; \
}
-#define MILLIONu (1000U * 1000U)
-#define BILLIONu (1000U * 1000U * 1000U)
+#define MILLION ((int64_t) 1000 * 1000)
+#define BILLION ((int64_t) 1000 * 1000 * 1000)
-#define FILETIME_TO_UINT(filetime) \
- (*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu)
-
-#define FILETIME_TO_TIME_T(filetime) \
- (FILETIME_TO_UINT(filetime) / (10u * MILLIONu))
-
-#define FILETIME_TO_TIME_NS(filetime, secs) \
- ((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U)
-
-#define FILETIME_TO_TIMESPEC(ts, filetime) \
- do { \
- (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
- (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
- } while(0)
+static void uv__filetime_to_timespec(uv_timespec_t *ts, int64_t filetime) {
+ filetime -= 116444736 * BILLION;
+ ts->tv_sec = (long) (filetime / (10 * MILLION));
+ ts->tv_nsec = (long) ((filetime - ts->tv_sec * 10 * MILLION) * 100U);
+ if (ts->tv_nsec < 0) {
+ ts->tv_sec -= 1;
+ ts->tv_nsec += 1e9;
+ }
+}
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
do { \
- uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \
- (uint64_t) 116444736 * BILLIONu; \
- (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
- (filetime_ptr)->dwHighDateTime = bigtime >> 32; \
+ int64_t bigtime = ((time) * 10 * MILLION + 116444736 * BILLION); \
+ (filetime_ptr)->dwLowDateTime = (uint64_t) bigtime & 0xFFFFFFFF; \
+ (filetime_ptr)->dwHighDateTime = (uint64_t) bigtime >> 32; \
} while(0)
#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
@@ -764,7 +758,7 @@ void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) {
void* view;
if (rw_flags == UV_FS_O_WRONLY) {
- SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS);
return;
}
if (fd_info->is_directory) {
@@ -918,6 +912,11 @@ void fs__read(uv_fs_t* req) {
SET_REQ_RESULT(req, bytes);
} else {
error = GetLastError();
+
+ if (error == ERROR_ACCESS_DENIED) {
+ error = ERROR_INVALID_FLAGS;
+ }
+
if (error == ERROR_HANDLE_EOF) {
SET_REQ_RESULT(req, bytes);
} else {
@@ -942,7 +941,7 @@ void fs__write_filemap(uv_fs_t* req, HANDLE file,
FILETIME ft;
if (rw_flags == UV_FS_O_RDONLY) {
- SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FLAGS);
return;
}
if (fd_info->is_directory) {
@@ -1058,6 +1057,7 @@ void fs__write(uv_fs_t* req) {
OVERLAPPED overlapped, *overlapped_ptr;
LARGE_INTEGER offset_;
DWORD bytes;
+ DWORD error;
int result;
unsigned int index;
LARGE_INTEGER original_position;
@@ -1117,7 +1117,13 @@ void fs__write(uv_fs_t* req) {
if (result || bytes > 0) {
SET_REQ_RESULT(req, bytes);
} else {
- SET_REQ_WIN32_ERROR(req, GetLastError());
+ error = GetLastError();
+
+ if (error == ERROR_ACCESS_DENIED) {
+ error = ERROR_INVALID_FLAGS;
+ }
+
+ SET_REQ_WIN32_ERROR(req, error);
}
}
@@ -1224,7 +1230,8 @@ void fs__mkdir(uv_fs_t* req) {
SET_REQ_RESULT(req, 0);
} else {
SET_REQ_WIN32_ERROR(req, GetLastError());
- if (req->sys_errno_ == ERROR_INVALID_NAME)
+ if (req->sys_errno_ == ERROR_INVALID_NAME ||
+ req->sys_errno_ == ERROR_DIRECTORY)
req->result = UV_EINVAL;
}
}
@@ -1791,10 +1798,14 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
((_S_IREAD | _S_IWRITE) >> 6);
- FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
- FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
- FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
- FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
+ uv__filetime_to_timespec(&statbuf->st_atim,
+ file_info.BasicInformation.LastAccessTime.QuadPart);
+ uv__filetime_to_timespec(&statbuf->st_ctim,
+ file_info.BasicInformation.ChangeTime.QuadPart);
+ uv__filetime_to_timespec(&statbuf->st_mtim,
+ file_info.BasicInformation.LastWriteTime.QuadPart);
+ uv__filetime_to_timespec(&statbuf->st_birthtim,
+ file_info.BasicInformation.CreationTime.QuadPart);
statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
diff --git a/Utilities/cmlibuv/src/win/internal.h b/Utilities/cmlibuv/src/win/internal.h
index 3f56777..7e1aef4 100644
--- a/Utilities/cmlibuv/src/win/internal.h
+++ b/Utilities/cmlibuv/src/win/internal.h
@@ -119,8 +119,8 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
/*
* Pipes
*/
-int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
- char* name, size_t nameSize);
+int uv__create_stdio_pipe_pair(uv_loop_t* loop,
+ uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags);
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
diff --git a/Utilities/cmlibuv/src/win/pipe.c b/Utilities/cmlibuv/src/win/pipe.c
index f81245e..984b766 100644
--- a/Utilities/cmlibuv/src/win/pipe.c
+++ b/Utilities/cmlibuv/src/win/pipe.c
@@ -202,17 +202,17 @@ static void close_pipe(uv_pipe_t* pipe) {
}
-int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
- char* name, size_t nameSize) {
+static int uv__pipe_server(
+ HANDLE* pipeHandle_ptr, DWORD access,
+ char* name, size_t nameSize, char* random) {
HANDLE pipeHandle;
int err;
- char* ptr = (char*)handle;
for (;;) {
- uv_unique_pipe_name(ptr, name, nameSize);
+ uv_unique_pipe_name(random, name, nameSize);
pipeHandle = CreateNamedPipeA(name,
- access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
+ access | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
NULL);
@@ -226,26 +226,225 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
goto error;
}
- /* Pipe name collision. Increment the pointer and try again. */
- ptr++;
+ /* Pipe name collision. Increment the random number and try again. */
+ random++;
}
- if (CreateIoCompletionPort(pipeHandle,
+ *pipeHandle_ptr = pipeHandle;
+
+ return 0;
+
+ error:
+ if (pipeHandle != INVALID_HANDLE_VALUE)
+ CloseHandle(pipeHandle);
+
+ return err;
+}
+
+
+static int uv__create_pipe_pair(
+ HANDLE* server_pipe_ptr, HANDLE* client_pipe_ptr,
+ unsigned int server_flags, unsigned int client_flags,
+ int inherit_client, char* random) {
+ /* allowed flags are: UV_READABLE_PIPE | UV_WRITABLE_PIPE | UV_NONBLOCK_PIPE */
+ char pipe_name[64];
+ SECURITY_ATTRIBUTES sa;
+ DWORD server_access;
+ DWORD client_access;
+ HANDLE server_pipe;
+ HANDLE client_pipe;
+ int err;
+
+ server_pipe = INVALID_HANDLE_VALUE;
+ client_pipe = INVALID_HANDLE_VALUE;
+
+ server_access = 0;
+ if (server_flags & UV_READABLE_PIPE)
+ server_access |= PIPE_ACCESS_INBOUND;
+ if (server_flags & UV_WRITABLE_PIPE)
+ server_access |= PIPE_ACCESS_OUTBOUND;
+ if (server_flags & UV_NONBLOCK_PIPE)
+ server_access |= FILE_FLAG_OVERLAPPED;
+ server_access |= WRITE_DAC;
+
+ client_access = 0;
+ if (client_flags & UV_READABLE_PIPE)
+ client_access |= GENERIC_READ;
+ else
+ client_access |= FILE_READ_ATTRIBUTES;
+ if (client_flags & UV_WRITABLE_PIPE)
+ client_access |= GENERIC_WRITE;
+ else
+ client_access |= FILE_WRITE_ATTRIBUTES;
+ client_access |= WRITE_DAC;
+
+ /* Create server pipe handle. */
+ err = uv__pipe_server(&server_pipe,
+ server_access,
+ pipe_name,
+ sizeof(pipe_name),
+ random);
+ if (err)
+ goto error;
+
+ /* Create client pipe handle. */
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = inherit_client;
+
+ client_pipe = CreateFileA(pipe_name,
+ client_access,
+ 0,
+ &sa,
+ OPEN_EXISTING,
+ (client_flags & UV_NONBLOCK_PIPE) ? FILE_FLAG_OVERLAPPED : 0,
+ NULL);
+ if (client_pipe == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ goto error;
+ }
+
+#ifndef NDEBUG
+ /* Validate that the pipe was opened in the right mode. */
+ {
+ DWORD mode;
+ BOOL r;
+ r = GetNamedPipeHandleState(client_pipe, &mode, NULL, NULL, NULL, NULL, 0);
+ if (r == TRUE) {
+ assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
+ } else {
+ fprintf(stderr, "libuv assertion failure: GetNamedPipeHandleState failed\n");
+ }
+ }
+#endif
+
+ /* Do a blocking ConnectNamedPipe. This should not block because we have
+ * both ends of the pipe created. */
+ if (!ConnectNamedPipe(server_pipe, NULL)) {
+ if (GetLastError() != ERROR_PIPE_CONNECTED) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ *client_pipe_ptr = client_pipe;
+ *server_pipe_ptr = server_pipe;
+ return 0;
+
+ error:
+ if (server_pipe != INVALID_HANDLE_VALUE)
+ CloseHandle(server_pipe);
+
+ if (client_pipe != INVALID_HANDLE_VALUE)
+ CloseHandle(client_pipe);
+
+ return err;
+}
+
+
+int uv_pipe(uv_file fds[2], int read_flags, int write_flags) {
+ uv_file temp[2];
+ int err;
+ HANDLE readh;
+ HANDLE writeh;
+
+ /* Make the server side the inbound (read) end, */
+ /* so that both ends will have FILE_READ_ATTRIBUTES permission. */
+ /* TODO: better source of local randomness than &fds? */
+ read_flags |= UV_READABLE_PIPE;
+ write_flags |= UV_WRITABLE_PIPE;
+ err = uv__create_pipe_pair(&readh, &writeh, read_flags, write_flags, 0, (char*) &fds[0]);
+ if (err != 0)
+ return err;
+ temp[0] = _open_osfhandle((intptr_t) readh, 0);
+ if (temp[0] == -1) {
+ if (errno == UV_EMFILE)
+ err = UV_EMFILE;
+ else
+ err = UV_UNKNOWN;
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return err;
+ }
+ temp[1] = _open_osfhandle((intptr_t) writeh, 0);
+ if (temp[1] == -1) {
+ if (errno == UV_EMFILE)
+ err = UV_EMFILE;
+ else
+ err = UV_UNKNOWN;
+ _close(temp[0]);
+ CloseHandle(writeh);
+ return err;
+ }
+ fds[0] = temp[0];
+ fds[1] = temp[1];
+ return 0;
+}
+
+
+int uv__create_stdio_pipe_pair(uv_loop_t* loop,
+ uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
+ /* The parent_pipe is always the server_pipe and kept by libuv.
+ * The child_pipe is always the client_pipe and is passed to the child.
+ * The flags are specified with respect to their usage in the child. */
+ HANDLE server_pipe;
+ HANDLE client_pipe;
+ unsigned int server_flags;
+ unsigned int client_flags;
+ int err;
+
+ server_pipe = INVALID_HANDLE_VALUE;
+ client_pipe = INVALID_HANDLE_VALUE;
+
+ server_flags = 0;
+ client_flags = 0;
+ if (flags & UV_READABLE_PIPE) {
+ /* The server needs inbound (read) access too, otherwise CreateNamedPipe()
+ * won't give us the FILE_READ_ATTRIBUTES permission. We need that to probe
+ * the state of the write buffer when we're trying to shutdown the pipe. */
+ server_flags |= UV_READABLE_PIPE | UV_WRITABLE_PIPE;
+ client_flags |= UV_READABLE_PIPE;
+ }
+ if (flags & UV_WRITABLE_PIPE) {
+ server_flags |= UV_READABLE_PIPE;
+ client_flags |= UV_WRITABLE_PIPE;
+ }
+ server_flags |= UV_NONBLOCK_PIPE;
+ if (flags & UV_NONBLOCK_PIPE || parent_pipe->ipc) {
+ client_flags |= UV_NONBLOCK_PIPE;
+ }
+
+ err = uv__create_pipe_pair(&server_pipe, &client_pipe,
+ server_flags, client_flags, 1, (char*) server_pipe);
+ if (err)
+ goto error;
+
+ if (CreateIoCompletionPort(server_pipe,
loop->iocp,
- (ULONG_PTR)handle,
+ (ULONG_PTR) parent_pipe,
0) == NULL) {
err = GetLastError();
goto error;
}
- uv_pipe_connection_init(handle);
- handle->handle = pipeHandle;
+ uv_pipe_connection_init(parent_pipe);
+ parent_pipe->handle = server_pipe;
+ *child_pipe_ptr = client_pipe;
+
+ /* The server end is now readable and/or writable. */
+ if (flags & UV_READABLE_PIPE)
+ parent_pipe->flags |= UV_HANDLE_WRITABLE;
+ if (flags & UV_WRITABLE_PIPE)
+ parent_pipe->flags |= UV_HANDLE_READABLE;
return 0;
error:
- if (pipeHandle != INVALID_HANDLE_VALUE)
- CloseHandle(pipeHandle);
+ if (server_pipe != INVALID_HANDLE_VALUE)
+ CloseHandle(server_pipe);
+
+ if (client_pipe != INVALID_HANDLE_VALUE)
+ CloseHandle(client_pipe);
return err;
}
@@ -712,9 +911,8 @@ error:
handle->name = NULL;
}
- if (pipeHandle != INVALID_HANDLE_VALUE) {
+ if (pipeHandle != INVALID_HANDLE_VALUE)
CloseHandle(pipeHandle);
- }
/* Make this req pending reporting an error. */
SET_REQ_ERROR(req, err);
@@ -1054,7 +1252,6 @@ static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
assert(req != NULL);
assert(req->type == UV_WRITE);
assert(handle->type == UV_NAMED_PIPE);
- assert(req->write_buffer.base);
result = WriteFile(handle->handle,
req->write_buffer.base,
@@ -1599,7 +1796,6 @@ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
* it. */
eof_timer_destroy(handle);
- handle->flags &= ~UV_HANDLE_READABLE;
uv_read_stop((uv_stream_t*) handle);
handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf);
diff --git a/Utilities/cmlibuv/src/win/poll.c b/Utilities/cmlibuv/src/win/poll.c
index 8785859..9d37759 100644
--- a/Utilities/cmlibuv/src/win/poll.c
+++ b/Utilities/cmlibuv/src/win/poll.c
@@ -488,7 +488,8 @@ static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
assert(handle->type == UV_POLL);
assert(!(handle->flags & UV_HANDLE_CLOSING));
- assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
+ assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
+ UV_PRIORITIZED)) == 0);
handle->events = events;
handle->poll_cb = cb;
diff --git a/Utilities/cmlibuv/src/win/process-stdio.c b/Utilities/cmlibuv/src/win/process-stdio.c
index 355d618..0db3572 100644
--- a/Utilities/cmlibuv/src/win/process-stdio.c
+++ b/Utilities/cmlibuv/src/win/process-stdio.c
@@ -95,102 +95,6 @@ void uv_disable_stdio_inheritance(void) {
}
-static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
- uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
- char pipe_name[64];
- SECURITY_ATTRIBUTES sa;
- DWORD server_access = 0;
- DWORD client_access = 0;
- HANDLE child_pipe = INVALID_HANDLE_VALUE;
- int err;
- int overlap;
-
- if (flags & UV_READABLE_PIPE) {
- /* The server needs inbound access too, otherwise CreateNamedPipe() won't
- * give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
- * state of the write buffer when we're trying to shutdown the pipe. */
- server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
- client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
- }
- if (flags & UV_WRITABLE_PIPE) {
- server_access |= PIPE_ACCESS_INBOUND;
- client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
- }
-
- /* Create server pipe handle. */
- err = uv_stdio_pipe_server(loop,
- server_pipe,
- server_access,
- pipe_name,
- sizeof(pipe_name));
- if (err)
- goto error;
-
- /* Create child pipe handle. */
- sa.nLength = sizeof sa;
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
-
- overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
- child_pipe = CreateFileA(pipe_name,
- client_access,
- 0,
- &sa,
- OPEN_EXISTING,
- overlap ? FILE_FLAG_OVERLAPPED : 0,
- NULL);
- if (child_pipe == INVALID_HANDLE_VALUE) {
- err = GetLastError();
- goto error;
- }
-
-#ifndef NDEBUG
- /* Validate that the pipe was opened in the right mode. */
- {
- DWORD mode;
- BOOL r = GetNamedPipeHandleState(child_pipe,
- &mode,
- NULL,
- NULL,
- NULL,
- NULL,
- 0);
- assert(r == TRUE);
- assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
- }
-#endif
-
- /* Do a blocking ConnectNamedPipe. This should not block because we have both
- * ends of the pipe created. */
- if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
- if (GetLastError() != ERROR_PIPE_CONNECTED) {
- err = GetLastError();
- goto error;
- }
- }
-
- /* The server end is now readable and/or writable. */
- if (flags & UV_READABLE_PIPE)
- server_pipe->flags |= UV_HANDLE_WRITABLE;
- if (flags & UV_WRITABLE_PIPE)
- server_pipe->flags |= UV_HANDLE_READABLE;
-
- *child_pipe_ptr = child_pipe;
- return 0;
-
- error:
- if (server_pipe->handle != INVALID_HANDLE_VALUE) {
- uv_pipe_cleanup(loop, server_pipe);
- }
-
- if (child_pipe != INVALID_HANDLE_VALUE) {
- CloseHandle(child_pipe);
- }
-
- return err;
-}
-
-
static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
HANDLE current_process;
diff --git a/Utilities/cmlibuv/src/win/process.c b/Utilities/cmlibuv/src/win/process.c
index aada889..9ca4122 100644
--- a/Utilities/cmlibuv/src/win/process.c
+++ b/Utilities/cmlibuv/src/win/process.c
@@ -169,10 +169,9 @@ static WCHAR* search_path_join_test(const WCHAR* dir,
size_t cwd_len) {
WCHAR *result, *result_pos;
DWORD attrs;
- if (
- (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') ||
- (dir_len > 2 && dir[0] == L'/' && dir[1] == L'/')
- ) {
+ if (dir_len > 2 &&
+ ((dir[0] == L'\\' || dir[0] == L'/') &&
+ (dir[1] == L'\\' || dir[1] == L'/'))) {
/* It's a UNC path so ignore cwd */
cwd_len = 0;
} else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
@@ -645,7 +644,7 @@ int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
assert(r==nb);
B[nb] = L'\0';
- while (1) {
+ for (;;) {
wchar_t AA = *A++;
wchar_t BB = *B++;
if (AA < BB) {
diff --git a/Utilities/cmlibuv/src/win/stream.c b/Utilities/cmlibuv/src/win/stream.c
index 46a0709..abf477f 100644
--- a/Utilities/cmlibuv/src/win/stream.c
+++ b/Utilities/cmlibuv/src/win/stream.c
@@ -65,18 +65,11 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
}
-int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb) {
+int uv__read_start(uv_stream_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
int err;
- if (handle->flags & UV_HANDLE_READING) {
- return UV_EALREADY;
- }
-
- if (!(handle->flags & UV_HANDLE_READABLE)) {
- return UV_ENOTCONN;
- }
-
err = ERROR_INVALID_PARAMETER;
switch (handle->type) {
case UV_TCP:
@@ -195,6 +188,16 @@ int uv_try_write(uv_stream_t* stream,
}
+int uv_try_write2(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle) {
+ if (send_handle != NULL)
+ return UV_EAGAIN;
+ return uv_try_write(stream, bufs, nbufs);
+}
+
+
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
uv_loop_t* loop = handle->loop;
diff --git a/Utilities/cmlibuv/src/win/tcp.c b/Utilities/cmlibuv/src/win/tcp.c
index 0dcaa97..6ca11e0 100644
--- a/Utilities/cmlibuv/src/win/tcp.c
+++ b/Utilities/cmlibuv/src/win/tcp.c
@@ -236,12 +236,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
-
- if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
- closesocket(handle->socket);
- handle->socket = INVALID_SOCKET;
- handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
- }
+ assert(handle->socket == INVALID_SOCKET);
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
@@ -599,6 +594,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
}
}
+ /* If this flag is set, we already made this listen call in xfer. */
if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
listen(handle->socket, backlog) == SOCKET_ERROR) {
return WSAGetLastError();
@@ -769,7 +765,7 @@ static int uv__is_loopback(const struct sockaddr_storage* storage) {
}
// Check if Windows version is 10.0.16299 or later
-static int uv__is_fast_loopback_fail_supported() {
+static int uv__is_fast_loopback_fail_supported(void) {
OSVERSIONINFOW os_info;
if (!pRtlGetVersion)
return 0;
@@ -800,9 +796,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
if (err)
return err;
- if (handle->delayed_error) {
- return handle->delayed_error;
- }
+ if (handle->delayed_error != 0)
+ goto out;
if (!(handle->flags & UV_HANDLE_BOUND)) {
if (addrlen == sizeof(uv_addr_ip4_any_)) {
@@ -815,8 +810,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err)
return err;
- if (handle->delayed_error)
- return handle->delayed_error;
+ if (handle->delayed_error != 0)
+ goto out;
}
if (!handle->tcp.conn.func_connectex) {
@@ -844,11 +839,21 @@ static int uv_tcp_try_connect(uv_connect_t* req,
NULL);
}
+out:
+
UV_REQ_INIT(req, UV_CONNECT);
req->handle = (uv_stream_t*) handle;
req->cb = cb;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+ if (handle->delayed_error != 0) {
+ /* Process the req without IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ return 0;
+ }
+
success = handle->tcp.conn.func_connectex(handle->socket,
(const struct sockaddr*) &converted,
addrlen,
@@ -1015,6 +1020,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
*/
err = WSAECONNRESET;
}
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
handle->read_cb((uv_stream_t*)handle,
uv_translate_sys_error(err),
@@ -1038,7 +1044,6 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
}
- handle->flags &= ~UV_HANDLE_READABLE;
buf.base = 0;
buf.len = 0;
@@ -1075,7 +1080,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
}
} else {
/* Connection closed */
- handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
+ handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf);
@@ -1096,6 +1101,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
* Unix. */
err = WSAECONNRESET;
}
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
handle->read_cb((uv_stream_t*)handle,
uv_translate_sys_error(err),
@@ -1149,9 +1155,14 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
}
handle->stream.conn.write_reqs_pending--;
- if (handle->stream.conn.shutdown_req != NULL &&
- handle->stream.conn.write_reqs_pending == 0) {
- uv_want_endgame(loop, (uv_handle_t*)handle);
+ if (handle->stream.conn.write_reqs_pending == 0) {
+ if (handle->flags & UV_HANDLE_CLOSING) {
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+ }
+ if (handle->stream.conn.shutdown_req != NULL) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
}
DECREASE_PENDING_REQ_COUNT(handle);
@@ -1215,7 +1226,14 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
UNREGISTER_HANDLE_REQ(loop, handle, req);
err = 0;
- if (REQ_SUCCESS(req)) {
+ if (handle->delayed_error) {
+ /* To smooth over the differences between unixes errors that
+ * were reported synchronously on the first connect can be delayed
+ * until the next tick--which is now.
+ */
+ err = handle->delayed_error;
+ handle->delayed_error = 0;
+ } else if (REQ_SUCCESS(req)) {
if (handle->flags & UV_HANDLE_CLOSING) {
/* use UV_ECANCELED for consistency with Unix */
err = ERROR_OPERATION_ABORTED;
@@ -1320,7 +1338,7 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
if (handle->socket != INVALID_SOCKET) {
err = uv__tcp_nodelay(handle, handle->socket, enable);
if (err)
- return err;
+ return uv_translate_sys_error(err);
}
if (enable) {
@@ -1339,7 +1357,7 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
if (handle->socket != INVALID_SOCKET) {
err = uv__tcp_keepalive(handle, handle->socket, enable, delay);
if (err)
- return err;
+ return uv_translate_sys_error(err);
}
if (enable) {
@@ -1386,9 +1404,24 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
}
-static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
- SOCKET socket = tcp->socket;
+static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) {
+ SOCKET socket;
int non_ifs_lsp;
+ int reading;
+ int writing;
+
+ socket = tcp->socket;
+ reading = tcp->flags & UV_HANDLE_READING;
+ writing = tcp->stream.conn.write_reqs_pending > 0;
+ if (!reading && !writing)
+ return;
+
+ /* TODO: in libuv v2, keep explicit track of write_reqs, so we can cancel
+ * them each explicitly with CancelIoEx (like unix). */
+ if (reading)
+ CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped);
+ if (writing)
+ CancelIo((HANDLE) socket);
/* Check if we have any non-IFS LSPs stacked on top of TCP */
non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
@@ -1408,71 +1441,41 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
NULL,
NULL) != 0) {
/* Failed. We can't do CancelIo. */
- return -1;
+ return;
}
}
assert(socket != 0 && socket != INVALID_SOCKET);
- if (!CancelIo((HANDLE) socket)) {
- return GetLastError();
+ if (socket != tcp->socket) {
+ if (reading)
+ CancelIoEx((HANDLE) socket, &tcp->read_req.u.io.overlapped);
+ if (writing)
+ CancelIo((HANDLE) socket);
}
-
- /* It worked. */
- return 0;
}
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
- int close_socket = 1;
-
- if (tcp->flags & UV_HANDLE_READ_PENDING) {
- /* In order for winsock to do a graceful close there must not be any any
- * pending reads, or the socket must be shut down for writing */
- if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
- /* Just do shutdown on non-shared sockets, which ensures graceful close. */
- shutdown(tcp->socket, SD_SEND);
-
- } else if (uv_tcp_try_cancel_io(tcp) == 0) {
- /* In case of a shared socket, we try to cancel all outstanding I/O,. If
- * that works, don't close the socket yet - wait for the read req to
- * return and close the socket in uv_tcp_endgame. */
- close_socket = 0;
-
- } else {
- /* When cancelling isn't possible - which could happen when an LSP is
- * present on an old Windows version, we will have to close the socket
- * with a read pending. That is not nice because trailing sent bytes may
- * not make it to the other side. */
+ if (tcp->flags & UV_HANDLE_CONNECTION) {
+ uv_tcp_try_cancel_reqs(tcp);
+ if (tcp->flags & UV_HANDLE_READING) {
+ uv_read_stop((uv_stream_t*) tcp);
}
-
- } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
- tcp->tcp.serv.accept_reqs != NULL) {
- /* Under normal circumstances closesocket() will ensure that all pending
- * accept reqs are canceled. However, when the socket is shared the
- * presence of another reference to the socket in another process will keep
- * the accept reqs going, so we have to ensure that these are canceled. */
- if (uv_tcp_try_cancel_io(tcp) != 0) {
- /* When cancellation is not possible, there is another option: we can
- * close the incoming sockets, which will also cancel the accept
- * operations. However this is not cool because we might inadvertently
- * close a socket that just accepted a new connection, which will cause
- * the connection to be aborted. */
+ } else {
+ if (tcp->tcp.serv.accept_reqs != NULL) {
+ /* First close the incoming sockets to cancel the accept operations before
+ * we free their resources. */
unsigned int i;
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
- if (req->accept_socket != INVALID_SOCKET &&
- !HasOverlappedIoCompleted(&req->u.io.overlapped)) {
+ if (req->accept_socket != INVALID_SOCKET) {
closesocket(req->accept_socket);
req->accept_socket = INVALID_SOCKET;
}
}
}
- }
-
- if (tcp->flags & UV_HANDLE_READING) {
- tcp->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, tcp);
+ assert(!(tcp->flags & UV_HANDLE_READING));
}
if (tcp->flags & UV_HANDLE_LISTENING) {
@@ -1480,10 +1483,15 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
DECREASE_ACTIVE_COUNT(loop, tcp);
}
- if (close_socket) {
+ /* If any overlapped req failed to cancel, calling `closesocket` now would
+ * cause Win32 to send an RST packet. Try to avoid that for writes, if
+ * possibly applicable, by waiting to process the completion notifications
+ * first (which typically should be cancellations). There's not much we can
+ * do about canceled reads, which also will generate an RST packet. */
+ if (!(tcp->flags & UV_HANDLE_CONNECTION) ||
+ tcp->stream.conn.write_reqs_pending == 0) {
closesocket(tcp->socket);
tcp->socket = INVALID_SOCKET;
- tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
}
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
@@ -1571,3 +1579,118 @@ int uv__tcp_connect(uv_connect_t* req,
return 0;
}
+
+#ifndef WSA_FLAG_NO_HANDLE_INHERIT
+/* Added in Windows 7 SP1. Specify this to avoid race conditions, */
+/* but also manually clear the inherit flag in case this failed. */
+#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
+#endif
+
+int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
+ SOCKET server = INVALID_SOCKET;
+ SOCKET client0 = INVALID_SOCKET;
+ SOCKET client1 = INVALID_SOCKET;
+ SOCKADDR_IN name;
+ LPFN_ACCEPTEX func_acceptex;
+ WSAOVERLAPPED overlap;
+ char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32];
+ int namelen;
+ int err;
+ DWORD bytes;
+ DWORD flags;
+ DWORD client0_flags = WSA_FLAG_NO_HANDLE_INHERIT;
+ DWORD client1_flags = WSA_FLAG_NO_HANDLE_INHERIT;
+
+ if (flags0 & UV_NONBLOCK_PIPE)
+ client0_flags |= WSA_FLAG_OVERLAPPED;
+ if (flags1 & UV_NONBLOCK_PIPE)
+ client1_flags |= WSA_FLAG_OVERLAPPED;
+
+ server = WSASocketW(AF_INET, type, protocol, NULL, 0,
+ WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
+ if (server == INVALID_SOCKET)
+ goto wsaerror;
+ if (!SetHandleInformation((HANDLE) server, HANDLE_FLAG_INHERIT, 0))
+ goto error;
+ name.sin_family = AF_INET;
+ name.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ name.sin_port = 0;
+ if (bind(server, (SOCKADDR*) &name, sizeof(name)) != 0)
+ goto wsaerror;
+ if (listen(server, 1) != 0)
+ goto wsaerror;
+ namelen = sizeof(name);
+ if (getsockname(server, (SOCKADDR*) &name, &namelen) != 0)
+ goto wsaerror;
+ client0 = WSASocketW(AF_INET, type, protocol, NULL, 0, client0_flags);
+ if (client0 == INVALID_SOCKET)
+ goto wsaerror;
+ if (!SetHandleInformation((HANDLE) client0, HANDLE_FLAG_INHERIT, 0))
+ goto error;
+ if (connect(client0, (SOCKADDR*) &name, sizeof(name)) != 0)
+ goto wsaerror;
+ client1 = WSASocketW(AF_INET, type, protocol, NULL, 0, client1_flags);
+ if (client1 == INVALID_SOCKET)
+ goto wsaerror;
+ if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0))
+ goto error;
+ if (!uv_get_acceptex_function(server, &func_acceptex)) {
+ err = WSAEAFNOSUPPORT;
+ goto cleanup;
+ }
+ memset(&overlap, 0, sizeof(overlap));
+ if (!func_acceptex(server,
+ client1,
+ accept_buffer,
+ 0,
+ sizeof(struct sockaddr_storage),
+ sizeof(struct sockaddr_storage),
+ &bytes,
+ &overlap)) {
+ err = WSAGetLastError();
+ if (err == ERROR_IO_PENDING) {
+ /* Result should complete immediately, since we already called connect,
+ * but empirically, we sometimes have to poll the kernel a couple times
+ * until it notices that. */
+ while (!WSAGetOverlappedResult(client1, &overlap, &bytes, FALSE, &flags)) {
+ err = WSAGetLastError();
+ if (err != WSA_IO_INCOMPLETE)
+ goto cleanup;
+ SwitchToThread();
+ }
+ }
+ else {
+ goto cleanup;
+ }
+ }
+ if (setsockopt(client1, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ (char*) &server, sizeof(server)) != 0) {
+ goto wsaerror;
+ }
+
+ closesocket(server);
+
+ fds[0] = client0;
+ fds[1] = client1;
+
+ return 0;
+
+ wsaerror:
+ err = WSAGetLastError();
+ goto cleanup;
+
+ error:
+ err = GetLastError();
+ goto cleanup;
+
+ cleanup:
+ if (server != INVALID_SOCKET)
+ closesocket(server);
+ if (client0 != INVALID_SOCKET)
+ closesocket(client0);
+ if (client1 != INVALID_SOCKET)
+ closesocket(client1);
+
+ assert(err);
+ return uv_translate_sys_error(err);
+}
diff --git a/Utilities/cmlibuv/src/win/thread.c b/Utilities/cmlibuv/src/win/thread.c
index 89c53ad..ea5dc04 100644
--- a/Utilities/cmlibuv/src/win/thread.c
+++ b/Utilities/cmlibuv/src/win/thread.c
@@ -103,7 +103,7 @@ static UINT __stdcall uv__thread_start(void* arg) {
uv__free(ctx_p);
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
- uv_key_set(&uv__current_thread_key, (void*) ctx.self);
+ uv_key_set(&uv__current_thread_key, ctx.self);
ctx.entry(ctx.arg);
@@ -183,7 +183,18 @@ int uv_thread_create_ex(uv_thread_t* tid,
uv_thread_t uv_thread_self(void) {
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
- return (uv_thread_t) uv_key_get(&uv__current_thread_key);
+ uv_thread_t key = uv_key_get(&uv__current_thread_key);
+ if (key == NULL) {
+ /* If the thread wasn't started by uv_thread_create (such as the main
+ * thread), we assign an id to it now. */
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &key, 0,
+ FALSE, DUPLICATE_SAME_ACCESS)) {
+ uv_fatal_error(GetLastError(), "DuplicateHandle");
+ }
+ uv_key_set(&uv__current_thread_key, key);
+ }
+ return key;
}
@@ -237,113 +248,60 @@ void uv_mutex_unlock(uv_mutex_t* mutex) {
LeaveCriticalSection(mutex);
}
+/* Ensure that the ABI for this type remains stable in v1.x */
+#ifdef _WIN64
+STATIC_ASSERT(sizeof(uv_rwlock_t) == 80);
+#else
+STATIC_ASSERT(sizeof(uv_rwlock_t) == 48);
+#endif
int uv_rwlock_init(uv_rwlock_t* rwlock) {
- /* Initialize the semaphore that acts as the write lock. */
- HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
- if (handle == NULL)
- return uv_translate_sys_error(GetLastError());
- rwlock->state_.write_semaphore_ = handle;
-
- /* Initialize the critical section protecting the reader count. */
- InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
-
- /* Initialize the reader count. */
- rwlock->state_.num_readers_ = 0;
+ memset(rwlock, 0, sizeof(*rwlock));
+ InitializeSRWLock(&rwlock->read_write_lock_);
return 0;
}
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
- DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
- CloseHandle(rwlock->state_.write_semaphore_);
+ /* SRWLock does not need explicit destruction so long as there are no waiting threads
+ See: https://docs.microsoft.com/windows/win32/api/synchapi/nf-synchapi-initializesrwlock#remarks */
}
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
- /* Acquire the lock that protects the reader count. */
- EnterCriticalSection(&rwlock->state_.num_readers_lock_);
-
- /* Increase the reader count, and lock for write if this is the first
- * reader.
- */
- if (++rwlock->state_.num_readers_ == 1) {
- DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
- if (r != WAIT_OBJECT_0)
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
- }
-
- /* Release the lock that protects the reader count. */
- LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+ AcquireSRWLockShared(&rwlock->read_write_lock_);
}
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
- int err;
-
- if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
+ if (!TryAcquireSRWLockShared(&rwlock->read_write_lock_))
return UV_EBUSY;
- err = 0;
-
- if (rwlock->state_.num_readers_ == 0) {
- /* Currently there are no other readers, which means that the write lock
- * needs to be acquired.
- */
- DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
- if (r == WAIT_OBJECT_0)
- rwlock->state_.num_readers_++;
- else if (r == WAIT_TIMEOUT)
- err = UV_EBUSY;
- else if (r == WAIT_FAILED)
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
-
- } else {
- /* The write lock has already been acquired because there are other
- * active readers.
- */
- rwlock->state_.num_readers_++;
- }
-
- LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
- return err;
+ return 0;
}
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
- EnterCriticalSection(&rwlock->state_.num_readers_lock_);
-
- if (--rwlock->state_.num_readers_ == 0) {
- if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
- uv_fatal_error(GetLastError(), "ReleaseSemaphore");
- }
-
- LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+ ReleaseSRWLockShared(&rwlock->read_write_lock_);
}
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
- DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
- if (r != WAIT_OBJECT_0)
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
+ AcquireSRWLockExclusive(&rwlock->read_write_lock_);
}
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
- DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
- if (r == WAIT_OBJECT_0)
- return 0;
- else if (r == WAIT_TIMEOUT)
+ if (!TryAcquireSRWLockExclusive(&rwlock->read_write_lock_))
return UV_EBUSY;
- else
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
+
+ return 0;
}
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
- if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
- uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+ ReleaseSRWLockExclusive(&rwlock->read_write_lock_);
}
diff --git a/Utilities/cmlibuv/src/win/udp.c b/Utilities/cmlibuv/src/win/udp.c
index 68ca728..7b5efa2 100644
--- a/Utilities/cmlibuv/src/win/udp.c
+++ b/Utilities/cmlibuv/src/win/udp.c
@@ -284,7 +284,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
handle->flags &= ~UV_HANDLE_ZERO_READ;
handle->recv_buffer = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
+ handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &handle->recv_buffer);
if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
return;
@@ -501,7 +501,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
/* Do a nonblocking receive.
* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
buf = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
if (buf.base == NULL || buf.len == 0) {
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
goto done;
@@ -1083,11 +1083,11 @@ int uv__udp_connect(uv_udp_t* handle,
int uv__udp_disconnect(uv_udp_t* handle) {
int err;
- struct sockaddr addr;
+ struct sockaddr_storage addr;
memset(&addr, 0, sizeof(addr));
- err = connect(handle->socket, &addr, sizeof(addr));
+ err = connect(handle->socket, (struct sockaddr*) &addr, sizeof(addr));
if (err)
return uv_translate_sys_error(WSAGetLastError());
diff --git a/Utilities/cmlibuv/src/win/util.c b/Utilities/cmlibuv/src/win/util.c
index aad8f1a..33e874a 100644
--- a/Utilities/cmlibuv/src/win/util.c
+++ b/Utilities/cmlibuv/src/win/util.c
@@ -1664,26 +1664,36 @@ int uv_os_unsetenv(const char* name) {
int uv_os_gethostname(char* buffer, size_t* size) {
- char buf[UV_MAXHOSTNAMESIZE];
+ WCHAR buf[UV_MAXHOSTNAMESIZE];
size_t len;
+ char* utf8_str;
+ int convert_result;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
uv__once_init(); /* Initialize winsock */
- if (gethostname(buf, sizeof(buf)) != 0)
+ if (pGetHostNameW == NULL)
+ return UV_ENOSYS;
+
+ if (pGetHostNameW(buf, UV_MAXHOSTNAMESIZE) != 0)
return uv_translate_sys_error(WSAGetLastError());
- buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
- len = strlen(buf);
+ convert_result = uv__convert_utf16_to_utf8(buf, -1, &utf8_str);
+
+ if (convert_result != 0)
+ return convert_result;
+ len = strlen(utf8_str);
if (len >= *size) {
*size = len + 1;
+ uv__free(utf8_str);
return UV_ENOBUFS;
}
- memcpy(buffer, buf, len + 1);
+ memcpy(buffer, utf8_str, len + 1);
+ uv__free(utf8_str);
*size = len;
return 0;
}
diff --git a/Utilities/cmlibuv/src/win/winapi.c b/Utilities/cmlibuv/src/win/winapi.c
index bb86ec8..bf306cd 100644
--- a/Utilities/cmlibuv/src/win/winapi.c
+++ b/Utilities/cmlibuv/src/win/winapi.c
@@ -45,12 +45,15 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
/* User32.dll function pointer */
sSetWinEventHook pSetWinEventHook;
+/* ws2_32.dll function pointer */
+uv_sGetHostNameW pGetHostNameW;
void uv_winapi_init(void) {
HMODULE ntdll_module;
HMODULE powrprof_module;
HMODULE user32_module;
HMODULE kernel32_module;
+ HMODULE ws2_32_module;
ntdll_module = GetModuleHandleA("ntdll.dll");
if (ntdll_module == NULL) {
@@ -134,4 +137,11 @@ void uv_winapi_init(void) {
pSetWinEventHook = (sSetWinEventHook)
GetProcAddress(user32_module, "SetWinEventHook");
}
+
+ ws2_32_module = LoadLibraryA("ws2_32.dll");
+ if (ws2_32_module != NULL) {
+ pGetHostNameW = (uv_sGetHostNameW) GetProcAddress(
+ ws2_32_module,
+ "GetHostNameW");
+ }
}
diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h
index 9bc4559..e815f8f 100644
--- a/Utilities/cmlibuv/src/win/winapi.h
+++ b/Utilities/cmlibuv/src/win/winapi.h
@@ -4768,4 +4768,11 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
/* User32.dll function pointer */
extern sSetWinEventHook pSetWinEventHook;
+/* ws2_32.dll function pointer */
+/* mingw doesn't have this definition, so let's declare it here locally */
+typedef int (WINAPI *uv_sGetHostNameW)
+ (PWSTR,
+ int);
+extern uv_sGetHostNameW pGetHostNameW;
+
#endif /* UV_WIN_WINAPI_H_ */
diff --git a/Utilities/cmnghttp2/CMakeLists.txt b/Utilities/cmnghttp2/CMakeLists.txt
index 3bc2778..9002ab6 100644
--- a/Utilities/cmnghttp2/CMakeLists.txt
+++ b/Utilities/cmnghttp2/CMakeLists.txt
@@ -1,16 +1,16 @@
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
endif()
# Re-use some check result cache entries from cmcurl:
-# * HAVE_ARPA_INET_H
-# * HAVE_NETINET_IN_H
-# * HAVE_SSIZE_T
-if(NOT HAVE_SSIZE_T)
+# * HAVE_ARPA_INET_H (referenced in cmakeconfig.h.in)
+# * HAVE_NETINET_IN_H (referenced in cmakeconfig.h.in)
+# * HAVE_SIZEOF_SSIZE_T (referenced here)
+if(NOT HAVE_SIZEOF_SSIZE_T)
set(ssize_t KWIML_INT_intptr_t)
endif()
configure_file(cmakeconfig.h.in config.h)
diff --git a/Utilities/cmpdcurses/.gitattributes b/Utilities/cmpdcurses/.gitattributes
new file mode 100644
index 0000000..562b12e
--- /dev/null
+++ b/Utilities/cmpdcurses/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmpdcurses/CMakeLists.txt b/Utilities/cmpdcurses/CMakeLists.txt
new file mode 100644
index 0000000..94ca601
--- /dev/null
+++ b/Utilities/cmpdcurses/CMakeLists.txt
@@ -0,0 +1,73 @@
+project(PDCurses C)
+
+if(NOT WIN32)
+ message(FATAL_ERROR "PDCurses not (yet) supported on non-Windows platforms")
+endif()
+
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
+add_library(cmpdcurses STATIC
+ curses.h
+ curspriv.h
+ panel.h
+
+ common/acs437.h
+ common/acsuni.h
+
+ pdcurses/addch.c
+ pdcurses/addchstr.c
+ pdcurses/addstr.c
+ pdcurses/attr.c
+ pdcurses/beep.c
+ pdcurses/bkgd.c
+ pdcurses/border.c
+ pdcurses/clear.c
+ pdcurses/color.c
+ pdcurses/debug.c
+ pdcurses/delch.c
+ pdcurses/deleteln.c
+ pdcurses/getch.c
+ pdcurses/getstr.c
+ pdcurses/getyx.c
+ pdcurses/inch.c
+ pdcurses/inchstr.c
+ pdcurses/initscr.c
+ pdcurses/inopts.c
+ pdcurses/insch.c
+ pdcurses/insstr.c
+ pdcurses/instr.c
+ pdcurses/kernel.c
+ pdcurses/keyname.c
+ pdcurses/mouse.c
+ pdcurses/move.c
+ pdcurses/outopts.c
+ pdcurses/overlay.c
+ pdcurses/pad.c
+ pdcurses/panel.c
+ pdcurses/printw.c
+ pdcurses/refresh.c
+ pdcurses/scanw.c
+ pdcurses/scr_dump.c
+ pdcurses/scroll.c
+ pdcurses/slk.c
+ pdcurses/termattr.c
+ pdcurses/touch.c
+ pdcurses/util.c
+ pdcurses/window.c
+
+ wincon/pdcclip.c
+ wincon/pdcdisp.c
+ wincon/pdcgetsc.c
+ wincon/pdckbd.c
+ wincon/pdcscrn.c
+ wincon/pdcsetsc.c
+ wincon/pdcutil.c
+ wincon/pdcwin.h
+ )
+target_include_directories(cmpdcurses PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
diff --git a/Utilities/cmpdcurses/README.md b/Utilities/cmpdcurses/README.md
new file mode 100644
index 0000000..35d3f63
--- /dev/null
+++ b/Utilities/cmpdcurses/README.md
@@ -0,0 +1,65 @@
+Welcome to PDCurses!
+====================
+
+PDCurses is an implementation of X/Open curses for multiple platforms.
+The latest version can be found at:
+
+ https://pdcurses.org/
+
+For changes, see the [History] file. The main documentation is now in
+the [docs] directory.
+
+
+Legal Stuff
+-----------
+
+The core package is in the public domain, but small portions of PDCurses
+are subject to copyright under various licenses. Each directory
+contains a README.md file, with a section titled "Distribution Status"
+which describes the status of the files in that directory.
+
+If you use PDCurses in an application, an acknowledgement would be
+appreciated, but is not mandatory. If you make corrections or
+enhancements to PDCurses, please forward them to the current maintainer
+for the benefit of other users.
+
+This software is provided AS IS with NO WARRANTY whatsoever.
+
+
+Ports
+-----
+
+PDCurses has been ported to DOS, OS/2, Windows, X11 and SDL. A directory
+containing the port-specific source files exists for each of these
+platforms.
+
+Build instructions are in the README.md file for each platform:
+
+- [DOS]
+- [OS/2]
+- [SDL 1.x]
+- [SDL 2.x]
+- [Windows]
+- [X11]
+
+
+Distribution Status
+-------------------
+
+All files in this directory (not including subdirectories) are released
+to the public domain.
+
+
+Maintainer
+----------
+
+William McBrine <wmcbrine@gmail.com>
+
+[History]: docs/HISTORY.md
+[docs]: docs/README.md
+[DOS]: dos/README.md
+[OS/2]: os2/README.md
+[SDL 1.x]: sdl1/README.md
+[SDL 2.x]: sdl2/README.md
+[Windows]: wincon/README.md
+[X11]: x11/README.md
diff --git a/Utilities/cmpdcurses/common/acs437.h b/Utilities/cmpdcurses/common/acs437.h
new file mode 100644
index 0000000..24cbd78
--- /dev/null
+++ b/Utilities/cmpdcurses/common/acs437.h
@@ -0,0 +1,35 @@
+/* ACS definitions originally by jshumate@wrdis01.robins.af.mil -- these
+ match code page 437 and compatible pages (CP850, CP852, etc.) */
+
+chtype acs_map[128] =
+{
+ PDC_ACS(0), PDC_ACS(1), PDC_ACS(2), PDC_ACS(3), PDC_ACS(4),
+ PDC_ACS(5), PDC_ACS(6), PDC_ACS(7), PDC_ACS(8), PDC_ACS(9),
+ PDC_ACS(10), PDC_ACS(11), PDC_ACS(12), PDC_ACS(13), PDC_ACS(14),
+ PDC_ACS(15), PDC_ACS(16), PDC_ACS(17), PDC_ACS(18), PDC_ACS(19),
+ PDC_ACS(20), PDC_ACS(21), PDC_ACS(22), PDC_ACS(23), PDC_ACS(24),
+ PDC_ACS(25), PDC_ACS(26), PDC_ACS(27), PDC_ACS(28), PDC_ACS(29),
+ PDC_ACS(30), PDC_ACS(31), ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*',
+
+ PDC_ACS(0x1a), PDC_ACS(0x1b), PDC_ACS(0x18), PDC_ACS(0x19),
+
+ '/',
+
+ 0xdb,
+
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=',
+ '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+
+ PDC_ACS(0x04), 0xb1,
+
+ 'b', 'c', 'd', 'e',
+
+ 0xf8, 0xf1, 0xb0, PDC_ACS(0x0f), 0xd9, 0xbf, 0xda, 0xc0, 0xc5, 0x2d,
+ 0x2d, 0xc4, 0x2d, 0x5f, 0xc3, 0xb4, 0xc1, 0xc2, 0xb3, 0xf3, 0xf2,
+ 0xe3, 0xd8, 0x9c, 0xf9,
+
+ PDC_ACS(127)
+};
diff --git a/Utilities/cmpdcurses/common/acsuni.h b/Utilities/cmpdcurses/common/acsuni.h
new file mode 100644
index 0000000..2fdad8a
--- /dev/null
+++ b/Utilities/cmpdcurses/common/acsuni.h
@@ -0,0 +1,35 @@
+/* ACS Unicode mapping */
+
+chtype acs_map[128] =
+{
+ PDC_ACS(0), PDC_ACS(1), PDC_ACS(2), PDC_ACS(3), PDC_ACS(4),
+ PDC_ACS(5), PDC_ACS(6), PDC_ACS(7), PDC_ACS(8), PDC_ACS(9),
+ PDC_ACS(10), PDC_ACS(11), PDC_ACS(12), PDC_ACS(13), PDC_ACS(14),
+ PDC_ACS(15), PDC_ACS(16), PDC_ACS(17), PDC_ACS(18), PDC_ACS(19),
+ PDC_ACS(20), PDC_ACS(21), PDC_ACS(22), PDC_ACS(23), PDC_ACS(24),
+ PDC_ACS(25), PDC_ACS(26), PDC_ACS(27), PDC_ACS(28), PDC_ACS(29),
+ PDC_ACS(30), PDC_ACS(31), ' ', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*',
+
+ 0x2192, 0x2190, 0x2191, 0x2193,
+
+ '/',
+
+ 0x2588,
+
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=',
+ '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+
+ 0x2666, 0x2592,
+
+ 'b', 'c', 'd', 'e',
+
+ 0x00b0, 0x00b1, 0x2591, 0x00a4, 0x2518, 0x2510, 0x250c, 0x2514,
+ 0x253c, 0x23ba, 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524,
+ 0x2534, 0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3,
+ 0x00b7,
+
+ PDC_ACS(127)
+};
diff --git a/Utilities/cmpdcurses/curses.h b/Utilities/cmpdcurses/curses.h
new file mode 100644
index 0000000..7a148d4
--- /dev/null
+++ b/Utilities/cmpdcurses/curses.h
@@ -0,0 +1,1417 @@
+/*----------------------------------------------------------------------*
+ * PDCurses *
+ *----------------------------------------------------------------------*/
+
+#ifndef __PDCURSES__
+#define __PDCURSES__ 1
+
+/*man-start**************************************************************
+
+Define before inclusion (only those needed):
+
+ XCURSES if building / built for X11
+ PDC_RGB if you want to use RGB color definitions
+ (Red = 1, Green = 2, Blue = 4) instead of BGR
+ PDC_WIDE if building / built with wide-character support
+ PDC_DLL_BUILD if building / built as a Windows DLL
+ PDC_NCMOUSE to use the ncurses mouse API instead
+ of PDCurses' traditional mouse API
+
+Defined by this header:
+
+ PDCURSES PDCurses-only features are available
+ PDC_BUILD API build version
+ PDC_VER_MAJOR major version number
+ PDC_VER_MINOR minor version number
+ PDC_VERDOT version string
+
+**man-end****************************************************************/
+
+#define PDCURSES 1
+#define PDC_BUILD 3906
+#define PDC_VER_MAJOR 3
+#define PDC_VER_MINOR 9
+#define PDC_VERDOT "3.9"
+
+#define CHTYPE_LONG 1 /* chtype >= 32 bits */
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+# define PDC_99 1
+#endif
+
+#if defined(__cplusplus) && __cplusplus >= 199711L
+# define PDC_PP98 1
+#endif
+
+/*----------------------------------------------------------------------*/
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#ifdef PDC_WIDE
+# include <wchar.h>
+#endif
+
+#if defined(PDC_99) && !defined(__bool_true_false_are_defined)
+# include <stdbool.h>
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+# ifndef PDC_PP98
+# define bool _bool
+# endif
+#endif
+
+/*----------------------------------------------------------------------
+ *
+ * Constants and Types
+ *
+ */
+
+#undef FALSE
+#define FALSE 0
+
+#undef TRUE
+#define TRUE 1
+
+#undef ERR
+#define ERR (-1)
+
+#undef OK
+#define OK 0
+
+#if !defined(PDC_PP98) && !defined(__bool_true_false_are_defined)
+typedef unsigned char bool;
+#endif
+
+#if _LP64
+typedef unsigned int chtype;
+#else
+typedef unsigned long chtype; /* 16-bit attr + 16-bit char */
+#endif
+
+#ifdef PDC_WIDE
+typedef chtype cchar_t;
+#endif
+
+typedef chtype attr_t;
+
+/*----------------------------------------------------------------------
+ *
+ * Version Info
+ *
+ */
+
+/* Use this structure with PDC_get_version() for run-time info about the
+ way the library was built, in case it doesn't match the header. */
+
+typedef struct
+{
+ short flags; /* flags OR'd together (see below) */
+ short build; /* PDC_BUILD at compile time */
+ unsigned char major; /* PDC_VER_MAJOR */
+ unsigned char minor; /* PDC_VER_MINOR */
+ unsigned char csize; /* sizeof chtype */
+ unsigned char bsize; /* sizeof bool */
+} PDC_VERSION;
+
+enum
+{
+ PDC_VFLAG_DEBUG = 1, /* set if built with -DPDCDEBUG */
+ PDC_VFLAG_WIDE = 2, /* -DPDC_WIDE */
+ PDC_VFLAG_UTF8 = 4, /* -DPDC_FORCE_UTF8 */
+ PDC_VFLAG_DLL = 8, /* -DPDC_DLL_BUILD */
+ PDC_VFLAG_RGB = 16 /* -DPDC_RGB */
+};
+
+/*----------------------------------------------------------------------
+ *
+ * Mouse Interface
+ *
+ */
+
+#if _LP64
+typedef unsigned int mmask_t;
+#else
+typedef unsigned long mmask_t;
+#endif
+
+typedef struct
+{
+ int x; /* absolute column, 0 based, measured in characters */
+ int y; /* absolute row, 0 based, measured in characters */
+ short button[3]; /* state of each button */
+ int changes; /* flags indicating what has changed with the mouse */
+} MOUSE_STATUS;
+
+#define BUTTON_RELEASED 0x0000
+#define BUTTON_PRESSED 0x0001
+#define BUTTON_CLICKED 0x0002
+#define BUTTON_DOUBLE_CLICKED 0x0003
+#define BUTTON_TRIPLE_CLICKED 0x0004
+#define BUTTON_MOVED 0x0005 /* PDCurses */
+#define WHEEL_SCROLLED 0x0006 /* PDCurses */
+#define BUTTON_ACTION_MASK 0x0007 /* PDCurses */
+
+#define PDC_BUTTON_SHIFT 0x0008 /* PDCurses */
+#define PDC_BUTTON_CONTROL 0x0010 /* PDCurses */
+#define PDC_BUTTON_ALT 0x0020 /* PDCurses */
+#define BUTTON_MODIFIER_MASK 0x0038 /* PDCurses */
+
+#define MOUSE_X_POS (Mouse_status.x)
+#define MOUSE_Y_POS (Mouse_status.y)
+
+/*
+ * Bits associated with the .changes field:
+ * 3 2 1 0
+ * 210987654321098765432109876543210
+ * 1 <- button 1 has changed
+ * 10 <- button 2 has changed
+ * 100 <- button 3 has changed
+ * 1000 <- mouse has moved
+ * 10000 <- mouse position report
+ * 100000 <- mouse wheel up
+ * 1000000 <- mouse wheel down
+ * 10000000 <- mouse wheel left
+ * 100000000 <- mouse wheel right
+ */
+
+#define PDC_MOUSE_MOVED 0x0008
+#define PDC_MOUSE_POSITION 0x0010
+#define PDC_MOUSE_WHEEL_UP 0x0020
+#define PDC_MOUSE_WHEEL_DOWN 0x0040
+#define PDC_MOUSE_WHEEL_LEFT 0x0080
+#define PDC_MOUSE_WHEEL_RIGHT 0x0100
+
+#define A_BUTTON_CHANGED (Mouse_status.changes & 7)
+#define MOUSE_MOVED (Mouse_status.changes & PDC_MOUSE_MOVED)
+#define MOUSE_POS_REPORT (Mouse_status.changes & PDC_MOUSE_POSITION)
+#define BUTTON_CHANGED(x) (Mouse_status.changes & (1 << ((x) - 1)))
+#define BUTTON_STATUS(x) (Mouse_status.button[(x) - 1])
+#define MOUSE_WHEEL_UP (Mouse_status.changes & PDC_MOUSE_WHEEL_UP)
+#define MOUSE_WHEEL_DOWN (Mouse_status.changes & PDC_MOUSE_WHEEL_DOWN)
+#define MOUSE_WHEEL_LEFT (Mouse_status.changes & PDC_MOUSE_WHEEL_LEFT)
+#define MOUSE_WHEEL_RIGHT (Mouse_status.changes & PDC_MOUSE_WHEEL_RIGHT)
+
+/* mouse bit-masks */
+
+#define BUTTON1_RELEASED 0x00000001L
+#define BUTTON1_PRESSED 0x00000002L
+#define BUTTON1_CLICKED 0x00000004L
+#define BUTTON1_DOUBLE_CLICKED 0x00000008L
+#define BUTTON1_TRIPLE_CLICKED 0x00000010L
+#define BUTTON1_MOVED 0x00000010L /* PDCurses */
+
+#define BUTTON2_RELEASED 0x00000020L
+#define BUTTON2_PRESSED 0x00000040L
+#define BUTTON2_CLICKED 0x00000080L
+#define BUTTON2_DOUBLE_CLICKED 0x00000100L
+#define BUTTON2_TRIPLE_CLICKED 0x00000200L
+#define BUTTON2_MOVED 0x00000200L /* PDCurses */
+
+#define BUTTON3_RELEASED 0x00000400L
+#define BUTTON3_PRESSED 0x00000800L
+#define BUTTON3_CLICKED 0x00001000L
+#define BUTTON3_DOUBLE_CLICKED 0x00002000L
+#define BUTTON3_TRIPLE_CLICKED 0x00004000L
+#define BUTTON3_MOVED 0x00004000L /* PDCurses */
+
+/* For the ncurses-compatible functions only, BUTTON4_PRESSED and
+ BUTTON5_PRESSED are returned for mouse scroll wheel up and down;
+ otherwise PDCurses doesn't support buttons 4 and 5 */
+
+#define BUTTON4_RELEASED 0x00008000L
+#define BUTTON4_PRESSED 0x00010000L
+#define BUTTON4_CLICKED 0x00020000L
+#define BUTTON4_DOUBLE_CLICKED 0x00040000L
+#define BUTTON4_TRIPLE_CLICKED 0x00080000L
+
+#define BUTTON5_RELEASED 0x00100000L
+#define BUTTON5_PRESSED 0x00200000L
+#define BUTTON5_CLICKED 0x00400000L
+#define BUTTON5_DOUBLE_CLICKED 0x00800000L
+#define BUTTON5_TRIPLE_CLICKED 0x01000000L
+
+#define MOUSE_WHEEL_SCROLL 0x02000000L /* PDCurses */
+#define BUTTON_MODIFIER_SHIFT 0x04000000L /* PDCurses */
+#define BUTTON_MODIFIER_CONTROL 0x08000000L /* PDCurses */
+#define BUTTON_MODIFIER_ALT 0x10000000L /* PDCurses */
+
+#define ALL_MOUSE_EVENTS 0x1fffffffL
+#define REPORT_MOUSE_POSITION 0x20000000L
+
+/* ncurses mouse interface */
+
+typedef struct
+{
+ short id; /* unused, always 0 */
+ int x, y, z; /* x, y same as MOUSE_STATUS; z unused */
+ mmask_t bstate; /* equivalent to changes + button[], but
+ in the same format as used for mousemask() */
+} MEVENT;
+
+#if defined(PDC_NCMOUSE) && !defined(NCURSES_MOUSE_VERSION)
+# define NCURSES_MOUSE_VERSION 2
+#endif
+
+#ifdef NCURSES_MOUSE_VERSION
+# define BUTTON_SHIFT BUTTON_MODIFIER_SHIFT
+# define BUTTON_CONTROL BUTTON_MODIFIER_CONTROL
+# define BUTTON_CTRL BUTTON_MODIFIER_CONTROL
+# define BUTTON_ALT BUTTON_MODIFIER_ALT
+#else
+# define BUTTON_SHIFT PDC_BUTTON_SHIFT
+# define BUTTON_CONTROL PDC_BUTTON_CONTROL
+# define BUTTON_ALT PDC_BUTTON_ALT
+#endif
+
+/*----------------------------------------------------------------------
+ *
+ * Window and Screen Structures
+ *
+ */
+
+typedef struct _win /* definition of a window */
+{
+ int _cury; /* current pseudo-cursor */
+ int _curx;
+ int _maxy; /* max window coordinates */
+ int _maxx;
+ int _begy; /* origin on screen */
+ int _begx;
+ int _flags; /* window properties */
+ chtype _attrs; /* standard attributes and colors */
+ chtype _bkgd; /* background, normally blank */
+ bool _clear; /* causes clear at next refresh */
+ bool _leaveit; /* leaves cursor where it is */
+ bool _scroll; /* allows window scrolling */
+ bool _nodelay; /* input character wait flag */
+ bool _immed; /* immediate update flag */
+ bool _sync; /* synchronise window ancestors */
+ bool _use_keypad; /* flags keypad key mode active */
+ chtype **_y; /* pointer to line pointer array */
+ int *_firstch; /* first changed character in line */
+ int *_lastch; /* last changed character in line */
+ int _tmarg; /* top of scrolling region */
+ int _bmarg; /* bottom of scrolling region */
+ int _delayms; /* milliseconds of delay for getch() */
+ int _parx, _pary; /* coords relative to parent (0,0) */
+ struct _win *_parent; /* subwin's pointer to parent win */
+} WINDOW;
+
+/* Color pair structure */
+
+typedef struct
+{
+ short f; /* foreground color */
+ short b; /* background color */
+ int count; /* allocation order */
+ bool set; /* pair has been set */
+} PDC_PAIR;
+
+/* Avoid using the SCREEN struct directly -- use the corresponding
+ functions if possible. This struct may eventually be made private. */
+
+typedef struct
+{
+ bool alive; /* if initscr() called, and not endwin() */
+ bool autocr; /* if cr -> lf */
+ bool cbreak; /* if terminal unbuffered */
+ bool echo; /* if terminal echo */
+ bool raw_inp; /* raw input mode (v. cooked input) */
+ bool raw_out; /* raw output mode (7 v. 8 bits) */
+ bool audible; /* FALSE if the bell is visual */
+ bool mono; /* TRUE if current screen is mono */
+ bool resized; /* TRUE if TERM has been resized */
+ bool orig_attr; /* TRUE if we have the original colors */
+ short orig_fore; /* original screen foreground color */
+ short orig_back; /* original screen foreground color */
+ int cursrow; /* position of physical cursor */
+ int curscol; /* position of physical cursor */
+ int visibility; /* visibility of cursor */
+ int orig_cursor; /* original cursor size */
+ int lines; /* new value for LINES */
+ int cols; /* new value for COLS */
+ mmask_t _trap_mbe; /* trap these mouse button events */
+ int mouse_wait; /* time to wait (in ms) for a
+ button release after a press, in
+ order to count it as a click */
+ int slklines; /* lines in use by slk_init() */
+ WINDOW *slk_winptr; /* window for slk */
+ int linesrippedoff; /* lines ripped off via ripoffline() */
+ int linesrippedoffontop; /* lines ripped off on
+ top via ripoffline() */
+ int delaytenths; /* 1/10ths second to wait block
+ getch() for */
+ bool _preserve; /* TRUE if screen background
+ to be preserved */
+ int _restore; /* specifies if screen background
+ to be restored, and how */
+ unsigned long key_modifiers; /* key modifiers (SHIFT, CONTROL, etc.)
+ on last key press */
+ bool return_key_modifiers; /* TRUE if modifier keys are
+ returned as "real" keys */
+ bool key_code; /* TRUE if last key is a special key;
+ used internally by get_wch() */
+ MOUSE_STATUS mouse_status; /* last returned mouse status */
+ short line_color; /* color of line attributes - default -1 */
+ attr_t termattrs; /* attribute capabilities */
+ WINDOW *lastscr; /* the last screen image */
+ FILE *dbfp; /* debug trace file pointer */
+ bool color_started; /* TRUE after start_color() */
+ bool dirty; /* redraw on napms() after init_color() */
+ int sel_start; /* start of selection (y * COLS + x) */
+ int sel_end; /* end of selection */
+ int *c_buffer; /* character buffer */
+ int c_pindex; /* putter index */
+ int c_gindex; /* getter index */
+ int *c_ungch; /* array of ungotten chars */
+ int c_ungind; /* ungetch() push index */
+ int c_ungmax; /* allocated size of ungetch() buffer */
+ PDC_PAIR *atrtab; /* table of color pairs */
+} SCREEN;
+
+/*----------------------------------------------------------------------
+ *
+ * External Variables
+ *
+ */
+
+#ifdef PDC_DLL_BUILD
+# ifdef CURSES_LIBRARY
+# define PDCEX __declspec(dllexport) extern
+# else
+# define PDCEX __declspec(dllimport)
+# endif
+#else
+# define PDCEX extern
+#endif
+
+PDCEX int LINES; /* terminal height */
+PDCEX int COLS; /* terminal width */
+PDCEX WINDOW *stdscr; /* the default screen window */
+PDCEX WINDOW *curscr; /* the current screen image */
+PDCEX SCREEN *SP; /* curses variables */
+PDCEX MOUSE_STATUS Mouse_status;
+PDCEX int COLORS;
+PDCEX int COLOR_PAIRS;
+PDCEX int TABSIZE;
+PDCEX chtype acs_map[]; /* alternate character set map */
+PDCEX char ttytype[]; /* terminal name/description */
+
+/*man-start**************************************************************
+
+Text Attributes
+===============
+
+PDCurses uses a 32-bit integer for its chtype:
+
+ +--------------------------------------------------------------------+
+ |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|..| 2| 1| 0|
+ +--------------------------------------------------------------------+
+ color pair | modifiers | character eg 'a'
+
+There are 256 color pairs (8 bits), 8 bits for modifiers, and 16 bits
+for character data. The modifiers are bold, underline, right-line,
+left-line, italic, reverse and blink, plus the alternate character set
+indicator.
+
+**man-end****************************************************************/
+
+/*** Video attribute macros ***/
+
+#define A_NORMAL (chtype)0
+
+#define A_ALTCHARSET (chtype)0x00010000
+#define A_RIGHT (chtype)0x00020000
+#define A_LEFT (chtype)0x00040000
+#define A_ITALIC (chtype)0x00080000
+#define A_UNDERLINE (chtype)0x00100000
+#define A_REVERSE (chtype)0x00200000
+#define A_BLINK (chtype)0x00400000
+#define A_BOLD (chtype)0x00800000
+
+#define A_ATTRIBUTES (chtype)0xffff0000
+#define A_CHARTEXT (chtype)0x0000ffff
+#define A_COLOR (chtype)0xff000000
+
+#define PDC_COLOR_SHIFT 24
+
+#define A_LEFTLINE A_LEFT
+#define A_RIGHTLINE A_RIGHT
+#define A_STANDOUT (A_REVERSE | A_BOLD) /* X/Open */
+
+#define A_DIM A_NORMAL
+#define A_INVIS A_NORMAL
+#define A_PROTECT A_NORMAL
+
+#define A_HORIZONTAL A_NORMAL
+#define A_LOW A_NORMAL
+#define A_TOP A_NORMAL
+#define A_VERTICAL A_NORMAL
+
+#define CHR_MSK A_CHARTEXT /* Obsolete */
+#define ATR_MSK A_ATTRIBUTES /* Obsolete */
+#define ATR_NRM A_NORMAL /* Obsolete */
+
+/* For use with attr_t -- X/Open says, "these shall be distinct", so
+ this is a non-conforming implementation. */
+
+#define WA_NORMAL A_NORMAL
+
+#define WA_ALTCHARSET A_ALTCHARSET
+#define WA_BLINK A_BLINK
+#define WA_BOLD A_BOLD
+#define WA_DIM A_DIM
+#define WA_INVIS A_INVIS
+#define WA_ITALIC A_ITALIC
+#define WA_LEFT A_LEFT
+#define WA_PROTECT A_PROTECT
+#define WA_REVERSE A_REVERSE
+#define WA_RIGHT A_RIGHT
+#define WA_STANDOUT A_STANDOUT
+#define WA_UNDERLINE A_UNDERLINE
+
+#define WA_HORIZONTAL A_HORIZONTAL
+#define WA_LOW A_LOW
+#define WA_TOP A_TOP
+#define WA_VERTICAL A_VERTICAL
+
+#define WA_ATTRIBUTES A_ATTRIBUTES
+
+/*** Alternate character set macros ***/
+
+#define PDC_ACS(w) ((chtype)w | A_ALTCHARSET)
+
+/* VT100-compatible symbols -- box chars */
+
+#define ACS_ULCORNER PDC_ACS('l')
+#define ACS_LLCORNER PDC_ACS('m')
+#define ACS_URCORNER PDC_ACS('k')
+#define ACS_LRCORNER PDC_ACS('j')
+#define ACS_RTEE PDC_ACS('u')
+#define ACS_LTEE PDC_ACS('t')
+#define ACS_BTEE PDC_ACS('v')
+#define ACS_TTEE PDC_ACS('w')
+#define ACS_HLINE PDC_ACS('q')
+#define ACS_VLINE PDC_ACS('x')
+#define ACS_PLUS PDC_ACS('n')
+
+/* VT100-compatible symbols -- other */
+
+#define ACS_S1 PDC_ACS('o')
+#define ACS_S9 PDC_ACS('s')
+#define ACS_DIAMOND PDC_ACS('`')
+#define ACS_CKBOARD PDC_ACS('a')
+#define ACS_DEGREE PDC_ACS('f')
+#define ACS_PLMINUS PDC_ACS('g')
+#define ACS_BULLET PDC_ACS('~')
+
+/* Teletype 5410v1 symbols -- these are defined in SysV curses, but
+ are not well-supported by most terminals. Stick to VT100 characters
+ for optimum portability. */
+
+#define ACS_LARROW PDC_ACS(',')
+#define ACS_RARROW PDC_ACS('+')
+#define ACS_DARROW PDC_ACS('.')
+#define ACS_UARROW PDC_ACS('-')
+#define ACS_BOARD PDC_ACS('h')
+#define ACS_LANTERN PDC_ACS('i')
+#define ACS_BLOCK PDC_ACS('0')
+
+/* That goes double for these -- undocumented SysV symbols. Don't use
+ them. */
+
+#define ACS_S3 PDC_ACS('p')
+#define ACS_S7 PDC_ACS('r')
+#define ACS_LEQUAL PDC_ACS('y')
+#define ACS_GEQUAL PDC_ACS('z')
+#define ACS_PI PDC_ACS('{')
+#define ACS_NEQUAL PDC_ACS('|')
+#define ACS_STERLING PDC_ACS('}')
+
+/* Box char aliases */
+
+#define ACS_BSSB ACS_ULCORNER
+#define ACS_SSBB ACS_LLCORNER
+#define ACS_BBSS ACS_URCORNER
+#define ACS_SBBS ACS_LRCORNER
+#define ACS_SBSS ACS_RTEE
+#define ACS_SSSB ACS_LTEE
+#define ACS_SSBS ACS_BTEE
+#define ACS_BSSS ACS_TTEE
+#define ACS_BSBS ACS_HLINE
+#define ACS_SBSB ACS_VLINE
+#define ACS_SSSS ACS_PLUS
+
+/* cchar_t aliases */
+
+#ifdef PDC_WIDE
+# define WACS_ULCORNER (&(acs_map['l']))
+# define WACS_LLCORNER (&(acs_map['m']))
+# define WACS_URCORNER (&(acs_map['k']))
+# define WACS_LRCORNER (&(acs_map['j']))
+# define WACS_RTEE (&(acs_map['u']))
+# define WACS_LTEE (&(acs_map['t']))
+# define WACS_BTEE (&(acs_map['v']))
+# define WACS_TTEE (&(acs_map['w']))
+# define WACS_HLINE (&(acs_map['q']))
+# define WACS_VLINE (&(acs_map['x']))
+# define WACS_PLUS (&(acs_map['n']))
+
+# define WACS_S1 (&(acs_map['o']))
+# define WACS_S9 (&(acs_map['s']))
+# define WACS_DIAMOND (&(acs_map['`']))
+# define WACS_CKBOARD (&(acs_map['a']))
+# define WACS_DEGREE (&(acs_map['f']))
+# define WACS_PLMINUS (&(acs_map['g']))
+# define WACS_BULLET (&(acs_map['~']))
+
+# define WACS_LARROW (&(acs_map[',']))
+# define WACS_RARROW (&(acs_map['+']))
+# define WACS_DARROW (&(acs_map['.']))
+# define WACS_UARROW (&(acs_map['-']))
+# define WACS_BOARD (&(acs_map['h']))
+# define WACS_LANTERN (&(acs_map['i']))
+# define WACS_BLOCK (&(acs_map['0']))
+
+# define WACS_S3 (&(acs_map['p']))
+# define WACS_S7 (&(acs_map['r']))
+# define WACS_LEQUAL (&(acs_map['y']))
+# define WACS_GEQUAL (&(acs_map['z']))
+# define WACS_PI (&(acs_map['{']))
+# define WACS_NEQUAL (&(acs_map['|']))
+# define WACS_STERLING (&(acs_map['}']))
+
+# define WACS_BSSB WACS_ULCORNER
+# define WACS_SSBB WACS_LLCORNER
+# define WACS_BBSS WACS_URCORNER
+# define WACS_SBBS WACS_LRCORNER
+# define WACS_SBSS WACS_RTEE
+# define WACS_SSSB WACS_LTEE
+# define WACS_SSBS WACS_BTEE
+# define WACS_BSSS WACS_TTEE
+# define WACS_BSBS WACS_HLINE
+# define WACS_SBSB WACS_VLINE
+# define WACS_SSSS WACS_PLUS
+#endif
+
+/*** Color macros ***/
+
+#define COLOR_BLACK 0
+
+#ifdef PDC_RGB /* RGB */
+# define COLOR_RED 1
+# define COLOR_GREEN 2
+# define COLOR_BLUE 4
+#else /* BGR */
+# define COLOR_BLUE 1
+# define COLOR_GREEN 2
+# define COLOR_RED 4
+#endif
+
+#define COLOR_CYAN (COLOR_BLUE | COLOR_GREEN)
+#define COLOR_MAGENTA (COLOR_RED | COLOR_BLUE)
+#define COLOR_YELLOW (COLOR_RED | COLOR_GREEN)
+
+#define COLOR_WHITE 7
+
+/*----------------------------------------------------------------------
+ *
+ * Function and Keypad Key Definitions
+ * Many are just for compatibility
+ *
+ */
+
+#define KEY_CODE_YES 0x100 /* If get_wch() gives a key code */
+
+#define KEY_BREAK 0x101 /* Not on PC KBD */
+#define KEY_DOWN 0x102 /* Down arrow key */
+#define KEY_UP 0x103 /* Up arrow key */
+#define KEY_LEFT 0x104 /* Left arrow key */
+#define KEY_RIGHT 0x105 /* Right arrow key */
+#define KEY_HOME 0x106 /* home key */
+#define KEY_BACKSPACE 0x107 /* not on pc */
+#define KEY_F0 0x108 /* function keys; 64 reserved */
+
+#define KEY_DL 0x148 /* delete line */
+#define KEY_IL 0x149 /* insert line */
+#define KEY_DC 0x14a /* delete character */
+#define KEY_IC 0x14b /* insert char or enter ins mode */
+#define KEY_EIC 0x14c /* exit insert char mode */
+#define KEY_CLEAR 0x14d /* clear screen */
+#define KEY_EOS 0x14e /* clear to end of screen */
+#define KEY_EOL 0x14f /* clear to end of line */
+#define KEY_SF 0x150 /* scroll 1 line forward */
+#define KEY_SR 0x151 /* scroll 1 line back (reverse) */
+#define KEY_NPAGE 0x152 /* next page */
+#define KEY_PPAGE 0x153 /* previous page */
+#define KEY_STAB 0x154 /* set tab */
+#define KEY_CTAB 0x155 /* clear tab */
+#define KEY_CATAB 0x156 /* clear all tabs */
+#define KEY_ENTER 0x157 /* enter or send (unreliable) */
+#define KEY_SRESET 0x158 /* soft/reset (partial/unreliable) */
+#define KEY_RESET 0x159 /* reset/hard reset (unreliable) */
+#define KEY_PRINT 0x15a /* print/copy */
+#define KEY_LL 0x15b /* home down/bottom (lower left) */
+#define KEY_ABORT 0x15c /* abort/terminate key (any) */
+#define KEY_SHELP 0x15d /* short help */
+#define KEY_LHELP 0x15e /* long help */
+#define KEY_BTAB 0x15f /* Back tab key */
+#define KEY_BEG 0x160 /* beg(inning) key */
+#define KEY_CANCEL 0x161 /* cancel key */
+#define KEY_CLOSE 0x162 /* close key */
+#define KEY_COMMAND 0x163 /* cmd (command) key */
+#define KEY_COPY 0x164 /* copy key */
+#define KEY_CREATE 0x165 /* create key */
+#define KEY_END 0x166 /* end key */
+#define KEY_EXIT 0x167 /* exit key */
+#define KEY_FIND 0x168 /* find key */
+#define KEY_HELP 0x169 /* help key */
+#define KEY_MARK 0x16a /* mark key */
+#define KEY_MESSAGE 0x16b /* message key */
+#define KEY_MOVE 0x16c /* move key */
+#define KEY_NEXT 0x16d /* next object key */
+#define KEY_OPEN 0x16e /* open key */
+#define KEY_OPTIONS 0x16f /* options key */
+#define KEY_PREVIOUS 0x170 /* previous object key */
+#define KEY_REDO 0x171 /* redo key */
+#define KEY_REFERENCE 0x172 /* ref(erence) key */
+#define KEY_REFRESH 0x173 /* refresh key */
+#define KEY_REPLACE 0x174 /* replace key */
+#define KEY_RESTART 0x175 /* restart key */
+#define KEY_RESUME 0x176 /* resume key */
+#define KEY_SAVE 0x177 /* save key */
+#define KEY_SBEG 0x178 /* shifted beginning key */
+#define KEY_SCANCEL 0x179 /* shifted cancel key */
+#define KEY_SCOMMAND 0x17a /* shifted command key */
+#define KEY_SCOPY 0x17b /* shifted copy key */
+#define KEY_SCREATE 0x17c /* shifted create key */
+#define KEY_SDC 0x17d /* shifted delete char key */
+#define KEY_SDL 0x17e /* shifted delete line key */
+#define KEY_SELECT 0x17f /* select key */
+#define KEY_SEND 0x180 /* shifted end key */
+#define KEY_SEOL 0x181 /* shifted clear line key */
+#define KEY_SEXIT 0x182 /* shifted exit key */
+#define KEY_SFIND 0x183 /* shifted find key */
+#define KEY_SHOME 0x184 /* shifted home key */
+#define KEY_SIC 0x185 /* shifted input key */
+
+#define KEY_SLEFT 0x187 /* shifted left arrow key */
+#define KEY_SMESSAGE 0x188 /* shifted message key */
+#define KEY_SMOVE 0x189 /* shifted move key */
+#define KEY_SNEXT 0x18a /* shifted next key */
+#define KEY_SOPTIONS 0x18b /* shifted options key */
+#define KEY_SPREVIOUS 0x18c /* shifted prev key */
+#define KEY_SPRINT 0x18d /* shifted print key */
+#define KEY_SREDO 0x18e /* shifted redo key */
+#define KEY_SREPLACE 0x18f /* shifted replace key */
+#define KEY_SRIGHT 0x190 /* shifted right arrow */
+#define KEY_SRSUME 0x191 /* shifted resume key */
+#define KEY_SSAVE 0x192 /* shifted save key */
+#define KEY_SSUSPEND 0x193 /* shifted suspend key */
+#define KEY_SUNDO 0x194 /* shifted undo key */
+#define KEY_SUSPEND 0x195 /* suspend key */
+#define KEY_UNDO 0x196 /* undo key */
+
+/* PDCurses-specific key definitions -- PC only */
+
+#define ALT_0 0x197
+#define ALT_1 0x198
+#define ALT_2 0x199
+#define ALT_3 0x19a
+#define ALT_4 0x19b
+#define ALT_5 0x19c
+#define ALT_6 0x19d
+#define ALT_7 0x19e
+#define ALT_8 0x19f
+#define ALT_9 0x1a0
+#define ALT_A 0x1a1
+#define ALT_B 0x1a2
+#define ALT_C 0x1a3
+#define ALT_D 0x1a4
+#define ALT_E 0x1a5
+#define ALT_F 0x1a6
+#define ALT_G 0x1a7
+#define ALT_H 0x1a8
+#define ALT_I 0x1a9
+#define ALT_J 0x1aa
+#define ALT_K 0x1ab
+#define ALT_L 0x1ac
+#define ALT_M 0x1ad
+#define ALT_N 0x1ae
+#define ALT_O 0x1af
+#define ALT_P 0x1b0
+#define ALT_Q 0x1b1
+#define ALT_R 0x1b2
+#define ALT_S 0x1b3
+#define ALT_T 0x1b4
+#define ALT_U 0x1b5
+#define ALT_V 0x1b6
+#define ALT_W 0x1b7
+#define ALT_X 0x1b8
+#define ALT_Y 0x1b9
+#define ALT_Z 0x1ba
+
+#define CTL_LEFT 0x1bb /* Control-Left-Arrow */
+#define CTL_RIGHT 0x1bc
+#define CTL_PGUP 0x1bd
+#define CTL_PGDN 0x1be
+#define CTL_HOME 0x1bf
+#define CTL_END 0x1c0
+
+#define KEY_A1 0x1c1 /* upper left on Virtual keypad */
+#define KEY_A2 0x1c2 /* upper middle on Virt. keypad */
+#define KEY_A3 0x1c3 /* upper right on Vir. keypad */
+#define KEY_B1 0x1c4 /* middle left on Virt. keypad */
+#define KEY_B2 0x1c5 /* center on Virt. keypad */
+#define KEY_B3 0x1c6 /* middle right on Vir. keypad */
+#define KEY_C1 0x1c7 /* lower left on Virt. keypad */
+#define KEY_C2 0x1c8 /* lower middle on Virt. keypad */
+#define KEY_C3 0x1c9 /* lower right on Vir. keypad */
+
+#define PADSLASH 0x1ca /* slash on keypad */
+#define PADENTER 0x1cb /* enter on keypad */
+#define CTL_PADENTER 0x1cc /* ctl-enter on keypad */
+#define ALT_PADENTER 0x1cd /* alt-enter on keypad */
+#define PADSTOP 0x1ce /* stop on keypad */
+#define PADSTAR 0x1cf /* star on keypad */
+#define PADMINUS 0x1d0 /* minus on keypad */
+#define PADPLUS 0x1d1 /* plus on keypad */
+#define CTL_PADSTOP 0x1d2 /* ctl-stop on keypad */
+#define CTL_PADCENTER 0x1d3 /* ctl-enter on keypad */
+#define CTL_PADPLUS 0x1d4 /* ctl-plus on keypad */
+#define CTL_PADMINUS 0x1d5 /* ctl-minus on keypad */
+#define CTL_PADSLASH 0x1d6 /* ctl-slash on keypad */
+#define CTL_PADSTAR 0x1d7 /* ctl-star on keypad */
+#define ALT_PADPLUS 0x1d8 /* alt-plus on keypad */
+#define ALT_PADMINUS 0x1d9 /* alt-minus on keypad */
+#define ALT_PADSLASH 0x1da /* alt-slash on keypad */
+#define ALT_PADSTAR 0x1db /* alt-star on keypad */
+#define ALT_PADSTOP 0x1dc /* alt-stop on keypad */
+#define CTL_INS 0x1dd /* ctl-insert */
+#define ALT_DEL 0x1de /* alt-delete */
+#define ALT_INS 0x1df /* alt-insert */
+#define CTL_UP 0x1e0 /* ctl-up arrow */
+#define CTL_DOWN 0x1e1 /* ctl-down arrow */
+#define CTL_TAB 0x1e2 /* ctl-tab */
+#define ALT_TAB 0x1e3
+#define ALT_MINUS 0x1e4
+#define ALT_EQUAL 0x1e5
+#define ALT_HOME 0x1e6
+#define ALT_PGUP 0x1e7
+#define ALT_PGDN 0x1e8
+#define ALT_END 0x1e9
+#define ALT_UP 0x1ea /* alt-up arrow */
+#define ALT_DOWN 0x1eb /* alt-down arrow */
+#define ALT_RIGHT 0x1ec /* alt-right arrow */
+#define ALT_LEFT 0x1ed /* alt-left arrow */
+#define ALT_ENTER 0x1ee /* alt-enter */
+#define ALT_ESC 0x1ef /* alt-escape */
+#define ALT_BQUOTE 0x1f0 /* alt-back quote */
+#define ALT_LBRACKET 0x1f1 /* alt-left bracket */
+#define ALT_RBRACKET 0x1f2 /* alt-right bracket */
+#define ALT_SEMICOLON 0x1f3 /* alt-semi-colon */
+#define ALT_FQUOTE 0x1f4 /* alt-forward quote */
+#define ALT_COMMA 0x1f5 /* alt-comma */
+#define ALT_STOP 0x1f6 /* alt-stop */
+#define ALT_FSLASH 0x1f7 /* alt-forward slash */
+#define ALT_BKSP 0x1f8 /* alt-backspace */
+#define CTL_BKSP 0x1f9 /* ctl-backspace */
+#define PAD0 0x1fa /* keypad 0 */
+
+#define CTL_PAD0 0x1fb /* ctl-keypad 0 */
+#define CTL_PAD1 0x1fc
+#define CTL_PAD2 0x1fd
+#define CTL_PAD3 0x1fe
+#define CTL_PAD4 0x1ff
+#define CTL_PAD5 0x200
+#define CTL_PAD6 0x201
+#define CTL_PAD7 0x202
+#define CTL_PAD8 0x203
+#define CTL_PAD9 0x204
+
+#define ALT_PAD0 0x205 /* alt-keypad 0 */
+#define ALT_PAD1 0x206
+#define ALT_PAD2 0x207
+#define ALT_PAD3 0x208
+#define ALT_PAD4 0x209
+#define ALT_PAD5 0x20a
+#define ALT_PAD6 0x20b
+#define ALT_PAD7 0x20c
+#define ALT_PAD8 0x20d
+#define ALT_PAD9 0x20e
+
+#define CTL_DEL 0x20f /* clt-delete */
+#define ALT_BSLASH 0x210 /* alt-back slash */
+#define CTL_ENTER 0x211 /* ctl-enter */
+
+#define SHF_PADENTER 0x212 /* shift-enter on keypad */
+#define SHF_PADSLASH 0x213 /* shift-slash on keypad */
+#define SHF_PADSTAR 0x214 /* shift-star on keypad */
+#define SHF_PADPLUS 0x215 /* shift-plus on keypad */
+#define SHF_PADMINUS 0x216 /* shift-minus on keypad */
+#define SHF_UP 0x217 /* shift-up on keypad */
+#define SHF_DOWN 0x218 /* shift-down on keypad */
+#define SHF_IC 0x219 /* shift-insert on keypad */
+#define SHF_DC 0x21a /* shift-delete on keypad */
+
+#define KEY_MOUSE 0x21b /* "mouse" key */
+#define KEY_SHIFT_L 0x21c /* Left-shift */
+#define KEY_SHIFT_R 0x21d /* Right-shift */
+#define KEY_CONTROL_L 0x21e /* Left-control */
+#define KEY_CONTROL_R 0x21f /* Right-control */
+#define KEY_ALT_L 0x220 /* Left-alt */
+#define KEY_ALT_R 0x221 /* Right-alt */
+#define KEY_RESIZE 0x222 /* Window resize */
+#define KEY_SUP 0x223 /* Shifted up arrow */
+#define KEY_SDOWN 0x224 /* Shifted down arrow */
+
+#define KEY_MIN KEY_BREAK /* Minimum curses key value */
+#define KEY_MAX KEY_SDOWN /* Maximum curses key */
+
+#define KEY_F(n) (KEY_F0 + (n))
+
+/*----------------------------------------------------------------------
+ *
+ * Functions
+ *
+ */
+
+/* Standard */
+
+PDCEX int addch(const chtype);
+PDCEX int addchnstr(const chtype *, int);
+PDCEX int addchstr(const chtype *);
+PDCEX int addnstr(const char *, int);
+PDCEX int addstr(const char *);
+PDCEX int attroff(chtype);
+PDCEX int attron(chtype);
+PDCEX int attrset(chtype);
+PDCEX int attr_get(attr_t *, short *, void *);
+PDCEX int attr_off(attr_t, void *);
+PDCEX int attr_on(attr_t, void *);
+PDCEX int attr_set(attr_t, short, void *);
+PDCEX int baudrate(void);
+PDCEX int beep(void);
+PDCEX int bkgd(chtype);
+PDCEX void bkgdset(chtype);
+PDCEX int border(chtype, chtype, chtype, chtype,
+ chtype, chtype, chtype, chtype);
+PDCEX int box(WINDOW *, chtype, chtype);
+PDCEX bool can_change_color(void);
+PDCEX int cbreak(void);
+PDCEX int chgat(int, attr_t, short, const void *);
+PDCEX int clearok(WINDOW *, bool);
+PDCEX int clear(void);
+PDCEX int clrtobot(void);
+PDCEX int clrtoeol(void);
+PDCEX int color_content(short, short *, short *, short *);
+PDCEX int color_set(short, void *);
+PDCEX int copywin(const WINDOW *, WINDOW *, int, int, int,
+ int, int, int, int);
+PDCEX int curs_set(int);
+PDCEX int def_prog_mode(void);
+PDCEX int def_shell_mode(void);
+PDCEX int delay_output(int);
+PDCEX int delch(void);
+PDCEX int deleteln(void);
+PDCEX void delscreen(SCREEN *);
+PDCEX int delwin(WINDOW *);
+PDCEX WINDOW *derwin(WINDOW *, int, int, int, int);
+PDCEX int doupdate(void);
+PDCEX WINDOW *dupwin(WINDOW *);
+PDCEX int echochar(const chtype);
+PDCEX int echo(void);
+PDCEX int endwin(void);
+PDCEX char erasechar(void);
+PDCEX int erase(void);
+PDCEX void filter(void);
+PDCEX int flash(void);
+PDCEX int flushinp(void);
+PDCEX chtype getbkgd(WINDOW *);
+PDCEX int getnstr(char *, int);
+PDCEX int getstr(char *);
+PDCEX WINDOW *getwin(FILE *);
+PDCEX int halfdelay(int);
+PDCEX bool has_colors(void);
+PDCEX bool has_ic(void);
+PDCEX bool has_il(void);
+PDCEX int hline(chtype, int);
+PDCEX void idcok(WINDOW *, bool);
+PDCEX int idlok(WINDOW *, bool);
+PDCEX void immedok(WINDOW *, bool);
+PDCEX int inchnstr(chtype *, int);
+PDCEX int inchstr(chtype *);
+PDCEX chtype inch(void);
+PDCEX int init_color(short, short, short, short);
+PDCEX int init_pair(short, short, short);
+PDCEX WINDOW *initscr(void);
+PDCEX int innstr(char *, int);
+PDCEX int insch(chtype);
+PDCEX int insdelln(int);
+PDCEX int insertln(void);
+PDCEX int insnstr(const char *, int);
+PDCEX int insstr(const char *);
+PDCEX int instr(char *);
+PDCEX int intrflush(WINDOW *, bool);
+PDCEX bool isendwin(void);
+PDCEX bool is_linetouched(WINDOW *, int);
+PDCEX bool is_wintouched(WINDOW *);
+PDCEX char *keyname(int);
+PDCEX int keypad(WINDOW *, bool);
+PDCEX char killchar(void);
+PDCEX int leaveok(WINDOW *, bool);
+PDCEX char *longname(void);
+PDCEX int meta(WINDOW *, bool);
+PDCEX int move(int, int);
+PDCEX int mvaddch(int, int, const chtype);
+PDCEX int mvaddchnstr(int, int, const chtype *, int);
+PDCEX int mvaddchstr(int, int, const chtype *);
+PDCEX int mvaddnstr(int, int, const char *, int);
+PDCEX int mvaddstr(int, int, const char *);
+PDCEX int mvchgat(int, int, int, attr_t, short, const void *);
+PDCEX int mvcur(int, int, int, int);
+PDCEX int mvdelch(int, int);
+PDCEX int mvderwin(WINDOW *, int, int);
+PDCEX int mvgetch(int, int);
+PDCEX int mvgetnstr(int, int, char *, int);
+PDCEX int mvgetstr(int, int, char *);
+PDCEX int mvhline(int, int, chtype, int);
+PDCEX chtype mvinch(int, int);
+PDCEX int mvinchnstr(int, int, chtype *, int);
+PDCEX int mvinchstr(int, int, chtype *);
+PDCEX int mvinnstr(int, int, char *, int);
+PDCEX int mvinsch(int, int, chtype);
+PDCEX int mvinsnstr(int, int, const char *, int);
+PDCEX int mvinsstr(int, int, const char *);
+PDCEX int mvinstr(int, int, char *);
+PDCEX int mvprintw(int, int, const char *, ...);
+PDCEX int mvscanw(int, int, const char *, ...);
+PDCEX int mvvline(int, int, chtype, int);
+PDCEX int mvwaddchnstr(WINDOW *, int, int, const chtype *, int);
+PDCEX int mvwaddchstr(WINDOW *, int, int, const chtype *);
+PDCEX int mvwaddch(WINDOW *, int, int, const chtype);
+PDCEX int mvwaddnstr(WINDOW *, int, int, const char *, int);
+PDCEX int mvwaddstr(WINDOW *, int, int, const char *);
+PDCEX int mvwchgat(WINDOW *, int, int, int, attr_t, short, const void *);
+PDCEX int mvwdelch(WINDOW *, int, int);
+PDCEX int mvwgetch(WINDOW *, int, int);
+PDCEX int mvwgetnstr(WINDOW *, int, int, char *, int);
+PDCEX int mvwgetstr(WINDOW *, int, int, char *);
+PDCEX int mvwhline(WINDOW *, int, int, chtype, int);
+PDCEX int mvwinchnstr(WINDOW *, int, int, chtype *, int);
+PDCEX int mvwinchstr(WINDOW *, int, int, chtype *);
+PDCEX chtype mvwinch(WINDOW *, int, int);
+PDCEX int mvwinnstr(WINDOW *, int, int, char *, int);
+PDCEX int mvwinsch(WINDOW *, int, int, chtype);
+PDCEX int mvwinsnstr(WINDOW *, int, int, const char *, int);
+PDCEX int mvwinsstr(WINDOW *, int, int, const char *);
+PDCEX int mvwinstr(WINDOW *, int, int, char *);
+PDCEX int mvwin(WINDOW *, int, int);
+PDCEX int mvwprintw(WINDOW *, int, int, const char *, ...);
+PDCEX int mvwscanw(WINDOW *, int, int, const char *, ...);
+PDCEX int mvwvline(WINDOW *, int, int, chtype, int);
+PDCEX int napms(int);
+PDCEX WINDOW *newpad(int, int);
+PDCEX SCREEN *newterm(const char *, FILE *, FILE *);
+PDCEX WINDOW *newwin(int, int, int, int);
+PDCEX int nl(void);
+PDCEX int nocbreak(void);
+PDCEX int nodelay(WINDOW *, bool);
+PDCEX int noecho(void);
+PDCEX int nonl(void);
+PDCEX void noqiflush(void);
+PDCEX int noraw(void);
+PDCEX int notimeout(WINDOW *, bool);
+PDCEX int overlay(const WINDOW *, WINDOW *);
+PDCEX int overwrite(const WINDOW *, WINDOW *);
+PDCEX int pair_content(short, short *, short *);
+PDCEX int pechochar(WINDOW *, chtype);
+PDCEX int pnoutrefresh(WINDOW *, int, int, int, int, int, int);
+PDCEX int prefresh(WINDOW *, int, int, int, int, int, int);
+PDCEX int printw(const char *, ...);
+PDCEX int putwin(WINDOW *, FILE *);
+PDCEX void qiflush(void);
+PDCEX int raw(void);
+PDCEX int redrawwin(WINDOW *);
+PDCEX int refresh(void);
+PDCEX int reset_prog_mode(void);
+PDCEX int reset_shell_mode(void);
+PDCEX int resetty(void);
+PDCEX int ripoffline(int, int (*)(WINDOW *, int));
+PDCEX int savetty(void);
+PDCEX int scanw(const char *, ...);
+PDCEX int scr_dump(const char *);
+PDCEX int scr_init(const char *);
+PDCEX int scr_restore(const char *);
+PDCEX int scr_set(const char *);
+PDCEX int scrl(int);
+PDCEX int scroll(WINDOW *);
+PDCEX int scrollok(WINDOW *, bool);
+PDCEX SCREEN *set_term(SCREEN *);
+PDCEX int setscrreg(int, int);
+PDCEX int slk_attroff(const chtype);
+PDCEX int slk_attr_off(const attr_t, void *);
+PDCEX int slk_attron(const chtype);
+PDCEX int slk_attr_on(const attr_t, void *);
+PDCEX int slk_attrset(const chtype);
+PDCEX int slk_attr_set(const attr_t, short, void *);
+PDCEX int slk_clear(void);
+PDCEX int slk_color(short);
+PDCEX int slk_init(int);
+PDCEX char *slk_label(int);
+PDCEX int slk_noutrefresh(void);
+PDCEX int slk_refresh(void);
+PDCEX int slk_restore(void);
+PDCEX int slk_set(int, const char *, int);
+PDCEX int slk_touch(void);
+PDCEX int standend(void);
+PDCEX int standout(void);
+PDCEX int start_color(void);
+PDCEX WINDOW *subpad(WINDOW *, int, int, int, int);
+PDCEX WINDOW *subwin(WINDOW *, int, int, int, int);
+PDCEX int syncok(WINDOW *, bool);
+PDCEX chtype termattrs(void);
+PDCEX attr_t term_attrs(void);
+PDCEX char *termname(void);
+PDCEX void timeout(int);
+PDCEX int touchline(WINDOW *, int, int);
+PDCEX int touchwin(WINDOW *);
+PDCEX int typeahead(int);
+PDCEX int untouchwin(WINDOW *);
+PDCEX void use_env(bool);
+PDCEX int vidattr(chtype);
+PDCEX int vid_attr(attr_t, short, void *);
+PDCEX int vidputs(chtype, int (*)(int));
+PDCEX int vid_puts(attr_t, short, void *, int (*)(int));
+PDCEX int vline(chtype, int);
+PDCEX int vw_printw(WINDOW *, const char *, va_list);
+PDCEX int vwprintw(WINDOW *, const char *, va_list);
+PDCEX int vw_scanw(WINDOW *, const char *, va_list);
+PDCEX int vwscanw(WINDOW *, const char *, va_list);
+PDCEX int waddchnstr(WINDOW *, const chtype *, int);
+PDCEX int waddchstr(WINDOW *, const chtype *);
+PDCEX int waddch(WINDOW *, const chtype);
+PDCEX int waddnstr(WINDOW *, const char *, int);
+PDCEX int waddstr(WINDOW *, const char *);
+PDCEX int wattroff(WINDOW *, chtype);
+PDCEX int wattron(WINDOW *, chtype);
+PDCEX int wattrset(WINDOW *, chtype);
+PDCEX int wattr_get(WINDOW *, attr_t *, short *, void *);
+PDCEX int wattr_off(WINDOW *, attr_t, void *);
+PDCEX int wattr_on(WINDOW *, attr_t, void *);
+PDCEX int wattr_set(WINDOW *, attr_t, short, void *);
+PDCEX void wbkgdset(WINDOW *, chtype);
+PDCEX int wbkgd(WINDOW *, chtype);
+PDCEX int wborder(WINDOW *, chtype, chtype, chtype, chtype,
+ chtype, chtype, chtype, chtype);
+PDCEX int wchgat(WINDOW *, int, attr_t, short, const void *);
+PDCEX int wclear(WINDOW *);
+PDCEX int wclrtobot(WINDOW *);
+PDCEX int wclrtoeol(WINDOW *);
+PDCEX int wcolor_set(WINDOW *, short, void *);
+PDCEX void wcursyncup(WINDOW *);
+PDCEX int wdelch(WINDOW *);
+PDCEX int wdeleteln(WINDOW *);
+PDCEX int wechochar(WINDOW *, const chtype);
+PDCEX int werase(WINDOW *);
+PDCEX int wgetch(WINDOW *);
+PDCEX int wgetnstr(WINDOW *, char *, int);
+PDCEX int wgetstr(WINDOW *, char *);
+PDCEX int whline(WINDOW *, chtype, int);
+PDCEX int winchnstr(WINDOW *, chtype *, int);
+PDCEX int winchstr(WINDOW *, chtype *);
+PDCEX chtype winch(WINDOW *);
+PDCEX int winnstr(WINDOW *, char *, int);
+PDCEX int winsch(WINDOW *, chtype);
+PDCEX int winsdelln(WINDOW *, int);
+PDCEX int winsertln(WINDOW *);
+PDCEX int winsnstr(WINDOW *, const char *, int);
+PDCEX int winsstr(WINDOW *, const char *);
+PDCEX int winstr(WINDOW *, char *);
+PDCEX int wmove(WINDOW *, int, int);
+PDCEX int wnoutrefresh(WINDOW *);
+PDCEX int wprintw(WINDOW *, const char *, ...);
+PDCEX int wredrawln(WINDOW *, int, int);
+PDCEX int wrefresh(WINDOW *);
+PDCEX int wscanw(WINDOW *, const char *, ...);
+PDCEX int wscrl(WINDOW *, int);
+PDCEX int wsetscrreg(WINDOW *, int, int);
+PDCEX int wstandend(WINDOW *);
+PDCEX int wstandout(WINDOW *);
+PDCEX void wsyncdown(WINDOW *);
+PDCEX void wsyncup(WINDOW *);
+PDCEX void wtimeout(WINDOW *, int);
+PDCEX int wtouchln(WINDOW *, int, int, int);
+PDCEX int wvline(WINDOW *, chtype, int);
+
+/* Wide-character functions */
+
+#ifdef PDC_WIDE
+PDCEX int addnwstr(const wchar_t *, int);
+PDCEX int addwstr(const wchar_t *);
+PDCEX int add_wch(const cchar_t *);
+PDCEX int add_wchnstr(const cchar_t *, int);
+PDCEX int add_wchstr(const cchar_t *);
+PDCEX int bkgrnd(const cchar_t *);
+PDCEX void bkgrndset(const cchar_t *);
+PDCEX int border_set(const cchar_t *, const cchar_t *, const cchar_t *,
+ const cchar_t *, const cchar_t *, const cchar_t *,
+ const cchar_t *, const cchar_t *);
+PDCEX int box_set(WINDOW *, const cchar_t *, const cchar_t *);
+PDCEX int echo_wchar(const cchar_t *);
+PDCEX int erasewchar(wchar_t *);
+PDCEX int getbkgrnd(cchar_t *);
+PDCEX int getcchar(const cchar_t *, wchar_t *, attr_t *, short *, void *);
+PDCEX int getn_wstr(wint_t *, int);
+PDCEX int get_wch(wint_t *);
+PDCEX int get_wstr(wint_t *);
+PDCEX int hline_set(const cchar_t *, int);
+PDCEX int innwstr(wchar_t *, int);
+PDCEX int ins_nwstr(const wchar_t *, int);
+PDCEX int ins_wch(const cchar_t *);
+PDCEX int ins_wstr(const wchar_t *);
+PDCEX int inwstr(wchar_t *);
+PDCEX int in_wch(cchar_t *);
+PDCEX int in_wchnstr(cchar_t *, int);
+PDCEX int in_wchstr(cchar_t *);
+PDCEX char *key_name(wchar_t);
+PDCEX int killwchar(wchar_t *);
+PDCEX int mvaddnwstr(int, int, const wchar_t *, int);
+PDCEX int mvaddwstr(int, int, const wchar_t *);
+PDCEX int mvadd_wch(int, int, const cchar_t *);
+PDCEX int mvadd_wchnstr(int, int, const cchar_t *, int);
+PDCEX int mvadd_wchstr(int, int, const cchar_t *);
+PDCEX int mvgetn_wstr(int, int, wint_t *, int);
+PDCEX int mvget_wch(int, int, wint_t *);
+PDCEX int mvget_wstr(int, int, wint_t *);
+PDCEX int mvhline_set(int, int, const cchar_t *, int);
+PDCEX int mvinnwstr(int, int, wchar_t *, int);
+PDCEX int mvins_nwstr(int, int, const wchar_t *, int);
+PDCEX int mvins_wch(int, int, const cchar_t *);
+PDCEX int mvins_wstr(int, int, const wchar_t *);
+PDCEX int mvinwstr(int, int, wchar_t *);
+PDCEX int mvin_wch(int, int, cchar_t *);
+PDCEX int mvin_wchnstr(int, int, cchar_t *, int);
+PDCEX int mvin_wchstr(int, int, cchar_t *);
+PDCEX int mvvline_set(int, int, const cchar_t *, int);
+PDCEX int mvwaddnwstr(WINDOW *, int, int, const wchar_t *, int);
+PDCEX int mvwaddwstr(WINDOW *, int, int, const wchar_t *);
+PDCEX int mvwadd_wch(WINDOW *, int, int, const cchar_t *);
+PDCEX int mvwadd_wchnstr(WINDOW *, int, int, const cchar_t *, int);
+PDCEX int mvwadd_wchstr(WINDOW *, int, int, const cchar_t *);
+PDCEX int mvwgetn_wstr(WINDOW *, int, int, wint_t *, int);
+PDCEX int mvwget_wch(WINDOW *, int, int, wint_t *);
+PDCEX int mvwget_wstr(WINDOW *, int, int, wint_t *);
+PDCEX int mvwhline_set(WINDOW *, int, int, const cchar_t *, int);
+PDCEX int mvwinnwstr(WINDOW *, int, int, wchar_t *, int);
+PDCEX int mvwins_nwstr(WINDOW *, int, int, const wchar_t *, int);
+PDCEX int mvwins_wch(WINDOW *, int, int, const cchar_t *);
+PDCEX int mvwins_wstr(WINDOW *, int, int, const wchar_t *);
+PDCEX int mvwin_wch(WINDOW *, int, int, cchar_t *);
+PDCEX int mvwin_wchnstr(WINDOW *, int, int, cchar_t *, int);
+PDCEX int mvwin_wchstr(WINDOW *, int, int, cchar_t *);
+PDCEX int mvwinwstr(WINDOW *, int, int, wchar_t *);
+PDCEX int mvwvline_set(WINDOW *, int, int, const cchar_t *, int);
+PDCEX int pecho_wchar(WINDOW *, const cchar_t*);
+PDCEX int setcchar(cchar_t*, const wchar_t*, const attr_t,
+ short, const void*);
+PDCEX int slk_wset(int, const wchar_t *, int);
+PDCEX int unget_wch(const wchar_t);
+PDCEX int vline_set(const cchar_t *, int);
+PDCEX int waddnwstr(WINDOW *, const wchar_t *, int);
+PDCEX int waddwstr(WINDOW *, const wchar_t *);
+PDCEX int wadd_wch(WINDOW *, const cchar_t *);
+PDCEX int wadd_wchnstr(WINDOW *, const cchar_t *, int);
+PDCEX int wadd_wchstr(WINDOW *, const cchar_t *);
+PDCEX int wbkgrnd(WINDOW *, const cchar_t *);
+PDCEX void wbkgrndset(WINDOW *, const cchar_t *);
+PDCEX int wborder_set(WINDOW *, const cchar_t *, const cchar_t *,
+ const cchar_t *, const cchar_t *, const cchar_t *,
+ const cchar_t *, const cchar_t *, const cchar_t *);
+PDCEX int wecho_wchar(WINDOW *, const cchar_t *);
+PDCEX int wgetbkgrnd(WINDOW *, cchar_t *);
+PDCEX int wgetn_wstr(WINDOW *, wint_t *, int);
+PDCEX int wget_wch(WINDOW *, wint_t *);
+PDCEX int wget_wstr(WINDOW *, wint_t *);
+PDCEX int whline_set(WINDOW *, const cchar_t *, int);
+PDCEX int winnwstr(WINDOW *, wchar_t *, int);
+PDCEX int wins_nwstr(WINDOW *, const wchar_t *, int);
+PDCEX int wins_wch(WINDOW *, const cchar_t *);
+PDCEX int wins_wstr(WINDOW *, const wchar_t *);
+PDCEX int winwstr(WINDOW *, wchar_t *);
+PDCEX int win_wch(WINDOW *, cchar_t *);
+PDCEX int win_wchnstr(WINDOW *, cchar_t *, int);
+PDCEX int win_wchstr(WINDOW *, cchar_t *);
+PDCEX wchar_t *wunctrl(cchar_t *);
+PDCEX int wvline_set(WINDOW *, const cchar_t *, int);
+#endif
+
+/* Quasi-standard */
+
+PDCEX chtype getattrs(WINDOW *);
+PDCEX int getbegx(WINDOW *);
+PDCEX int getbegy(WINDOW *);
+PDCEX int getmaxx(WINDOW *);
+PDCEX int getmaxy(WINDOW *);
+PDCEX int getparx(WINDOW *);
+PDCEX int getpary(WINDOW *);
+PDCEX int getcurx(WINDOW *);
+PDCEX int getcury(WINDOW *);
+PDCEX void traceoff(void);
+PDCEX void traceon(void);
+PDCEX char *unctrl(chtype);
+
+PDCEX int crmode(void);
+PDCEX int nocrmode(void);
+PDCEX int draino(int);
+PDCEX int resetterm(void);
+PDCEX int fixterm(void);
+PDCEX int saveterm(void);
+PDCEX void setsyx(int, int);
+
+PDCEX int mouse_set(mmask_t);
+PDCEX int mouse_on(mmask_t);
+PDCEX int mouse_off(mmask_t);
+PDCEX int request_mouse_pos(void);
+PDCEX void wmouse_position(WINDOW *, int *, int *);
+PDCEX mmask_t getmouse(void);
+
+/* ncurses */
+
+PDCEX int alloc_pair(int, int);
+PDCEX int assume_default_colors(int, int);
+PDCEX const char *curses_version(void);
+PDCEX int find_pair(int, int);
+PDCEX int free_pair(int);
+PDCEX bool has_key(int);
+PDCEX bool is_keypad(const WINDOW *);
+PDCEX bool is_leaveok(const WINDOW *);
+PDCEX bool is_pad(const WINDOW *);
+PDCEX int set_tabsize(int);
+PDCEX int use_default_colors(void);
+PDCEX int wresize(WINDOW *, int, int);
+
+PDCEX bool has_mouse(void);
+PDCEX int mouseinterval(int);
+PDCEX mmask_t mousemask(mmask_t, mmask_t *);
+PDCEX bool mouse_trafo(int *, int *, bool);
+PDCEX int nc_getmouse(MEVENT *);
+PDCEX int ungetmouse(MEVENT *);
+PDCEX bool wenclose(const WINDOW *, int, int);
+PDCEX bool wmouse_trafo(const WINDOW *, int *, int *, bool);
+
+/* PDCurses */
+
+PDCEX int addrawch(chtype);
+PDCEX int insrawch(chtype);
+PDCEX bool is_termresized(void);
+PDCEX int mvaddrawch(int, int, chtype);
+PDCEX int mvdeleteln(int, int);
+PDCEX int mvinsertln(int, int);
+PDCEX int mvinsrawch(int, int, chtype);
+PDCEX int mvwaddrawch(WINDOW *, int, int, chtype);
+PDCEX int mvwdeleteln(WINDOW *, int, int);
+PDCEX int mvwinsertln(WINDOW *, int, int);
+PDCEX int mvwinsrawch(WINDOW *, int, int, chtype);
+PDCEX int raw_output(bool);
+PDCEX int resize_term(int, int);
+PDCEX WINDOW *resize_window(WINDOW *, int, int);
+PDCEX int waddrawch(WINDOW *, chtype);
+PDCEX int winsrawch(WINDOW *, chtype);
+PDCEX char wordchar(void);
+
+#ifdef PDC_WIDE
+PDCEX wchar_t *slk_wlabel(int);
+#endif
+
+PDCEX void PDC_debug(const char *, ...);
+PDCEX void PDC_get_version(PDC_VERSION *);
+PDCEX int PDC_ungetch(int);
+PDCEX int PDC_set_blink(bool);
+PDCEX int PDC_set_bold(bool);
+PDCEX int PDC_set_line_color(short);
+PDCEX void PDC_set_title(const char *);
+
+PDCEX int PDC_clearclipboard(void);
+PDCEX int PDC_freeclipboard(char *);
+PDCEX int PDC_getclipboard(char **, long *);
+PDCEX int PDC_setclipboard(const char *, long);
+
+PDCEX unsigned long PDC_get_key_modifiers(void);
+PDCEX int PDC_return_key_modifiers(bool);
+
+#ifdef XCURSES
+PDCEX WINDOW *Xinitscr(int, char **);
+PDCEX void XCursesExit(void);
+PDCEX int sb_init(void);
+PDCEX int sb_set_horz(int, int, int);
+PDCEX int sb_set_vert(int, int, int);
+PDCEX int sb_get_horz(int *, int *, int *);
+PDCEX int sb_get_vert(int *, int *, int *);
+PDCEX int sb_refresh(void);
+#endif
+
+/* NetBSD */
+
+PDCEX int touchoverlap(const WINDOW *, WINDOW *);
+PDCEX int underend(void);
+PDCEX int underscore(void);
+PDCEX int wunderend(WINDOW *);
+PDCEX int wunderscore(WINDOW *);
+
+/*** Functions defined as macros ***/
+
+/* getch() and ungetch() conflict with some DOS libraries */
+
+#define getch() wgetch(stdscr)
+#define ungetch(ch) PDC_ungetch(ch)
+
+#define COLOR_PAIR(n) (((chtype)(n) << PDC_COLOR_SHIFT) & A_COLOR)
+#define PAIR_NUMBER(n) (((n) & A_COLOR) >> PDC_COLOR_SHIFT)
+
+/* These will _only_ work as macros */
+
+#define getbegyx(w, y, x) (y = getbegy(w), x = getbegx(w))
+#define getmaxyx(w, y, x) (y = getmaxy(w), x = getmaxx(w))
+#define getparyx(w, y, x) (y = getpary(w), x = getparx(w))
+#define getyx(w, y, x) (y = getcury(w), x = getcurx(w))
+
+#define getsyx(y, x) { if (curscr->_leaveit) (y)=(x)=-1; \
+ else getyx(curscr,(y),(x)); }
+
+#ifdef NCURSES_MOUSE_VERSION
+# define getmouse(x) nc_getmouse(x)
+#endif
+
+/* Deprecated */
+
+#define PDC_save_key_modifiers(x) (OK)
+#define PDC_get_input_fd() 0
+
+/* return codes from PDC_getclipboard() and PDC_setclipboard() calls */
+
+#define PDC_CLIP_SUCCESS 0
+#define PDC_CLIP_ACCESS_ERROR 1
+#define PDC_CLIP_EMPTY 2
+#define PDC_CLIP_MEMORY_ERROR 3
+
+/* PDCurses key modifier masks */
+
+#define PDC_KEY_MODIFIER_SHIFT 1
+#define PDC_KEY_MODIFIER_CONTROL 2
+#define PDC_KEY_MODIFIER_ALT 4
+#define PDC_KEY_MODIFIER_NUMLOCK 8
+
+#ifdef __cplusplus
+# ifndef PDC_PP98
+# undef bool
+# endif
+}
+#endif
+
+#endif /* __PDCURSES__ */
diff --git a/Utilities/cmpdcurses/curspriv.h b/Utilities/cmpdcurses/curspriv.h
new file mode 100644
index 0000000..a5d1ac4
--- /dev/null
+++ b/Utilities/cmpdcurses/curspriv.h
@@ -0,0 +1,122 @@
+/* Private definitions and declarations for use within PDCurses.
+ These should generally not be referenced by applications. */
+
+#ifndef __CURSES_INTERNALS__
+#define __CURSES_INTERNALS__ 1
+
+#define CURSES_LIBRARY
+#include <curses.h>
+
+#if defined(__TURBOC__) || defined(__EMX__) || defined(__DJGPP__) || \
+ defined(PDC_99) || defined(__WATCOMC__)
+# ifndef HAVE_VSSCANF
+# define HAVE_VSSCANF /* have vsscanf() */
+# endif
+#endif
+
+#if defined(PDC_99) || defined(__WATCOMC__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF /* have vsnprintf() */
+# endif
+#endif
+
+/*----------------------------------------------------------------------*/
+
+typedef struct /* structure for ripped off lines */
+{
+ int line;
+ int (*init)(WINDOW *, int);
+} RIPPEDOFFLINE;
+
+/* Window properties */
+
+#define _SUBWIN 0x01 /* window is a subwindow */
+#define _PAD 0x10 /* X/Open Pad. */
+#define _SUBPAD 0x20 /* X/Open subpad. */
+
+/* Miscellaneous */
+
+#define _NO_CHANGE -1 /* flags line edge unchanged */
+
+#define _ECHAR 0x08 /* Erase char (^H) */
+#define _DWCHAR 0x17 /* Delete Word char (^W) */
+#define _DLCHAR 0x15 /* Delete Line char (^U) */
+
+/*----------------------------------------------------------------------*/
+
+/* Platform implementation functions */
+
+void PDC_beep(void);
+bool PDC_can_change_color(void);
+int PDC_color_content(short, short *, short *, short *);
+bool PDC_check_key(void);
+int PDC_curs_set(int);
+void PDC_doupdate(void);
+void PDC_flushinp(void);
+int PDC_get_columns(void);
+int PDC_get_cursor_mode(void);
+int PDC_get_key(void);
+int PDC_get_rows(void);
+void PDC_gotoyx(int, int);
+bool PDC_has_mouse(void);
+int PDC_init_color(short, short, short, short);
+int PDC_modifiers_set(void);
+int PDC_mouse_set(void);
+void PDC_napms(int);
+void PDC_reset_prog_mode(void);
+void PDC_reset_shell_mode(void);
+int PDC_resize_screen(int, int);
+void PDC_restore_screen_mode(int);
+void PDC_save_screen_mode(int);
+#ifdef XCURSES
+void PDC_set_args(int, char **);
+#endif
+void PDC_scr_close(void);
+void PDC_scr_free(void);
+int PDC_scr_open(void);
+void PDC_set_keyboard_binary(bool);
+void PDC_transform_line(int, int, int, const chtype *);
+const char *PDC_sysname(void);
+
+/* Internal cross-module functions */
+
+void PDC_init_atrtab(void);
+WINDOW *PDC_makelines(WINDOW *);
+WINDOW *PDC_makenew(int, int, int, int);
+int PDC_mouse_in_slk(int, int);
+void PDC_slk_free(void);
+void PDC_slk_initialize(void);
+void PDC_sync(WINDOW *);
+
+#ifdef PDC_WIDE
+int PDC_mbtowc(wchar_t *, const char *, size_t);
+size_t PDC_mbstowcs(wchar_t *, const char *, size_t);
+size_t PDC_wcstombs(char *, const wchar_t *, size_t);
+#endif
+
+#ifdef PDCDEBUG
+# define PDC_LOG(x) if (SP && SP->dbfp) PDC_debug x
+#else
+# define PDC_LOG(x)
+#endif
+
+/* Internal macros for attributes */
+
+#ifndef max
+# define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef min
+# define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define DIVROUND(num, divisor) ((num) + ((divisor) >> 1)) / (divisor)
+
+#define PDC_CLICK_PERIOD 150 /* time to wait for a click, if
+ not set by mouseinterval() */
+#define PDC_COLOR_PAIRS 256
+#define PDC_MAXCOL 768 /* maximum possible COLORS; may be less */
+
+#define _INBUFSIZ 512 /* size of terminal input buffer */
+#define NUNGETCH 256 /* max # chars to ungetch() */
+
+#endif /* __CURSES_INTERNALS__ */
diff --git a/Utilities/cmpdcurses/panel.h b/Utilities/cmpdcurses/panel.h
new file mode 100644
index 0000000..83d4f2c
--- /dev/null
+++ b/Utilities/cmpdcurses/panel.h
@@ -0,0 +1,54 @@
+/*----------------------------------------------------------------------*
+ * Panels for PDCurses *
+ *----------------------------------------------------------------------*/
+
+#ifndef __PDCURSES_PANEL_H__
+#define __PDCURSES_PANEL_H__ 1
+
+#include <curses.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct panelobs
+{
+ struct panelobs *above;
+ struct panel *pan;
+} PANELOBS;
+
+typedef struct panel
+{
+ WINDOW *win;
+ int wstarty;
+ int wendy;
+ int wstartx;
+ int wendx;
+ struct panel *below;
+ struct panel *above;
+ const void *user;
+ struct panelobs *obscure;
+} PANEL;
+
+PDCEX int bottom_panel(PANEL *pan);
+PDCEX int del_panel(PANEL *pan);
+PDCEX int hide_panel(PANEL *pan);
+PDCEX int move_panel(PANEL *pan, int starty, int startx);
+PDCEX PANEL *new_panel(WINDOW *win);
+PDCEX PANEL *panel_above(const PANEL *pan);
+PDCEX PANEL *panel_below(const PANEL *pan);
+PDCEX int panel_hidden(const PANEL *pan);
+PDCEX const void *panel_userptr(const PANEL *pan);
+PDCEX WINDOW *panel_window(const PANEL *pan);
+PDCEX int replace_panel(PANEL *pan, WINDOW *win);
+PDCEX int set_panel_userptr(PANEL *pan, const void *uptr);
+PDCEX int show_panel(PANEL *pan);
+PDCEX int top_panel(PANEL *pan);
+PDCEX void update_panels(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PDCURSES_PANEL_H__ */
diff --git a/Utilities/cmpdcurses/pdcurses/README.md b/Utilities/cmpdcurses/pdcurses/README.md
new file mode 100644
index 0000000..d7b7c65
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/README.md
@@ -0,0 +1,25 @@
+PDCurses Portable Core
+======================
+
+This directory contains core PDCurses source code files common to all
+platforms.
+
+
+Building
+--------
+
+These modules are built by the platform-specific makefiles, in the
+platform directories.
+
+
+Distribution Status
+-------------------
+
+The files in this directory are released to the public domain.
+
+
+Acknowledgements
+----------------
+
+The panel library was originally provided by
+Warren Tucker <wht@n4hgf.mt-park.ga.us>
diff --git a/Utilities/cmpdcurses/pdcurses/addch.c b/Utilities/cmpdcurses/pdcurses/addch.c
new file mode 100644
index 0000000..9931fd6
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/addch.c
@@ -0,0 +1,408 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+addch
+-----
+
+### Synopsis
+
+ int addch(const chtype ch);
+ int waddch(WINDOW *win, const chtype ch);
+ int mvaddch(int y, int x, const chtype ch);
+ int mvwaddch(WINDOW *win, int y, int x, const chtype ch);
+ int echochar(const chtype ch);
+ int wechochar(WINDOW *win, const chtype ch);
+
+ int addrawch(chtype ch);
+ int waddrawch(WINDOW *win, chtype ch);
+ int mvaddrawch(int y, int x, chtype ch);
+ int mvwaddrawch(WINDOW *win, int y, int x, chtype ch);
+
+ int add_wch(const cchar_t *wch);
+ int wadd_wch(WINDOW *win, const cchar_t *wch);
+ int mvadd_wch(int y, int x, const cchar_t *wch);
+ int mvwadd_wch(WINDOW *win, int y, int x, const cchar_t *wch);
+ int echo_wchar(const cchar_t *wch);
+ int wecho_wchar(WINDOW *win, const cchar_t *wch);
+
+### Description
+
+ addch() adds the chtype ch to the default window (stdscr) at the
+ current cursor position, and advances the cursor. Note that chtypes
+ can convey both text (a single character) and attributes, including a
+ color pair. add_wch() is the wide-character version of this function,
+ taking a pointer to a cchar_t instead of a chtype.
+
+ waddch() is like addch(), but also lets you specify the window. (This
+ is in fact the core output routine.) wadd_wch() is the wide version.
+
+ mvaddch() moves the cursor to the specified (y, x) position, and adds
+ ch to stdscr. mvadd_wch() is the wide version.
+
+ mvwaddch() moves the cursor to the specified position and adds ch to
+ the specified window. mvwadd_wch() is the wide version.
+
+ echochar() adds ch to stdscr at the current cursor position and calls
+ refresh(). echo_wchar() is the wide version.
+
+ wechochar() adds ch to the specified window and calls wrefresh().
+ wecho_wchar() is the wide version.
+
+ addrawch(), waddrawch(), mvaddrawch() and mvwaddrawch() are PDCurses-
+ specific wrappers for addch() etc. that disable the translation of
+ control characters.
+
+ The following applies to all these functions:
+
+ If the cursor moves on to the right margin, an automatic newline is
+ performed. If scrollok is enabled, and a character is added to the
+ bottom right corner of the window, the scrolling region will be
+ scrolled up one line. If scrolling is not allowed, ERR will be
+ returned.
+
+ If ch is a tab, newline, or backspace, the cursor will be moved
+ appropriately within the window. If ch is a newline, the clrtoeol
+ routine is called before the cursor is moved to the beginning of the
+ next line. If newline mapping is off, the cursor will be moved to
+ the next line, but the x coordinate will be unchanged. If ch is a
+ tab the cursor is moved to the next tab position within the window.
+ If ch is another control character, it will be drawn in the ^X
+ notation. Calling the inch() routine after adding a control
+ character returns the representation of the control character, not
+ the control character.
+
+ Video attributes can be combined with a character by ORing them into
+ the parameter. Text, including attributes, can be copied from one
+ place to another by using inch() and addch().
+
+ Note that in PDCurses, for now, a cchar_t and a chtype are the same.
+ The text field is 16 bits wide, and is treated as Unicode (UCS-2)
+ when PDCurses is built with wide-character support (define PDC_WIDE).
+ So, in functions that take a chtype, like addch(), both the wide and
+ narrow versions will handle Unicode. But for portability, you should
+ use the wide functions.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ addch Y Y Y
+ waddch Y Y Y
+ mvaddch Y Y Y
+ mvwaddch Y Y Y
+ echochar Y Y Y
+ wechochar Y Y Y
+ add_wch Y Y Y
+ wadd_wch Y Y Y
+ mvadd_wch Y Y Y
+ mvwadd_wch Y Y Y
+ echo_wchar Y Y Y
+ wecho_wchar Y Y Y
+ addrawch - - -
+ waddrawch - - -
+ mvaddrawch - - -
+ mvwaddrawch - - -
+
+**man-end****************************************************************/
+
+int waddch(WINDOW *win, const chtype ch)
+{
+ int x, y;
+ chtype text, attr;
+ bool xlat;
+
+ PDC_LOG(("waddch() - called: win=%p ch=%x (text=%c attr=0x%x)\n",
+ win, ch, ch & A_CHARTEXT, ch & A_ATTRIBUTES));
+
+ if (!win || !SP)
+ return ERR;
+
+ x = win->_curx;
+ y = win->_cury;
+
+ if (y > win->_maxy || x > win->_maxx || y < 0 || x < 0)
+ return ERR;
+
+ xlat = !SP->raw_out && !(ch & A_ALTCHARSET);
+ text = ch & A_CHARTEXT;
+ attr = ch & A_ATTRIBUTES;
+
+ if (xlat && (text < ' ' || text == 0x7f))
+ {
+ int x2;
+
+ switch (text)
+ {
+ case '\t':
+ for (x2 = ((x / TABSIZE) + 1) * TABSIZE; x < x2; x++)
+ {
+ if (waddch(win, attr | ' ') == ERR)
+ return ERR;
+
+ /* if tab to next line, exit the loop */
+
+ if (!win->_curx)
+ break;
+ }
+ return OK;
+
+ case '\n':
+ /* if lf -> crlf */
+
+ if (!SP->raw_out)
+ x = 0;
+
+ wclrtoeol(win);
+
+ if (++y > win->_bmarg)
+ {
+ y--;
+
+ if (wscrl(win, 1) == ERR)
+ return ERR;
+ }
+
+ break;
+
+ case '\b':
+ /* don't back over left margin */
+
+ if (--x < 0)
+ case '\r':
+ x = 0;
+
+ break;
+
+ case 0x7f:
+ if (waddch(win, attr | '^') == ERR)
+ return ERR;
+
+ return waddch(win, attr | '?');
+
+ default:
+ /* handle control chars */
+
+ if (waddch(win, attr | '^') == ERR)
+ return ERR;
+
+ return waddch(win, ch + '@');
+ }
+ }
+ else
+ {
+ /* If the incoming character doesn't have its own attribute,
+ then use the current attributes for the window. If it has
+ attributes but not a color component, OR the attributes to
+ the current attributes for the window. If it has a color
+ component, use the attributes solely from the incoming
+ character. */
+
+ if (!(attr & A_COLOR))
+ attr |= win->_attrs;
+
+ /* wrs (4/10/93): Apply the same sort of logic for the window
+ background, in that it only takes precedence if other color
+ attributes are not there and that the background character
+ will only print if the printing character is blank. */
+
+ if (!(attr & A_COLOR))
+ attr |= win->_bkgd & A_ATTRIBUTES;
+ else
+ attr |= win->_bkgd & (A_ATTRIBUTES ^ A_COLOR);
+
+ if (text == ' ')
+ text = win->_bkgd & A_CHARTEXT;
+
+ /* Add the attribute back into the character. */
+
+ text |= attr;
+
+ /* Only change _firstch/_lastch if the character to be added is
+ different from the character/attribute that is already in
+ that position in the window. */
+
+ if (win->_y[y][x] != text)
+ {
+ if (win->_firstch[y] == _NO_CHANGE)
+ win->_firstch[y] = win->_lastch[y] = x;
+ else
+ if (x < win->_firstch[y])
+ win->_firstch[y] = x;
+ else
+ if (x > win->_lastch[y])
+ win->_lastch[y] = x;
+
+ win->_y[y][x] = text;
+ }
+
+ if (++x >= win->_maxx)
+ {
+ /* wrap around test */
+
+ x = 0;
+
+ if (++y > win->_bmarg)
+ {
+ y--;
+
+ if (wscrl(win, 1) == ERR)
+ {
+ PDC_sync(win);
+ return ERR;
+ }
+ }
+ }
+ }
+
+ win->_curx = x;
+ win->_cury = y;
+
+ if (win->_immed)
+ wrefresh(win);
+ if (win->_sync)
+ wsyncup(win);
+
+ return OK;
+}
+
+int addch(const chtype ch)
+{
+ PDC_LOG(("addch() - called: ch=%x\n", ch));
+
+ return waddch(stdscr, ch);
+}
+
+int mvaddch(int y, int x, const chtype ch)
+{
+ PDC_LOG(("mvaddch() - called: y=%d x=%d ch=%x\n", y, x, ch));
+
+ if (move(y,x) == ERR)
+ return ERR;
+
+ return waddch(stdscr, ch);
+}
+
+int mvwaddch(WINDOW *win, int y, int x, const chtype ch)
+{
+ PDC_LOG(("mvwaddch() - called: win=%p y=%d x=%d ch=%d\n", win, y, x, ch));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return waddch(win, ch);
+}
+
+int echochar(const chtype ch)
+{
+ PDC_LOG(("echochar() - called: ch=%x\n", ch));
+
+ return wechochar(stdscr, ch);
+}
+
+int wechochar(WINDOW *win, const chtype ch)
+{
+ PDC_LOG(("wechochar() - called: win=%p ch=%x\n", win, ch));
+
+ if (waddch(win, ch) == ERR)
+ return ERR;
+
+ return wrefresh(win);
+}
+
+int waddrawch(WINDOW *win, chtype ch)
+{
+ PDC_LOG(("waddrawch() - called: win=%p ch=%x (text=%c attr=0x%x)\n",
+ win, ch, ch & A_CHARTEXT, ch & A_ATTRIBUTES));
+
+ if ((ch & A_CHARTEXT) < ' ' || (ch & A_CHARTEXT) == 0x7f)
+ ch |= A_ALTCHARSET;
+
+ return waddch(win, ch);
+}
+
+int addrawch(chtype ch)
+{
+ PDC_LOG(("addrawch() - called: ch=%x\n", ch));
+
+ return waddrawch(stdscr, ch);
+}
+
+int mvaddrawch(int y, int x, chtype ch)
+{
+ PDC_LOG(("mvaddrawch() - called: y=%d x=%d ch=%d\n", y, x, ch));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return waddrawch(stdscr, ch);
+}
+
+int mvwaddrawch(WINDOW *win, int y, int x, chtype ch)
+{
+ PDC_LOG(("mvwaddrawch() - called: win=%p y=%d x=%d ch=%d\n",
+ win, y, x, ch));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return waddrawch(win, ch);
+}
+
+#ifdef PDC_WIDE
+int wadd_wch(WINDOW *win, const cchar_t *wch)
+{
+ PDC_LOG(("wadd_wch() - called: win=%p wch=%x\n", win, *wch));
+
+ return wch ? waddch(win, *wch) : ERR;
+}
+
+int add_wch(const cchar_t *wch)
+{
+ PDC_LOG(("add_wch() - called: wch=%x\n", *wch));
+
+ return wadd_wch(stdscr, wch);
+}
+
+int mvadd_wch(int y, int x, const cchar_t *wch)
+{
+ PDC_LOG(("mvaddch() - called: y=%d x=%d wch=%x\n", y, x, *wch));
+
+ if (move(y,x) == ERR)
+ return ERR;
+
+ return wadd_wch(stdscr, wch);
+}
+
+int mvwadd_wch(WINDOW *win, int y, int x, const cchar_t *wch)
+{
+ PDC_LOG(("mvwaddch() - called: win=%p y=%d x=%d wch=%d\n",
+ win, y, x, *wch));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wadd_wch(win, wch);
+}
+
+int echo_wchar(const cchar_t *wch)
+{
+ PDC_LOG(("echo_wchar() - called: wch=%x\n", *wch));
+
+ return wecho_wchar(stdscr, wch);
+}
+
+int wecho_wchar(WINDOW *win, const cchar_t *wch)
+{
+ PDC_LOG(("wecho_wchar() - called: win=%p wch=%x\n", win, *wch));
+
+ if (!wch || (wadd_wch(win, wch) == ERR))
+ return ERR;
+
+ return wrefresh(win);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/addchstr.c b/Utilities/cmpdcurses/pdcurses/addchstr.c
new file mode 100644
index 0000000..10fc279
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/addchstr.c
@@ -0,0 +1,244 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+addchstr
+--------
+
+### Synopsis
+
+ int addchstr(const chtype *ch);
+ int addchnstr(const chtype *ch, int n);
+ int waddchstr(WINDOW *win, const chtype *ch);
+ int waddchnstr(WINDOW *win, const chtype *ch, int n);
+ int mvaddchstr(int y, int x, const chtype *ch);
+ int mvaddchnstr(int y, int x, const chtype *ch, int n);
+ int mvwaddchstr(WINDOW *, int y, int x, const chtype *ch);
+ int mvwaddchnstr(WINDOW *, int y, int x, const chtype *ch, int n);
+
+ int add_wchstr(const cchar_t *wch);
+ int add_wchnstr(const cchar_t *wch, int n);
+ int wadd_wchstr(WINDOW *win, const cchar_t *wch);
+ int wadd_wchnstr(WINDOW *win, const cchar_t *wch, int n);
+ int mvadd_wchstr(int y, int x, const cchar_t *wch);
+ int mvadd_wchnstr(int y, int x, const cchar_t *wch, int n);
+ int mvwadd_wchstr(WINDOW *win, int y, int x, const cchar_t *wch);
+ int mvwadd_wchnstr(WINDOW *win, int y, int x, const cchar_t *wch,
+ int n);
+
+### Description
+
+ These routines write a chtype or cchar_t string directly into the
+ window structure, starting at the current or specified position. The
+ four routines with n as the last argument copy at most n elements,
+ but no more than will fit on the line. If n == -1 then the whole
+ string is copied, up to the maximum number that will fit on the line.
+
+ The cursor position is not advanced. These routines do not check for
+ newline or other special characters, nor does any line wrapping
+ occur.
+
+### Return Value
+
+ All functions return OK or ERR.
+
+### Portability
+ X/Open ncurses NetBSD
+ addchstr Y Y Y
+ waddchstr Y Y Y
+ mvaddchstr Y Y Y
+ mvwaddchstr Y Y Y
+ addchnstr Y Y Y
+ waddchnstr Y Y Y
+ mvaddchnstr Y Y Y
+ mvwaddchnstr Y Y Y
+ add_wchstr Y Y Y
+ wadd_wchstr Y Y Y
+ mvadd_wchstr Y Y Y
+ mvwadd_wchstr Y Y Y
+ add_wchnstr Y Y Y
+ wadd_wchnstr Y Y Y
+ mvadd_wchnstr Y Y Y
+ mvwadd_wchnstr Y Y Y
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+int waddchnstr(WINDOW *win, const chtype *ch, int n)
+{
+ int y, x, maxx, minx;
+ chtype *ptr;
+
+ PDC_LOG(("waddchnstr() - called: win=%p n=%d\n", win, n));
+
+ if (!win || !ch || !n || n < -1)
+ return ERR;
+
+ x = win->_curx;
+ y = win->_cury;
+ ptr = &(win->_y[y][x]);
+
+ if (n == -1 || n > win->_maxx - x)
+ n = win->_maxx - x;
+
+ minx = win->_firstch[y];
+ maxx = win->_lastch[y];
+
+ for (; n && *ch; n--, x++, ptr++, ch++)
+ {
+ if (*ptr != *ch)
+ {
+ if (x < minx || minx == _NO_CHANGE)
+ minx = x;
+
+ if (x > maxx)
+ maxx = x;
+
+ PDC_LOG(("y %d x %d minx %d maxx %d *ptr %x *ch"
+ " %x firstch: %d lastch: %d\n",
+ y, x, minx, maxx, *ptr, *ch,
+ win->_firstch[y], win->_lastch[y]));
+
+ *ptr = *ch;
+ }
+ }
+
+ win->_firstch[y] = minx;
+ win->_lastch[y] = maxx;
+
+ return OK;
+}
+
+int addchstr(const chtype *ch)
+{
+ PDC_LOG(("addchstr() - called\n"));
+
+ return waddchnstr(stdscr, ch, -1);
+}
+
+int addchnstr(const chtype *ch, int n)
+{
+ PDC_LOG(("addchnstr() - called\n"));
+
+ return waddchnstr(stdscr, ch, n);
+}
+
+int waddchstr(WINDOW *win, const chtype *ch)
+{
+ PDC_LOG(("waddchstr() - called: win=%p\n", win));
+
+ return waddchnstr(win, ch, -1);
+}
+
+int mvaddchstr(int y, int x, const chtype *ch)
+{
+ PDC_LOG(("mvaddchstr() - called: y %d x %d\n", y, x));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return waddchnstr(stdscr, ch, -1);
+}
+
+int mvaddchnstr(int y, int x, const chtype *ch, int n)
+{
+ PDC_LOG(("mvaddchnstr() - called: y %d x %d n %d\n", y, x, n));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return waddchnstr(stdscr, ch, n);
+}
+
+int mvwaddchstr(WINDOW *win, int y, int x, const chtype *ch)
+{
+ PDC_LOG(("mvwaddchstr() - called:\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return waddchnstr(win, ch, -1);
+}
+
+int mvwaddchnstr(WINDOW *win, int y, int x, const chtype *ch, int n)
+{
+ PDC_LOG(("mvwaddchnstr() - called: y %d x %d n %d \n", y, x, n));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return waddchnstr(win, ch, n);
+}
+
+#ifdef PDC_WIDE
+int wadd_wchnstr(WINDOW *win, const cchar_t *wch, int n)
+{
+ PDC_LOG(("wadd_wchnstr() - called: win=%p n=%d\n", win, n));
+
+ return waddchnstr(win, wch, n);
+}
+
+int add_wchstr(const cchar_t *wch)
+{
+ PDC_LOG(("add_wchstr() - called\n"));
+
+ return wadd_wchnstr(stdscr, wch, -1);
+}
+
+int add_wchnstr(const cchar_t *wch, int n)
+{
+ PDC_LOG(("add_wchnstr() - called\n"));
+
+ return wadd_wchnstr(stdscr, wch, n);
+}
+
+int wadd_wchstr(WINDOW *win, const cchar_t *wch)
+{
+ PDC_LOG(("wadd_wchstr() - called: win=%p\n", win));
+
+ return wadd_wchnstr(win, wch, -1);
+}
+
+int mvadd_wchstr(int y, int x, const cchar_t *wch)
+{
+ PDC_LOG(("mvadd_wchstr() - called: y %d x %d\n", y, x));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wadd_wchnstr(stdscr, wch, -1);
+}
+
+int mvadd_wchnstr(int y, int x, const cchar_t *wch, int n)
+{
+ PDC_LOG(("mvadd_wchnstr() - called: y %d x %d n %d\n", y, x, n));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wadd_wchnstr(stdscr, wch, n);
+}
+
+int mvwadd_wchstr(WINDOW *win, int y, int x, const cchar_t *wch)
+{
+ PDC_LOG(("mvwadd_wchstr() - called:\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wadd_wchnstr(win, wch, -1);
+}
+
+int mvwadd_wchnstr(WINDOW *win, int y, int x, const cchar_t *wch, int n)
+{
+ PDC_LOG(("mvwadd_wchnstr() - called: y %d x %d n %d \n", y, x, n));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wadd_wchnstr(win, wch, n);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/addstr.c b/Utilities/cmpdcurses/pdcurses/addstr.c
new file mode 100644
index 0000000..a7d8539
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/addstr.c
@@ -0,0 +1,239 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+addstr
+------
+
+### Synopsis
+
+ int addstr(const char *str);
+ int addnstr(const char *str, int n);
+ int waddstr(WINDOW *win, const char *str);
+ int waddnstr(WINDOW *win, const char *str, int n);
+ int mvaddstr(int y, int x, const char *str);
+ int mvaddnstr(int y, int x, const char *str, int n);
+ int mvwaddstr(WINDOW *win, int y, int x, const char *str);
+ int mvwaddnstr(WINDOW *win, int y, int x, const char *str, int n);
+
+ int addwstr(const wchar_t *wstr);
+ int addnwstr(const wchar_t *wstr, int n);
+ int waddwstr(WINDOW *win, const wchar_t *wstr);
+ int waddnwstr(WINDOW *win, const wchar_t *wstr, int n);
+ int mvaddwstr(int y, int x, const wchar_t *wstr);
+ int mvaddnwstr(int y, int x, const wchar_t *wstr, int n);
+ int mvwaddwstr(WINDOW *win, int y, int x, const wchar_t *wstr);
+ int mvwaddnwstr(WINDOW *win, int y, int x, const wchar_t *wstr, int n);
+
+### Description
+
+ These routines write all the characters of the null-terminated string
+ str or wide-character string wstr to the given window. The
+ functionality is similar to calling waddch() once for each character
+ in the string; except that, when PDCurses is built with wide-
+ character support enabled, the narrow-character functions treat the
+ string as a multibyte string in the current locale, and convert it.
+ The routines with n as the last argument write at most n characters;
+ if n is negative, then the entire string will be added.
+
+### Return Value
+
+ All functions return OK or ERR.
+
+### Portability
+ X/Open ncurses NetBSD
+ addstr Y Y Y
+ waddstr Y Y Y
+ mvaddstr Y Y Y
+ mvwaddstr Y Y Y
+ addnstr Y Y Y
+ waddnstr Y Y Y
+ mvaddnstr Y Y Y
+ mvwaddnstr Y Y Y
+ addwstr Y Y Y
+ waddwstr Y Y Y
+ mvaddwstr Y Y Y
+ mvwaddwstr Y Y Y
+ addnwstr Y Y Y
+ waddnwstr Y Y Y
+ mvaddnwstr Y Y Y
+ mvwaddnwstr Y Y Y
+
+**man-end****************************************************************/
+
+int waddnstr(WINDOW *win, const char *str, int n)
+{
+ int i = 0;
+
+ PDC_LOG(("waddnstr() - called: string=\"%s\" n %d \n", str, n));
+
+ if (!win || !str)
+ return ERR;
+
+ while (str[i] && (i < n || n < 0))
+ {
+#ifdef PDC_WIDE
+ wchar_t wch;
+ int retval = PDC_mbtowc(&wch, str + i, n >= 0 ? n - i : 6);
+
+ if (retval <= 0)
+ return OK;
+
+ i += retval;
+#else
+ chtype wch = (unsigned char)(str[i++]);
+#endif
+ if (waddch(win, wch) == ERR)
+ return ERR;
+ }
+
+ return OK;
+}
+
+int addstr(const char *str)
+{
+ PDC_LOG(("addstr() - called: string=\"%s\"\n", str));
+
+ return waddnstr(stdscr, str, -1);
+}
+
+int addnstr(const char *str, int n)
+{
+ PDC_LOG(("addnstr() - called: string=\"%s\" n %d \n", str, n));
+
+ return waddnstr(stdscr, str, n);
+}
+
+int waddstr(WINDOW *win, const char *str)
+{
+ PDC_LOG(("waddstr() - called: string=\"%s\"\n", str));
+
+ return waddnstr(win, str, -1);
+}
+
+int mvaddstr(int y, int x, const char *str)
+{
+ PDC_LOG(("mvaddstr() - called: y %d x %d string=\"%s\"\n", y, x, str));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return waddnstr(stdscr, str, -1);
+}
+
+int mvaddnstr(int y, int x, const char *str, int n)
+{
+ PDC_LOG(("mvaddnstr() - called: y %d x %d string=\"%s\" n %d \n",
+ y, x, str, n));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return waddnstr(stdscr, str, n);
+}
+
+int mvwaddstr(WINDOW *win, int y, int x, const char *str)
+{
+ PDC_LOG(("mvwaddstr() - called: string=\"%s\"\n", str));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return waddnstr(win, str, -1);
+}
+
+int mvwaddnstr(WINDOW *win, int y, int x, const char *str, int n)
+{
+ PDC_LOG(("mvwaddnstr() - called: y %d x %d string=\"%s\" n %d \n",
+ y, x, str, n));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return waddnstr(win, str, n);
+}
+
+#ifdef PDC_WIDE
+int waddnwstr(WINDOW *win, const wchar_t *wstr, int n)
+{
+ int i = 0;
+
+ PDC_LOG(("waddnwstr() - called\n"));
+
+ if (!win || !wstr)
+ return ERR;
+
+ while (wstr[i] && (i < n || n < 0))
+ {
+ chtype wch = wstr[i++];
+
+ if (waddch(win, wch) == ERR)
+ return ERR;
+ }
+
+ return OK;
+}
+
+int addwstr(const wchar_t *wstr)
+{
+ PDC_LOG(("addwstr() - called\n"));
+
+ return waddnwstr(stdscr, wstr, -1);
+}
+
+int addnwstr(const wchar_t *wstr, int n)
+{
+ PDC_LOG(("addnwstr() - called\n"));
+
+ return waddnwstr(stdscr, wstr, n);
+}
+
+int waddwstr(WINDOW *win, const wchar_t *wstr)
+{
+ PDC_LOG(("waddwstr() - called\n"));
+
+ return waddnwstr(win, wstr, -1);
+}
+
+int mvaddwstr(int y, int x, const wchar_t *wstr)
+{
+ PDC_LOG(("mvaddstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return waddnwstr(stdscr, wstr, -1);
+}
+
+int mvaddnwstr(int y, int x, const wchar_t *wstr, int n)
+{
+ PDC_LOG(("mvaddnstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return waddnwstr(stdscr, wstr, n);
+}
+
+int mvwaddwstr(WINDOW *win, int y, int x, const wchar_t *wstr)
+{
+ PDC_LOG(("mvwaddstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return waddnwstr(win, wstr, -1);
+}
+
+int mvwaddnwstr(WINDOW *win, int y, int x, const wchar_t *wstr, int n)
+{
+ PDC_LOG(("mvwaddnstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return waddnwstr(win, wstr, n);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/attr.c b/Utilities/cmpdcurses/pdcurses/attr.c
new file mode 100644
index 0000000..b5907da
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/attr.c
@@ -0,0 +1,409 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+attr
+----
+
+### Synopsis
+
+ int attroff(chtype attrs);
+ int wattroff(WINDOW *win, chtype attrs);
+ int attron(chtype attrs);
+ int wattron(WINDOW *win, chtype attrs);
+ int attrset(chtype attrs);
+ int wattrset(WINDOW *win, chtype attrs);
+ int standend(void);
+ int wstandend(WINDOW *win);
+ int standout(void);
+ int wstandout(WINDOW *win);
+
+ int color_set(short color_pair, void *opts);
+ int wcolor_set(WINDOW *win, short color_pair, void *opts);
+
+ int attr_get(attr_t *attrs, short *color_pair, void *opts);
+ int attr_off(attr_t attrs, void *opts);
+ int attr_on(attr_t attrs, void *opts);
+ int attr_set(attr_t attrs, short color_pair, void *opts);
+ int wattr_get(WINDOW *win, attr_t *attrs, short *color_pair,
+ void *opts);
+ int wattr_off(WINDOW *win, attr_t attrs, void *opts);
+ int wattr_on(WINDOW *win, attr_t attrs, void *opts);
+ int wattr_set(WINDOW *win, attr_t attrs, short color_pair,
+ void *opts);
+
+ int chgat(int n, attr_t attr, short color, const void *opts);
+ int mvchgat(int y, int x, int n, attr_t attr, short color,
+ const void *opts);
+ int mvwchgat(WINDOW *win, int y, int x, int n, attr_t attr,
+ short color, const void *opts);
+ int wchgat(WINDOW *win, int n, attr_t attr, short color,
+ const void *opts);
+
+ chtype getattrs(WINDOW *win);
+
+ int underend(void);
+ int wunderend(WINDOW *win);
+ int underscore(void);
+ int wunderscore(WINDOW *win);
+
+### Description
+
+ These functions manipulate the current attributes and/or colors of
+ the named window. These attributes can be any combination of
+ A_STANDOUT, A_REVERSE, A_BOLD, A_DIM, A_BLINK, A_UNDERLINE. These
+ constants are defined in <curses.h> and can be combined with the
+ bitwise-OR operator (|).
+
+ The current attributes of a window are applied to all chtypes that
+ are written into the window with waddch(). Attributes are a property
+ of the chtype, and move with the character through any scrolling or
+ insert/delete operations.
+
+ wattrset() sets the current attributes of the given window to attrs.
+ attrset() is the stdscr version.
+
+ wattroff() turns off the named attributes without affecting any other
+ attributes; wattron() turns them on.
+
+ wcolor_set() sets the window color to the value of color_pair. opts
+ is unused.
+
+ standout() is the same as attron(A_STANDOUT). standend() is the same
+ as attrset(A_NORMAL); that is, it turns off all attributes.
+
+ The attr_* and wattr_* functions are intended for use with the WA_*
+ attributes. In PDCurses, these are the same as A_*, and there is no
+ difference in bevahior from the chtype-based functions. In all cases,
+ opts is unused.
+
+ wattr_get() retrieves the attributes and color pair for the specified
+ window.
+
+ wchgat() sets the color pair and attributes for the next n cells on
+ the current line of a given window, without changing the existing
+ text, or alterting the window's attributes. An n of -1 extends the
+ change to the edge of the window. The changes take effect
+ immediately. opts is unused.
+
+ wunderscore() turns on the A_UNDERLINE attribute; wunderend() turns
+ it off. underscore() and underend() are the stdscr versions.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ attroff Y Y Y
+ wattroff Y Y Y
+ attron Y Y Y
+ wattron Y Y Y
+ attrset Y Y Y
+ wattrset Y Y Y
+ standend Y Y Y
+ wstandend Y Y Y
+ standout Y Y Y
+ wstandout Y Y Y
+ color_set Y Y Y
+ wcolor_set Y Y Y
+ attr_get Y Y Y
+ wattr_get Y Y Y
+ attr_on Y Y Y
+ wattr_on Y Y Y
+ attr_off Y Y Y
+ wattr_off Y Y Y
+ attr_set Y Y Y
+ wattr_set Y Y Y
+ chgat Y Y Y
+ wchgat Y Y Y
+ mvchgat Y Y Y
+ mvwchgat Y Y Y
+ getattrs - Y Y
+ underend - - Y
+ wunderend - - Y
+ underscore - - Y
+ wunderscore - - Y
+
+**man-end****************************************************************/
+
+int wattroff(WINDOW *win, chtype attrs)
+{
+ PDC_LOG(("wattroff() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_attrs &= (~attrs & A_ATTRIBUTES);
+
+ return OK;
+}
+
+int attroff(chtype attrs)
+{
+ PDC_LOG(("attroff() - called\n"));
+
+ return wattroff(stdscr, attrs);
+}
+
+int wattron(WINDOW *win, chtype attrs)
+{
+ chtype newcolr, oldcolr, newattr, oldattr;
+
+ PDC_LOG(("wattron() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ if ((win->_attrs & A_COLOR) && (attrs & A_COLOR))
+ {
+ oldcolr = win->_attrs & A_COLOR;
+ oldattr = win->_attrs ^ oldcolr;
+ newcolr = attrs & A_COLOR;
+ newattr = (attrs & A_ATTRIBUTES) ^ newcolr;
+ newattr |= oldattr;
+ win->_attrs = newattr | newcolr;
+ }
+ else
+ win->_attrs |= (attrs & A_ATTRIBUTES);
+
+ return OK;
+}
+
+int attron(chtype attrs)
+{
+ PDC_LOG(("attron() - called\n"));
+
+ return wattron(stdscr, attrs);
+}
+
+int wattrset(WINDOW *win, chtype attrs)
+{
+ PDC_LOG(("wattrset() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_attrs = attrs & A_ATTRIBUTES;
+
+ return OK;
+}
+
+int attrset(chtype attrs)
+{
+ PDC_LOG(("attrset() - called\n"));
+
+ return wattrset(stdscr, attrs);
+}
+
+int standend(void)
+{
+ PDC_LOG(("standend() - called\n"));
+
+ return wattrset(stdscr, A_NORMAL);
+}
+
+int standout(void)
+{
+ PDC_LOG(("standout() - called\n"));
+
+ return wattrset(stdscr, A_STANDOUT);
+}
+
+int wstandend(WINDOW *win)
+{
+ PDC_LOG(("wstandend() - called\n"));
+
+ return wattrset(win, A_NORMAL);
+}
+
+int wstandout(WINDOW *win)
+{
+ PDC_LOG(("wstandout() - called\n"));
+
+ return wattrset(win, A_STANDOUT);
+}
+
+chtype getattrs(WINDOW *win)
+{
+ return win ? win->_attrs : 0;
+}
+
+int wcolor_set(WINDOW *win, short color_pair, void *opts)
+{
+ PDC_LOG(("wcolor_set() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_attrs = (win->_attrs & ~A_COLOR) | COLOR_PAIR(color_pair);
+
+ return OK;
+}
+
+int color_set(short color_pair, void *opts)
+{
+ PDC_LOG(("color_set() - called\n"));
+
+ return wcolor_set(stdscr, color_pair, opts);
+}
+
+int wattr_get(WINDOW *win, attr_t *attrs, short *color_pair, void *opts)
+{
+ PDC_LOG(("wattr_get() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ if (attrs)
+ *attrs = win->_attrs & (A_ATTRIBUTES & ~A_COLOR);
+
+ if (color_pair)
+ *color_pair = PAIR_NUMBER(win->_attrs);
+
+ return OK;
+}
+
+int attr_get(attr_t *attrs, short *color_pair, void *opts)
+{
+ PDC_LOG(("attr_get() - called\n"));
+
+ return wattr_get(stdscr, attrs, color_pair, opts);
+}
+
+int wattr_off(WINDOW *win, attr_t attrs, void *opts)
+{
+ PDC_LOG(("wattr_off() - called\n"));
+
+ return wattroff(win, attrs);
+}
+
+int attr_off(attr_t attrs, void *opts)
+{
+ PDC_LOG(("attr_off() - called\n"));
+
+ return wattroff(stdscr, attrs);
+}
+
+int wattr_on(WINDOW *win, attr_t attrs, void *opts)
+{
+ PDC_LOG(("wattr_off() - called\n"));
+
+ return wattron(win, attrs);
+}
+
+int attr_on(attr_t attrs, void *opts)
+{
+ PDC_LOG(("attr_on() - called\n"));
+
+ return wattron(stdscr, attrs);
+}
+
+int wattr_set(WINDOW *win, attr_t attrs, short color_pair, void *opts)
+{
+ PDC_LOG(("wattr_set() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_attrs = (attrs & (A_ATTRIBUTES & ~A_COLOR)) | COLOR_PAIR(color_pair);
+
+ return OK;
+}
+
+int attr_set(attr_t attrs, short color_pair, void *opts)
+{
+ PDC_LOG(("attr_get() - called\n"));
+
+ return wattr_set(stdscr, attrs, color_pair, opts);
+}
+
+int wchgat(WINDOW *win, int n, attr_t attr, short color, const void *opts)
+{
+ chtype *dest, newattr;
+ int startpos, endpos;
+
+ PDC_LOG(("wchgat() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ newattr = (attr & A_ATTRIBUTES) | COLOR_PAIR(color);
+
+ startpos = win->_curx;
+ endpos = ((n < 0) ? win->_maxx : min(startpos + n, win->_maxx)) - 1;
+ dest = win->_y[win->_cury];
+
+ for (n = startpos; n <= endpos; n++)
+ dest[n] = (dest[n] & A_CHARTEXT) | newattr;
+
+ n = win->_cury;
+
+ if (startpos < win->_firstch[n] || win->_firstch[n] == _NO_CHANGE)
+ win->_firstch[n] = startpos;
+
+ if (endpos > win->_lastch[n])
+ win->_lastch[n] = endpos;
+
+ PDC_sync(win);
+
+ return OK;
+}
+
+int chgat(int n, attr_t attr, short color, const void *opts)
+{
+ PDC_LOG(("chgat() - called\n"));
+
+ return wchgat(stdscr, n, attr, color, opts);
+}
+
+int mvchgat(int y, int x, int n, attr_t attr, short color, const void *opts)
+{
+ PDC_LOG(("mvchgat() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wchgat(stdscr, n, attr, color, opts);
+}
+
+int mvwchgat(WINDOW *win, int y, int x, int n, attr_t attr, short color,
+ const void *opts)
+{
+ PDC_LOG(("mvwchgat() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wchgat(win, n, attr, color, opts);
+}
+
+int underend(void)
+{
+ PDC_LOG(("underend() - called\n"));
+
+ return wattroff(stdscr, A_UNDERLINE);
+}
+
+int wunderend(WINDOW *win)
+{
+ PDC_LOG(("wunderend() - called\n"));
+
+ return wattroff(win, A_UNDERLINE);
+}
+
+int underscore(void)
+{
+ PDC_LOG(("underscore() - called\n"));
+
+ return wattron(stdscr, A_UNDERLINE);
+}
+
+int wunderscore(WINDOW *win)
+{
+ PDC_LOG(("wunderscore() - called\n"));
+
+ return wattron(win, A_UNDERLINE);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/beep.c b/Utilities/cmpdcurses/pdcurses/beep.c
new file mode 100644
index 0000000..690c794
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/beep.c
@@ -0,0 +1,74 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+beep
+----
+
+### Synopsis
+
+ int beep(void);
+ int flash(void);
+
+### Description
+
+ beep() sounds the audible bell on the terminal, if possible; if not,
+ it calls flash().
+
+ flash() "flashes" the screen, by inverting the foreground and
+ background of every cell, pausing, and then restoring the original
+ attributes.
+
+### Return Value
+
+ These functions return ERR if called before initscr(), otherwise OK.
+
+### Portability
+ X/Open ncurses NetBSD
+ beep Y Y Y
+ flash Y Y Y
+
+**man-end****************************************************************/
+
+int beep(void)
+{
+ PDC_LOG(("beep() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ if (SP->audible)
+ PDC_beep();
+ else
+ flash();
+
+ return OK;
+}
+
+int flash(void)
+{
+ int z, y, x;
+
+ PDC_LOG(("flash() - called\n"));
+
+ if (!curscr)
+ return ERR;
+
+ /* Reverse each cell; wait; restore the screen */
+
+ for (z = 0; z < 2; z++)
+ {
+ for (y = 0; y < LINES; y++)
+ for (x = 0; x < COLS; x++)
+ curscr->_y[y][x] ^= A_REVERSE;
+
+ wrefresh(curscr);
+
+ if (!z)
+ napms(50);
+ }
+
+ return OK;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/bkgd.c b/Utilities/cmpdcurses/pdcurses/bkgd.c
new file mode 100644
index 0000000..f576437
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/bkgd.c
@@ -0,0 +1,226 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+bkgd
+----
+
+### Synopsis
+
+ int bkgd(chtype ch);
+ void bkgdset(chtype ch);
+ chtype getbkgd(WINDOW *win);
+ int wbkgd(WINDOW *win, chtype ch);
+ void wbkgdset(WINDOW *win, chtype ch);
+
+ int bkgrnd(const cchar_t *wch);
+ void bkgrndset(const cchar_t *wch);
+ int getbkgrnd(cchar_t *wch);
+ int wbkgrnd(WINDOW *win, const cchar_t *wch);
+ void wbkgrndset(WINDOW *win, const cchar_t *wch);
+ int wgetbkgrnd(WINDOW *win, cchar_t *wch);
+
+### Description
+
+ bkgdset() and wbkgdset() manipulate the background of a window. The
+ background is a chtype consisting of any combination of attributes
+ and a character; it is combined with each chtype added or inserted to
+ the window by waddch() or winsch(). Only the attribute part is used
+ to set the background of non-blank characters, while both character
+ and attributes are used for blank positions.
+
+ bkgd() and wbkgd() not only change the background, but apply it
+ immediately to every cell in the window.
+
+ wbkgrnd(), wbkgrndset() and wgetbkgrnd() are the "wide-character"
+ versions of these functions, taking a pointer to a cchar_t instead of
+ a chtype. However, in PDCurses, cchar_t and chtype are the same.
+
+ The attributes that are defined with the attrset()/attron() set of
+ functions take precedence over the background attributes if there is
+ a conflict (e.g., different color pairs).
+
+### Return Value
+
+ bkgd() and wbkgd() return OK, unless the window is NULL, in which
+ case they return ERR.
+
+### Portability
+ X/Open ncurses NetBSD
+ bkgd Y Y Y
+ bkgdset Y Y Y
+ getbkgd Y Y Y
+ wbkgd Y Y Y
+ wbkgdset Y Y Y
+ bkgrnd Y Y Y
+ bkgrndset Y Y Y
+ getbkgrnd Y Y Y
+ wbkgrnd Y Y Y
+ wbkgrndset Y Y Y
+ wgetbkgrnd Y Y Y
+
+**man-end****************************************************************/
+
+int wbkgd(WINDOW *win, chtype ch)
+{
+ int x, y;
+ chtype oldcolr, oldch, newcolr, newch, colr, attr;
+ chtype oldattr = 0, newattr = 0;
+ chtype *winptr;
+
+ PDC_LOG(("wbkgd() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ if (win->_bkgd == ch)
+ return OK;
+
+ oldcolr = win->_bkgd & A_COLOR;
+ if (oldcolr)
+ oldattr = (win->_bkgd & A_ATTRIBUTES) ^ oldcolr;
+
+ oldch = win->_bkgd & A_CHARTEXT;
+
+ wbkgdset(win, ch);
+
+ newcolr = win->_bkgd & A_COLOR;
+ if (newcolr)
+ newattr = (win->_bkgd & A_ATTRIBUTES) ^ newcolr;
+
+ newch = win->_bkgd & A_CHARTEXT;
+
+ /* what follows is what seems to occur in the System V
+ implementation of this routine */
+
+ for (y = 0; y < win->_maxy; y++)
+ {
+ for (x = 0; x < win->_maxx; x++)
+ {
+ winptr = win->_y[y] + x;
+
+ ch = *winptr;
+
+ /* determine the colors and attributes of the character read
+ from the window */
+
+ colr = ch & A_COLOR;
+ attr = ch & (A_ATTRIBUTES ^ A_COLOR);
+
+ /* if the color is the same as the old background color,
+ then make it the new background color, otherwise leave it */
+
+ if (colr == oldcolr)
+ colr = newcolr;
+
+ /* remove any attributes (non color) from the character that
+ were part of the old background, then combine the
+ remaining ones with the new background */
+
+ attr ^= oldattr;
+ attr |= newattr;
+
+ /* change character if it is there because it was the old
+ background character */
+
+ ch &= A_CHARTEXT;
+ if (ch == oldch)
+ ch = newch;
+
+ ch |= (attr | colr);
+
+ *winptr = ch;
+
+ }
+ }
+
+ touchwin(win);
+ PDC_sync(win);
+ return OK;
+}
+
+int bkgd(chtype ch)
+{
+ PDC_LOG(("bkgd() - called\n"));
+
+ return wbkgd(stdscr, ch);
+}
+
+void wbkgdset(WINDOW *win, chtype ch)
+{
+ PDC_LOG(("wbkgdset() - called\n"));
+
+ if (win)
+ {
+ if (!(ch & A_CHARTEXT))
+ ch |= ' ';
+
+ win->_bkgd = ch;
+ }
+}
+
+void bkgdset(chtype ch)
+{
+ PDC_LOG(("bkgdset() - called\n"));
+
+ wbkgdset(stdscr, ch);
+}
+
+chtype getbkgd(WINDOW *win)
+{
+ PDC_LOG(("getbkgd() - called\n"));
+
+ return win ? win->_bkgd : (chtype)ERR;
+}
+
+#ifdef PDC_WIDE
+int wbkgrnd(WINDOW *win, const cchar_t *wch)
+{
+ PDC_LOG(("wbkgrnd() - called\n"));
+
+ return wch ? wbkgd(win, *wch) : ERR;
+}
+
+int bkgrnd(const cchar_t *wch)
+{
+ PDC_LOG(("bkgrnd() - called\n"));
+
+ return wbkgrnd(stdscr, wch);
+}
+
+void wbkgrndset(WINDOW *win, const cchar_t *wch)
+{
+ PDC_LOG(("wbkgdset() - called\n"));
+
+ if (wch)
+ wbkgdset(win, *wch);
+}
+
+void bkgrndset(const cchar_t *wch)
+{
+ PDC_LOG(("bkgrndset() - called\n"));
+
+ wbkgrndset(stdscr, wch);
+}
+
+int wgetbkgrnd(WINDOW *win, cchar_t *wch)
+{
+ PDC_LOG(("wgetbkgrnd() - called\n"));
+
+ if (!win || !wch)
+ return ERR;
+
+ *wch = win->_bkgd;
+
+ return OK;
+}
+
+int getbkgrnd(cchar_t *wch)
+{
+ PDC_LOG(("getbkgrnd() - called\n"));
+
+ return wgetbkgrnd(stdscr, wch);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/border.c b/Utilities/cmpdcurses/pdcurses/border.c
new file mode 100644
index 0000000..62458b6
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/border.c
@@ -0,0 +1,414 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+border
+------
+
+### Synopsis
+
+ int border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl,
+ chtype tr, chtype bl, chtype br);
+ int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts,
+ chtype bs, chtype tl, chtype tr, chtype bl, chtype br);
+ int box(WINDOW *win, chtype verch, chtype horch);
+ int hline(chtype ch, int n);
+ int vline(chtype ch, int n);
+ int whline(WINDOW *win, chtype ch, int n);
+ int wvline(WINDOW *win, chtype ch, int n);
+ int mvhline(int y, int x, chtype ch, int n);
+ int mvvline(int y, int x, chtype ch, int n);
+ int mvwhline(WINDOW *win, int y, int x, chtype ch, int n);
+ int mvwvline(WINDOW *win, int y, int x, chtype ch, int n);
+
+ int border_set(const cchar_t *ls, const cchar_t *rs,
+ const cchar_t *ts, const cchar_t *bs,
+ const cchar_t *tl, const cchar_t *tr,
+ const cchar_t *bl, const cchar_t *br);
+ int wborder_set(WINDOW *win, const cchar_t *ls, const cchar_t *rs,
+ const cchar_t *ts, const cchar_t *bs,
+ const cchar_t *tl, const cchar_t *tr,
+ const cchar_t *bl, const cchar_t *br);
+ int box_set(WINDOW *win, const cchar_t *verch, const cchar_t *horch);
+ int hline_set(const cchar_t *wch, int n);
+ int vline_set(const cchar_t *wch, int n);
+ int whline_set(WINDOW *win, const cchar_t *wch, int n);
+ int wvline_set(WINDOW *win, const cchar_t *wch, int n);
+ int mvhline_set(int y, int x, const cchar_t *wch, int n);
+ int mvvline_set(int y, int x, const cchar_t *wch, int n);
+ int mvwhline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n);
+ int mvwvline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n);
+
+### Description
+
+ border(), wborder(), and box() draw a border around the edge of the
+ window. If any argument is zero, an appropriate default is used:
+
+ ls left side of border ACS_VLINE
+ rs right side of border ACS_VLINE
+ ts top side of border ACS_HLINE
+ bs bottom side of border ACS_HLINE
+ tl top left corner of border ACS_ULCORNER
+ tr top right corner of border ACS_URCORNER
+ bl bottom left corner of border ACS_LLCORNER
+ br bottom right corner of border ACS_LRCORNER
+
+ hline() and whline() draw a horizontal line, using ch, starting from
+ the current cursor position. The cursor position does not change. The
+ line is at most n characters long, or as many as will fit in the
+ window.
+
+ vline() and wvline() draw a vertical line, using ch, starting from
+ the current cursor position. The cursor position does not change. The
+ line is at most n characters long, or as many as will fit in the
+ window.
+
+ The *_set functions are the "wide-character" versions, taking
+ pointers to cchar_t instead of chtype. Note that in PDCurses, chtype
+ and cchar_t are the same.
+
+### Return Value
+
+ These functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ border Y Y Y
+ wborder Y Y Y
+ box Y Y Y
+ hline Y Y Y
+ vline Y Y Y
+ whline Y Y Y
+ wvline Y Y Y
+ mvhline Y Y Y
+ mvvline Y Y Y
+ mvwhline Y Y Y
+ mvwvline Y Y Y
+ border_set Y Y Y
+ wborder_set Y Y Y
+ box_set Y Y Y
+ hline_set Y Y Y
+ vline_set Y Y Y
+ whline_set Y Y Y
+ wvline_set Y Y Y
+ mvhline_set Y Y Y
+ mvvline_set Y Y Y
+ mvwhline_set Y Y Y
+ mvwvline_set Y Y Y
+
+**man-end****************************************************************/
+
+/* _attr_passthru() -- Takes a single chtype 'ch' and checks if the
+ current attribute of window 'win', as set by wattrset(), and/or the
+ current background of win, as set by wbkgd(), should by combined with
+ it. Attributes set explicitly in ch take precedence. */
+
+static chtype _attr_passthru(WINDOW *win, chtype ch)
+{
+ chtype attr;
+
+ /* If the incoming character doesn't have its own attribute, then
+ use the current attributes for the window. If the incoming
+ character has attributes, but not a color component, OR the
+ attributes to the current attributes for the window. If the
+ incoming character has a color component, use only the attributes
+ from the incoming character. */
+
+ attr = ch & A_ATTRIBUTES;
+ if (!(attr & A_COLOR))
+ attr |= win->_attrs;
+
+ /* wrs (4/10/93) -- Apply the same sort of logic for the window
+ background, in that it only takes precedence if other color
+ attributes are not there. */
+
+ if (!(attr & A_COLOR))
+ attr |= win->_bkgd & A_ATTRIBUTES;
+ else
+ attr |= win->_bkgd & (A_ATTRIBUTES ^ A_COLOR);
+
+ ch = (ch & A_CHARTEXT) | attr;
+
+ return ch;
+}
+
+int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs,
+ chtype tl, chtype tr, chtype bl, chtype br)
+{
+ int i, ymax, xmax;
+
+ PDC_LOG(("wborder() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ ymax = win->_maxy - 1;
+ xmax = win->_maxx - 1;
+
+ ls = _attr_passthru(win, ls ? ls : ACS_VLINE);
+ rs = _attr_passthru(win, rs ? rs : ACS_VLINE);
+ ts = _attr_passthru(win, ts ? ts : ACS_HLINE);
+ bs = _attr_passthru(win, bs ? bs : ACS_HLINE);
+ tl = _attr_passthru(win, tl ? tl : ACS_ULCORNER);
+ tr = _attr_passthru(win, tr ? tr : ACS_URCORNER);
+ bl = _attr_passthru(win, bl ? bl : ACS_LLCORNER);
+ br = _attr_passthru(win, br ? br : ACS_LRCORNER);
+
+ for (i = 1; i < xmax; i++)
+ {
+ win->_y[0][i] = ts;
+ win->_y[ymax][i] = bs;
+ }
+
+ for (i = 1; i < ymax; i++)
+ {
+ win->_y[i][0] = ls;
+ win->_y[i][xmax] = rs;
+ }
+
+ win->_y[0][0] = tl;
+ win->_y[0][xmax] = tr;
+ win->_y[ymax][0] = bl;
+ win->_y[ymax][xmax] = br;
+
+ for (i = 0; i <= ymax; i++)
+ {
+ win->_firstch[i] = 0;
+ win->_lastch[i] = xmax;
+ }
+
+ PDC_sync(win);
+
+ return OK;
+}
+
+int border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl,
+ chtype tr, chtype bl, chtype br)
+{
+ PDC_LOG(("border() - called\n"));
+
+ return wborder(stdscr, ls, rs, ts, bs, tl, tr, bl, br);
+}
+
+int box(WINDOW *win, chtype verch, chtype horch)
+{
+ PDC_LOG(("box() - called\n"));
+
+ return wborder(win, verch, verch, horch, horch, 0, 0, 0, 0);
+}
+
+int whline(WINDOW *win, chtype ch, int n)
+{
+ chtype *dest;
+ int startpos, endpos;
+
+ PDC_LOG(("whline() - called\n"));
+
+ if (!win || n < 1)
+ return ERR;
+
+ startpos = win->_curx;
+ endpos = min(startpos + n, win->_maxx) - 1;
+ dest = win->_y[win->_cury];
+ ch = _attr_passthru(win, ch ? ch : ACS_HLINE);
+
+ for (n = startpos; n <= endpos; n++)
+ dest[n] = ch;
+
+ n = win->_cury;
+
+ if (startpos < win->_firstch[n] || win->_firstch[n] == _NO_CHANGE)
+ win->_firstch[n] = startpos;
+
+ if (endpos > win->_lastch[n])
+ win->_lastch[n] = endpos;
+
+ PDC_sync(win);
+
+ return OK;
+}
+
+int hline(chtype ch, int n)
+{
+ PDC_LOG(("hline() - called\n"));
+
+ return whline(stdscr, ch, n);
+}
+
+int mvhline(int y, int x, chtype ch, int n)
+{
+ PDC_LOG(("mvhline() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return whline(stdscr, ch, n);
+}
+
+int mvwhline(WINDOW *win, int y, int x, chtype ch, int n)
+{
+ PDC_LOG(("mvwhline() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return whline(win, ch, n);
+}
+
+int wvline(WINDOW *win, chtype ch, int n)
+{
+ int endpos, x;
+
+ PDC_LOG(("wvline() - called\n"));
+
+ if (!win || n < 1)
+ return ERR;
+
+ endpos = min(win->_cury + n, win->_maxy);
+ x = win->_curx;
+
+ ch = _attr_passthru(win, ch ? ch : ACS_VLINE);
+
+ for (n = win->_cury; n < endpos; n++)
+ {
+ win->_y[n][x] = ch;
+
+ if (x < win->_firstch[n] || win->_firstch[n] == _NO_CHANGE)
+ win->_firstch[n] = x;
+
+ if (x > win->_lastch[n])
+ win->_lastch[n] = x;
+ }
+
+ PDC_sync(win);
+
+ return OK;
+}
+
+int vline(chtype ch, int n)
+{
+ PDC_LOG(("vline() - called\n"));
+
+ return wvline(stdscr, ch, n);
+}
+
+int mvvline(int y, int x, chtype ch, int n)
+{
+ PDC_LOG(("mvvline() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wvline(stdscr, ch, n);
+}
+
+int mvwvline(WINDOW *win, int y, int x, chtype ch, int n)
+{
+ PDC_LOG(("mvwvline() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wvline(win, ch, n);
+}
+
+#ifdef PDC_WIDE
+int wborder_set(WINDOW *win, const cchar_t *ls, const cchar_t *rs,
+ const cchar_t *ts, const cchar_t *bs, const cchar_t *tl,
+ const cchar_t *tr, const cchar_t *bl, const cchar_t *br)
+{
+ PDC_LOG(("wborder_set() - called\n"));
+
+ return wborder(win, ls ? *ls : 0, rs ? *rs : 0, ts ? *ts : 0,
+ bs ? *bs : 0, tl ? *tl : 0, tr ? *tr : 0,
+ bl ? *bl : 0, br ? *br : 0);
+}
+
+int border_set(const cchar_t *ls, const cchar_t *rs, const cchar_t *ts,
+ const cchar_t *bs, const cchar_t *tl, const cchar_t *tr,
+ const cchar_t *bl, const cchar_t *br)
+{
+ PDC_LOG(("border_set() - called\n"));
+
+ return wborder_set(stdscr, ls, rs, ts, bs, tl, tr, bl, br);
+}
+
+int box_set(WINDOW *win, const cchar_t *verch, const cchar_t *horch)
+{
+ PDC_LOG(("box_set() - called\n"));
+
+ return wborder_set(win, verch, verch, horch, horch,
+ (const cchar_t *)NULL, (const cchar_t *)NULL,
+ (const cchar_t *)NULL, (const cchar_t *)NULL);
+}
+
+int whline_set(WINDOW *win, const cchar_t *wch, int n)
+{
+ PDC_LOG(("whline_set() - called\n"));
+
+ return wch ? whline(win, *wch, n) : ERR;
+}
+
+int hline_set(const cchar_t *wch, int n)
+{
+ PDC_LOG(("hline_set() - called\n"));
+
+ return whline_set(stdscr, wch, n);
+}
+
+int mvhline_set(int y, int x, const cchar_t *wch, int n)
+{
+ PDC_LOG(("mvhline_set() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return whline_set(stdscr, wch, n);
+}
+
+int mvwhline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n)
+{
+ PDC_LOG(("mvwhline_set() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return whline_set(win, wch, n);
+}
+
+int wvline_set(WINDOW *win, const cchar_t *wch, int n)
+{
+ PDC_LOG(("wvline_set() - called\n"));
+
+ return wch ? wvline(win, *wch, n) : ERR;
+}
+
+int vline_set(const cchar_t *wch, int n)
+{
+ PDC_LOG(("vline_set() - called\n"));
+
+ return wvline_set(stdscr, wch, n);
+}
+
+int mvvline_set(int y, int x, const cchar_t *wch, int n)
+{
+ PDC_LOG(("mvvline_set() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wvline_set(stdscr, wch, n);
+}
+
+int mvwvline_set(WINDOW *win, int y, int x, const cchar_t *wch, int n)
+{
+ PDC_LOG(("mvwvline_set() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wvline_set(win, wch, n);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/clear.c b/Utilities/cmpdcurses/pdcurses/clear.c
new file mode 100644
index 0000000..50ff7ad
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/clear.c
@@ -0,0 +1,159 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+clear
+-----
+
+### Synopsis
+
+ int clear(void);
+ int wclear(WINDOW *win);
+ int erase(void);
+ int werase(WINDOW *win);
+ int clrtobot(void);
+ int wclrtobot(WINDOW *win);
+ int clrtoeol(void);
+ int wclrtoeol(WINDOW *win);
+
+### Description
+
+ erase() and werase() copy blanks (i.e. the background chtype) to
+ every cell of the window.
+
+ clear() and wclear() are similar to erase() and werase(), but they
+ also call clearok() to ensure that the the window is cleared on the
+ next wrefresh().
+
+ clrtobot() and wclrtobot() clear the window from the current cursor
+ position to the end of the window.
+
+ clrtoeol() and wclrtoeol() clear the window from the current cursor
+ position to the end of the current line.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ clear Y Y Y
+ wclear Y Y Y
+ erase Y Y Y
+ werase Y Y Y
+ clrtobot Y Y Y
+ wclrtobot Y Y Y
+ clrtoeol Y Y Y
+ wclrtoeol Y Y Y
+
+**man-end****************************************************************/
+
+int wclrtoeol(WINDOW *win)
+{
+ int x, y, minx;
+ chtype blank, *ptr;
+
+ PDC_LOG(("wclrtoeol() - called: Row: %d Col: %d\n",
+ win->_cury, win->_curx));
+
+ if (!win)
+ return ERR;
+
+ y = win->_cury;
+ x = win->_curx;
+
+ /* wrs (4/10/93) account for window background */
+
+ blank = win->_bkgd;
+
+ for (minx = x, ptr = &win->_y[y][x]; minx < win->_maxx; minx++, ptr++)
+ *ptr = blank;
+
+ if (x < win->_firstch[y] || win->_firstch[y] == _NO_CHANGE)
+ win->_firstch[y] = x;
+
+ win->_lastch[y] = win->_maxx - 1;
+
+ PDC_sync(win);
+ return OK;
+}
+
+int clrtoeol(void)
+{
+ PDC_LOG(("clrtoeol() - called\n"));
+
+ return wclrtoeol(stdscr);
+}
+
+int wclrtobot(WINDOW *win)
+{
+ int savey, savex;
+
+ PDC_LOG(("wclrtobot() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ savey = win->_cury;
+ savex = win->_curx;
+
+ /* should this involve scrolling region somehow ? */
+
+ if (win->_cury + 1 < win->_maxy)
+ {
+ win->_curx = 0;
+ win->_cury++;
+ for (; win->_maxy > win->_cury; win->_cury++)
+ wclrtoeol(win);
+ win->_cury = savey;
+ win->_curx = savex;
+ }
+ wclrtoeol(win);
+
+ PDC_sync(win);
+ return OK;
+}
+
+int clrtobot(void)
+{
+ PDC_LOG(("clrtobot() - called\n"));
+
+ return wclrtobot(stdscr);
+}
+
+int werase(WINDOW *win)
+{
+ PDC_LOG(("werase() - called\n"));
+
+ if (wmove(win, 0, 0) == ERR)
+ return ERR;
+
+ return wclrtobot(win);
+}
+
+int erase(void)
+{
+ PDC_LOG(("erase() - called\n"));
+
+ return werase(stdscr);
+}
+
+int wclear(WINDOW *win)
+{
+ PDC_LOG(("wclear() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_clear = TRUE;
+ return werase(win);
+}
+
+int clear(void)
+{
+ PDC_LOG(("clear() - called\n"));
+
+ return wclear(stdscr);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/color.c b/Utilities/cmpdcurses/pdcurses/color.c
new file mode 100644
index 0000000..7d4df24
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/color.c
@@ -0,0 +1,362 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+color
+-----
+
+### Synopsis
+
+ bool has_colors(void);
+ int start_color(void);
+ int init_pair(short pair, short fg, short bg);
+ int pair_content(short pair, short *fg, short *bg);
+ bool can_change_color(void);
+ int init_color(short color, short red, short green, short blue);
+ int color_content(short color, short *red, short *green, short *blue);
+
+ int alloc_pair(int fg, int bg);
+ int assume_default_colors(int f, int b);
+ int find_pair(int fg, int bg);
+ int free_pair(int pair);
+ int use_default_colors(void);
+
+ int PDC_set_line_color(short color);
+
+### Description
+
+ To use these routines, first, call start_color(). Colors are always
+ used in pairs, referred to as color-pairs. A color-pair is created by
+ init_pair(), and consists of a foreground color and a background
+ color. After initialization, COLOR_PAIR(n) can be used like any other
+ video attribute.
+
+ has_colors() reports whether the terminal supports color.
+
+ start_color() initializes eight basic colors (black, red, green,
+ yellow, blue, magenta, cyan, and white), and two global variables:
+ COLORS and COLOR_PAIRS (respectively defining the maximum number of
+ colors and color-pairs the terminal is capable of displaying).
+
+ init_pair() changes the definition of a color-pair. It takes three
+ arguments: the number of the color-pair to be redefined, and the new
+ values of the foreground and background colors. The pair number must
+ be between 0 and COLOR_PAIRS - 1, inclusive. The foreground and
+ background must be between 0 and COLORS - 1, inclusive. If the color
+ pair was previously initialized, the screen is refreshed, and all
+ occurrences of that color-pair are changed to the new definition.
+
+ pair_content() is used to determine what the colors of a given color-
+ pair consist of.
+
+ can_change_color() indicates if the terminal has the capability to
+ change the definition of its colors.
+
+ init_color() is used to redefine a color, if possible. Each of the
+ components -- red, green, and blue -- is specified in a range from 0
+ to 1000, inclusive.
+
+ color_content() reports the current definition of a color in the same
+ format as used by init_color().
+
+ assume_default_colors() and use_default_colors() emulate the ncurses
+ extensions of the same names. assume_default_colors(f, b) is
+ essentially the same as init_pair(0, f, b) (which isn't allowed); it
+ redefines the default colors. use_default_colors() allows the use of
+ -1 as a foreground or background color with init_pair(), and calls
+ assume_default_colors(-1, -1); -1 represents the foreground or
+ background color that the terminal had at startup. If the environment
+ variable PDC_ORIGINAL_COLORS is set at the time start_color() is
+ called, that's equivalent to calling use_default_colors().
+
+ alloc_pair(), find_pair() and free_pair() are also from ncurses.
+ free_pair() marks a pair as unused; find_pair() returns an existing
+ pair with the specified foreground and background colors, if one
+ exists. And alloc_pair() returns such a pair whether or not it was
+ previously set, overwriting the oldest initialized pair if there are
+ no free pairs.
+
+ PDC_set_line_color() is used to set the color, globally, for the
+ color of the lines drawn for the attributes: A_UNDERLINE, A_LEFT and
+ A_RIGHT. A value of -1 (the default) indicates that the current
+ foreground color should be used.
+
+ NOTE: COLOR_PAIR() and PAIR_NUMBER() are implemented as macros.
+
+### Return Value
+
+ Most functions return OK on success and ERR on error. has_colors()
+ and can_change_colors() return TRUE or FALSE. alloc_pair() and
+ find_pair() return a pair number, or -1 on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ has_colors Y Y Y
+ start_color Y Y Y
+ init_pair Y Y Y
+ pair_content Y Y Y
+ can_change_color Y Y Y
+ init_color Y Y Y
+ color_content Y Y Y
+ alloc_pair - Y -
+ assume_default_colors - Y Y
+ find_pair - Y -
+ free_pair - Y -
+ use_default_colors - Y Y
+ PDC_set_line_color - - -
+
+**man-end****************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+int COLORS = 0;
+int COLOR_PAIRS = PDC_COLOR_PAIRS;
+
+static bool default_colors = FALSE;
+static short first_col = 0;
+static int allocnum = 0;
+
+int start_color(void)
+{
+ PDC_LOG(("start_color() - called\n"));
+
+ if (!SP || SP->mono)
+ return ERR;
+
+ SP->color_started = TRUE;
+
+ PDC_set_blink(FALSE); /* Also sets COLORS */
+
+ if (!default_colors && SP->orig_attr && getenv("PDC_ORIGINAL_COLORS"))
+ default_colors = TRUE;
+
+ PDC_init_atrtab();
+
+ return OK;
+}
+
+static void _normalize(short *fg, short *bg)
+{
+ if (*fg == -1)
+ *fg = SP->orig_attr ? SP->orig_fore : COLOR_WHITE;
+
+ if (*bg == -1)
+ *bg = SP->orig_attr ? SP->orig_back : COLOR_BLACK;
+}
+
+static void _init_pair_core(short pair, short fg, short bg)
+{
+ PDC_PAIR *p = SP->atrtab + pair;
+
+ _normalize(&fg, &bg);
+
+ /* To allow the PDC_PRESERVE_SCREEN option to work, we only reset
+ curscr if this call to init_pair() alters a color pair created by
+ the user. */
+
+ if (p->set)
+ {
+ if (p->f != fg || p->b != bg)
+ curscr->_clear = TRUE;
+ }
+
+ p->f = fg;
+ p->b = bg;
+ p->count = allocnum++;
+ p->set = TRUE;
+}
+
+int init_pair(short pair, short fg, short bg)
+{
+ PDC_LOG(("init_pair() - called: pair %d fg %d bg %d\n", pair, fg, bg));
+
+ if (!SP || !SP->color_started || pair < 1 || pair >= COLOR_PAIRS ||
+ fg < first_col || fg >= COLORS || bg < first_col || bg >= COLORS)
+ return ERR;
+
+ _init_pair_core(pair, fg, bg);
+
+ return OK;
+}
+
+bool has_colors(void)
+{
+ PDC_LOG(("has_colors() - called\n"));
+
+ return SP ? !(SP->mono) : FALSE;
+}
+
+int init_color(short color, short red, short green, short blue)
+{
+ PDC_LOG(("init_color() - called\n"));
+
+ if (!SP || color < 0 || color >= COLORS || !PDC_can_change_color() ||
+ red < -1 || red > 1000 || green < -1 || green > 1000 ||
+ blue < -1 || blue > 1000)
+ return ERR;
+
+ SP->dirty = TRUE;
+
+ return PDC_init_color(color, red, green, blue);
+}
+
+int color_content(short color, short *red, short *green, short *blue)
+{
+ PDC_LOG(("color_content() - called\n"));
+
+ if (color < 0 || color >= COLORS || !red || !green || !blue)
+ return ERR;
+
+ if (PDC_can_change_color())
+ return PDC_color_content(color, red, green, blue);
+ else
+ {
+ /* Simulated values for platforms that don't support palette
+ changing */
+
+ short maxval = (color & 8) ? 1000 : 680;
+
+ *red = (color & COLOR_RED) ? maxval : 0;
+ *green = (color & COLOR_GREEN) ? maxval : 0;
+ *blue = (color & COLOR_BLUE) ? maxval : 0;
+
+ return OK;
+ }
+}
+
+bool can_change_color(void)
+{
+ PDC_LOG(("can_change_color() - called\n"));
+
+ return PDC_can_change_color();
+}
+
+int pair_content(short pair, short *fg, short *bg)
+{
+ PDC_LOG(("pair_content() - called\n"));
+
+ if (pair < 0 || pair >= COLOR_PAIRS || !fg || !bg)
+ return ERR;
+
+ *fg = SP->atrtab[pair].f;
+ *bg = SP->atrtab[pair].b;
+
+ return OK;
+}
+
+int assume_default_colors(int f, int b)
+{
+ PDC_LOG(("assume_default_colors() - called: f %d b %d\n", f, b));
+
+ if (f < -1 || f >= COLORS || b < -1 || b >= COLORS)
+ return ERR;
+
+ if (SP->color_started)
+ _init_pair_core(0, f, b);
+
+ return OK;
+}
+
+int use_default_colors(void)
+{
+ PDC_LOG(("use_default_colors() - called\n"));
+
+ default_colors = TRUE;
+ first_col = -1;
+
+ return assume_default_colors(-1, -1);
+}
+
+int PDC_set_line_color(short color)
+{
+ PDC_LOG(("PDC_set_line_color() - called: %d\n", color));
+
+ if (!SP || color < -1 || color >= COLORS)
+ return ERR;
+
+ SP->line_color = color;
+
+ return OK;
+}
+
+void PDC_init_atrtab(void)
+{
+ PDC_PAIR *p = SP->atrtab;
+ short i, fg, bg;
+
+ if (SP->color_started && !default_colors)
+ {
+ fg = COLOR_WHITE;
+ bg = COLOR_BLACK;
+ }
+ else
+ fg = bg = -1;
+
+ _normalize(&fg, &bg);
+
+ for (i = 0; i < PDC_COLOR_PAIRS; i++)
+ {
+ p[i].f = fg;
+ p[i].b = bg;
+ p[i].set = FALSE;
+ }
+}
+
+int free_pair(int pair)
+{
+ if (pair < 1 || pair >= PDC_COLOR_PAIRS || !(SP->atrtab[pair].set))
+ return ERR;
+
+ SP->atrtab[pair].set = FALSE;
+ return OK;
+}
+
+int find_pair(int fg, int bg)
+{
+ int i;
+ PDC_PAIR *p = SP->atrtab;
+
+ for (i = 0; i < PDC_COLOR_PAIRS; i++)
+ if (p[i].set && p[i].f == fg && p[i].b == bg)
+ return i;
+
+ return -1;
+}
+
+static int _find_oldest()
+{
+ int i, lowind = 0, lowval = 0;
+ PDC_PAIR *p = SP->atrtab;
+
+ for (i = 1; i < PDC_COLOR_PAIRS; i++)
+ {
+ if (!p[i].set)
+ return i;
+
+ if (!lowval || (p[i].count < lowval))
+ {
+ lowind = i;
+ lowval = p[i].count;
+ }
+ }
+
+ return lowind;
+}
+
+int alloc_pair(int fg, int bg)
+{
+ int i = find_pair(fg, bg);
+
+ if (-1 == i)
+ {
+ i = _find_oldest();
+
+ if (ERR == init_pair(i, fg, bg))
+ return -1;
+ }
+
+ return i;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/debug.c b/Utilities/cmpdcurses/pdcurses/debug.c
new file mode 100644
index 0000000..6444886
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/debug.c
@@ -0,0 +1,106 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+debug
+-----
+
+### Synopsis
+
+ void traceon(void);
+ void traceoff(void);
+ void PDC_debug(const char *, ...);
+
+### Description
+
+ traceon() and traceoff() toggle the recording of debugging
+ information to the file "trace". Although not standard, similar
+ functions are in some other curses implementations.
+
+ PDC_debug() is the function that writes to the file, based on whether
+ traceon() has been called. It's used from the PDC_LOG() macro.
+
+ The environment variable PDC_TRACE_FLUSH controls whether the trace
+ file contents are fflushed after each write. The default is not. Set
+ it to enable this (may affect performance).
+
+### Portability
+ X/Open ncurses NetBSD
+ traceon - - -
+ traceoff - - -
+ PDC_debug - - -
+
+**man-end****************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+static bool want_fflush = FALSE;
+
+void PDC_debug(const char *fmt, ...)
+{
+ va_list args;
+ char hms[9];
+ time_t now;
+
+ if (!SP || !SP->dbfp)
+ return;
+
+ time(&now);
+ strftime(hms, 9, "%H:%M:%S", localtime(&now));
+ fprintf(SP->dbfp, "At: %8.8ld - %s ", (long) clock(), hms);
+
+ va_start(args, fmt);
+ vfprintf(SP->dbfp, fmt, args);
+ va_end(args);
+
+ /* If you are crashing and losing debugging information, enable this
+ by setting the environment variable PDC_TRACE_FLUSH. This may
+ impact performance. */
+
+ if (want_fflush)
+ fflush(SP->dbfp);
+
+ /* If with PDC_TRACE_FLUSH enabled you are still losing logging in
+ crashes, you may need to add a platform-dependent mechanism to
+ flush the OS buffers as well (such as fsync() on POSIX) -- but
+ expect terrible performance. */
+}
+
+void traceon(void)
+{
+ if (!SP)
+ return;
+
+ if (SP->dbfp)
+ fclose(SP->dbfp);
+
+ /* open debug log file append */
+ SP->dbfp = fopen("trace", "a");
+ if (!SP->dbfp)
+ {
+ fprintf(stderr, "PDC_debug(): Unable to open debug log file\n");
+ return;
+ }
+
+ if (getenv("PDC_TRACE_FLUSH"))
+ want_fflush = TRUE;
+
+ PDC_LOG(("traceon() - called\n"));
+}
+
+void traceoff(void)
+{
+ if (!SP || !SP->dbfp)
+ return;
+
+ PDC_LOG(("traceoff() - called\n"));
+
+ fclose(SP->dbfp);
+ SP->dbfp = NULL;
+ want_fflush = FALSE;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/delch.c b/Utilities/cmpdcurses/pdcurses/delch.c
new file mode 100644
index 0000000..970a5a8
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/delch.c
@@ -0,0 +1,96 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+delch
+-----
+
+### Synopsis
+
+ int delch(void);
+ int wdelch(WINDOW *win);
+ int mvdelch(int y, int x);
+ int mvwdelch(WINDOW *win, int y, int x);
+
+### Description
+
+ The character under the cursor in the window is deleted. All
+ characters to the right on the same line are moved to the left one
+ position and the last character on the line is filled with a blank.
+ The cursor position does not change (after moving to y, x if
+ coordinates are specified).
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ delch Y Y Y
+ wdelch Y Y Y
+ mvdelch Y Y Y
+ mvwdelch Y Y Y
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+int wdelch(WINDOW *win)
+{
+ int y, x, maxx;
+ chtype *temp1;
+
+ PDC_LOG(("wdelch() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ y = win->_cury;
+ x = win->_curx;
+ maxx = win->_maxx - 1;
+ temp1 = &win->_y[y][x];
+
+ memmove(temp1, temp1 + 1, (maxx - x) * sizeof(chtype));
+
+ /* wrs (4/10/93) account for window background */
+
+ win->_y[y][maxx] = win->_bkgd;
+
+ win->_lastch[y] = maxx;
+
+ if ((win->_firstch[y] == _NO_CHANGE) || (win->_firstch[y] > x))
+ win->_firstch[y] = x;
+
+ PDC_sync(win);
+
+ return OK;
+}
+
+int delch(void)
+{
+ PDC_LOG(("delch() - called\n"));
+
+ return wdelch(stdscr);
+}
+
+int mvdelch(int y, int x)
+{
+ PDC_LOG(("mvdelch() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wdelch(stdscr);
+}
+
+int mvwdelch(WINDOW *win, int y, int x)
+{
+ PDC_LOG(("mvwdelch() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wdelch(win);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/deleteln.c b/Utilities/cmpdcurses/pdcurses/deleteln.c
new file mode 100644
index 0000000..8e7563f
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/deleteln.c
@@ -0,0 +1,211 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+deleteln
+--------
+
+### Synopsis
+
+ int deleteln(void);
+ int wdeleteln(WINDOW *win);
+ int insdelln(int n);
+ int winsdelln(WINDOW *win, int n);
+ int insertln(void);
+ int winsertln(WINDOW *win);
+
+ int mvdeleteln(int y, int x);
+ int mvwdeleteln(WINDOW *win, int y, int x);
+ int mvinsertln(int y, int x);
+ int mvwinsertln(WINDOW *win, int y, int x);
+
+### Description
+
+ With the deleteln() and wdeleteln() functions, the line under the
+ cursor in the window is deleted. All lines below the current line are
+ moved up one line. The bottom line of the window is cleared. The
+ cursor position does not change.
+
+ With the insertln() and winsertn() functions, a blank line is
+ inserted above the current line and the bottom line is lost.
+
+ mvdeleteln(), mvwdeleteln(), mvinsertln() and mvwinsertln() allow
+ moving the cursor and inserting/deleting in one call.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ deleteln Y Y Y
+ wdeleteln Y Y Y
+ mvdeleteln - - -
+ mvwdeleteln - - -
+ insdelln Y Y Y
+ winsdelln Y Y Y
+ insertln Y Y Y
+ winsertln Y Y Y
+ mvinsertln - - -
+ mvwinsertln - - -
+
+**man-end****************************************************************/
+
+int wdeleteln(WINDOW *win)
+{
+ chtype blank, *temp, *ptr;
+ int y;
+
+ PDC_LOG(("wdeleteln() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ /* wrs (4/10/93) account for window background */
+
+ blank = win->_bkgd;
+
+ temp = win->_y[win->_cury];
+
+ for (y = win->_cury; y < win->_bmarg; y++)
+ {
+ win->_y[y] = win->_y[y + 1];
+ win->_firstch[y] = 0;
+ win->_lastch[y] = win->_maxx - 1;
+ }
+
+ for (ptr = temp; (ptr - temp < win->_maxx); ptr++)
+ *ptr = blank; /* make a blank line */
+
+ if (win->_cury <= win->_bmarg)
+ {
+ win->_firstch[win->_bmarg] = 0;
+ win->_lastch[win->_bmarg] = win->_maxx - 1;
+ win->_y[win->_bmarg] = temp;
+ }
+
+ return OK;
+}
+
+int deleteln(void)
+{
+ PDC_LOG(("deleteln() - called\n"));
+
+ return wdeleteln(stdscr);
+}
+
+int mvdeleteln(int y, int x)
+{
+ PDC_LOG(("mvdeleteln() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wdeleteln(stdscr);
+}
+
+int mvwdeleteln(WINDOW *win, int y, int x)
+{
+ PDC_LOG(("mvwdeleteln() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wdeleteln(win);
+}
+
+int winsdelln(WINDOW *win, int n)
+{
+ int i;
+
+ PDC_LOG(("winsdelln() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ if (n > 0)
+ {
+ for (i = 0; i < n; i++)
+ if (winsertln(win) == ERR)
+ return ERR;
+ }
+ else if (n < 0)
+ {
+ n = -n;
+ for (i = 0; i < n; i++)
+ if (wdeleteln(win) == ERR)
+ return ERR;
+ }
+
+ return OK;
+}
+
+int insdelln(int n)
+{
+ PDC_LOG(("insdelln() - called\n"));
+
+ return winsdelln(stdscr, n);
+}
+
+int winsertln(WINDOW *win)
+{
+ chtype blank, *temp, *end;
+ int y;
+
+ PDC_LOG(("winsertln() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ /* wrs (4/10/93) account for window background */
+
+ blank = win->_bkgd;
+
+ temp = win->_y[win->_maxy - 1];
+
+ for (y = win->_maxy - 1; y > win->_cury; y--)
+ {
+ win->_y[y] = win->_y[y - 1];
+ win->_firstch[y] = 0;
+ win->_lastch[y] = win->_maxx - 1;
+ }
+
+ win->_y[win->_cury] = temp;
+
+ for (end = &temp[win->_maxx - 1]; temp <= end; temp++)
+ *temp = blank;
+
+ win->_firstch[win->_cury] = 0;
+ win->_lastch[win->_cury] = win->_maxx - 1;
+
+ return OK;
+}
+
+int insertln(void)
+{
+ PDC_LOG(("insertln() - called\n"));
+
+ return winsertln(stdscr);
+}
+
+int mvinsertln(int y, int x)
+{
+ PDC_LOG(("mvinsertln() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winsertln(stdscr);
+}
+
+int mvwinsertln(WINDOW *win, int y, int x)
+{
+ PDC_LOG(("mvwinsertln() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winsertln(win);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/getch.c b/Utilities/cmpdcurses/pdcurses/getch.c
new file mode 100644
index 0000000..58a44c2
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/getch.c
@@ -0,0 +1,589 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+getch
+-----
+
+### Synopsis
+
+ int getch(void);
+ int wgetch(WINDOW *win);
+ int mvgetch(int y, int x);
+ int mvwgetch(WINDOW *win, int y, int x);
+ int ungetch(int ch);
+ int flushinp(void);
+
+ int get_wch(wint_t *wch);
+ int wget_wch(WINDOW *win, wint_t *wch);
+ int mvget_wch(int y, int x, wint_t *wch);
+ int mvwget_wch(WINDOW *win, int y, int x, wint_t *wch);
+ int unget_wch(const wchar_t wch);
+
+ unsigned long PDC_get_key_modifiers(void);
+ int PDC_return_key_modifiers(bool flag);
+
+### Description
+
+ With the getch(), wgetch(), mvgetch(), and mvwgetch() functions, a
+ character is read from the terminal associated with the window. In
+ nodelay mode, if there is no input waiting, the value ERR is
+ returned. In delay mode, the program will hang until the system
+ passes text through to the program. Depending on the setting of
+ cbreak(), this will be after one character or after the first
+ newline. Unless noecho() has been set, the character will also be
+ echoed into the designated window.
+
+ If keypad() is TRUE, and a function key is pressed, the token for
+ that function key will be returned instead of the raw characters.
+ Possible function keys are defined in <curses.h> with integers
+ beginning with 0401, whose names begin with KEY_.
+
+ If nodelay(win, TRUE) has been called on the window and no input is
+ waiting, the value ERR is returned.
+
+ ungetch() places ch back onto the input queue to be returned by the
+ next call to wgetch().
+
+ flushinp() throws away any type-ahead that has been typed by the user
+ and has not yet been read by the program.
+
+ wget_wch() is the wide-character version of wgetch(), available when
+ PDCurses is built with the PDC_WIDE option. It takes a pointer to a
+ wint_t rather than returning the key as an int, and instead returns
+ KEY_CODE_YES if the key is a function key. Otherwise, it returns OK
+ or ERR. It's important to check for KEY_CODE_YES, since regular wide
+ characters can have the same values as function key codes.
+
+ unget_wch() puts a wide character on the input queue.
+
+ PDC_get_key_modifiers() returns the keyboard modifiers (shift,
+ control, alt, numlock) effective at the time of the last getch()
+ call. Use the macros PDC_KEY_MODIFIER_* to determine which
+ modifier(s) were set. PDC_return_key_modifiers() tells getch() to
+ return modifier keys pressed alone as keystrokes (KEY_ALT_L, etc.).
+ These may not work on all platforms.
+
+ NOTE: getch() and ungetch() are implemented as macros, to avoid
+ conflict with many DOS compiler's runtime libraries.
+
+### Return Value
+
+ These functions return ERR or the value of the character, meta
+ character or function key token.
+
+### Portability
+ X/Open ncurses NetBSD
+ getch Y Y Y
+ wgetch Y Y Y
+ mvgetch Y Y Y
+ mvwgetch Y Y Y
+ ungetch Y Y Y
+ flushinp Y Y Y
+ get_wch Y Y Y
+ wget_wch Y Y Y
+ mvget_wch Y Y Y
+ mvwget_wch Y Y Y
+ unget_wch Y Y Y
+ PDC_get_key_modifiers - - -
+
+**man-end****************************************************************/
+
+#include <stdlib.h>
+
+static int _get_box(int *y_start, int *y_end, int *x_start, int *x_end)
+{
+ int start, end;
+
+ if (SP->sel_start < SP->sel_end)
+ {
+ start = SP->sel_start;
+ end = SP->sel_end;
+ }
+ else
+ {
+ start = SP->sel_end;
+ end = SP->sel_start;
+ }
+
+ *y_start = start / COLS;
+ *x_start = start % COLS;
+
+ *y_end = end / COLS;
+ *x_end = end % COLS;
+
+ return (end - start) + (*y_end - *y_start);
+}
+
+static void _highlight(void)
+{
+ int i, j, y_start, y_end, x_start, x_end;
+
+ if (-1 == SP->sel_start)
+ return;
+
+ _get_box(&y_start, &y_end, &x_start, &x_end);
+
+ for (j = y_start; j <= y_end; j++)
+ for (i = (j == y_start ? x_start : 0);
+ i < (j == y_end ? x_end : COLS); i++)
+ curscr->_y[j][i] ^= A_REVERSE;
+
+ wrefresh(curscr);
+}
+
+static void _copy(void)
+{
+#ifdef PDC_WIDE
+ wchar_t *wtmp;
+# define TMP wtmp
+# define MASK A_CHARTEXT
+#else
+# define TMP tmp
+# define MASK 0xff
+#endif
+ char *tmp;
+ long pos;
+ int i, j, y_start, y_end, x_start, x_end, len;
+
+ if (-1 == SP->sel_start)
+ return;
+
+ len = _get_box(&y_start, &y_end, &x_start, &x_end);
+
+ if (!len)
+ return;
+
+#ifdef PDC_WIDE
+ wtmp = malloc((len + 1) * sizeof(wchar_t));
+ len *= 3;
+#endif
+ tmp = malloc(len + 1);
+
+ for (j = y_start, pos = 0; j <= y_end; j++)
+ {
+ for (i = (j == y_start ? x_start : 0);
+ i < (j == y_end ? x_end : COLS); i++)
+ TMP[pos++] = curscr->_y[j][i] & MASK;
+
+ while (y_start != y_end && pos > 0 && TMP[pos - 1] == 32)
+ pos--;
+
+ if (j < y_end)
+ TMP[pos++] = 10;
+ }
+ TMP[pos] = 0;
+
+#ifdef PDC_WIDE
+ pos = PDC_wcstombs(tmp, wtmp, len);
+#endif
+
+ PDC_setclipboard(tmp, pos);
+ free(tmp);
+#ifdef PDC_WIDE
+ free(wtmp);
+#endif
+}
+
+static int _paste(void)
+{
+#ifdef PDC_WIDE
+ wchar_t *wpaste;
+# define PASTE wpaste
+#else
+# define PASTE paste
+#endif
+ char *paste;
+ long len, newmax;
+ int key;
+
+ key = PDC_getclipboard(&paste, &len);
+ if (PDC_CLIP_SUCCESS != key || !len)
+ return -1;
+
+#ifdef PDC_WIDE
+ wpaste = malloc(len * sizeof(wchar_t));
+ len = PDC_mbstowcs(wpaste, paste, len);
+#endif
+ newmax = len + SP->c_ungind;
+ if (newmax > SP->c_ungmax)
+ {
+ SP->c_ungch = realloc(SP->c_ungch, newmax * sizeof(int));
+ if (!SP->c_ungch)
+ return -1;
+ SP->c_ungmax = newmax;
+ }
+ while (len > 1)
+ PDC_ungetch(PASTE[--len]);
+ key = *PASTE;
+#ifdef PDC_WIDE
+ free(wpaste);
+#endif
+ PDC_freeclipboard(paste);
+ SP->key_modifiers = 0;
+
+ return key;
+}
+
+static int _mouse_key(void)
+{
+ int i, key = KEY_MOUSE, changes = SP->mouse_status.changes;
+ unsigned long mbe = SP->_trap_mbe;
+
+ /* Selection highlighting? */
+
+ if ((!mbe || SP->mouse_status.button[0] & BUTTON_SHIFT) && changes & 1)
+ {
+ i = SP->mouse_status.y * COLS + SP->mouse_status.x;
+ switch (SP->mouse_status.button[0] & BUTTON_ACTION_MASK)
+ {
+ case BUTTON_PRESSED:
+ _highlight();
+ SP->sel_start = SP->sel_end = i;
+ return -1;
+ case BUTTON_MOVED:
+ _highlight();
+ SP->sel_end = i;
+ _highlight();
+ return -1;
+ case BUTTON_RELEASED:
+ _copy();
+ return -1;
+ }
+ }
+ else if ((!mbe || SP->mouse_status.button[1] & BUTTON_SHIFT) &&
+ changes & 2 && (SP->mouse_status.button[1] &
+ BUTTON_ACTION_MASK) == BUTTON_CLICKED)
+ {
+ SP->key_code = FALSE;
+ return _paste();
+ }
+
+ /* Filter unwanted mouse events */
+
+ for (i = 0; i < 3; i++)
+ {
+ if (changes & (1 << i))
+ {
+ int shf = i * 5;
+ short button = SP->mouse_status.button[i] & BUTTON_ACTION_MASK;
+
+ if ( (!(mbe & (BUTTON1_PRESSED << shf)) &&
+ (button == BUTTON_PRESSED))
+
+ || (!(mbe & (BUTTON1_CLICKED << shf)) &&
+ (button == BUTTON_CLICKED))
+
+ || (!(mbe & (BUTTON1_DOUBLE_CLICKED << shf)) &&
+ (button == BUTTON_DOUBLE_CLICKED))
+
+ || (!(mbe & (BUTTON1_MOVED << shf)) &&
+ (button == BUTTON_MOVED))
+
+ || (!(mbe & (BUTTON1_RELEASED << shf)) &&
+ (button == BUTTON_RELEASED))
+ )
+ SP->mouse_status.changes ^= (1 << i);
+ }
+ }
+
+ if (changes & PDC_MOUSE_MOVED)
+ {
+ if (!(mbe & (BUTTON1_MOVED|BUTTON2_MOVED|BUTTON3_MOVED)))
+ SP->mouse_status.changes ^= PDC_MOUSE_MOVED;
+ }
+
+ if (changes & (PDC_MOUSE_WHEEL_UP|PDC_MOUSE_WHEEL_DOWN))
+ {
+ if (!(mbe & MOUSE_WHEEL_SCROLL))
+ SP->mouse_status.changes &=
+ ~(PDC_MOUSE_WHEEL_UP|PDC_MOUSE_WHEEL_DOWN);
+ }
+
+ if (!changes)
+ return -1;
+
+ /* Check for click in slk area */
+
+ i = PDC_mouse_in_slk(SP->mouse_status.y, SP->mouse_status.x);
+
+ if (i)
+ {
+ if (SP->mouse_status.button[0] & (BUTTON_PRESSED|BUTTON_CLICKED))
+ key = KEY_F(i);
+ else
+ key = -1;
+ }
+
+ return key;
+}
+
+int wgetch(WINDOW *win)
+{
+ int key, waitcount;
+
+ PDC_LOG(("wgetch() - called\n"));
+
+ if (!win || !SP)
+ return ERR;
+
+ waitcount = 0;
+
+ /* set the number of 1/20th second napms() calls */
+
+ if (SP->delaytenths)
+ waitcount = 2 * SP->delaytenths;
+ else
+ if (win->_delayms)
+ {
+ /* Can't really do millisecond intervals, so delay in
+ 1/20ths of a second (50ms) */
+
+ waitcount = win->_delayms / 50;
+ if (!waitcount)
+ waitcount = 1;
+ }
+
+ /* refresh window when wgetch is called if there have been changes
+ to it and it is not a pad */
+
+ if (!(win->_flags & _PAD) && ((!win->_leaveit &&
+ (win->_begx + win->_curx != SP->curscol ||
+ win->_begy + win->_cury != SP->cursrow)) || is_wintouched(win)))
+ wrefresh(win);
+
+ /* if ungotten char exists, remove and return it */
+
+ if (SP->c_ungind)
+ return SP->c_ungch[--(SP->c_ungind)];
+
+ /* if normal and data in buffer */
+
+ if ((!SP->raw_inp && !SP->cbreak) && (SP->c_gindex < SP->c_pindex))
+ return SP->c_buffer[SP->c_gindex++];
+
+ /* prepare to buffer data */
+
+ SP->c_pindex = 0;
+ SP->c_gindex = 0;
+
+ /* to get here, no keys are buffered. go and get one. */
+
+ for (;;) /* loop for any buffering */
+ {
+ /* is there a keystroke ready? */
+
+ if (!PDC_check_key())
+ {
+ /* if not, handle timeout() and halfdelay() */
+
+ if (SP->delaytenths || win->_delayms)
+ {
+ if (!waitcount)
+ return ERR;
+
+ waitcount--;
+ }
+ else
+ if (win->_nodelay)
+ return ERR;
+
+ napms(50); /* sleep for 1/20th second */
+ continue; /* then check again */
+ }
+
+ /* if there is, fetch it */
+
+ key = PDC_get_key();
+
+ /* copy or paste? */
+
+ if (SP->key_modifiers & PDC_KEY_MODIFIER_SHIFT)
+ {
+ if (0x03 == key)
+ {
+ _copy();
+ continue;
+ }
+ else if (0x16 == key)
+ key = _paste();
+ }
+
+ /* filter mouse events; translate mouse clicks in the slk
+ area to function keys */
+
+ if (SP->key_code && key == KEY_MOUSE)
+ key = _mouse_key();
+
+ /* filter special keys if not in keypad mode */
+
+ if (SP->key_code && !win->_use_keypad)
+ key = -1;
+
+ /* unwanted key? loop back */
+
+ if (key == -1)
+ continue;
+
+ _highlight();
+ SP->sel_start = SP->sel_end = -1;
+
+ /* translate CR */
+
+ if (key == '\r' && SP->autocr && !SP->raw_inp)
+ key = '\n';
+
+ /* if echo is enabled */
+
+ if (SP->echo && !SP->key_code)
+ {
+ waddch(win, key);
+ wrefresh(win);
+ }
+
+ /* if no buffering */
+
+ if (SP->raw_inp || SP->cbreak)
+ return key;
+
+ /* if no overflow, put data in buffer */
+
+ if (key == '\b')
+ {
+ if (SP->c_pindex > SP->c_gindex)
+ SP->c_pindex--;
+ }
+ else
+ if (SP->c_pindex < _INBUFSIZ - 2)
+ SP->c_buffer[SP->c_pindex++] = key;
+
+ /* if we got a line */
+
+ if (key == '\n' || key == '\r')
+ return SP->c_buffer[SP->c_gindex++];
+ }
+}
+
+int mvgetch(int y, int x)
+{
+ PDC_LOG(("mvgetch() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wgetch(stdscr);
+}
+
+int mvwgetch(WINDOW *win, int y, int x)
+{
+ PDC_LOG(("mvwgetch() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wgetch(win);
+}
+
+int PDC_ungetch(int ch)
+{
+ PDC_LOG(("ungetch() - called\n"));
+
+ if (SP->c_ungind >= SP->c_ungmax) /* pushback stack full */
+ return ERR;
+
+ SP->c_ungch[SP->c_ungind++] = ch;
+
+ return OK;
+}
+
+int flushinp(void)
+{
+ PDC_LOG(("flushinp() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ PDC_flushinp();
+
+ SP->c_gindex = 1; /* set indices to kill buffer */
+ SP->c_pindex = 0;
+ SP->c_ungind = 0; /* clear SP->c_ungch array */
+
+ return OK;
+}
+
+unsigned long PDC_get_key_modifiers(void)
+{
+ PDC_LOG(("PDC_get_key_modifiers() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ return SP->key_modifiers;
+}
+
+int PDC_return_key_modifiers(bool flag)
+{
+ PDC_LOG(("PDC_return_key_modifiers() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->return_key_modifiers = flag;
+ return PDC_modifiers_set();
+}
+
+#ifdef PDC_WIDE
+int wget_wch(WINDOW *win, wint_t *wch)
+{
+ int key;
+
+ PDC_LOG(("wget_wch() - called\n"));
+
+ if (!wch)
+ return ERR;
+
+ key = wgetch(win);
+
+ if (key == ERR)
+ return ERR;
+
+ *wch = key;
+
+ return SP->key_code ? KEY_CODE_YES : OK;
+}
+
+int get_wch(wint_t *wch)
+{
+ PDC_LOG(("get_wch() - called\n"));
+
+ return wget_wch(stdscr, wch);
+}
+
+int mvget_wch(int y, int x, wint_t *wch)
+{
+ PDC_LOG(("mvget_wch() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wget_wch(stdscr, wch);
+}
+
+int mvwget_wch(WINDOW *win, int y, int x, wint_t *wch)
+{
+ PDC_LOG(("mvwget_wch() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wget_wch(win, wch);
+}
+
+int unget_wch(const wchar_t wch)
+{
+ return PDC_ungetch(wch);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/getstr.c b/Utilities/cmpdcurses/pdcurses/getstr.c
new file mode 100644
index 0000000..603769f
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/getstr.c
@@ -0,0 +1,473 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+getstr
+------
+
+### Synopsis
+
+ int getstr(char *str);
+ int wgetstr(WINDOW *win, char *str);
+ int mvgetstr(int y, int x, char *str);
+ int mvwgetstr(WINDOW *win, int y, int x, char *str);
+ int getnstr(char *str, int n);
+ int wgetnstr(WINDOW *win, char *str, int n);
+ int mvgetnstr(int y, int x, char *str, int n);
+ int mvwgetnstr(WINDOW *win, int y, int x, char *str, int n);
+
+ int get_wstr(wint_t *wstr);
+ int wget_wstr(WINDOW *win, wint_t *wstr);
+ int mvget_wstr(int y, int x, wint_t *wstr);
+ int mvwget_wstr(WINDOW *win, int, int, wint_t *wstr);
+ int getn_wstr(wint_t *wstr, int n);
+ int wgetn_wstr(WINDOW *win, wint_t *wstr, int n);
+ int mvgetn_wstr(int y, int x, wint_t *wstr, int n);
+ int mvwgetn_wstr(WINDOW *win, int y, int x, wint_t *wstr, int n);
+
+### Description
+
+ These routines call wgetch() repeatedly to build a string,
+ interpreting erase and kill characters along the way, until a newline
+ or carriage return is received. When PDCurses is built with wide-
+ character support enabled, the narrow-character functions convert the
+ wgetch()'d values into a multibyte string in the current locale
+ before returning it. The resulting string is placed in the area
+ pointed to by *str. The routines with n as the last argument read at
+ most n characters.
+
+ Note that there's no way to know how long the buffer passed to
+ wgetstr() is, so use wgetnstr() to avoid buffer overflows.
+
+### Return Value
+
+ These functions return ERR on failure or any other value on success.
+
+### Portability
+ X/Open ncurses NetBSD
+ getstr Y Y Y
+ wgetstr Y Y Y
+ mvgetstr Y Y Y
+ mvwgetstr Y Y Y
+ getnstr Y Y Y
+ wgetnstr Y Y Y
+ mvgetnstr Y Y Y
+ mvwgetnstr Y Y Y
+ get_wstr Y Y Y
+ wget_wstr Y Y Y
+ mvget_wstr Y Y Y
+ mvwget_wstr Y Y Y
+ getn_wstr Y Y Y
+ wgetn_wstr Y Y Y
+ mvgetn_wstr Y Y Y
+ mvwgetn_wstr Y Y Y
+
+**man-end****************************************************************/
+
+#define MAXLINE 255
+
+int wgetnstr(WINDOW *win, char *str, int n)
+{
+#ifdef PDC_WIDE
+ wchar_t wstr[MAXLINE + 1];
+
+ if (n < 0 || n > MAXLINE)
+ n = MAXLINE;
+
+ if (wgetn_wstr(win, (wint_t *)wstr, n) == ERR)
+ return ERR;
+
+ return PDC_wcstombs(str, wstr, n);
+#else
+ int ch, i, num, x, chars;
+ char *p;
+ bool stop, oldecho, oldcbreak, oldnodelay;
+
+ PDC_LOG(("wgetnstr() - called\n"));
+
+ if (!win || !str)
+ return ERR;
+
+ chars = 0;
+ p = str;
+ stop = FALSE;
+
+ x = win->_curx;
+
+ oldcbreak = SP->cbreak; /* remember states */
+ oldecho = SP->echo;
+ oldnodelay = win->_nodelay;
+
+ SP->echo = FALSE; /* we do echo ourselves */
+ cbreak(); /* ensure each key is returned immediately */
+ win->_nodelay = FALSE; /* don't return -1 */
+
+ wrefresh(win);
+
+ while (!stop)
+ {
+ ch = wgetch(win);
+
+ switch (ch)
+ {
+
+ case '\t':
+ ch = ' ';
+ num = TABSIZE - (win->_curx - x) % TABSIZE;
+ for (i = 0; i < num; i++)
+ {
+ if (chars < n)
+ {
+ if (oldecho)
+ waddch(win, ch);
+ *p++ = ch;
+ ++chars;
+ }
+ else
+ beep();
+ }
+ break;
+
+ case _ECHAR: /* CTRL-H -- Delete character */
+ if (p > str)
+ {
+ if (oldecho)
+ waddstr(win, "\b \b");
+ ch = (unsigned char)(*--p);
+ if ((ch < ' ') && (oldecho))
+ waddstr(win, "\b \b");
+ chars--;
+ }
+ break;
+
+ case _DLCHAR: /* CTRL-U -- Delete line */
+ while (p > str)
+ {
+ if (oldecho)
+ waddstr(win, "\b \b");
+ ch = (unsigned char)(*--p);
+ if ((ch < ' ') && (oldecho))
+ waddstr(win, "\b \b");
+ }
+ chars = 0;
+ break;
+
+ case _DWCHAR: /* CTRL-W -- Delete word */
+
+ while ((p > str) && (*(p - 1) == ' '))
+ {
+ if (oldecho)
+ waddstr(win, "\b \b");
+
+ --p; /* remove space */
+ chars--;
+ }
+ while ((p > str) && (*(p - 1) != ' '))
+ {
+ if (oldecho)
+ waddstr(win, "\b \b");
+
+ ch = (unsigned char)(*--p);
+ if ((ch < ' ') && (oldecho))
+ waddstr(win, "\b \b");
+ chars--;
+ }
+ break;
+
+ case '\n':
+ case '\r':
+ stop = TRUE;
+ if (oldecho)
+ waddch(win, '\n');
+ break;
+
+ default:
+ if (chars < n)
+ {
+ if (!SP->key_code && ch < 0x100)
+ {
+ *p++ = ch;
+ if (oldecho)
+ waddch(win, ch);
+ chars++;
+ }
+ }
+ else
+ beep();
+
+ break;
+
+ }
+
+ wrefresh(win);
+ }
+
+ *p = '\0';
+
+ SP->echo = oldecho; /* restore old settings */
+ SP->cbreak = oldcbreak;
+ win->_nodelay = oldnodelay;
+
+ return OK;
+#endif
+}
+
+int getstr(char *str)
+{
+ PDC_LOG(("getstr() - called\n"));
+
+ return wgetnstr(stdscr, str, MAXLINE);
+}
+
+int wgetstr(WINDOW *win, char *str)
+{
+ PDC_LOG(("wgetstr() - called\n"));
+
+ return wgetnstr(win, str, MAXLINE);
+}
+
+int mvgetstr(int y, int x, char *str)
+{
+ PDC_LOG(("mvgetstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wgetnstr(stdscr, str, MAXLINE);
+}
+
+int mvwgetstr(WINDOW *win, int y, int x, char *str)
+{
+ PDC_LOG(("mvwgetstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wgetnstr(win, str, MAXLINE);
+}
+
+int getnstr(char *str, int n)
+{
+ PDC_LOG(("getnstr() - called\n"));
+
+ return wgetnstr(stdscr, str, n);
+}
+
+int mvgetnstr(int y, int x, char *str, int n)
+{
+ PDC_LOG(("mvgetnstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wgetnstr(stdscr, str, n);
+}
+
+int mvwgetnstr(WINDOW *win, int y, int x, char *str, int n)
+{
+ PDC_LOG(("mvwgetnstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wgetnstr(win, str, n);
+}
+
+#ifdef PDC_WIDE
+int wgetn_wstr(WINDOW *win, wint_t *wstr, int n)
+{
+ int ch, i, num, x, chars;
+ wint_t *p;
+ bool stop, oldecho, oldcbreak, oldnodelay;
+
+ PDC_LOG(("wgetn_wstr() - called\n"));
+
+ if (!win || !wstr)
+ return ERR;
+
+ chars = 0;
+ p = wstr;
+ stop = FALSE;
+
+ x = win->_curx;
+
+ oldcbreak = SP->cbreak; /* remember states */
+ oldecho = SP->echo;
+ oldnodelay = win->_nodelay;
+
+ SP->echo = FALSE; /* we do echo ourselves */
+ cbreak(); /* ensure each key is returned immediately */
+ win->_nodelay = FALSE; /* don't return -1 */
+
+ wrefresh(win);
+
+ while (!stop)
+ {
+ ch = wgetch(win);
+
+ switch (ch)
+ {
+
+ case '\t':
+ ch = ' ';
+ num = TABSIZE - (win->_curx - x) % TABSIZE;
+ for (i = 0; i < num; i++)
+ {
+ if (chars < n)
+ {
+ if (oldecho)
+ waddch(win, ch);
+ *p++ = ch;
+ ++chars;
+ }
+ else
+ beep();
+ }
+ break;
+
+ case _ECHAR: /* CTRL-H -- Delete character */
+ if (p > wstr)
+ {
+ if (oldecho)
+ waddstr(win, "\b \b");
+ ch = *--p;
+ if ((ch < ' ') && (oldecho))
+ waddstr(win, "\b \b");
+ chars--;
+ }
+ break;
+
+ case _DLCHAR: /* CTRL-U -- Delete line */
+ while (p > wstr)
+ {
+ if (oldecho)
+ waddstr(win, "\b \b");
+ ch = *--p;
+ if ((ch < ' ') && (oldecho))
+ waddstr(win, "\b \b");
+ }
+ chars = 0;
+ break;
+
+ case _DWCHAR: /* CTRL-W -- Delete word */
+
+ while ((p > wstr) && (*(p - 1) == ' '))
+ {
+ if (oldecho)
+ waddstr(win, "\b \b");
+
+ --p; /* remove space */
+ chars--;
+ }
+ while ((p > wstr) && (*(p - 1) != ' '))
+ {
+ if (oldecho)
+ waddstr(win, "\b \b");
+
+ ch = *--p;
+ if ((ch < ' ') && (oldecho))
+ waddstr(win, "\b \b");
+ chars--;
+ }
+ break;
+
+ case '\n':
+ case '\r':
+ stop = TRUE;
+ if (oldecho)
+ waddch(win, '\n');
+ break;
+
+ default:
+ if (chars < n)
+ {
+ if (!SP->key_code)
+ {
+ *p++ = ch;
+ if (oldecho)
+ waddch(win, ch);
+ chars++;
+ }
+ }
+ else
+ beep();
+
+ break;
+
+ }
+
+ wrefresh(win);
+ }
+
+ *p = '\0';
+
+ SP->echo = oldecho; /* restore old settings */
+ SP->cbreak = oldcbreak;
+ win->_nodelay = oldnodelay;
+
+ return OK;
+}
+
+int get_wstr(wint_t *wstr)
+{
+ PDC_LOG(("get_wstr() - called\n"));
+
+ return wgetn_wstr(stdscr, wstr, MAXLINE);
+}
+
+int wget_wstr(WINDOW *win, wint_t *wstr)
+{
+ PDC_LOG(("wget_wstr() - called\n"));
+
+ return wgetn_wstr(win, wstr, MAXLINE);
+}
+
+int mvget_wstr(int y, int x, wint_t *wstr)
+{
+ PDC_LOG(("mvget_wstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wgetn_wstr(stdscr, wstr, MAXLINE);
+}
+
+int mvwget_wstr(WINDOW *win, int y, int x, wint_t *wstr)
+{
+ PDC_LOG(("mvwget_wstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wgetn_wstr(win, wstr, MAXLINE);
+}
+
+int getn_wstr(wint_t *wstr, int n)
+{
+ PDC_LOG(("getn_wstr() - called\n"));
+
+ return wgetn_wstr(stdscr, wstr, n);
+}
+
+int mvgetn_wstr(int y, int x, wint_t *wstr, int n)
+{
+ PDC_LOG(("mvgetn_wstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wgetn_wstr(stdscr, wstr, n);
+}
+
+int mvwgetn_wstr(WINDOW *win, int y, int x, wint_t *wstr, int n)
+{
+ PDC_LOG(("mvwgetn_wstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wgetn_wstr(win, wstr, n);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/getyx.c b/Utilities/cmpdcurses/pdcurses/getyx.c
new file mode 100644
index 0000000..9400076
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/getyx.c
@@ -0,0 +1,142 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+getyx
+-----
+
+### Synopsis
+
+ void getyx(WINDOW *win, int y, int x);
+ void getparyx(WINDOW *win, int y, int x);
+ void getbegyx(WINDOW *win, int y, int x);
+ void getmaxyx(WINDOW *win, int y, int x);
+
+ void getsyx(int y, int x);
+ void setsyx(int y, int x);
+
+ int getbegy(WINDOW *win);
+ int getbegx(WINDOW *win);
+ int getcury(WINDOW *win);
+ int getcurx(WINDOW *win);
+ int getpary(WINDOW *win);
+ int getparx(WINDOW *win);
+ int getmaxy(WINDOW *win);
+ int getmaxx(WINDOW *win);
+
+### Description
+
+ The getyx() macro (defined in curses.h -- the prototypes here are
+ merely illustrative) puts the current cursor position of the
+ specified window into y and x. getbegyx() and getmaxyx() return the
+ starting coordinates and size of the specified window, respectively.
+ getparyx() returns the starting coordinates of the parent's window,
+ if the specified window is a subwindow; otherwise it sets y and x to
+ -1. These are all macros.
+
+ getsyx() gets the coordinates of the virtual screen cursor, and
+ stores them in y and x. If leaveok() is TRUE, it returns -1, -1. If
+ lines have been removed with ripoffline(), then getsyx() includes
+ these lines in its count; so, the returned y and x values should only
+ be used with setsyx().
+
+ setsyx() sets the virtual screen cursor to the y, x coordinates. If
+ either y or x is -1, leaveok() is set TRUE, else it's set FALSE.
+
+ getsyx() and setsyx() are meant to be used by a library routine that
+ manipulates curses windows without altering the position of the
+ cursor. Note that getsyx() is defined only as a macro.
+
+ getbegy(), getbegx(), getcurx(), getcury(), getmaxy(), getmaxx(),
+ getpary(), and getparx() return the appropriate coordinate or size
+ values, or ERR in the case of a NULL window.
+
+### Portability
+ X/Open ncurses NetBSD
+ getyx Y Y Y
+ getparyx Y Y Y
+ getbegyx Y Y Y
+ getmaxyx Y Y Y
+ getsyx - Y Y
+ setsyx - Y Y
+ getbegy - Y Y
+ getbegx - Y Y
+ getcury - Y Y
+ getcurx - Y Y
+ getpary - Y Y
+ getparx - Y Y
+ getmaxy - Y Y
+ getmaxx - Y Y
+
+**man-end****************************************************************/
+
+int getbegy(WINDOW *win)
+{
+ PDC_LOG(("getbegy() - called\n"));
+
+ return win ? win->_begy : ERR;
+}
+
+int getbegx(WINDOW *win)
+{
+ PDC_LOG(("getbegx() - called\n"));
+
+ return win ? win->_begx : ERR;
+}
+
+int getcury(WINDOW *win)
+{
+ PDC_LOG(("getcury() - called\n"));
+
+ return win ? win->_cury : ERR;
+}
+
+int getcurx(WINDOW *win)
+{
+ PDC_LOG(("getcurx() - called\n"));
+
+ return win ? win->_curx : ERR;
+}
+
+int getpary(WINDOW *win)
+{
+ PDC_LOG(("getpary() - called\n"));
+
+ return win ? win->_pary : ERR;
+}
+
+int getparx(WINDOW *win)
+{
+ PDC_LOG(("getparx() - called\n"));
+
+ return win ? win->_parx : ERR;
+}
+
+int getmaxy(WINDOW *win)
+{
+ PDC_LOG(("getmaxy() - called\n"));
+
+ return win ? win->_maxy : ERR;
+}
+
+int getmaxx(WINDOW *win)
+{
+ PDC_LOG(("getmaxx() - called\n"));
+
+ return win ? win->_maxx : ERR;
+}
+
+void setsyx(int y, int x)
+{
+ PDC_LOG(("setsyx() - called\n"));
+
+ if (curscr)
+ {
+ curscr->_leaveit = y == -1 || x == -1;
+
+ if (!curscr->_leaveit)
+ wmove(curscr, y, x);
+ }
+}
diff --git a/Utilities/cmpdcurses/pdcurses/inch.c b/Utilities/cmpdcurses/pdcurses/inch.c
new file mode 100644
index 0000000..e3275a8
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/inch.c
@@ -0,0 +1,126 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+inch
+----
+
+### Synopsis
+
+ chtype inch(void);
+ chtype winch(WINDOW *win);
+ chtype mvinch(int y, int x);
+ chtype mvwinch(WINDOW *win, int y, int x);
+
+ int in_wch(cchar_t *wcval);
+ int win_wch(WINDOW *win, cchar_t *wcval);
+ int mvin_wch(int y, int x, cchar_t *wcval);
+ int mvwin_wch(WINDOW *win, int y, int x, cchar_t *wcval);
+
+### Description
+
+ The inch() functions retrieve the character and attribute from the
+ current or specified window position, in the form of a chtype. If a
+ NULL window is specified, (chtype)ERR is returned.
+
+ The in_wch() functions are the wide-character versions; instead of
+ returning a chtype, they store a cchar_t at the address specified by
+ wcval, and return OK or ERR. (No value is stored when ERR is
+ returned.) Note that in PDCurses, chtype and cchar_t are the same.
+
+### Portability
+ X/Open ncurses NetBSD
+ inch Y Y Y
+ winch Y Y Y
+ mvinch Y Y Y
+ mvwinch Y Y Y
+ in_wch Y Y Y
+ win_wch Y Y Y
+ mvin_wch Y Y Y
+ mvwin_wch Y Y Y
+
+**man-end****************************************************************/
+
+chtype winch(WINDOW *win)
+{
+ PDC_LOG(("winch() - called\n"));
+
+ if (!win)
+ return (chtype)ERR;
+
+ return win->_y[win->_cury][win->_curx];
+}
+
+chtype inch(void)
+{
+ PDC_LOG(("inch() - called\n"));
+
+ return winch(stdscr);
+}
+
+chtype mvinch(int y, int x)
+{
+ PDC_LOG(("mvinch() - called\n"));
+
+ if (move(y, x) == ERR)
+ return (chtype)ERR;
+
+ return stdscr->_y[stdscr->_cury][stdscr->_curx];
+}
+
+chtype mvwinch(WINDOW *win, int y, int x)
+{
+ PDC_LOG(("mvwinch() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return (chtype)ERR;
+
+ return win->_y[win->_cury][win->_curx];
+}
+
+#ifdef PDC_WIDE
+int win_wch(WINDOW *win, cchar_t *wcval)
+{
+ PDC_LOG(("win_wch() - called\n"));
+
+ if (!win || !wcval)
+ return ERR;
+
+ *wcval = win->_y[win->_cury][win->_curx];
+
+ return OK;
+}
+
+int in_wch(cchar_t *wcval)
+{
+ PDC_LOG(("in_wch() - called\n"));
+
+ return win_wch(stdscr, wcval);
+}
+
+int mvin_wch(int y, int x, cchar_t *wcval)
+{
+ PDC_LOG(("mvin_wch() - called\n"));
+
+ if (!wcval || (move(y, x) == ERR))
+ return ERR;
+
+ *wcval = stdscr->_y[stdscr->_cury][stdscr->_curx];
+
+ return OK;
+}
+
+int mvwin_wch(WINDOW *win, int y, int x, cchar_t *wcval)
+{
+ PDC_LOG(("mvwin_wch() - called\n"));
+
+ if (!wcval || (wmove(win, y, x) == ERR))
+ return ERR;
+
+ *wcval = win->_y[win->_cury][win->_curx];
+
+ return OK;
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/inchstr.c b/Utilities/cmpdcurses/pdcurses/inchstr.c
new file mode 100644
index 0000000..97a0083
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/inchstr.c
@@ -0,0 +1,213 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+inchstr
+-------
+
+### Synopsis
+
+ int inchstr(chtype *ch);
+ int inchnstr(chtype *ch, int n);
+ int winchstr(WINDOW *win, chtype *ch);
+ int winchnstr(WINDOW *win, chtype *ch, int n);
+ int mvinchstr(int y, int x, chtype *ch);
+ int mvinchnstr(int y, int x, chtype *ch, int n);
+ int mvwinchstr(WINDOW *, int y, int x, chtype *ch);
+ int mvwinchnstr(WINDOW *, int y, int x, chtype *ch, int n);
+
+ int in_wchstr(cchar_t *wch);
+ int in_wchnstr(cchar_t *wch, int n);
+ int win_wchstr(WINDOW *win, cchar_t *wch);
+ int win_wchnstr(WINDOW *win, cchar_t *wch, int n);
+ int mvin_wchstr(int y, int x, cchar_t *wch);
+ int mvin_wchnstr(int y, int x, cchar_t *wch, int n);
+ int mvwin_wchstr(WINDOW *win, int y, int x, cchar_t *wch);
+ int mvwin_wchnstr(WINDOW *win, int y, int x, cchar_t *wch, int n);
+
+### Description
+
+ These routines read a chtype or cchar_t string from the window,
+ starting at the current or specified position, and ending at the
+ right margin, or after n elements, whichever is less.
+
+### Return Value
+
+ All functions return the number of elements read, or ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ inchstr Y Y Y
+ winchstr Y Y Y
+ mvinchstr Y Y Y
+ mvwinchstr Y Y Y
+ inchnstr Y Y Y
+ winchnstr Y Y Y
+ mvinchnstr Y Y Y
+ mvwinchnstr Y Y Y
+ in_wchstr Y Y Y
+ win_wchstr Y Y Y
+ mvin_wchstr Y Y Y
+ mvwin_wchstr Y Y Y
+ in_wchnstr Y Y Y
+ win_wchnstr Y Y Y
+ mvin_wchnstr Y Y Y
+ mvwin_wchnstr Y Y Y
+
+**man-end****************************************************************/
+
+int winchnstr(WINDOW *win, chtype *ch, int n)
+{
+ chtype *src;
+ int i;
+
+ PDC_LOG(("winchnstr() - called\n"));
+
+ if (!win || !ch || n < 0)
+ return ERR;
+
+ if ((win->_curx + n) > win->_maxx)
+ n = win->_maxx - win->_curx;
+
+ src = win->_y[win->_cury] + win->_curx;
+
+ for (i = 0; i < n; i++)
+ *ch++ = *src++;
+
+ *ch = (chtype)0;
+
+ return OK;
+}
+
+int inchstr(chtype *ch)
+{
+ PDC_LOG(("inchstr() - called\n"));
+
+ return winchnstr(stdscr, ch, stdscr->_maxx - stdscr->_curx);
+}
+
+int winchstr(WINDOW *win, chtype *ch)
+{
+ PDC_LOG(("winchstr() - called\n"));
+
+ return winchnstr(win, ch, win->_maxx - win->_curx);
+}
+
+int mvinchstr(int y, int x, chtype *ch)
+{
+ PDC_LOG(("mvinchstr() - called: y %d x %d\n", y, x));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winchnstr(stdscr, ch, stdscr->_maxx - stdscr->_curx);
+}
+
+int mvwinchstr(WINDOW *win, int y, int x, chtype *ch)
+{
+ PDC_LOG(("mvwinchstr() - called:\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winchnstr(win, ch, win->_maxx - win->_curx);
+}
+
+int inchnstr(chtype *ch, int n)
+{
+ PDC_LOG(("inchnstr() - called\n"));
+
+ return winchnstr(stdscr, ch, n);
+}
+
+int mvinchnstr(int y, int x, chtype *ch, int n)
+{
+ PDC_LOG(("mvinchnstr() - called: y %d x %d n %d\n", y, x, n));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winchnstr(stdscr, ch, n);
+}
+
+int mvwinchnstr(WINDOW *win, int y, int x, chtype *ch, int n)
+{
+ PDC_LOG(("mvwinchnstr() - called: y %d x %d n %d \n", y, x, n));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winchnstr(win, ch, n);
+}
+
+#ifdef PDC_WIDE
+int win_wchnstr(WINDOW *win, cchar_t *wch, int n)
+{
+ PDC_LOG(("win_wchnstr() - called\n"));
+
+ return winchnstr(win, wch, n);
+}
+
+int in_wchstr(cchar_t *wch)
+{
+ PDC_LOG(("in_wchstr() - called\n"));
+
+ return win_wchnstr(stdscr, wch, stdscr->_maxx - stdscr->_curx);
+}
+
+int win_wchstr(WINDOW *win, cchar_t *wch)
+{
+ PDC_LOG(("win_wchstr() - called\n"));
+
+ return win_wchnstr(win, wch, win->_maxx - win->_curx);
+}
+
+int mvin_wchstr(int y, int x, cchar_t *wch)
+{
+ PDC_LOG(("mvin_wchstr() - called: y %d x %d\n", y, x));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return win_wchnstr(stdscr, wch, stdscr->_maxx - stdscr->_curx);
+}
+
+int mvwin_wchstr(WINDOW *win, int y, int x, cchar_t *wch)
+{
+ PDC_LOG(("mvwin_wchstr() - called:\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return win_wchnstr(win, wch, win->_maxx - win->_curx);
+}
+
+int in_wchnstr(cchar_t *wch, int n)
+{
+ PDC_LOG(("in_wchnstr() - called\n"));
+
+ return win_wchnstr(stdscr, wch, n);
+}
+
+int mvin_wchnstr(int y, int x, cchar_t *wch, int n)
+{
+ PDC_LOG(("mvin_wchnstr() - called: y %d x %d n %d\n", y, x, n));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return win_wchnstr(stdscr, wch, n);
+}
+
+int mvwin_wchnstr(WINDOW *win, int y, int x, cchar_t *wch, int n)
+{
+ PDC_LOG(("mvwinchnstr() - called: y %d x %d n %d \n", y, x, n));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return win_wchnstr(win, wch, n);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/initscr.c b/Utilities/cmpdcurses/pdcurses/initscr.c
new file mode 100644
index 0000000..e9a62ac
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/initscr.c
@@ -0,0 +1,431 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+initscr
+-------
+
+### Synopsis
+
+ WINDOW *initscr(void);
+ WINDOW *Xinitscr(int argc, char **argv);
+ int endwin(void);
+ bool isendwin(void);
+ SCREEN *newterm(const char *type, FILE *outfd, FILE *infd);
+ SCREEN *set_term(SCREEN *new);
+ void delscreen(SCREEN *sp);
+
+ int resize_term(int nlines, int ncols);
+ bool is_termresized(void);
+ const char *curses_version(void);
+ void PDC_get_version(PDC_VERSION *ver);
+
+ int set_tabsize(int tabsize);
+
+### Description
+
+ initscr() should be the first curses routine called. It will
+ initialize all curses data structures, and arrange that the first
+ call to refresh() will clear the screen. In case of error, initscr()
+ will write a message to standard error and end the program.
+
+ endwin() should be called before exiting or escaping from curses mode
+ temporarily. It will restore tty modes, move the cursor to the lower
+ left corner of the screen and reset the terminal into the proper
+ non-visual mode. To resume curses after a temporary escape, call
+ refresh() or doupdate().
+
+ isendwin() returns TRUE if endwin() has been called without a
+ subsequent refresh, unless SP is NULL.
+
+ In some implementations of curses, newterm() allows the use of
+ multiple terminals. Here, it's just an alternative interface for
+ initscr(). It always returns SP, or NULL.
+
+ delscreen() frees the memory allocated by newterm() or initscr(),
+ since it's not freed by endwin(). This function is usually not
+ needed. In PDCurses, the parameter must be the value of SP, and
+ delscreen() sets SP to NULL.
+
+ set_term() does nothing meaningful in PDCurses, but is included for
+ compatibility with other curses implementations.
+
+ resize_term() is effectively two functions: When called with nonzero
+ values for nlines and ncols, it attempts to resize the screen to the
+ given size. When called with (0, 0), it merely adjusts the internal
+ structures to match the current size after the screen is resized by
+ the user. On the currently supported platforms, SDL, Windows console,
+ and X11 allow user resizing, while DOS, OS/2, SDL and Windows console
+ allow programmatic resizing. If you want to support user resizing,
+ you should check for getch() returning KEY_RESIZE, and/or call
+ is_termresized() at appropriate times; if either condition occurs,
+ call resize_term(0, 0). Then, with either user or programmatic
+ resizing, you'll have to resize any windows you've created, as
+ appropriate; resize_term() only handles stdscr and curscr.
+
+ is_termresized() returns TRUE if the curses screen has been resized
+ by the user, and a call to resize_term() is needed. Checking for
+ KEY_RESIZE is generally preferable, unless you're not handling the
+ keyboard.
+
+ curses_version() returns a string describing the version of PDCurses.
+
+ PDC_get_version() fills a PDC_VERSION structure provided by the user
+ with more detailed version info (see curses.h).
+
+ set_tabsize() sets the tab interval, stored in TABSIZE.
+
+### Return Value
+
+ All functions return NULL on error, except endwin(), which always
+ returns OK, and resize_term(), which returns either OK or ERR.
+
+### Portability
+ X/Open ncurses NetBSD
+ initscr Y Y Y
+ endwin Y Y Y
+ isendwin Y Y Y
+ newterm Y Y Y
+ set_term Y Y Y
+ delscreen Y Y Y
+ resize_term - Y Y
+ set_tabsize - Y Y
+ curses_version - Y -
+ is_termresized - - -
+
+**man-end****************************************************************/
+
+#include <stdlib.h>
+
+char ttytype[128];
+
+const char *_curses_notice = "PDCurses " PDC_VERDOT " - " __DATE__;
+
+SCREEN *SP = (SCREEN*)NULL; /* curses variables */
+WINDOW *curscr = (WINDOW *)NULL; /* the current screen image */
+WINDOW *stdscr = (WINDOW *)NULL; /* the default screen window */
+
+int LINES = 0; /* current terminal height */
+int COLS = 0; /* current terminal width */
+int TABSIZE = 8;
+
+MOUSE_STATUS Mouse_status;
+
+extern RIPPEDOFFLINE linesripped[5];
+extern char linesrippedoff;
+
+WINDOW *initscr(void)
+{
+ int i;
+
+ PDC_LOG(("initscr() - called\n"));
+
+ if (SP && SP->alive)
+ return NULL;
+
+ SP = calloc(1, sizeof(SCREEN));
+ if (!SP)
+ return NULL;
+
+ if (PDC_scr_open() == ERR)
+ {
+ fprintf(stderr, "initscr(): Unable to create SP\n");
+ exit(8);
+ }
+
+ SP->autocr = TRUE; /* cr -> lf by default */
+ SP->raw_out = FALSE; /* tty I/O modes */
+ SP->raw_inp = FALSE; /* tty I/O modes */
+ SP->cbreak = TRUE;
+ SP->key_modifiers = 0L;
+ SP->return_key_modifiers = FALSE;
+ SP->echo = TRUE;
+ SP->visibility = 1;
+ SP->resized = FALSE;
+ SP->_trap_mbe = 0L;
+ SP->linesrippedoff = 0;
+ SP->linesrippedoffontop = 0;
+ SP->delaytenths = 0;
+ SP->line_color = -1;
+ SP->lastscr = (WINDOW *)NULL;
+ SP->dbfp = NULL;
+ SP->color_started = FALSE;
+ SP->dirty = FALSE;
+ SP->sel_start = -1;
+ SP->sel_end = -1;
+
+ SP->orig_cursor = PDC_get_cursor_mode();
+
+ LINES = SP->lines = PDC_get_rows();
+ COLS = SP->cols = PDC_get_columns();
+
+ if (LINES < 2 || COLS < 2)
+ {
+ fprintf(stderr, "initscr(): LINES=%d COLS=%d: too small.\n",
+ LINES, COLS);
+ exit(4);
+ }
+
+ curscr = newwin(LINES, COLS, 0, 0);
+ if (!curscr)
+ {
+ fprintf(stderr, "initscr(): Unable to create curscr.\n");
+ exit(2);
+ }
+
+ SP->lastscr = newwin(LINES, COLS, 0, 0);
+ if (!SP->lastscr)
+ {
+ fprintf(stderr, "initscr(): Unable to create SP->lastscr.\n");
+ exit(2);
+ }
+
+ wattrset(SP->lastscr, (chtype)(-1));
+ werase(SP->lastscr);
+
+ PDC_slk_initialize();
+ LINES -= SP->slklines;
+
+ /* We have to sort out ripped off lines here, and reduce the height
+ of stdscr by the number of lines ripped off */
+
+ for (i = 0; i < linesrippedoff; i++)
+ {
+ if (linesripped[i].line < 0)
+ (*linesripped[i].init)(newwin(1, COLS, LINES - 1, 0), COLS);
+ else
+ (*linesripped[i].init)(newwin(1, COLS,
+ SP->linesrippedoffontop++, 0), COLS);
+
+ SP->linesrippedoff++;
+ LINES--;
+ }
+
+ linesrippedoff = 0;
+
+ stdscr = newwin(LINES, COLS, SP->linesrippedoffontop, 0);
+ if (!stdscr)
+ {
+ fprintf(stderr, "initscr(): Unable to create stdscr.\n");
+ exit(1);
+ }
+
+ wclrtobot(stdscr);
+
+ /* If preserving the existing screen, don't allow a screen clear */
+
+ if (SP->_preserve)
+ {
+ untouchwin(curscr);
+ untouchwin(stdscr);
+ stdscr->_clear = FALSE;
+ curscr->_clear = FALSE;
+ }
+ else
+ curscr->_clear = TRUE;
+
+ SP->atrtab = calloc(PDC_COLOR_PAIRS, sizeof(PDC_PAIR));
+ if (!SP->atrtab)
+ return NULL;
+ PDC_init_atrtab(); /* set up default colors */
+
+ MOUSE_X_POS = MOUSE_Y_POS = -1;
+ BUTTON_STATUS(1) = BUTTON_RELEASED;
+ BUTTON_STATUS(2) = BUTTON_RELEASED;
+ BUTTON_STATUS(3) = BUTTON_RELEASED;
+ Mouse_status.changes = 0;
+
+ SP->alive = TRUE;
+
+ def_shell_mode();
+
+ sprintf(ttytype, "pdcurses|PDCurses for %s", PDC_sysname());
+
+ SP->c_buffer = malloc(_INBUFSIZ * sizeof(int));
+ if (!SP->c_buffer)
+ return NULL;
+ SP->c_pindex = 0;
+ SP->c_gindex = 1;
+
+ SP->c_ungch = malloc(NUNGETCH * sizeof(int));
+ if (!SP->c_ungch)
+ return NULL;
+ SP->c_ungind = 0;
+ SP->c_ungmax = NUNGETCH;
+
+ return stdscr;
+}
+
+#ifdef XCURSES
+WINDOW *Xinitscr(int argc, char **argv)
+{
+ PDC_LOG(("Xinitscr() - called\n"));
+
+ PDC_set_args(argc, argv);
+ return initscr();
+}
+#endif
+
+int endwin(void)
+{
+ PDC_LOG(("endwin() - called\n"));
+
+ /* Allow temporary exit from curses using endwin() */
+
+ def_prog_mode();
+ PDC_scr_close();
+
+ SP->alive = FALSE;
+
+ return OK;
+}
+
+bool isendwin(void)
+{
+ PDC_LOG(("isendwin() - called\n"));
+
+ return SP ? !(SP->alive) : FALSE;
+}
+
+SCREEN *newterm(const char *type, FILE *outfd, FILE *infd)
+{
+ PDC_LOG(("newterm() - called\n"));
+
+ return initscr() ? SP : NULL;
+}
+
+SCREEN *set_term(SCREEN *new)
+{
+ PDC_LOG(("set_term() - called\n"));
+
+ /* We only support one screen */
+
+ return (new == SP) ? SP : NULL;
+}
+
+void delscreen(SCREEN *sp)
+{
+ PDC_LOG(("delscreen() - called\n"));
+
+ if (!SP || sp != SP)
+ return;
+
+ free(SP->c_ungch);
+ free(SP->c_buffer);
+ free(SP->atrtab);
+
+ PDC_slk_free(); /* free the soft label keys, if needed */
+
+ delwin(stdscr);
+ delwin(curscr);
+ delwin(SP->lastscr);
+ stdscr = (WINDOW *)NULL;
+ curscr = (WINDOW *)NULL;
+ SP->lastscr = (WINDOW *)NULL;
+
+ SP->alive = FALSE;
+
+ PDC_scr_free();
+
+ free(SP);
+ SP = (SCREEN *)NULL;
+}
+
+int resize_term(int nlines, int ncols)
+{
+ PDC_LOG(("resize_term() - called: nlines %d\n", nlines));
+
+ if (!stdscr || PDC_resize_screen(nlines, ncols) == ERR)
+ return ERR;
+
+ SP->resized = FALSE;
+
+ SP->lines = PDC_get_rows();
+ LINES = SP->lines - SP->linesrippedoff - SP->slklines;
+ SP->cols = COLS = PDC_get_columns();
+
+ if (SP->cursrow >= SP->lines)
+ SP->cursrow = SP->lines - 1;
+ if (SP->curscol >= SP->cols)
+ SP->curscol = SP->cols - 1;
+
+ if (wresize(curscr, SP->lines, SP->cols) == ERR ||
+ wresize(stdscr, LINES, COLS) == ERR ||
+ wresize(SP->lastscr, SP->lines, SP->cols) == ERR)
+ return ERR;
+
+ werase(SP->lastscr);
+ curscr->_clear = TRUE;
+
+ if (SP->slk_winptr)
+ {
+ if (wresize(SP->slk_winptr, SP->slklines, COLS) == ERR)
+ return ERR;
+
+ wmove(SP->slk_winptr, 0, 0);
+ wclrtobot(SP->slk_winptr);
+ PDC_slk_initialize();
+ slk_noutrefresh();
+ }
+
+ touchwin(stdscr);
+ wnoutrefresh(stdscr);
+
+ return OK;
+}
+
+bool is_termresized(void)
+{
+ PDC_LOG(("is_termresized() - called\n"));
+
+ return SP->resized;
+}
+
+const char *curses_version(void)
+{
+ return _curses_notice;
+}
+
+void PDC_get_version(PDC_VERSION *ver)
+{
+ if (!ver)
+ return;
+
+ ver->flags = 0
+#ifdef PDCDEBUG
+ | PDC_VFLAG_DEBUG
+#endif
+#ifdef PDC_WIDE
+ | PDC_VFLAG_WIDE
+#endif
+#ifdef PDC_FORCE_UTF8
+ | PDC_VFLAG_UTF8
+#endif
+#ifdef PDC_DLL_BUILD
+ | PDC_VFLAG_DLL
+#endif
+#ifdef PDC_RGB
+ | PDC_VFLAG_RGB
+#endif
+ ;
+
+ ver->build = PDC_BUILD;
+ ver->major = PDC_VER_MAJOR;
+ ver->minor = PDC_VER_MINOR;
+ ver->csize = sizeof(chtype);
+ ver->bsize = sizeof(bool);
+}
+
+int set_tabsize(int tabsize)
+{
+ PDC_LOG(("set_tabsize() - called: tabsize %d\n", tabsize));
+
+ if (tabsize < 1)
+ return ERR;
+
+ TABSIZE = tabsize;
+
+ return OK;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/inopts.c b/Utilities/cmpdcurses/pdcurses/inopts.c
new file mode 100644
index 0000000..e38bb53
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/inopts.c
@@ -0,0 +1,368 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+inopts
+------
+
+### Synopsis
+
+ int cbreak(void);
+ int nocbreak(void);
+ int echo(void);
+ int noecho(void);
+ int halfdelay(int tenths);
+ int intrflush(WINDOW *win, bool bf);
+ int keypad(WINDOW *win, bool bf);
+ int meta(WINDOW *win, bool bf);
+ int nl(void);
+ int nonl(void);
+ int nodelay(WINDOW *win, bool bf);
+ int notimeout(WINDOW *win, bool bf);
+ int raw(void);
+ int noraw(void);
+ void noqiflush(void);
+ void qiflush(void);
+ void timeout(int delay);
+ void wtimeout(WINDOW *win, int delay);
+ int typeahead(int fildes);
+
+ int crmode(void);
+ int nocrmode(void);
+
+ bool is_keypad(const WINDOW *win);
+
+### Description
+
+ cbreak() and nocbreak() toggle cbreak mode. In cbreak mode,
+ characters typed by the user are made available immediately, and
+ erase/kill character processing is not performed. In nocbreak mode,
+ typed characters are buffered until a newline or carriage return.
+ Interrupt and flow control characters are unaffected by this mode.
+ PDCurses always starts in cbreak mode.
+
+ echo() and noecho() control whether typed characters are echoed by
+ the input routine. Initially, input characters are echoed. Subsequent
+ calls to echo() and noecho() do not flush type-ahead.
+
+ halfdelay() is similar to cbreak(), but allows for a time limit to be
+ specified, in tenths of a second. This causes getch() to block for
+ that period before returning ERR if no key has been received. tenths
+ must be between 1 and 255.
+
+ keypad() controls whether getch() returns function/special keys as
+ single key codes (e.g., the left arrow key as KEY_LEFT). Per X/Open,
+ the default for keypad mode is OFF. You'll probably want it on. With
+ keypad mode off, if a special key is pressed, getch() does nothing or
+ returns ERR.
+
+ nodelay() controls whether wgetch() is a non-blocking call. If the
+ option is enabled, and no input is ready, wgetch() will return ERR.
+ If disabled, wgetch() will hang until input is ready.
+
+ nl() enables the translation of a carriage return into a newline on
+ input. nonl() disables this. Initially, the translation does occur.
+
+ raw() and noraw() toggle raw mode. Raw mode is similar to cbreak
+ mode, in that characters typed are immediately passed through to the
+ user program. The difference is that in raw mode, the INTR, QUIT,
+ SUSP, and STOP characters are passed through without being
+ interpreted, and without generating a signal.
+
+ In PDCurses, the meta() function sets raw mode on or off.
+
+ timeout() and wtimeout() set blocking or non-blocking reads for the
+ specified window. If the delay is negative, a blocking read is used;
+ if zero, then non-blocking reads are done -- if no input is waiting,
+ ERR is returned immediately. If the delay is positive, the read
+ blocks for the delay period; if the period expires, ERR is returned.
+ The delay is given in milliseconds, but this is rounded down to 50ms
+ (1/20th sec) intervals, with a minimum of one interval if a postive
+ delay is given; i.e., 1-99 will wait 50ms, 100-149 will wait 100ms,
+ etc.
+
+ intrflush(), notimeout(), noqiflush(), qiflush() and typeahead() do
+ nothing in PDCurses, but are included for compatibility with other
+ curses implementations.
+
+ crmode() and nocrmode() are archaic equivalents to cbreak() and
+ nocbreak(), respectively.
+
+ is_keypad() reports whether the specified window is in keypad mode.
+
+### Return Value
+
+ All functions except is_keypad() and the void functions return OK on
+ success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ cbreak Y Y Y
+ nocbreak Y Y Y
+ echo Y Y Y
+ noecho Y Y Y
+ halfdelay Y Y Y
+ intrflush Y Y Y
+ keypad Y Y Y
+ meta Y Y Y
+ nl Y Y Y
+ nonl Y Y Y
+ nodelay Y Y Y
+ notimeout Y Y Y
+ raw Y Y Y
+ noraw Y Y Y
+ noqiflush Y Y Y
+ qiflush Y Y Y
+ timeout Y Y Y
+ wtimeout Y Y Y
+ typeahead Y Y Y
+ crmode Y Y Y
+ nocrmode Y Y Y
+ is_keypad - Y Y
+
+**man-end****************************************************************/
+
+int cbreak(void)
+{
+ PDC_LOG(("cbreak() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->cbreak = TRUE;
+
+ return OK;
+}
+
+int nocbreak(void)
+{
+ PDC_LOG(("nocbreak() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->cbreak = FALSE;
+ SP->delaytenths = 0;
+
+ return OK;
+}
+
+int echo(void)
+{
+ PDC_LOG(("echo() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->echo = TRUE;
+
+ return OK;
+}
+
+int noecho(void)
+{
+ PDC_LOG(("noecho() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->echo = FALSE;
+
+ return OK;
+}
+
+int halfdelay(int tenths)
+{
+ PDC_LOG(("halfdelay() - called\n"));
+
+ if (!SP || tenths < 1 || tenths > 255)
+ return ERR;
+
+ SP->delaytenths = tenths;
+
+ return OK;
+}
+
+int intrflush(WINDOW *win, bool bf)
+{
+ PDC_LOG(("intrflush() - called\n"));
+
+ return OK;
+}
+
+int keypad(WINDOW *win, bool bf)
+{
+ PDC_LOG(("keypad() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_use_keypad = bf;
+
+ return OK;
+}
+
+int meta(WINDOW *win, bool bf)
+{
+ PDC_LOG(("meta() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->raw_inp = bf;
+
+ return OK;
+}
+
+int nl(void)
+{
+ PDC_LOG(("nl() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->autocr = TRUE;
+
+ return OK;
+}
+
+int nonl(void)
+{
+ PDC_LOG(("nonl() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->autocr = FALSE;
+
+ return OK;
+}
+
+int nodelay(WINDOW *win, bool flag)
+{
+ PDC_LOG(("nodelay() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_nodelay = flag;
+
+ return OK;
+}
+
+int notimeout(WINDOW *win, bool flag)
+{
+ PDC_LOG(("notimeout() - called\n"));
+
+ return OK;
+}
+
+int raw(void)
+{
+ PDC_LOG(("raw() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ PDC_set_keyboard_binary(TRUE);
+ SP->raw_inp = TRUE;
+
+ return OK;
+}
+
+int noraw(void)
+{
+ PDC_LOG(("noraw() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ PDC_set_keyboard_binary(FALSE);
+ SP->raw_inp = FALSE;
+
+ return OK;
+}
+
+void noqiflush(void)
+{
+ PDC_LOG(("noqiflush() - called\n"));
+}
+
+void qiflush(void)
+{
+ PDC_LOG(("qiflush() - called\n"));
+}
+
+int typeahead(int fildes)
+{
+ PDC_LOG(("typeahead() - called\n"));
+
+ return OK;
+}
+
+void wtimeout(WINDOW *win, int delay)
+{
+ PDC_LOG(("wtimeout() - called\n"));
+
+ if (!win)
+ return;
+
+ if (delay < 0)
+ {
+ /* This causes a blocking read on the window, so turn on delay
+ mode */
+
+ win->_nodelay = FALSE;
+ win->_delayms = 0;
+ }
+ else if (!delay)
+ {
+ /* This causes a non-blocking read on the window, so turn off
+ delay mode */
+
+ win->_nodelay = TRUE;
+ win->_delayms = 0;
+ }
+ else
+ {
+ /* This causes the read on the window to delay for the number of
+ milliseconds. Also forces the window into non-blocking read
+ mode */
+
+ /*win->_nodelay = TRUE;*/
+ win->_delayms = delay;
+ }
+}
+
+void timeout(int delay)
+{
+ PDC_LOG(("timeout() - called\n"));
+
+ wtimeout(stdscr, delay);
+}
+
+int crmode(void)
+{
+ PDC_LOG(("crmode() - called\n"));
+
+ return cbreak();
+}
+
+int nocrmode(void)
+{
+ PDC_LOG(("nocrmode() - called\n"));
+
+ return nocbreak();
+}
+
+bool is_keypad(const WINDOW *win)
+{
+ PDC_LOG(("is_keypad() - called\n"));
+
+ if (!win)
+ return FALSE;
+
+ return win->_use_keypad;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/insch.c b/Utilities/cmpdcurses/pdcurses/insch.c
new file mode 100644
index 0000000..da6cb2d
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/insch.c
@@ -0,0 +1,270 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+insch
+-----
+
+### Synopsis
+
+ int insch(chtype ch);
+ int winsch(WINDOW *win, chtype ch);
+ int mvinsch(int y, int x, chtype ch);
+ int mvwinsch(WINDOW *win, int y, int x, chtype ch);
+
+ int insrawch(chtype ch);
+ int winsrawch(WINDOW *win, chtype ch);
+ int mvinsrawch(int y, int x, chtype ch);
+ int mvwinsrawch(WINDOW *win, int y, int x, chtype ch);
+
+ int ins_wch(const cchar_t *wch);
+ int wins_wch(WINDOW *win, const cchar_t *wch);
+ int mvins_wch(int y, int x, const cchar_t *wch);
+ int mvwins_wch(WINDOW *win, int y, int x, const cchar_t *wch);
+
+### Description
+
+ The insch() functions insert a chtype into the window at the current
+ or specified cursor position. The cursor is NOT advanced. A newline
+ is equivalent to clrtoeol(); tabs are expanded; other control
+ characters are converted as with unctrl().
+
+ The ins_wch() functions are the wide-character equivalents, taking
+ cchar_t pointers rather than chtypes.
+
+ Video attributes can be combined with a character by ORing them into
+ the parameter. Text, including attributes, can be copied from one
+ place to another using inch() and insch().
+
+ insrawch() etc. are PDCurses-specific wrappers for insch() etc. that
+ disable the translation of control characters.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ insch Y Y Y
+ winsch Y Y Y
+ mvinsch Y Y Y
+ mvwinsch Y Y Y
+ ins_wch Y Y Y
+ wins_wch Y Y Y
+ mvins_wch Y Y Y
+ mvwins_wch Y Y Y
+ insrawch - - -
+ winsrawch - - -
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+int winsch(WINDOW *win, chtype ch)
+{
+ int x, y;
+ chtype attr;
+ bool xlat;
+
+ PDC_LOG(("winsch() - called: win=%p ch=%x (text=%c attr=0x%x)\n",
+ win, ch, ch & A_CHARTEXT, ch & A_ATTRIBUTES));
+
+ if (!win)
+ return ERR;
+
+ x = win->_curx;
+ y = win->_cury;
+
+ if (y > win->_maxy || x > win->_maxx || y < 0 || x < 0)
+ return ERR;
+
+ xlat = !SP->raw_out && !(ch & A_ALTCHARSET);
+ attr = ch & A_ATTRIBUTES;
+ ch &= A_CHARTEXT;
+
+ if (xlat && (ch < ' ' || ch == 0x7f))
+ {
+ int x2;
+
+ switch (ch)
+ {
+ case '\t':
+ for (x2 = ((x / TABSIZE) + 1) * TABSIZE; x < x2; x++)
+ {
+ if (winsch(win, attr | ' ') == ERR)
+ return ERR;
+ }
+ return OK;
+
+ case '\n':
+ wclrtoeol(win);
+ break;
+
+ case 0x7f:
+ if (winsch(win, attr | '?') == ERR)
+ return ERR;
+
+ return winsch(win, attr | '^');
+
+ default:
+ /* handle control chars */
+
+ if (winsch(win, attr | (ch + '@')) == ERR)
+ return ERR;
+
+ return winsch(win, attr | '^');
+ }
+ }
+ else
+ {
+ int maxx;
+ chtype *temp;
+
+ /* If the incoming character doesn't have its own attribute,
+ then use the current attributes for the window. If it has
+ attributes but not a color component, OR the attributes to
+ the current attributes for the window. If it has a color
+ component, use the attributes solely from the incoming
+ character. */
+
+ if (!(attr & A_COLOR))
+ attr |= win->_attrs;
+
+ /* wrs (4/10/93): Apply the same sort of logic for the window
+ background, in that it only takes precedence if other color
+ attributes are not there and that the background character
+ will only print if the printing character is blank. */
+
+ if (!(attr & A_COLOR))
+ attr |= win->_bkgd & A_ATTRIBUTES;
+ else
+ attr |= win->_bkgd & (A_ATTRIBUTES ^ A_COLOR);
+
+ if (ch == ' ')
+ ch = win->_bkgd & A_CHARTEXT;
+
+ /* Add the attribute back into the character. */
+
+ ch |= attr;
+
+ maxx = win->_maxx;
+ temp = &win->_y[y][x];
+
+ memmove(temp + 1, temp, (maxx - x - 1) * sizeof(chtype));
+
+ win->_lastch[y] = maxx - 1;
+
+ if ((win->_firstch[y] == _NO_CHANGE) || (win->_firstch[y] > x))
+ win->_firstch[y] = x;
+
+ *temp = ch;
+ }
+
+ PDC_sync(win);
+
+ return OK;
+}
+
+int insch(chtype ch)
+{
+ PDC_LOG(("insch() - called\n"));
+
+ return winsch(stdscr, ch);
+}
+
+int mvinsch(int y, int x, chtype ch)
+{
+ PDC_LOG(("mvinsch() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winsch(stdscr, ch);
+}
+
+int mvwinsch(WINDOW *win, int y, int x, chtype ch)
+{
+ PDC_LOG(("mvwinsch() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winsch(win, ch);
+}
+
+int winsrawch(WINDOW *win, chtype ch)
+{
+ PDC_LOG(("winsrawch() - called: win=%p ch=%x "
+ "(char=%c attr=0x%x)\n", win, ch,
+ ch & A_CHARTEXT, ch & A_ATTRIBUTES));
+
+ if ((ch & A_CHARTEXT) < ' ' || (ch & A_CHARTEXT) == 0x7f)
+ ch |= A_ALTCHARSET;
+
+ return winsch(win, ch);
+}
+
+int insrawch(chtype ch)
+{
+ PDC_LOG(("insrawch() - called\n"));
+
+ return winsrawch(stdscr, ch);
+}
+
+int mvinsrawch(int y, int x, chtype ch)
+{
+ PDC_LOG(("mvinsrawch() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winsrawch(stdscr, ch);
+}
+
+int mvwinsrawch(WINDOW *win, int y, int x, chtype ch)
+{
+ PDC_LOG(("mvwinsrawch() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winsrawch(win, ch);
+}
+
+#ifdef PDC_WIDE
+int wins_wch(WINDOW *win, const cchar_t *wch)
+{
+ PDC_LOG(("wins_wch() - called\n"));
+
+ return wch ? winsch(win, *wch) : ERR;
+}
+
+int ins_wch(const cchar_t *wch)
+{
+ PDC_LOG(("ins_wch() - called\n"));
+
+ return wins_wch(stdscr, wch);
+}
+
+int mvins_wch(int y, int x, const cchar_t *wch)
+{
+ PDC_LOG(("mvins_wch() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wins_wch(stdscr, wch);
+}
+
+int mvwins_wch(WINDOW *win, int y, int x, const cchar_t *wch)
+{
+ PDC_LOG(("mvwins_wch() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wins_wch(win, wch);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/insstr.c b/Utilities/cmpdcurses/pdcurses/insstr.c
new file mode 100644
index 0000000..2e2cfb7
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/insstr.c
@@ -0,0 +1,263 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+insstr
+------
+
+### Synopsis
+
+ int insstr(const char *str);
+ int insnstr(const char *str, int n);
+ int winsstr(WINDOW *win, const char *str);
+ int winsnstr(WINDOW *win, const char *str, int n);
+ int mvinsstr(int y, int x, const char *str);
+ int mvinsnstr(int y, int x, const char *str, int n);
+ int mvwinsstr(WINDOW *win, int y, int x, const char *str);
+ int mvwinsnstr(WINDOW *win, int y, int x, const char *str, int n);
+
+ int ins_wstr(const wchar_t *wstr);
+ int ins_nwstr(const wchar_t *wstr, int n);
+ int wins_wstr(WINDOW *win, const wchar_t *wstr);
+ int wins_nwstr(WINDOW *win, const wchar_t *wstr, int n);
+ int mvins_wstr(int y, int x, const wchar_t *wstr);
+ int mvins_nwstr(int y, int x, const wchar_t *wstr, int n);
+ int mvwins_wstr(WINDOW *win, int y, int x, const wchar_t *wstr);
+ int mvwins_nwstr(WINDOW *win, int y, int x, const wchar_t *wstr, int n);
+
+### Description
+
+ The insstr() functions insert a character string into a window at the
+ current cursor position, by repeatedly calling winsch(). When
+ PDCurses is built with wide-character support enabled, the narrow-
+ character functions treat the string as a multibyte string in the
+ current locale, and convert it first. All characters to the right of
+ the cursor are moved to the right, with the possibility of the
+ rightmost characters on the line being lost. The cursor position
+ does not change (after moving to y, x, if specified). The routines
+ with n as the last argument insert at most n characters; if n is
+ negative, then the entire string is inserted.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ insstr Y Y Y
+ winsstr Y Y Y
+ mvinsstr Y Y Y
+ mvwinsstr Y Y Y
+ insnstr Y Y Y
+ winsnstr Y Y Y
+ mvinsnstr Y Y Y
+ mvwinsnstr Y Y Y
+ ins_wstr Y Y Y
+ wins_wstr Y Y Y
+ mvins_wstr Y Y Y
+ mvwins_wstr Y Y Y
+ ins_nwstr Y Y Y
+ wins_nwstr Y Y Y
+ mvins_nwstr Y Y Y
+ mvwins_nwstr Y Y Y
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+int winsnstr(WINDOW *win, const char *str, int n)
+{
+#ifdef PDC_WIDE
+ wchar_t wstr[513], *p;
+ int i;
+#endif
+ int len;
+
+ PDC_LOG(("winsnstr() - called: string=\"%s\" n %d \n", str, n));
+
+ if (!win || !str)
+ return ERR;
+
+ len = strlen(str);
+
+ if (n < 0 || n > len)
+ n = len;
+
+#ifdef PDC_WIDE
+ if (n > 512)
+ n = 512;
+
+ p = wstr;
+ i = 0;
+
+ while (str[i] && i < n)
+ {
+ int retval = PDC_mbtowc(p, str + i, n - i);
+
+ if (retval <= 0)
+ break;
+ p++;
+ i += retval;
+ }
+
+ while (p > wstr)
+ if (winsch(win, *--p) == ERR)
+#else
+ while (n)
+ if (winsch(win, (unsigned char)(str[--n])) == ERR)
+#endif
+ return ERR;
+
+ return OK;
+}
+
+int insstr(const char *str)
+{
+ PDC_LOG(("insstr() - called: string=\"%s\"\n", str));
+
+ return winsnstr(stdscr, str, -1);
+}
+
+int winsstr(WINDOW *win, const char *str)
+{
+ PDC_LOG(("winsstr() - called: string=\"%s\"\n", str));
+
+ return winsnstr(win, str, -1);
+}
+
+int mvinsstr(int y, int x, const char *str)
+{
+ PDC_LOG(("mvinsstr() - called: y %d x %d string=\"%s\"\n", y, x, str));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winsnstr(stdscr, str, -1);
+}
+
+int mvwinsstr(WINDOW *win, int y, int x, const char *str)
+{
+ PDC_LOG(("mvwinsstr() - called: string=\"%s\"\n", str));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winsnstr(win, str, -1);
+}
+
+int insnstr(const char *str, int n)
+{
+ PDC_LOG(("insnstr() - called: string=\"%s\" n %d \n", str, n));
+
+ return winsnstr(stdscr, str, n);
+}
+
+int mvinsnstr(int y, int x, const char *str, int n)
+{
+ PDC_LOG(("mvinsnstr() - called: y %d x %d string=\"%s\" n %d \n",
+ y, x, str, n));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winsnstr(stdscr, str, n);
+}
+
+int mvwinsnstr(WINDOW *win, int y, int x, const char *str, int n)
+{
+ PDC_LOG(("mvwinsnstr() - called: y %d x %d string=\"%s\" n %d \n",
+ y, x, str, n));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winsnstr(win, str, n);
+}
+
+#ifdef PDC_WIDE
+int wins_nwstr(WINDOW *win, const wchar_t *wstr, int n)
+{
+ const wchar_t *p;
+ int len;
+
+ PDC_LOG(("wins_nwstr() - called\n"));
+
+ if (!win || !wstr)
+ return ERR;
+
+ for (len = 0, p = wstr; *p; p++)
+ len++;
+
+ if (n < 0 || n > len)
+ n = len;
+
+ while (n)
+ if (winsch(win, wstr[--n]) == ERR)
+ return ERR;
+
+ return OK;
+}
+
+int ins_wstr(const wchar_t *wstr)
+{
+ PDC_LOG(("ins_wstr() - called\n"));
+
+ return wins_nwstr(stdscr, wstr, -1);
+}
+
+int wins_wstr(WINDOW *win, const wchar_t *wstr)
+{
+ PDC_LOG(("wins_wstr() - called\n"));
+
+ return wins_nwstr(win, wstr, -1);
+}
+
+int mvins_wstr(int y, int x, const wchar_t *wstr)
+{
+ PDC_LOG(("mvins_wstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wins_nwstr(stdscr, wstr, -1);
+}
+
+int mvwins_wstr(WINDOW *win, int y, int x, const wchar_t *wstr)
+{
+ PDC_LOG(("mvwinsstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wins_nwstr(win, wstr, -1);
+}
+
+int ins_nwstr(const wchar_t *wstr, int n)
+{
+ PDC_LOG(("ins_nwstr() - called\n"));
+
+ return wins_nwstr(stdscr, wstr, n);
+}
+
+int mvins_nwstr(int y, int x, const wchar_t *wstr, int n)
+{
+ PDC_LOG(("mvinsnstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return wins_nwstr(stdscr, wstr, n);
+}
+
+int mvwins_nwstr(WINDOW *win, int y, int x, const wchar_t *wstr, int n)
+{
+ PDC_LOG(("mvwinsnstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return wins_nwstr(win, wstr, n);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/instr.c b/Utilities/cmpdcurses/pdcurses/instr.c
new file mode 100644
index 0000000..bd8dbf9
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/instr.c
@@ -0,0 +1,245 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+instr
+-----
+
+### Synopsis
+
+ int instr(char *str);
+ int innstr(char *str, int n);
+ int winstr(WINDOW *win, char *str);
+ int winnstr(WINDOW *win, char *str, int n);
+ int mvinstr(int y, int x, char *str);
+ int mvinnstr(int y, int x, char *str, int n);
+ int mvwinstr(WINDOW *win, int y, int x, char *str);
+ int mvwinnstr(WINDOW *win, int y, int x, char *str, int n);
+
+ int inwstr(wchar_t *wstr);
+ int innwstr(wchar_t *wstr, int n);
+ int winwstr(WINDOW *win, wchar_t *wstr);
+ int winnwstr(WINDOW *win, wchar_t *wstr, int n);
+ int mvinwstr(int y, int x, wchar_t *wstr);
+ int mvinnwstr(int y, int x, wchar_t *wstr, int n);
+ int mvwinwstr(WINDOW *win, int y, int x, wchar_t *wstr);
+ int mvwinnwstr(WINDOW *win, int y, int x, wchar_t *wstr, int n);
+
+### Description
+
+ These functions take characters (or wide characters) from the current
+ or specified position in the window, and return them as a string in
+ str (or wstr). Attributes are ignored. The functions with n as the
+ last argument return a string at most n characters long.
+
+### Return Value
+
+ Upon successful completion, innstr(), mvinnstr(), mvwinnstr() and
+ winnstr() return the number of characters actually read into the
+ string; instr(), mvinstr(), mvwinstr() and winstr() return OK.
+ Otherwise, all these functions return ERR.
+
+### Portability
+ X/Open ncurses NetBSD
+ instr Y Y Y
+ winstr Y Y Y
+ mvinstr Y Y Y
+ mvwinstr Y Y Y
+ innstr Y Y Y
+ winnstr Y Y Y
+ mvinnstr Y Y Y
+ mvwinnstr Y Y Y
+ inwstr Y Y Y
+ winwstr Y Y Y
+ mvinwstr Y Y Y
+ mvwinwstr Y Y Y
+ innwstr Y Y Y
+ winnwstr Y Y Y
+ mvinnwstr Y Y Y
+ mvwinnwstr Y Y Y
+
+**man-end****************************************************************/
+
+int winnstr(WINDOW *win, char *str, int n)
+{
+#ifdef PDC_WIDE
+ wchar_t wstr[513];
+
+ if (n < 0 || n > 512)
+ n = 512;
+
+ if (winnwstr(win, wstr, n) == ERR)
+ return ERR;
+
+ return PDC_wcstombs(str, wstr, n);
+#else
+ chtype *src;
+ int i;
+
+ PDC_LOG(("winnstr() - called: n %d \n", n));
+
+ if (!win || !str)
+ return ERR;
+
+ if (n < 0 || (win->_curx + n) > win->_maxx)
+ n = win->_maxx - win->_curx;
+
+ src = win->_y[win->_cury] + win->_curx;
+
+ for (i = 0; i < n; i++)
+ str[i] = src[i] & A_CHARTEXT;
+
+ str[i] = '\0';
+
+ return i;
+#endif
+}
+
+int instr(char *str)
+{
+ PDC_LOG(("instr() - called: string=\"%s\"\n", str));
+
+ return (ERR == winnstr(stdscr, str, stdscr->_maxx)) ? ERR : OK;
+}
+
+int winstr(WINDOW *win, char *str)
+{
+ PDC_LOG(("winstr() - called: \n"));
+
+ return (ERR == winnstr(win, str, win->_maxx)) ? ERR : OK;
+}
+
+int mvinstr(int y, int x, char *str)
+{
+ PDC_LOG(("mvinstr() - called: y %d x %d \n", y, x));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return (ERR == winnstr(stdscr, str, stdscr->_maxx)) ? ERR : OK;
+}
+
+int mvwinstr(WINDOW *win, int y, int x, char *str)
+{
+ PDC_LOG(("mvwinstr() - called: y %d x %d \n", y, x));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return (ERR == winnstr(win, str, win->_maxx)) ? ERR : OK;
+}
+
+int innstr(char *str, int n)
+{
+ PDC_LOG(("innstr() - called: n %d \n", n));
+
+ return winnstr(stdscr, str, n);
+}
+
+int mvinnstr(int y, int x, char *str, int n)
+{
+ PDC_LOG(("mvinnstr() - called: y %d x %d n %d \n", y, x, n));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winnstr(stdscr, str, n);
+}
+
+int mvwinnstr(WINDOW *win, int y, int x, char *str, int n)
+{
+ PDC_LOG(("mvwinnstr() - called: y %d x %d n %d \n", y, x, n));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winnstr(win, str, n);
+}
+
+#ifdef PDC_WIDE
+int winnwstr(WINDOW *win, wchar_t *wstr, int n)
+{
+ chtype *src;
+ int i;
+
+ PDC_LOG(("winnstr() - called: n %d \n", n));
+
+ if (!win || !wstr)
+ return ERR;
+
+ if (n < 0 || (win->_curx + n) > win->_maxx)
+ n = win->_maxx - win->_curx;
+
+ src = win->_y[win->_cury] + win->_curx;
+
+ for (i = 0; i < n; i++)
+ wstr[i] = src[i] & A_CHARTEXT;
+
+ wstr[i] = L'\0';
+
+ return i;
+}
+
+int inwstr(wchar_t *wstr)
+{
+ PDC_LOG(("inwstr() - called\n"));
+
+ return (ERR == winnwstr(stdscr, wstr, stdscr->_maxx)) ? ERR : OK;
+}
+
+int winwstr(WINDOW *win, wchar_t *wstr)
+{
+ PDC_LOG(("winwstr() - called\n"));
+
+ return (ERR == winnwstr(win, wstr, win->_maxx)) ? ERR : OK;
+}
+
+int mvinwstr(int y, int x, wchar_t *wstr)
+{
+ PDC_LOG(("mvinwstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return (ERR == winnwstr(stdscr, wstr, stdscr->_maxx)) ? ERR : OK;
+}
+
+int mvwinwstr(WINDOW *win, int y, int x, wchar_t *wstr)
+{
+ PDC_LOG(("mvwinstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return (ERR == winnwstr(win, wstr, win->_maxx)) ? ERR : OK;
+}
+
+int innwstr(wchar_t *wstr, int n)
+{
+ PDC_LOG(("innwstr() - called\n"));
+
+ return winnwstr(stdscr, wstr, n);
+}
+
+int mvinnwstr(int y, int x, wchar_t *wstr, int n)
+{
+ PDC_LOG(("mvinnstr() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ return winnwstr(stdscr, wstr, n);
+}
+
+int mvwinnwstr(WINDOW *win, int y, int x, wchar_t *wstr, int n)
+{
+ PDC_LOG(("mvwinnwstr() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ return winnwstr(win, wstr, n);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/kernel.c b/Utilities/cmpdcurses/pdcurses/kernel.c
new file mode 100644
index 0000000..81915e7
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/kernel.c
@@ -0,0 +1,297 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+kernel
+------
+
+### Synopsis
+
+ int def_prog_mode(void);
+ int def_shell_mode(void);
+ int reset_prog_mode(void);
+ int reset_shell_mode(void);
+ int resetty(void);
+ int savetty(void);
+ int ripoffline(int line, int (*init)(WINDOW *, int));
+ int curs_set(int visibility);
+ int napms(int ms);
+
+ int draino(int ms);
+ int resetterm(void);
+ int fixterm(void);
+ int saveterm(void);
+
+### Description
+
+ def_prog_mode() and def_shell_mode() save the current terminal modes
+ as the "program" (in curses) or "shell" (not in curses) state for use
+ by the reset_prog_mode() and reset_shell_mode() functions. This is
+ done automatically by initscr().
+
+ reset_prog_mode() and reset_shell_mode() restore the terminal to
+ "program" (in curses) or "shell" (not in curses) state. These are
+ done automatically by endwin() and doupdate() after an endwin(), so
+ they would normally not be called before these functions.
+
+ savetty() and resetty() save and restore the state of the terminal
+ modes. savetty() saves the current state in a buffer, and resetty()
+ restores the state to what it was at the last call to savetty().
+
+ curs_set() alters the appearance of the cursor. A visibility of 0
+ makes it disappear; 1 makes it appear "normal" (usually an underline)
+ and 2 makes it "highly visible" (usually a block).
+
+ ripoffline() reduces the size of stdscr by one line. If the "line"
+ parameter is positive, the line is removed from the top of the
+ screen; if negative, from the bottom. Up to 5 lines can be ripped off
+ stdscr by calling ripoffline() repeatedly. The function argument,
+ init, is called from within initscr() or newterm(), so ripoffline()
+ must be called before either of these functions. The init function
+ receives a pointer to a one-line WINDOW, and the width of the window.
+ Calling ripoffline() with a NULL init function pointer is an error.
+
+ napms() suspends the program for the specified number of
+ milliseconds. draino() is an archaic equivalent. Note that since
+ napms() attempts to give up a time slice and yield control back to
+ the OS, all times are approximate. (In DOS, the delay is actually
+ rounded down to 50ms (1/20th sec) intervals, with a minimum of one
+ interval; i.e., 1-99 will wait 50ms, 100-149 will wait 100ms, etc.)
+ 0 returns immediately.
+
+ resetterm(), fixterm() and saveterm() are archaic equivalents for
+ reset_shell_mode(), reset_prog_mode() and def_prog_mode(),
+ respectively.
+
+### Return Value
+
+ All functions return OK on success and ERR on error, except
+ curs_set(), which returns the previous visibility.
+
+### Portability
+ X/Open ncurses NetBSD
+ def_prog_mode Y Y Y
+ def_shell_mode Y Y Y
+ reset_prog_mode Y Y Y
+ reset_shell_mode Y Y Y
+ resetty Y Y Y
+ savetty Y Y Y
+ ripoffline Y Y Y
+ curs_set Y Y Y
+ napms Y Y Y
+ fixterm - Y -
+ resetterm - Y -
+ saveterm - Y -
+ draino - - -
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+RIPPEDOFFLINE linesripped[5];
+char linesrippedoff = 0;
+
+static struct cttyset
+{
+ bool been_set;
+ SCREEN saved;
+} ctty[3];
+
+enum { PDC_SH_TTY, PDC_PR_TTY, PDC_SAVE_TTY };
+
+static void _save_mode(int i)
+{
+ ctty[i].been_set = TRUE;
+
+ memcpy(&(ctty[i].saved), SP, sizeof(SCREEN));
+
+ PDC_save_screen_mode(i);
+}
+
+static int _restore_mode(int i)
+{
+ if (ctty[i].been_set == TRUE)
+ {
+ memcpy(SP, &(ctty[i].saved), sizeof(SCREEN));
+
+ if (ctty[i].saved.raw_out)
+ raw();
+
+ PDC_restore_screen_mode(i);
+
+ if ((LINES != ctty[i].saved.lines) ||
+ (COLS != ctty[i].saved.cols))
+ resize_term(ctty[i].saved.lines, ctty[i].saved.cols);
+
+ PDC_curs_set(ctty[i].saved.visibility);
+
+ PDC_gotoyx(ctty[i].saved.cursrow, ctty[i].saved.curscol);
+ }
+
+ return ctty[i].been_set ? OK : ERR;
+}
+
+int def_prog_mode(void)
+{
+ PDC_LOG(("def_prog_mode() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ _save_mode(PDC_PR_TTY);
+
+ return OK;
+}
+
+int def_shell_mode(void)
+{
+ PDC_LOG(("def_shell_mode() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ _save_mode(PDC_SH_TTY);
+
+ return OK;
+}
+
+int reset_prog_mode(void)
+{
+ PDC_LOG(("reset_prog_mode() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ _restore_mode(PDC_PR_TTY);
+ PDC_reset_prog_mode();
+
+ return OK;
+}
+
+int reset_shell_mode(void)
+{
+ PDC_LOG(("reset_shell_mode() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ _restore_mode(PDC_SH_TTY);
+ PDC_reset_shell_mode();
+
+ return OK;
+}
+
+int resetty(void)
+{
+ PDC_LOG(("resetty() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ return _restore_mode(PDC_SAVE_TTY);
+}
+
+int savetty(void)
+{
+ PDC_LOG(("savetty() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ _save_mode(PDC_SAVE_TTY);
+
+ return OK;
+}
+
+int curs_set(int visibility)
+{
+ int ret_vis;
+
+ PDC_LOG(("curs_set() - called: visibility=%d\n", visibility));
+
+ if (!SP || visibility < 0 || visibility > 2)
+ return ERR;
+
+ ret_vis = PDC_curs_set(visibility);
+
+ /* If the cursor is changing from invisible to visible, update
+ its position */
+
+ if (visibility && !ret_vis)
+ PDC_gotoyx(SP->cursrow, SP->curscol);
+
+ return ret_vis;
+}
+
+int napms(int ms)
+{
+ PDC_LOG(("napms() - called: ms=%d\n", ms));
+
+ if (!SP)
+ return ERR;
+
+ if (SP->dirty)
+ {
+ int curs_state = SP->visibility;
+ bool leave_state = is_leaveok(curscr);
+
+ SP->dirty = FALSE;
+
+ leaveok(curscr, TRUE);
+
+ wrefresh(curscr);
+
+ leaveok(curscr, leave_state);
+ curs_set(curs_state);
+ }
+
+ if (ms)
+ PDC_napms(ms);
+
+ return OK;
+}
+
+int ripoffline(int line, int (*init)(WINDOW *, int))
+{
+ PDC_LOG(("ripoffline() - called: line=%d\n", line));
+
+ if (linesrippedoff < 5 && line && init)
+ {
+ linesripped[(int)linesrippedoff].line = line;
+ linesripped[(int)linesrippedoff++].init = init;
+
+ return OK;
+ }
+
+ return ERR;
+}
+
+int draino(int ms)
+{
+ PDC_LOG(("draino() - called\n"));
+
+ return napms(ms);
+}
+
+int resetterm(void)
+{
+ PDC_LOG(("resetterm() - called\n"));
+
+ return reset_shell_mode();
+}
+
+int fixterm(void)
+{
+ PDC_LOG(("fixterm() - called\n"));
+
+ return reset_prog_mode();
+}
+
+int saveterm(void)
+{
+ PDC_LOG(("saveterm() - called\n"));
+
+ return def_prog_mode();
+}
diff --git a/Utilities/cmpdcurses/pdcurses/keyname.c b/Utilities/cmpdcurses/pdcurses/keyname.c
new file mode 100644
index 0000000..44e8dd4
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/keyname.c
@@ -0,0 +1,129 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+keyname
+-------
+
+### Synopsis
+
+ char *keyname(int key);
+
+ char *key_name(wchar_t c);
+
+ bool has_key(int key);
+
+### Description
+
+ keyname() returns a string corresponding to the argument key. key may
+ be any key returned by wgetch().
+
+ key_name() is the wide-character version. It takes a wchar_t
+ parameter, but still returns a char *.
+
+ has_key() returns TRUE for recognized keys, FALSE otherwise. This
+ function is an ncurses extension.
+
+### Portability
+ X/Open ncurses NetBSD
+ keyname Y Y Y
+ key_name Y Y Y
+ has_key - Y Y
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+static const char *names[] =
+{
+ "KEY_BREAK", "KEY_DOWN", "KEY_UP", "KEY_LEFT", "KEY_RIGHT",
+ "KEY_HOME", "KEY_BACKSPACE", "KEY_F0", "KEY_F(1)", "KEY_F(2)",
+ "KEY_F(3)", "KEY_F(4)", "KEY_F(5)", "KEY_F(6)", "KEY_F(7)",
+ "KEY_F(8)", "KEY_F(9)", "KEY_F(10)", "KEY_F(11)", "KEY_F(12)",
+ "KEY_F(13)", "KEY_F(14)", "KEY_F(15)", "KEY_F(16)", "KEY_F(17)",
+ "KEY_F(18)", "KEY_F(19)", "KEY_F(20)", "KEY_F(21)", "KEY_F(22)",
+ "KEY_F(23)", "KEY_F(24)", "KEY_F(25)", "KEY_F(26)", "KEY_F(27)",
+ "KEY_F(28)", "KEY_F(29)", "KEY_F(30)", "KEY_F(31)", "KEY_F(32)",
+ "KEY_F(33)", "KEY_F(34)", "KEY_F(35)", "KEY_F(36)", "KEY_F(37)",
+ "KEY_F(38)", "KEY_F(39)", "KEY_F(40)", "KEY_F(41)", "KEY_F(42)",
+ "KEY_F(43)", "KEY_F(44)", "KEY_F(45)", "KEY_F(46)", "KEY_F(47)",
+ "KEY_F(48)", "KEY_F(49)", "KEY_F(50)", "KEY_F(51)", "KEY_F(52)",
+ "KEY_F(53)", "KEY_F(54)", "KEY_F(55)", "KEY_F(56)", "KEY_F(57)",
+ "KEY_F(58)", "KEY_F(59)", "KEY_F(60)", "KEY_F(61)", "KEY_F(62)",
+ "KEY_F(63)", "KEY_DL", "KEY_IL", "KEY_DC", "KEY_IC", "KEY_EIC",
+ "KEY_CLEAR", "KEY_EOS", "KEY_EOL", "KEY_SF", "KEY_SR", "KEY_NPAGE",
+ "KEY_PPAGE", "KEY_STAB", "KEY_CTAB", "KEY_CATAB", "KEY_ENTER",
+ "KEY_SRESET", "KEY_RESET", "KEY_PRINT", "KEY_LL", "KEY_ABORT",
+ "KEY_SHELP", "KEY_LHELP", "KEY_BTAB", "KEY_BEG", "KEY_CANCEL",
+ "KEY_CLOSE", "KEY_COMMAND", "KEY_COPY", "KEY_CREATE", "KEY_END",
+ "KEY_EXIT", "KEY_FIND", "KEY_HELP", "KEY_MARK", "KEY_MESSAGE",
+ "KEY_MOVE", "KEY_NEXT", "KEY_OPEN", "KEY_OPTIONS", "KEY_PREVIOUS",
+ "KEY_REDO", "KEY_REFERENCE", "KEY_REFRESH", "KEY_REPLACE",
+ "KEY_RESTART", "KEY_RESUME", "KEY_SAVE", "KEY_SBEG", "KEY_SCANCEL",
+ "KEY_SCOMMAND", "KEY_SCOPY", "KEY_SCREATE", "KEY_SDC", "KEY_SDL",
+ "KEY_SELECT", "KEY_SEND", "KEY_SEOL", "KEY_SEXIT", "KEY_SFIND",
+ "KEY_SHOME", "KEY_SIC", "UNKNOWN KEY", "KEY_SLEFT", "KEY_SMESSAGE",
+ "KEY_SMOVE", "KEY_SNEXT", "KEY_SOPTIONS", "KEY_SPREVIOUS",
+ "KEY_SPRINT", "KEY_SREDO", "KEY_SREPLACE", "KEY_SRIGHT",
+ "KEY_SRSUME", "KEY_SSAVE", "KEY_SSUSPEND", "KEY_SUNDO",
+ "KEY_SUSPEND", "KEY_UNDO", "ALT_0", "ALT_1", "ALT_2", "ALT_3",
+ "ALT_4", "ALT_5", "ALT_6", "ALT_7", "ALT_8", "ALT_9", "ALT_A",
+ "ALT_B", "ALT_C", "ALT_D", "ALT_E", "ALT_F", "ALT_G", "ALT_H",
+ "ALT_I", "ALT_J", "ALT_K", "ALT_L", "ALT_M", "ALT_N", "ALT_O",
+ "ALT_P", "ALT_Q", "ALT_R", "ALT_S", "ALT_T", "ALT_U", "ALT_V",
+ "ALT_W", "ALT_X", "ALT_Y", "ALT_Z", "CTL_LEFT", "CTL_RIGHT",
+ "CTL_PGUP", "CTL_PGDN", "CTL_HOME", "CTL_END", "KEY_A1", "KEY_A2",
+ "KEY_A3", "KEY_B1", "KEY_B2", "KEY_B3", "KEY_C1", "KEY_C2",
+ "KEY_C3", "PADSLASH", "PADENTER", "CTL_PADENTER", "ALT_PADENTER",
+ "PADSTOP", "PADSTAR", "PADMINUS", "PADPLUS", "CTL_PADSTOP",
+ "CTL_PADCENTER", "CTL_PADPLUS", "CTL_PADMINUS", "CTL_PADSLASH",
+ "CTL_PADSTAR", "ALT_PADPLUS", "ALT_PADMINUS", "ALT_PADSLASH",
+ "ALT_PADSTAR", "ALT_PADSTOP", "CTL_INS", "ALT_DEL", "ALT_INS",
+ "CTL_UP", "CTL_DOWN", "CTL_TAB", "ALT_TAB", "ALT_MINUS",
+ "ALT_EQUAL", "ALT_HOME", "ALT_PGUP", "ALT_PGDN", "ALT_END",
+ "ALT_UP", "ALT_DOWN", "ALT_RIGHT", "ALT_LEFT", "ALT_ENTER",
+ "ALT_ESC", "ALT_BQUOTE", "ALT_LBRACKET", "ALT_RBRACKET",
+ "ALT_SEMICOLON", "ALT_FQUOTE", "ALT_COMMA", "ALT_STOP",
+ "ALT_FSLASH", "ALT_BKSP", "CTL_BKSP", "PAD0", "CTL_PAD0",
+ "CTL_PAD1", "CTL_PAD2", "CTL_PAD3", "CTL_PAD4", "CTL_PAD5",
+ "CTL_PAD6", "CTL_PAD7","CTL_PAD8", "CTL_PAD9", "ALT_PAD0",
+ "ALT_PAD1", "ALT_PAD2", "ALT_PAD3", "ALT_PAD4", "ALT_PAD5",
+ "ALT_PAD6", "ALT_PAD7", "ALT_PAD8", "ALT_PAD9", "CTL_DEL",
+ "ALT_BSLASH", "CTL_ENTER", "SHF_PADENTER", "SHF_PADSLASH",
+ "SHF_PADSTAR", "SHF_PADPLUS", "SHF_PADMINUS", "SHF_UP", "SHF_DOWN",
+ "SHF_IC", "SHF_DC", "KEY_MOUSE", "KEY_SHIFT_L", "KEY_SHIFT_R",
+ "KEY_CONTROL_L", "KEY_CONTROL_R", "KEY_ALT_L", "KEY_ALT_R",
+ "KEY_RESIZE", "KEY_SUP", "KEY_SDOWN"
+};
+
+char *keyname(int key)
+{
+ static char _keyname[14];
+
+ /* Key names must be in exactly the same order as in curses.h */
+
+ PDC_LOG(("keyname() - called: key %d\n", key));
+
+ strcpy(_keyname, ((key >= 0) && (key < 0x80)) ? unctrl((chtype)key) :
+ has_key(key) ? names[key - KEY_MIN] : "UNKNOWN KEY");
+
+ return _keyname;
+}
+
+bool has_key(int key)
+{
+ PDC_LOG(("has_key() - called: key %d\n", key));
+
+ return (key >= KEY_MIN && key <= KEY_MAX);
+}
+
+#ifdef PDC_WIDE
+char *key_name(wchar_t c)
+{
+ PDC_LOG(("key_name() - called\n"));
+
+ return keyname((int)c);
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/mouse.c b/Utilities/cmpdcurses/pdcurses/mouse.c
new file mode 100644
index 0000000..d2e8619
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/mouse.c
@@ -0,0 +1,421 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+mouse
+-----
+
+### Synopsis
+
+ int mouse_set(mmask_t mbe);
+ int mouse_on(mmask_t mbe);
+ int mouse_off(mmask_t mbe);
+ int request_mouse_pos(void);
+ void wmouse_position(WINDOW *win, int *y, int *x);
+ mmask_t getmouse(void);
+
+ int mouseinterval(int wait);
+ bool wenclose(const WINDOW *win, int y, int x);
+ bool wmouse_trafo(const WINDOW *win, int *y, int *x, bool to_screen);
+ bool mouse_trafo(int *y, int *x, bool to_screen);
+ mmask_t mousemask(mmask_t mask, mmask_t *oldmask);
+ int nc_getmouse(MEVENT *event);
+ int ungetmouse(MEVENT *event);
+ bool has_mouse(void);
+
+### Description
+
+ As of PDCurses 3.0, there are two separate mouse interfaces: the
+ classic interface, which is based on the undocumented Sys V mouse
+ functions; and an ncurses-compatible interface. Both are active at
+ all times, and you can mix and match functions from each, though it's
+ not recommended. The ncurses interface is essentially an emulation
+ layer built on top of the classic interface; it's here to allow
+ easier porting of ncurses apps.
+
+ The classic interface: mouse_set(), mouse_on(), mouse_off(),
+ request_mouse_pos(), wmouse_position(), and getmouse(). An
+ application using this interface would start by calling mouse_set()
+ or mouse_on() with a non-zero value, often ALL_MOUSE_EVENTS. Then it
+ would check for a KEY_MOUSE return from getch(). If found, it would
+ call request_mouse_pos() to get the current mouse status.
+
+ mouse_set(), mouse_on() and mouse_off() are analagous to attrset(),
+ attron() and attroff(). These functions set the mouse button events
+ to trap. The button masks used in these functions are defined in
+ curses.h and can be or'ed together. They are the group of masks
+ starting with BUTTON1_RELEASED.
+
+ request_mouse_pos() requests curses to fill in the Mouse_status
+ structure with the current state of the mouse.
+
+ wmouse_position() determines if the current mouse position is within
+ the window passed as an argument. If the mouse is outside the current
+ window, -1 is returned in the y and x arguments; otherwise the y and
+ x coordinates of the mouse (relative to the top left corner of the
+ window) are returned in y and x.
+
+ getmouse() returns the current status of the trapped mouse buttons as
+ set by mouse_set() or mouse_on().
+
+ The ncurses interface: mouseinterval(), wenclose(), wmouse_trafo(),
+ mouse_trafo(), mousemask(), nc_getmouse(), ungetmouse() and
+ has_mouse(). A typical application using this interface would start
+ by calling mousemask() with a non-zero value, often ALL_MOUSE_EVENTS.
+ Then it would check for a KEY_MOUSE return from getch(). If found, it
+ would call nc_getmouse() to get the current mouse status.
+
+ mouseinterval() sets the timeout for a mouse click. On all current
+ platforms, PDCurses receives mouse button press and release events,
+ but must synthesize click events. It does this by checking whether a
+ release event is queued up after a press event. If it gets a press
+ event, and there are no more events waiting, it will wait for the
+ timeout interval, then check again for a release. A press followed by
+ a release is reported as BUTTON_CLICKED; otherwise it's passed
+ through as BUTTON_PRESSED. The default timeout is 150ms; valid values
+ are 0 (no clicks reported) through 1000ms. In x11, the timeout can
+ also be set via the clickPeriod resource. The return value from
+ mouseinterval() is the old timeout. To check the old value without
+ setting a new one, call it with a parameter of -1. Note that although
+ there's no classic equivalent for this function (apart from the
+ clickPeriod resource), the value set applies in both interfaces.
+
+ wenclose() reports whether the given screen-relative y, x coordinates
+ fall within the given window.
+
+ wmouse_trafo() converts between screen-relative and window-relative
+ coordinates. A to_screen parameter of TRUE means to convert from
+ window to screen; otherwise the reverse. The function returns FALSE
+ if the coordinates aren't within the window, or if any of the
+ parameters are NULL. The coordinates have been converted when the
+ function returns TRUE.
+
+ mouse_trafo() is the stdscr version of wmouse_trafo().
+
+ mousemask() is nearly equivalent to mouse_set(), but instead of
+ OK/ERR, it returns the value of the mask after setting it. (This
+ isn't necessarily the same value passed in, since the mask could be
+ altered on some platforms.) And if the second parameter is a non-null
+ pointer, mousemask() stores the previous mask value there. Also,
+ since the ncurses interface doesn't work with PDCurses' BUTTON_MOVED
+ events, mousemask() filters them out.
+
+ nc_getmouse() returns the current mouse status in an MEVENT struct.
+ This is equivalent to ncurses' getmouse(), renamed to avoid conflict
+ with PDCurses' getmouse(). But if you define PDC_NCMOUSE before
+ including curses.h, it defines getmouse() to nc_getmouse(), along
+ with a few other redefintions needed for compatibility with ncurses
+ code. nc_getmouse() calls request_mouse_pos(), which (not getmouse())
+ is the classic equivalent.
+
+ ungetmouse() is the mouse equivalent of ungetch(). However, PDCurses
+ doesn't maintain a queue of mouse events; only one can be pushed
+ back, and it can overwrite or be overwritten by real mouse events.
+
+ has_mouse() reports whether the mouse is available at all on the
+ current platform.
+
+### Portability
+ X/Open ncurses NetBSD
+ mouse_set - - -
+ mouse_on - - -
+ mouse_off - - -
+ request_mouse_pos - - -
+ wmouse_position - - -
+ getmouse - * -
+ mouseinterval - Y -
+ wenclose - Y -
+ wmouse_trafo - Y -
+ mouse_trafo - Y -
+ mousemask - Y -
+ nc_getmouse - * -
+ ungetmouse - Y -
+ has_mouse - Y -
+
+ * See above, under Description
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+static bool ungot = FALSE;
+
+int mouse_set(mmask_t mbe)
+{
+ PDC_LOG(("mouse_set() - called: event %x\n", mbe));
+
+ if (!SP)
+ return ERR;
+
+ SP->_trap_mbe = mbe;
+ return PDC_mouse_set();
+}
+
+int mouse_on(mmask_t mbe)
+{
+ PDC_LOG(("mouse_on() - called: event %x\n", mbe));
+
+ if (!SP)
+ return ERR;
+
+ SP->_trap_mbe |= mbe;
+ return PDC_mouse_set();
+}
+
+int mouse_off(mmask_t mbe)
+{
+ PDC_LOG(("mouse_off() - called: event %x\n", mbe));
+
+ if (!SP)
+ return ERR;
+
+ SP->_trap_mbe &= ~mbe;
+ return PDC_mouse_set();
+}
+
+int request_mouse_pos(void)
+{
+ PDC_LOG(("request_mouse_pos() - called\n"));
+
+ Mouse_status = SP->mouse_status;
+
+ return OK;
+}
+
+void wmouse_position(WINDOW *win, int *y, int *x)
+{
+ PDC_LOG(("wmouse_position() - called\n"));
+
+ if (win && wenclose(win, MOUSE_Y_POS, MOUSE_X_POS))
+ {
+ if (y)
+ *y = MOUSE_Y_POS - win->_begy;
+ if (x)
+ *x = MOUSE_X_POS - win->_begx;
+ }
+ else
+ {
+ if (y)
+ *y = -1;
+ if (x)
+ *x = -1;
+ }
+}
+
+mmask_t getmouse(void)
+{
+ PDC_LOG(("getmouse() - called\n"));
+
+ return SP ? SP->_trap_mbe : (mmask_t)0;
+}
+
+/* ncurses mouse interface */
+
+int mouseinterval(int wait)
+{
+ int old_wait;
+
+ PDC_LOG(("mouseinterval() - called: %d\n", wait));
+
+ if (!SP)
+ return ERR;
+
+ old_wait = SP->mouse_wait;
+
+ if (wait >= 0 && wait <= 1000)
+ SP->mouse_wait = wait;
+
+ return old_wait;
+}
+
+bool wenclose(const WINDOW *win, int y, int x)
+{
+ PDC_LOG(("wenclose() - called: %p %d %d\n", win, y, x));
+
+ return (win && y >= win->_begy && y < win->_begy + win->_maxy
+ && x >= win->_begx && x < win->_begx + win->_maxx);
+}
+
+bool wmouse_trafo(const WINDOW *win, int *y, int *x, bool to_screen)
+{
+ int newy, newx;
+
+ PDC_LOG(("wmouse_trafo() - called\n"));
+
+ if (!win || !y || !x)
+ return FALSE;
+
+ newy = *y;
+ newx = *x;
+
+ if (to_screen)
+ {
+ newy += win->_begy;
+ newx += win->_begx;
+
+ if (!wenclose(win, newy, newx))
+ return FALSE;
+ }
+ else
+ {
+ if (wenclose(win, newy, newx))
+ {
+ newy -= win->_begy;
+ newx -= win->_begx;
+ }
+ else
+ return FALSE;
+ }
+
+ *y = newy;
+ *x = newx;
+
+ return TRUE;
+}
+
+bool mouse_trafo(int *y, int *x, bool to_screen)
+{
+ PDC_LOG(("mouse_trafo() - called\n"));
+
+ return wmouse_trafo(stdscr, y, x, to_screen);
+}
+
+mmask_t mousemask(mmask_t mask, mmask_t *oldmask)
+{
+ PDC_LOG(("mousemask() - called\n"));
+
+ if (!SP)
+ return (mmask_t)0;
+
+ if (oldmask)
+ *oldmask = SP->_trap_mbe;
+
+ /* The ncurses interface doesn't work with our move events, so
+ filter them here */
+
+ mask &= ~(BUTTON1_MOVED | BUTTON2_MOVED | BUTTON3_MOVED);
+
+ mouse_set(mask);
+
+ return SP->_trap_mbe;
+}
+
+int nc_getmouse(MEVENT *event)
+{
+ int i;
+ mmask_t bstate = 0;
+
+ PDC_LOG(("nc_getmouse() - called\n"));
+
+ if (!event || !SP)
+ return ERR;
+
+ ungot = FALSE;
+
+ request_mouse_pos();
+
+ event->id = 0;
+
+ event->x = Mouse_status.x;
+ event->y = Mouse_status.y;
+ event->z = 0;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (Mouse_status.changes & (1 << i))
+ {
+ int shf = i * 5;
+ short button = Mouse_status.button[i] & BUTTON_ACTION_MASK;
+
+ if (button == BUTTON_RELEASED)
+ bstate |= (BUTTON1_RELEASED << shf);
+ else if (button == BUTTON_PRESSED)
+ bstate |= (BUTTON1_PRESSED << shf);
+ else if (button == BUTTON_CLICKED)
+ bstate |= (BUTTON1_CLICKED << shf);
+ else if (button == BUTTON_DOUBLE_CLICKED)
+ bstate |= (BUTTON1_DOUBLE_CLICKED << shf);
+
+ button = Mouse_status.button[i] & BUTTON_MODIFIER_MASK;
+
+ if (button & PDC_BUTTON_SHIFT)
+ bstate |= BUTTON_MODIFIER_SHIFT;
+ if (button & PDC_BUTTON_CONTROL)
+ bstate |= BUTTON_MODIFIER_CONTROL;
+ if (button & PDC_BUTTON_ALT)
+ bstate |= BUTTON_MODIFIER_ALT;
+ }
+ }
+
+ if (MOUSE_WHEEL_UP)
+ bstate |= BUTTON4_PRESSED;
+ else if (MOUSE_WHEEL_DOWN)
+ bstate |= BUTTON5_PRESSED;
+
+ /* extra filter pass -- mainly for button modifiers */
+
+ event->bstate = bstate & SP->_trap_mbe;
+
+ return OK;
+}
+
+int ungetmouse(MEVENT *event)
+{
+ int i;
+ mmask_t bstate;
+
+ PDC_LOG(("ungetmouse() - called\n"));
+
+ if (!event || ungot)
+ return ERR;
+
+ ungot = TRUE;
+
+ SP->mouse_status.x = event->x;
+ SP->mouse_status.y = event->y;
+
+ SP->mouse_status.changes = 0;
+ bstate = event->bstate;
+
+ for (i = 0; i < 3; i++)
+ {
+ int shf = i * 5;
+ short button = 0;
+
+ if (bstate & ((BUTTON1_RELEASED | BUTTON1_PRESSED |
+ BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED) << shf))
+ {
+ SP->mouse_status.changes |= 1 << i;
+
+ if (bstate & (BUTTON1_PRESSED << shf))
+ button = BUTTON_PRESSED;
+ if (bstate & (BUTTON1_CLICKED << shf))
+ button = BUTTON_CLICKED;
+ if (bstate & (BUTTON1_DOUBLE_CLICKED << shf))
+ button = BUTTON_DOUBLE_CLICKED;
+
+ if (bstate & BUTTON_MODIFIER_SHIFT)
+ button |= PDC_BUTTON_SHIFT;
+ if (bstate & BUTTON_MODIFIER_CONTROL)
+ button |= PDC_BUTTON_CONTROL;
+ if (bstate & BUTTON_MODIFIER_ALT)
+ button |= PDC_BUTTON_ALT;
+ }
+
+ SP->mouse_status.button[i] = button;
+ }
+
+ if (bstate & BUTTON4_PRESSED)
+ SP->mouse_status.changes |= PDC_MOUSE_WHEEL_UP;
+ else if (bstate & BUTTON5_PRESSED)
+ SP->mouse_status.changes |= PDC_MOUSE_WHEEL_DOWN;
+
+ return PDC_ungetch(KEY_MOUSE);
+}
+
+bool has_mouse(void)
+{
+ return PDC_has_mouse();
+}
diff --git a/Utilities/cmpdcurses/pdcurses/move.c b/Utilities/cmpdcurses/pdcurses/move.c
new file mode 100644
index 0000000..05f4aaa
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/move.c
@@ -0,0 +1,77 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+move
+----
+
+### Synopsis
+
+ int move(int y, int x);
+ int mvcur(int oldrow, int oldcol, int newrow, int newcol);
+ int wmove(WINDOW *win, int y, int x);
+
+### Description
+
+ move() and wmove() move the cursor associated with the window to the
+ given location. This does not move the physical cursor of the
+ terminal until refresh() is called. The position specified is
+ relative to the upper left corner of the window, which is (0,0).
+
+ mvcur() moves the physical cursor without updating any window cursor
+ positions.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ move Y Y Y
+ mvcur Y Y Y
+ wmove Y Y Y
+
+**man-end****************************************************************/
+
+int move(int y, int x)
+{
+ PDC_LOG(("move() - called: y=%d x=%d\n", y, x));
+
+ if (!stdscr || x < 0 || y < 0 || x >= stdscr->_maxx || y >= stdscr->_maxy)
+ return ERR;
+
+ stdscr->_curx = x;
+ stdscr->_cury = y;
+
+ return OK;
+}
+
+int mvcur(int oldrow, int oldcol, int newrow, int newcol)
+{
+ PDC_LOG(("mvcur() - called: oldrow %d oldcol %d newrow %d newcol %d\n",
+ oldrow, oldcol, newrow, newcol));
+
+ if (!SP || newrow < 0 || newrow >= LINES || newcol < 0 || newcol >= COLS)
+ return ERR;
+
+ PDC_gotoyx(newrow, newcol);
+ SP->cursrow = newrow;
+ SP->curscol = newcol;
+
+ return OK;
+}
+
+int wmove(WINDOW *win, int y, int x)
+{
+ PDC_LOG(("wmove() - called: y=%d x=%d\n", y, x));
+
+ if (!win || x < 0 || y < 0 || x >= win->_maxx || y >= win->_maxy)
+ return ERR;
+
+ win->_curx = x;
+ win->_cury = y;
+
+ return OK;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/outopts.c b/Utilities/cmpdcurses/pdcurses/outopts.c
new file mode 100644
index 0000000..f13715a
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/outopts.c
@@ -0,0 +1,175 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+outopts
+-------
+
+### Synopsis
+
+ int clearok(WINDOW *win, bool bf);
+ int idlok(WINDOW *win, bool bf);
+ void idcok(WINDOW *win, bool bf);
+ void immedok(WINDOW *win, bool bf);
+ int leaveok(WINDOW *win, bool bf);
+ int setscrreg(int top, int bot);
+ int wsetscrreg(WINDOW *win, int top, int bot);
+ int scrollok(WINDOW *win, bool bf);
+
+ int raw_output(bool bf);
+
+ bool is_leaveok(const WINDOW *win);
+
+### Description
+
+ With clearok(), if bf is TRUE, the next call to wrefresh() with this
+ window will clear the screen completely and redraw the entire screen.
+
+ immedok(), called with a second argument of TRUE, causes an automatic
+ wrefresh() every time a change is made to the specified window.
+
+ Normally, the hardware cursor is left at the location of the window
+ being refreshed. leaveok() allows the cursor to be left wherever the
+ update happens to leave it. It's useful for applications where the
+ cursor is not used, since it reduces the need for cursor motions. If
+ possible, the cursor is made invisible when this option is enabled.
+
+ wsetscrreg() sets a scrolling region in a window; "top" and "bot" are
+ the line numbers for the top and bottom margins. If this option and
+ scrollok() are enabled, any attempt to move off the bottom margin
+ will cause all lines in the scrolling region to scroll up one line.
+ setscrreg() is the stdscr version.
+
+ idlok() and idcok() do nothing in PDCurses, but are provided for
+ compatibility with other curses implementations.
+
+ raw_output() enables the output of raw characters using the standard
+ *add* and *ins* curses functions (that is, it disables translation of
+ control characters).
+
+ is_leaveok() reports whether the specified window is in leaveok mode.
+
+### Return Value
+
+ All functions except is_leaveok() return OK on success and ERR on
+ error.
+
+### Portability
+ X/Open ncurses NetBSD
+ clearok Y Y Y
+ idlok Y Y Y
+ idcok Y Y Y
+ immedok Y Y Y
+ leaveok Y Y Y
+ setscrreg Y Y Y
+ wsetscrreg Y Y Y
+ scrollok Y Y Y
+ is_leaveok - Y Y
+ raw_output - - -
+
+**man-end****************************************************************/
+
+int clearok(WINDOW *win, bool bf)
+{
+ PDC_LOG(("clearok() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_clear = bf;
+
+ return OK;
+}
+
+int idlok(WINDOW *win, bool bf)
+{
+ PDC_LOG(("idlok() - called\n"));
+
+ return OK;
+}
+
+void idcok(WINDOW *win, bool bf)
+{
+ PDC_LOG(("idcok() - called\n"));
+}
+
+void immedok(WINDOW *win, bool bf)
+{
+ PDC_LOG(("immedok() - called\n"));
+
+ if (win)
+ win->_immed = bf;
+}
+
+int leaveok(WINDOW *win, bool bf)
+{
+ PDC_LOG(("leaveok() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_leaveit = bf;
+
+ curs_set(!bf);
+
+ return OK;
+}
+
+int setscrreg(int top, int bottom)
+{
+ PDC_LOG(("setscrreg() - called: top %d bottom %d\n", top, bottom));
+
+ return wsetscrreg(stdscr, top, bottom);
+}
+
+int wsetscrreg(WINDOW *win, int top, int bottom)
+{
+ PDC_LOG(("wsetscrreg() - called: top %d bottom %d\n", top, bottom));
+
+ if (win && 0 <= top && top <= win->_cury &&
+ win->_cury <= bottom && bottom < win->_maxy)
+ {
+ win->_tmarg = top;
+ win->_bmarg = bottom;
+
+ return OK;
+ }
+ else
+ return ERR;
+}
+
+int scrollok(WINDOW *win, bool bf)
+{
+ PDC_LOG(("scrollok() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_scroll = bf;
+
+ return OK;
+}
+
+int raw_output(bool bf)
+{
+ PDC_LOG(("raw_output() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ SP->raw_out = bf;
+
+ return OK;
+}
+
+bool is_leaveok(const WINDOW *win)
+{
+ PDC_LOG(("is_leaveok() - called\n"));
+
+ if (!win)
+ return FALSE;
+
+ return win->_leaveit;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/overlay.c b/Utilities/cmpdcurses/pdcurses/overlay.c
new file mode 100644
index 0000000..5bcc627
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/overlay.c
@@ -0,0 +1,214 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+overlay
+-------
+
+### Synopsis
+
+ int overlay(const WINDOW *src_w, WINDOW *dst_w)
+ int overwrite(const WINDOW *src_w, WINDOW *dst_w)
+ int copywin(const WINDOW *src_w, WINDOW *dst_w, int src_tr,
+ int src_tc, int dst_tr, int dst_tc, int dst_br,
+ int dst_bc, int _overlay)
+
+### Description
+
+ overlay() and overwrite() copy all the text from src_w into dst_w.
+ The windows need not be the same size. Those characters in the source
+ window that intersect with the destination window are copied, so that
+ the characters appear in the same physical position on the screen.
+ The difference between the two functions is that overlay() is non-
+ destructive (blanks are not copied) while overwrite() is destructive
+ (blanks are copied).
+
+ copywin() is similar, but doesn't require that the two windows
+ overlap. The arguments src_tc and src_tr specify the top left corner
+ of the region to be copied. dst_tc, dst_tr, dst_br, and dst_bc
+ specify the region within the destination window to copy to. The
+ argument "overlay", if TRUE, indicates that the copy is done non-
+ destructively (as in overlay()); blanks in the source window are not
+ copied to the destination window. When overlay is FALSE, blanks are
+ copied.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ overlay Y Y Y
+ overwrite Y Y Y
+ copywin Y Y Y
+
+**man-end****************************************************************/
+
+/* Thanks to Andreas Otte <venn@@uni-paderborn.de> for the
+ corrected overlay()/overwrite() behavior. */
+
+static int _copy_win(const WINDOW *src_w, WINDOW *dst_w, int src_tr,
+ int src_tc, int src_br, int src_bc, int dst_tr,
+ int dst_tc, bool _overlay)
+{
+ int col, line, y1, fc, *minchng, *maxchng;
+ chtype *w1ptr, *w2ptr;
+
+ int lc = 0;
+ int xdiff = src_bc - src_tc;
+ int ydiff = src_br - src_tr;
+
+ if (!src_w || !dst_w)
+ return ERR;
+
+ minchng = dst_w->_firstch;
+ maxchng = dst_w->_lastch;
+
+ for (y1 = 0; y1 < dst_tr; y1++)
+ {
+ minchng++;
+ maxchng++;
+ }
+
+ for (line = 0; line < ydiff; line++)
+ {
+ w1ptr = src_w->_y[line + src_tr] + src_tc;
+ w2ptr = dst_w->_y[line + dst_tr] + dst_tc;
+
+ fc = _NO_CHANGE;
+
+ for (col = 0; col < xdiff; col++)
+ {
+ if ((*w1ptr) != (*w2ptr) &&
+ !((*w1ptr & A_CHARTEXT) == ' ' && _overlay))
+ {
+ *w2ptr = *w1ptr;
+
+ if (fc == _NO_CHANGE)
+ fc = col + dst_tc;
+
+ lc = col + dst_tc;
+ }
+
+ w1ptr++;
+ w2ptr++;
+ }
+
+ if (*minchng == _NO_CHANGE)
+ {
+ *minchng = fc;
+ *maxchng = lc;
+ }
+ else if (fc != _NO_CHANGE)
+ {
+ if (fc < *minchng)
+ *minchng = fc;
+ if (lc > *maxchng)
+ *maxchng = lc;
+ }
+
+ minchng++;
+ maxchng++;
+ }
+
+ return OK;
+}
+
+int _copy_overlap(const WINDOW *src_w, WINDOW *dst_w, bool overlay)
+{
+ int first_line, first_col, last_line, last_col;
+ int src_start_x, src_start_y, dst_start_x, dst_start_y;
+ int xdiff, ydiff;
+
+ if (!src_w || !dst_w)
+ return ERR;
+
+ first_col = max(dst_w->_begx, src_w->_begx);
+ first_line = max(dst_w->_begy, src_w->_begy);
+
+ last_col = min(src_w->_begx + src_w->_maxx, dst_w->_begx + dst_w->_maxx);
+ last_line = min(src_w->_begy + src_w->_maxy, dst_w->_begy + dst_w->_maxy);
+
+ /* determine the overlapping region of the two windows in real
+ coordinates */
+
+ /* if no overlapping region, do nothing */
+
+ if ((last_col < first_col) || (last_line < first_line))
+ return OK;
+
+ /* size of overlapping region */
+
+ xdiff = last_col - first_col;
+ ydiff = last_line - first_line;
+
+ if (src_w->_begx <= dst_w->_begx)
+ {
+ src_start_x = dst_w->_begx - src_w->_begx;
+ dst_start_x = 0;
+ }
+ else
+ {
+ dst_start_x = src_w->_begx - dst_w->_begx;
+ src_start_x = 0;
+ }
+
+ if (src_w->_begy <= dst_w->_begy)
+ {
+ src_start_y = dst_w->_begy - src_w->_begy;
+ dst_start_y = 0;
+ }
+ else
+ {
+ dst_start_y = src_w->_begy - dst_w->_begy;
+ src_start_y = 0;
+ }
+
+ return _copy_win(src_w, dst_w, src_start_y, src_start_x,
+ src_start_y + ydiff, src_start_x + xdiff,
+ dst_start_y, dst_start_x, overlay);
+}
+
+int overlay(const WINDOW *src_w, WINDOW *dst_w)
+{
+ PDC_LOG(("overlay() - called\n"));
+
+ return _copy_overlap(src_w, dst_w, TRUE);
+}
+
+int overwrite(const WINDOW *src_w, WINDOW *dst_w)
+{
+ PDC_LOG(("overwrite() - called\n"));
+
+ return _copy_overlap(src_w, dst_w, FALSE);
+}
+
+int copywin(const WINDOW *src_w, WINDOW *dst_w, int src_tr, int src_tc,
+ int dst_tr, int dst_tc, int dst_br, int dst_bc, int _overlay)
+{
+ int src_end_x, src_end_y;
+ int src_rows, src_cols, dst_rows, dst_cols;
+ int min_rows, min_cols;
+
+ PDC_LOG(("copywin() - called\n"));
+
+ if (!src_w || !dst_w || dst_w == curscr || dst_br >= dst_w->_maxy
+ || dst_bc >= dst_w->_maxx || dst_tr < 0 || dst_tc < 0)
+ return ERR;
+
+ src_rows = src_w->_maxy - src_tr;
+ src_cols = src_w->_maxx - src_tc;
+ dst_rows = dst_br - dst_tr + 1;
+ dst_cols = dst_bc - dst_tc + 1;
+
+ min_rows = min(src_rows, dst_rows);
+ min_cols = min(src_cols, dst_cols);
+
+ src_end_y = src_tr + min_rows;
+ src_end_x = src_tc + min_cols;
+
+ return _copy_win(src_w, dst_w, src_tr, src_tc, src_end_y, src_end_x,
+ dst_tr, dst_tc, _overlay);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/pad.c b/Utilities/cmpdcurses/pdcurses/pad.c
new file mode 100644
index 0000000..da8e968
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/pad.c
@@ -0,0 +1,280 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+pad
+---
+
+### Synopsis
+
+ WINDOW *newpad(int nlines, int ncols);
+ WINDOW *subpad(WINDOW *orig, int nlines, int ncols,
+ int begy, int begx);
+ int prefresh(WINDOW *win, int py, int px, int sy1, int sx1,
+ int sy2, int sx2);
+ int pnoutrefresh(WINDOW *w, int py, int px, int sy1, int sx1,
+ int sy2, int sx2);
+ int pechochar(WINDOW *pad, chtype ch);
+ int pecho_wchar(WINDOW *pad, const cchar_t *wch);
+
+ bool is_pad(const WINDOW *pad);
+
+### Description
+
+ A pad is a special kind of window, which is not restricted by the
+ screen size, and is not necessarily associated with a particular part
+ of the screen. You can use a pad when you need a large window, and
+ only a part of the window will be on the screen at one time. Pads are
+ not refreshed automatically (e.g., from scrolling or echoing of
+ input). You can't call wrefresh() with a pad as an argument; use
+ prefresh() or pnoutrefresh() instead. Note that these routines
+ require additional parameters to specify the part of the pad to be
+ displayed, and the location to use on the screen.
+
+ newpad() creates a new pad data structure.
+
+ subpad() creates a new sub-pad within a pad, at position (begy,
+ begx), with dimensions of nlines lines and ncols columns. This
+ position is relative to the pad, and not to the screen as with
+ subwin. Changes to either the parent pad or sub-pad will affect both.
+ When using sub-pads, you may need to call touchwin() before calling
+ prefresh().
+
+ pnoutrefresh() copies the specified pad to the virtual screen.
+
+ prefresh() calls pnoutrefresh(), followed by doupdate().
+
+ These routines are analogous to wnoutrefresh() and wrefresh(). (py,
+ px) specifies the upper left corner of the part of the pad to be
+ displayed; (sy1, sx1) and (sy2, sx2) describe the screen rectangle
+ that will contain the selected part of the pad.
+
+ pechochar() is functionally equivalent to addch() followed by a call
+ to prefresh(), with the last-used coordinates and dimensions.
+ pecho_wchar() is the wide-character version.
+
+ is_pad() reports whether the specified window is a pad.
+
+### Return Value
+
+ All functions except is_pad() return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ newpad Y Y Y
+ subpad Y Y Y
+ prefresh Y Y Y
+ pnoutrefresh Y Y Y
+ pechochar Y Y Y
+ pecho_wchar Y Y Y
+ is_pad - Y Y
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+/* save values for pechochar() */
+
+static int save_pminrow, save_pmincol;
+static int save_sminrow, save_smincol, save_smaxrow, save_smaxcol;
+
+WINDOW *newpad(int nlines, int ncols)
+{
+ WINDOW *win;
+
+ PDC_LOG(("newpad() - called: lines=%d cols=%d\n", nlines, ncols));
+
+ win = PDC_makenew(nlines, ncols, 0, 0);
+ if (win)
+ win = PDC_makelines(win);
+
+ if (!win)
+ return (WINDOW *)NULL;
+
+ werase(win);
+
+ win->_flags = _PAD;
+
+ /* save default values in case pechochar() is the first call to
+ prefresh(). */
+
+ save_pminrow = 0;
+ save_pmincol = 0;
+ save_sminrow = 0;
+ save_smincol = 0;
+ save_smaxrow = min(LINES, nlines) - 1;
+ save_smaxcol = min(COLS, ncols) - 1;
+
+ return win;
+}
+
+WINDOW *subpad(WINDOW *orig, int nlines, int ncols, int begy, int begx)
+{
+ WINDOW *win;
+ int i;
+
+ PDC_LOG(("subpad() - called: lines=%d cols=%d begy=%d begx=%d\n",
+ nlines, ncols, begy, begx));
+
+ if (!orig || !(orig->_flags & _PAD))
+ return (WINDOW *)NULL;
+
+ /* make sure window fits inside the original one */
+
+ if (begy < 0 || begx < 0 ||
+ (begy + nlines) > orig->_maxy ||
+ (begx + ncols) > orig->_maxx)
+ return (WINDOW *)NULL;
+
+ if (!nlines)
+ nlines = orig->_maxy - begy;
+
+ if (!ncols)
+ ncols = orig->_maxx - begx;
+
+ win = PDC_makenew(nlines, ncols, begy, begx);
+ if (!win)
+ return (WINDOW *)NULL;
+
+ /* initialize window variables */
+
+ win->_attrs = orig->_attrs;
+ win->_leaveit = orig->_leaveit;
+ win->_scroll = orig->_scroll;
+ win->_nodelay = orig->_nodelay;
+ win->_use_keypad = orig->_use_keypad;
+ win->_parent = orig;
+
+ for (i = 0; i < nlines; i++)
+ win->_y[i] = orig->_y[begy + i] + begx;
+
+ win->_flags = _SUBPAD;
+
+ /* save default values in case pechochar() is the first call
+ to prefresh(). */
+
+ save_pminrow = 0;
+ save_pmincol = 0;
+ save_sminrow = 0;
+ save_smincol = 0;
+ save_smaxrow = min(LINES, nlines) - 1;
+ save_smaxcol = min(COLS, ncols) - 1;
+
+ return win;
+}
+
+int prefresh(WINDOW *win, int py, int px, int sy1, int sx1, int sy2, int sx2)
+{
+ PDC_LOG(("prefresh() - called\n"));
+
+ if (pnoutrefresh(win, py, px, sy1, sx1, sy2, sx2) == ERR)
+ return ERR;
+
+ doupdate();
+ return OK;
+}
+
+int pnoutrefresh(WINDOW *w, int py, int px, int sy1, int sx1, int sy2, int sx2)
+{
+ int num_cols;
+ int sline;
+ int pline;
+
+ PDC_LOG(("pnoutrefresh() - called\n"));
+
+ if (py < 0)
+ py = 0;
+ if (px < 0)
+ px = 0;
+ if (sy1 < 0)
+ sy1 = 0;
+ if (sx1 < 0)
+ sx1 = 0;
+
+ if ((!w || !(w->_flags & (_PAD|_SUBPAD)) ||
+ (sy2 >= LINES) || (sx2 >= COLS)) ||
+ (sy2 < sy1) || (sx2 < sx1))
+ return ERR;
+
+ sline = sy1;
+ pline = py;
+
+ num_cols = min((sx2 - sx1 + 1), (w->_maxx - px));
+
+ while (sline <= sy2)
+ {
+ if (pline < w->_maxy)
+ {
+ memcpy(curscr->_y[sline] + sx1, w->_y[pline] + px,
+ num_cols * sizeof(chtype));
+
+ if ((curscr->_firstch[sline] == _NO_CHANGE)
+ || (curscr->_firstch[sline] > sx1))
+ curscr->_firstch[sline] = sx1;
+
+ if (sx2 > curscr->_lastch[sline])
+ curscr->_lastch[sline] = sx2;
+
+ w->_firstch[pline] = _NO_CHANGE; /* updated now */
+ w->_lastch[pline] = _NO_CHANGE; /* updated now */
+ }
+
+ sline++;
+ pline++;
+ }
+
+ if (w->_clear)
+ {
+ w->_clear = FALSE;
+ curscr->_clear = TRUE;
+ }
+
+ /* position the cursor to the pad's current position if possible --
+ is the pad current position going to end up displayed? if not,
+ then don't move the cursor; if so, move it to the correct place */
+
+ if (!w->_leaveit && w->_cury >= py && w->_curx >= px &&
+ w->_cury <= py + (sy2 - sy1) && w->_curx <= px + (sx2 - sx1))
+ {
+ curscr->_cury = (w->_cury - py) + sy1;
+ curscr->_curx = (w->_curx - px) + sx1;
+ }
+
+ return OK;
+}
+
+int pechochar(WINDOW *pad, chtype ch)
+{
+ PDC_LOG(("pechochar() - called\n"));
+
+ if (waddch(pad, ch) == ERR)
+ return ERR;
+
+ return prefresh(pad, save_pminrow, save_pmincol, save_sminrow,
+ save_smincol, save_smaxrow, save_smaxcol);
+}
+
+#ifdef PDC_WIDE
+int pecho_wchar(WINDOW *pad, const cchar_t *wch)
+{
+ PDC_LOG(("pecho_wchar() - called\n"));
+
+ if (!wch || (waddch(pad, *wch) == ERR))
+ return ERR;
+
+ return prefresh(pad, save_pminrow, save_pmincol, save_sminrow,
+ save_smincol, save_smaxrow, save_smaxcol);
+}
+#endif
+
+bool is_pad(const WINDOW *pad)
+{
+ PDC_LOG(("is_pad() - called\n"));
+
+ if (!pad)
+ return FALSE;
+
+ return (pad->_flags & _PAD) ? TRUE : FALSE;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/panel.c b/Utilities/cmpdcurses/pdcurses/panel.c
new file mode 100644
index 0000000..b3c48fc
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/panel.c
@@ -0,0 +1,633 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+panel
+-----
+
+### Synopsis
+
+ int bottom_panel(PANEL *pan);
+ int del_panel(PANEL *pan);
+ int hide_panel(PANEL *pan);
+ int move_panel(PANEL *pan, int starty, int startx);
+ PANEL *new_panel(WINDOW *win);
+ PANEL *panel_above(const PANEL *pan);
+ PANEL *panel_below(const PANEL *pan);
+ int panel_hidden(const PANEL *pan);
+ const void *panel_userptr(const PANEL *pan);
+ WINDOW *panel_window(const PANEL *pan);
+ int replace_panel(PANEL *pan, WINDOW *win);
+ int set_panel_userptr(PANEL *pan, const void *uptr);
+ int show_panel(PANEL *pan);
+ int top_panel(PANEL *pan);
+ void update_panels(void);
+
+### Description
+
+ For historic reasons, and for compatibility with other versions of
+ curses, the panel functions are prototyped in a separate header,
+ panel.h. In many implementations, they're also in a separate library,
+ but PDCurses incorporates them.
+
+ The panel functions provide a way to have depth relationships between
+ curses windows. Panels can overlap without making visible the
+ overlapped portions of underlying windows. The initial curses window,
+ stdscr, lies beneath all panels. The set of currently visible panels
+ is the 'deck' of panels.
+
+ You can create panels, fetch and set their associated windows,
+ shuffle panels in the deck, and manipulate them in other ways.
+
+ bottom_panel() places pan at the bottom of the deck. The size,
+ location and contents of the panel are unchanged.
+
+ del_panel() deletes pan, but not its associated winwow.
+
+ hide_panel() removes a panel from the deck and thus hides it from
+ view.
+
+ move_panel() moves the curses window associated with pan, so that its
+ upper lefthand corner is at the supplied coordinates. (Don't use
+ mvwin() on the window.)
+
+ new_panel() creates a new panel associated with win and returns the
+ panel pointer. The new panel is placed at the top of the deck.
+
+ panel_above() returns a pointer to the panel in the deck above pan,
+ or NULL if pan is the top panel. If the value of pan passed is NULL,
+ this function returns a pointer to the bottom panel in the deck.
+
+ panel_below() returns a pointer to the panel in the deck below pan,
+ or NULL if pan is the bottom panel. If the value of pan passed is
+ NULL, this function returns a pointer to the top panel in the deck.
+
+ panel_hidden() returns OK if pan is hidden and ERR if it is not.
+
+ panel_userptr() - Each panel has a user pointer available for
+ maintaining relevant information. This function returns a pointer to
+ that information previously set up by set_panel_userptr().
+
+ panel_window() returns a pointer to the curses window associated with
+ the panel.
+
+ replace_panel() replaces the current window of pan with win.
+
+ set_panel_userptr() - Each panel has a user pointer available for
+ maintaining relevant information. This function sets the value of
+ that information.
+
+ show_panel() makes a previously hidden panel visible and places it
+ back in the deck on top.
+
+ top_panel() places pan on the top of the deck. The size, location and
+ contents of the panel are unchanged.
+
+ update_panels() refreshes the virtual screen to reflect the depth
+ relationships between the panels in the deck. The user must use
+ doupdate() to refresh the physical screen.
+
+### Return Value
+
+ Each routine that returns a pointer to an object returns NULL if an
+ error occurs. Each panel routine that returns an integer, returns OK
+ if it executes successfully and ERR if it does not.
+
+### Portability
+ X/Open ncurses NetBSD
+ bottom_panel - Y Y
+ del_panel - Y Y
+ hide_panel - Y Y
+ move_panel - Y Y
+ new_panel - Y Y
+ panel_above - Y Y
+ panel_below - Y Y
+ panel_hidden - Y Y
+ panel_userptr - Y Y
+ panel_window - Y Y
+ replace_panel - Y Y
+ set_panel_userptr - Y Y
+ show_panel - Y Y
+ top_panel - Y Y
+ update_panels - Y Y
+
+ Credits:
+ Original Author - Warren Tucker <wht@n4hgf.mt-park.ga.us>
+
+**man-end****************************************************************/
+
+#include <panel.h>
+#include <stdlib.h>
+
+PANEL *_bottom_panel = (PANEL *)0;
+PANEL *_top_panel = (PANEL *)0;
+PANEL _stdscr_pseudo_panel = { (WINDOW *)0 };
+
+#ifdef PANEL_DEBUG
+
+static void dPanel(char *text, PANEL *pan)
+{
+ PDC_LOG(("%s id=%s b=%s a=%s y=%d x=%d", text, pan->user,
+ pan->below ? pan->below->user : "--",
+ pan->above ? pan->above->user : "--",
+ pan->wstarty, pan->wstartx));
+}
+
+static void dStack(char *fmt, int num, PANEL *pan)
+{
+ char s80[80];
+
+ sprintf(s80, fmt, num, pan);
+ PDC_LOG(("%s b=%s t=%s", s80, _bottom_panel ? _bottom_panel->user : "--",
+ _top_panel ? _top_panel->user : "--"));
+
+ if (pan)
+ PDC_LOG(("pan id=%s", pan->user));
+
+ pan = _bottom_panel;
+
+ while (pan)
+ {
+ dPanel("stk", pan);
+ pan = pan->above;
+ }
+}
+
+/* debugging hook for wnoutrefresh */
+
+static void Wnoutrefresh(PANEL *pan)
+{
+ dPanel("wnoutrefresh", pan);
+ wnoutrefresh(pan->win);
+}
+
+static void Touchpan(PANEL *pan)
+{
+ dPanel("Touchpan", pan);
+ touchwin(pan->win);
+}
+
+static void Touchline(PANEL *pan, int start, int count)
+{
+ char s80[80];
+
+ sprintf(s80, "Touchline s=%d c=%d", start, count);
+ dPanel(s80, pan);
+ touchline(pan->win, start, count);
+}
+
+#else /* PANEL_DEBUG */
+
+#define dPanel(text, pan)
+#define dStack(fmt, num, pan)
+#define Wnoutrefresh(pan) wnoutrefresh((pan)->win)
+#define Touchpan(pan) touchwin((pan)->win)
+#define Touchline(pan, start, count) touchline((pan)->win, start, count)
+
+#endif /* PANEL_DEBUG */
+
+static bool _panels_overlapped(PANEL *pan1, PANEL *pan2)
+{
+ if (!pan1 || !pan2)
+ return FALSE;
+
+ return ((pan1->wstarty >= pan2->wstarty && pan1->wstarty < pan2->wendy)
+ || (pan2->wstarty >= pan1->wstarty && pan2->wstarty < pan1->wendy))
+ && ((pan1->wstartx >= pan2->wstartx && pan1->wstartx < pan2->wendx)
+ || (pan2->wstartx >= pan1->wstartx && pan2->wstartx < pan1->wendx));
+}
+
+static void _free_obscure(PANEL *pan)
+{
+ PANELOBS *tobs = pan->obscure; /* "this" one */
+ PANELOBS *nobs; /* "next" one */
+
+ while (tobs)
+ {
+ nobs = tobs->above;
+ free((char *)tobs);
+ tobs = nobs;
+ }
+ pan->obscure = (PANELOBS *)0;
+}
+
+static void _override(PANEL *pan, int show)
+{
+ int y;
+ PANEL *pan2;
+ PANELOBS *tobs = pan->obscure; /* "this" one */
+
+ if (show == 1)
+ Touchpan(pan);
+ else if (!show)
+ {
+ Touchpan(pan);
+ Touchpan(&_stdscr_pseudo_panel);
+ }
+ else if (show == -1)
+ while (tobs && (tobs->pan != pan))
+ tobs = tobs->above;
+
+ while (tobs)
+ {
+ if ((pan2 = tobs->pan) != pan)
+ for (y = pan->wstarty; y < pan->wendy; y++)
+ if ((y >= pan2->wstarty) && (y < pan2->wendy) &&
+ ((is_linetouched(pan->win, y - pan->wstarty)) ||
+ (is_linetouched(stdscr, y))))
+ Touchline(pan2, y - pan2->wstarty, 1);
+
+ tobs = tobs->above;
+ }
+}
+
+static void _calculate_obscure(void)
+{
+ PANEL *pan, *pan2;
+ PANELOBS *tobs; /* "this" one */
+ PANELOBS *lobs; /* last one */
+
+ pan = _bottom_panel;
+
+ while (pan)
+ {
+ if (pan->obscure)
+ _free_obscure(pan);
+
+ lobs = (PANELOBS *)0;
+ pan2 = _bottom_panel;
+
+ while (pan2)
+ {
+ if (_panels_overlapped(pan, pan2))
+ {
+ if ((tobs = malloc(sizeof(PANELOBS))) == NULL)
+ return;
+
+ tobs->pan = pan2;
+ dPanel("obscured", pan2);
+ tobs->above = (PANELOBS *)0;
+
+ if (lobs)
+ lobs->above = tobs;
+ else
+ pan->obscure = tobs;
+
+ lobs = tobs;
+ }
+
+ pan2 = pan2->above;
+ }
+
+ _override(pan, 1);
+ pan = pan->above;
+ }
+}
+
+/* check to see if panel is in the stack */
+
+static bool _panel_is_linked(const PANEL *pan)
+{
+ PANEL *pan2 = _bottom_panel;
+
+ while (pan2)
+ {
+ if (pan2 == pan)
+ return TRUE;
+
+ pan2 = pan2->above;
+ }
+
+ return FALSE;
+}
+
+/* link panel into stack at top */
+
+static void _panel_link_top(PANEL *pan)
+{
+#ifdef PANEL_DEBUG
+ dStack("<lt%d>", 1, pan);
+ if (_panel_is_linked(pan))
+ return;
+#endif
+ pan->above = (PANEL *)0;
+ pan->below = (PANEL *)0;
+
+ if (_top_panel)
+ {
+ _top_panel->above = pan;
+ pan->below = _top_panel;
+ }
+
+ _top_panel = pan;
+
+ if (!_bottom_panel)
+ _bottom_panel = pan;
+
+ _calculate_obscure();
+ dStack("<lt%d>", 9, pan);
+}
+
+/* link panel into stack at bottom */
+
+static void _panel_link_bottom(PANEL *pan)
+{
+#ifdef PANEL_DEBUG
+ dStack("<lb%d>", 1, pan);
+ if (_panel_is_linked(pan))
+ return;
+#endif
+ pan->above = (PANEL *)0;
+ pan->below = (PANEL *)0;
+
+ if (_bottom_panel)
+ {
+ _bottom_panel->below = pan;
+ pan->above = _bottom_panel;
+ }
+
+ _bottom_panel = pan;
+
+ if (!_top_panel)
+ _top_panel = pan;
+
+ _calculate_obscure();
+ dStack("<lb%d>", 9, pan);
+}
+
+static void _panel_unlink(PANEL *pan)
+{
+ PANEL *prev;
+ PANEL *next;
+
+#ifdef PANEL_DEBUG
+ dStack("<u%d>", 1, pan);
+ if (!_panel_is_linked(pan))
+ return;
+#endif
+ _override(pan, 0);
+ _free_obscure(pan);
+
+ prev = pan->below;
+ next = pan->above;
+
+ /* if non-zero, we will not update the list head */
+
+ if (prev)
+ {
+ prev->above = next;
+ if(next)
+ next->below = prev;
+ }
+ else if (next)
+ next->below = prev;
+
+ if (pan == _bottom_panel)
+ _bottom_panel = next;
+
+ if (pan == _top_panel)
+ _top_panel = prev;
+
+ _calculate_obscure();
+
+ pan->above = (PANEL *)0;
+ pan->below = (PANEL *)0;
+ dStack("<u%d>", 9, pan);
+
+}
+
+/************************************************************************
+ * The following are the public functions for the panels library. *
+ ************************************************************************/
+
+int bottom_panel(PANEL *pan)
+{
+ if (!pan)
+ return ERR;
+
+ if (pan == _bottom_panel)
+ return OK;
+
+ if (_panel_is_linked(pan))
+ hide_panel(pan);
+
+ _panel_link_bottom(pan);
+
+ return OK;
+}
+
+int del_panel(PANEL *pan)
+{
+ if (pan)
+ {
+ if (_panel_is_linked(pan))
+ hide_panel(pan);
+
+ free((char *)pan);
+ return OK;
+ }
+
+ return ERR;
+}
+
+int hide_panel(PANEL *pan)
+{
+ if (!pan)
+ return ERR;
+
+ if (!_panel_is_linked(pan))
+ {
+ pan->above = (PANEL *)0;
+ pan->below = (PANEL *)0;
+ return ERR;
+ }
+
+ _panel_unlink(pan);
+
+ return OK;
+}
+
+int move_panel(PANEL *pan, int starty, int startx)
+{
+ WINDOW *win;
+ int maxy, maxx;
+
+ if (!pan)
+ return ERR;
+
+ if (_panel_is_linked(pan))
+ _override(pan, 0);
+
+ win = pan->win;
+
+ if (mvwin(win, starty, startx) == ERR)
+ return ERR;
+
+ getbegyx(win, pan->wstarty, pan->wstartx);
+ getmaxyx(win, maxy, maxx);
+ pan->wendy = pan->wstarty + maxy;
+ pan->wendx = pan->wstartx + maxx;
+
+ if (_panel_is_linked(pan))
+ _calculate_obscure();
+
+ return OK;
+}
+
+PANEL *new_panel(WINDOW *win)
+{
+ PANEL *pan;
+
+ if (!win)
+ return (PANEL *)NULL;
+
+ pan = malloc(sizeof(PANEL));
+
+ if (!_stdscr_pseudo_panel.win)
+ {
+ _stdscr_pseudo_panel.win = stdscr;
+ _stdscr_pseudo_panel.wstarty = 0;
+ _stdscr_pseudo_panel.wstartx = 0;
+ _stdscr_pseudo_panel.wendy = LINES;
+ _stdscr_pseudo_panel.wendx = COLS;
+ _stdscr_pseudo_panel.user = "stdscr";
+ _stdscr_pseudo_panel.obscure = (PANELOBS *)0;
+ }
+
+ if (pan)
+ {
+ int maxy, maxx;
+
+ pan->win = win;
+ pan->above = (PANEL *)0;
+ pan->below = (PANEL *)0;
+ getbegyx(win, pan->wstarty, pan->wstartx);
+ getmaxyx(win, maxy, maxx);
+ pan->wendy = pan->wstarty + maxy;
+ pan->wendx = pan->wstartx + maxx;
+#ifdef PANEL_DEBUG
+ pan->user = "new";
+#else
+ pan->user = (char *)0;
+#endif
+ pan->obscure = (PANELOBS *)0;
+ show_panel(pan);
+ }
+
+ return pan;
+}
+
+PANEL *panel_above(const PANEL *pan)
+{
+ return pan ? pan->above : _bottom_panel;
+}
+
+PANEL *panel_below(const PANEL *pan)
+{
+ return pan ? pan->below : _top_panel;
+}
+
+int panel_hidden(const PANEL *pan)
+{
+ if (!pan)
+ return ERR;
+
+ return _panel_is_linked(pan) ? ERR : OK;
+}
+
+const void *panel_userptr(const PANEL *pan)
+{
+ return pan ? pan->user : NULL;
+}
+
+WINDOW *panel_window(const PANEL *pan)
+{
+ PDC_LOG(("panel_window() - called\n"));
+
+ if (!pan)
+ return (WINDOW *)NULL;
+
+ return pan->win;
+}
+
+int replace_panel(PANEL *pan, WINDOW *win)
+{
+ int maxy, maxx;
+
+ if (!pan)
+ return ERR;
+
+ if (_panel_is_linked(pan))
+ _override(pan, 0);
+
+ pan->win = win;
+ getbegyx(win, pan->wstarty, pan->wstartx);
+ getmaxyx(win, maxy, maxx);
+ pan->wendy = pan->wstarty + maxy;
+ pan->wendx = pan->wstartx + maxx;
+
+ if (_panel_is_linked(pan))
+ _calculate_obscure();
+
+ return OK;
+}
+
+int set_panel_userptr(PANEL *pan, const void *uptr)
+{
+ if (!pan)
+ return ERR;
+
+ pan->user = uptr;
+ return OK;
+}
+
+int show_panel(PANEL *pan)
+{
+ if (!pan)
+ return ERR;
+
+ if (pan == _top_panel)
+ return OK;
+
+ if (_panel_is_linked(pan))
+ hide_panel(pan);
+
+ _panel_link_top(pan);
+
+ return OK;
+}
+
+int top_panel(PANEL *pan)
+{
+ return show_panel(pan);
+}
+
+void update_panels(void)
+{
+ PANEL *pan;
+
+ PDC_LOG(("update_panels() - called\n"));
+
+ pan = _bottom_panel;
+
+ while (pan)
+ {
+ _override(pan, -1);
+ pan = pan->above;
+ }
+
+ if (is_wintouched(stdscr))
+ Wnoutrefresh(&_stdscr_pseudo_panel);
+
+ pan = _bottom_panel;
+
+ while (pan)
+ {
+ if (is_wintouched(pan->win) || !pan->above)
+ Wnoutrefresh(pan);
+
+ pan = pan->above;
+ }
+}
diff --git a/Utilities/cmpdcurses/pdcurses/printw.c b/Utilities/cmpdcurses/pdcurses/printw.c
new file mode 100644
index 0000000..7d19a99
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/printw.c
@@ -0,0 +1,129 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+printw
+------
+
+### Synopsis
+
+ int printw(const char *fmt, ...);
+ int wprintw(WINDOW *win, const char *fmt, ...);
+ int mvprintw(int y, int x, const char *fmt, ...);
+ int mvwprintw(WINDOW *win, int y, int x, const char *fmt,...);
+ int vwprintw(WINDOW *win, const char *fmt, va_list varglist);
+ int vw_printw(WINDOW *win, const char *fmt, va_list varglist);
+
+### Description
+
+ The printw() functions add a formatted string to the window at the
+ current or specified cursor position. The format strings are the same
+ as used in the standard C library's printf(). (printw() can be used
+ as a drop-in replacement for printf().)
+
+ The duplication between vwprintw() and vw_printw() is for historic
+ reasons. In PDCurses, they're the same.
+
+### Return Value
+
+ All functions return the number of characters printed, or ERR on
+ error.
+
+### Portability
+ X/Open ncurses NetBSD
+ printw Y Y Y
+ wprintw Y Y Y
+ mvprintw Y Y Y
+ mvwprintw Y Y Y
+ vwprintw Y Y Y
+ vw_printw Y Y Y
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+int vwprintw(WINDOW *win, const char *fmt, va_list varglist)
+{
+ char printbuf[513];
+ int len;
+
+ PDC_LOG(("vwprintw() - called\n"));
+
+#ifdef HAVE_VSNPRINTF
+ len = vsnprintf(printbuf, 512, fmt, varglist);
+#else
+ len = vsprintf(printbuf, fmt, varglist);
+#endif
+ return (waddstr(win, printbuf) == ERR) ? ERR : len;
+}
+
+int printw(const char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ PDC_LOG(("printw() - called\n"));
+
+ va_start(args, fmt);
+ retval = vwprintw(stdscr, fmt, args);
+ va_end(args);
+
+ return retval;
+}
+
+int wprintw(WINDOW *win, const char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ PDC_LOG(("wprintw() - called\n"));
+
+ va_start(args, fmt);
+ retval = vwprintw(win, fmt, args);
+ va_end(args);
+
+ return retval;
+}
+
+int mvprintw(int y, int x, const char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ PDC_LOG(("mvprintw() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ va_start(args, fmt);
+ retval = vwprintw(stdscr, fmt, args);
+ va_end(args);
+
+ return retval;
+}
+
+int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ PDC_LOG(("mvwprintw() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ va_start(args, fmt);
+ retval = vwprintw(win, fmt, args);
+ va_end(args);
+
+ return retval;
+}
+
+int vw_printw(WINDOW *win, const char *fmt, va_list varglist)
+{
+ PDC_LOG(("vw_printw() - called\n"));
+
+ return vwprintw(win, fmt, varglist);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/refresh.c b/Utilities/cmpdcurses/pdcurses/refresh.c
new file mode 100644
index 0000000..cc0a25d
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/refresh.c
@@ -0,0 +1,279 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+refresh
+-------
+
+### Synopsis
+
+ int refresh(void);
+ int wrefresh(WINDOW *win);
+ int wnoutrefresh(WINDOW *win);
+ int doupdate(void);
+ int redrawwin(WINDOW *win);
+ int wredrawln(WINDOW *win, int beg_line, int num_lines);
+
+### Description
+
+ wrefresh() copies the named window to the physical terminal screen,
+ taking into account what is already there in order to optimize cursor
+ movement. refresh() does the same, using stdscr. These routines must
+ be called to get any output on the terminal, as other routines only
+ manipulate data structures. Unless leaveok() has been enabled, the
+ physical cursor of the terminal is left at the location of the
+ window's cursor.
+
+ wnoutrefresh() and doupdate() allow multiple updates with more
+ efficiency than wrefresh() alone. wrefresh() works by first calling
+ wnoutrefresh(), which copies the named window to the virtual screen.
+ It then calls doupdate(), which compares the virtual screen to the
+ physical screen and does the actual update. A series of calls to
+ wrefresh() will result in alternating calls to wnoutrefresh() and
+ doupdate(), causing several bursts of output to the screen. By first
+ calling wnoutrefresh() for each window, it is then possible to call
+ doupdate() only once.
+
+ In PDCurses, redrawwin() is equivalent to touchwin(), and wredrawln()
+ is the same as touchline(). In some other curses implementations,
+ there's a subtle distinction, but it has no meaning in PDCurses.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ refresh Y Y Y
+ wrefresh Y Y Y
+ wnoutrefresh Y Y Y
+ doupdate Y Y Y
+ redrawwin Y Y Y
+ wredrawln Y Y Y
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+int wnoutrefresh(WINDOW *win)
+{
+ int begy, begx; /* window's place on screen */
+ int i, j;
+
+ PDC_LOG(("wnoutrefresh() - called: win=%p\n", win));
+
+ if ( !win || (win->_flags & (_PAD|_SUBPAD)) )
+ return ERR;
+
+ begy = win->_begy;
+ begx = win->_begx;
+
+ for (i = 0, j = begy; i < win->_maxy; i++, j++)
+ {
+ if (win->_firstch[i] != _NO_CHANGE)
+ {
+ chtype *src = win->_y[i];
+ chtype *dest = curscr->_y[j] + begx;
+
+ int first = win->_firstch[i]; /* first changed */
+ int last = win->_lastch[i]; /* last changed */
+
+ /* ignore areas on the outside that are marked as changed,
+ but really aren't */
+
+ while (first <= last && src[first] == dest[first])
+ first++;
+
+ while (last >= first && src[last] == dest[last])
+ last--;
+
+ /* if any have really changed... */
+
+ if (first <= last)
+ {
+ memcpy(dest + first, src + first,
+ (last - first + 1) * sizeof(chtype));
+
+ first += begx;
+ last += begx;
+
+ if (first < curscr->_firstch[j] ||
+ curscr->_firstch[j] == _NO_CHANGE)
+ curscr->_firstch[j] = first;
+
+ if (last > curscr->_lastch[j])
+ curscr->_lastch[j] = last;
+ }
+
+ win->_firstch[i] = _NO_CHANGE; /* updated now */
+ }
+
+ win->_lastch[i] = _NO_CHANGE; /* updated now */
+ }
+
+ if (win->_clear)
+ win->_clear = FALSE;
+
+ if (!win->_leaveit)
+ {
+ curscr->_cury = win->_cury + begy;
+ curscr->_curx = win->_curx + begx;
+ }
+
+ return OK;
+}
+
+int doupdate(void)
+{
+ int y;
+ bool clearall;
+
+ PDC_LOG(("doupdate() - called\n"));
+
+ if (!SP || !curscr)
+ return ERR;
+
+ if (isendwin()) /* coming back after endwin() called */
+ {
+ reset_prog_mode();
+ clearall = TRUE;
+ SP->alive = TRUE; /* so isendwin() result is correct */
+ }
+ else
+ clearall = curscr->_clear;
+
+ for (y = 0; y < SP->lines; y++)
+ {
+ PDC_LOG(("doupdate() - Transforming line %d of %d: %s\n",
+ y, SP->lines, (curscr->_firstch[y] != _NO_CHANGE) ?
+ "Yes" : "No"));
+
+ if (clearall || curscr->_firstch[y] != _NO_CHANGE)
+ {
+ int first, last;
+
+ chtype *src = curscr->_y[y];
+ chtype *dest = SP->lastscr->_y[y];
+
+ if (clearall)
+ {
+ first = 0;
+ last = COLS - 1;
+ }
+ else
+ {
+ first = curscr->_firstch[y];
+ last = curscr->_lastch[y];
+ }
+
+ while (first <= last)
+ {
+ int len = 0;
+
+ /* build up a run of changed cells; if two runs are
+ separated by a single unchanged cell, ignore the
+ break */
+
+ if (clearall)
+ len = last - first + 1;
+ else
+ while (first + len <= last &&
+ (src[first + len] != dest[first + len] ||
+ (len && first + len < last &&
+ src[first + len + 1] != dest[first + len + 1])
+ )
+ )
+ len++;
+
+ /* update the screen, and SP->lastscr */
+
+ if (len)
+ {
+ PDC_transform_line(y, first, len, src + first);
+ memcpy(dest + first, src + first, len * sizeof(chtype));
+ first += len;
+ }
+
+ /* skip over runs of unchanged cells */
+
+ while (first <= last && src[first] == dest[first])
+ first++;
+ }
+
+ curscr->_firstch[y] = _NO_CHANGE;
+ curscr->_lastch[y] = _NO_CHANGE;
+ }
+ }
+
+ curscr->_clear = FALSE;
+
+ if (SP->visibility)
+ PDC_gotoyx(curscr->_cury, curscr->_curx);
+
+ SP->cursrow = curscr->_cury;
+ SP->curscol = curscr->_curx;
+
+ PDC_doupdate();
+
+ return OK;
+}
+
+int wrefresh(WINDOW *win)
+{
+ bool save_clear;
+
+ PDC_LOG(("wrefresh() - called\n"));
+
+ if ( !win || (win->_flags & (_PAD|_SUBPAD)) )
+ return ERR;
+
+ save_clear = win->_clear;
+
+ if (win == curscr)
+ curscr->_clear = TRUE;
+ else
+ wnoutrefresh(win);
+
+ if (save_clear && win->_maxy == SP->lines && win->_maxx == SP->cols)
+ curscr->_clear = TRUE;
+
+ return doupdate();
+}
+
+int refresh(void)
+{
+ PDC_LOG(("refresh() - called\n"));
+
+ return wrefresh(stdscr);
+}
+
+int wredrawln(WINDOW *win, int start, int num)
+{
+ int i;
+
+ PDC_LOG(("wredrawln() - called: win=%p start=%d num=%d\n",
+ win, start, num));
+
+ if (!win || start > win->_maxy || start + num > win->_maxy)
+ return ERR;
+
+ for (i = start; i < start + num; i++)
+ {
+ win->_firstch[i] = 0;
+ win->_lastch[i] = win->_maxx - 1;
+ }
+
+ return OK;
+}
+
+int redrawwin(WINDOW *win)
+{
+ PDC_LOG(("redrawwin() - called: win=%p\n", win));
+
+ if (!win)
+ return ERR;
+
+ return wredrawln(win, 0, win->_maxy);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/scanw.c b/Utilities/cmpdcurses/pdcurses/scanw.c
new file mode 100644
index 0000000..23a2d41
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/scanw.c
@@ -0,0 +1,581 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+scanw
+-----
+
+### Synopsis
+
+ int scanw(const char *fmt, ...);
+ int wscanw(WINDOW *win, const char *fmt, ...);
+ int mvscanw(int y, int x, const char *fmt, ...);
+ int mvwscanw(WINDOW *win, int y, int x, const char *fmt, ...);
+ int vwscanw(WINDOW *win, const char *fmt, va_list varglist);
+ int vw_scanw(WINDOW *win, const char *fmt, va_list varglist);
+
+### Description
+
+ These routines correspond to the standard C library's scanf() family.
+ Each gets a string from the window via wgetnstr(), and uses the
+ resulting line as input for the scan.
+
+ The duplication between vwscanw() and vw_scanw() is for historic
+ reasons. In PDCurses, they're the same.
+
+### Return Value
+
+ On successful completion, these functions return the number of items
+ successfully matched. Otherwise they return ERR.
+
+### Portability
+ X/Open ncurses NetBSD
+ scanw Y Y Y
+ wscanw Y Y Y
+ mvscanw Y Y Y
+ mvwscanw Y Y Y
+ vwscanw Y Y Y
+ vw_scanw Y Y Y
+
+**man-end****************************************************************/
+
+#include <string.h>
+
+#ifndef HAVE_VSSCANF
+# include <stdlib.h>
+# include <ctype.h>
+# include <limits.h>
+
+static int _pdc_vsscanf(const char *, const char *, va_list);
+
+# define vsscanf _pdc_vsscanf
+#endif
+
+int vwscanw(WINDOW *win, const char *fmt, va_list varglist)
+{
+ char scanbuf[256];
+
+ PDC_LOG(("vwscanw() - called\n"));
+
+ if (wgetnstr(win, scanbuf, 255) == ERR)
+ return ERR;
+
+ return vsscanf(scanbuf, fmt, varglist);
+}
+
+int scanw(const char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ PDC_LOG(("scanw() - called\n"));
+
+ va_start(args, fmt);
+ retval = vwscanw(stdscr, fmt, args);
+ va_end(args);
+
+ return retval;
+}
+
+int wscanw(WINDOW *win, const char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ PDC_LOG(("wscanw() - called\n"));
+
+ va_start(args, fmt);
+ retval = vwscanw(win, fmt, args);
+ va_end(args);
+
+ return retval;
+}
+
+int mvscanw(int y, int x, const char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ PDC_LOG(("mvscanw() - called\n"));
+
+ if (move(y, x) == ERR)
+ return ERR;
+
+ va_start(args, fmt);
+ retval = vwscanw(stdscr, fmt, args);
+ va_end(args);
+
+ return retval;
+}
+
+int mvwscanw(WINDOW *win, int y, int x, const char *fmt, ...)
+{
+ va_list args;
+ int retval;
+
+ PDC_LOG(("mvscanw() - called\n"));
+
+ if (wmove(win, y, x) == ERR)
+ return ERR;
+
+ va_start(args, fmt);
+ retval = vwscanw(win, fmt, args);
+ va_end(args);
+
+ return retval;
+}
+
+int vw_scanw(WINDOW *win, const char *fmt, va_list varglist)
+{
+ PDC_LOG(("vw_scanw() - called\n"));
+
+ return vwscanw(win, fmt, varglist);
+}
+
+#ifndef HAVE_VSSCANF
+
+/* _pdc_vsscanf() - Internal routine to parse and format an input
+ buffer. It scans a series of input fields; each field is formatted
+ according to a supplied format string and the formatted input is
+ stored in the variable number of addresses passed. Returns the number
+ of input fields or EOF on error.
+
+ Don't compile this unless required. Some compilers (at least Borland
+ C++ 3.0) have to link with math libraries due to the use of floats.
+
+ Based on vsscanf.c and input.c from emx 0.8f library source,
+ Copyright (c) 1990-1992 by Eberhard Mattes, who has kindly agreed to
+ its inclusion in PDCurses. */
+
+#define WHITE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')
+
+#define NEXT(x) \
+ do { \
+ x = *buf++; \
+ if (!x) \
+ return (count ? count : EOF); \
+ ++chars; \
+ } while (0)
+
+#define UNGETC() \
+ do { \
+ --buf; --chars; \
+ } while (0)
+
+static int _pdc_vsscanf(const char *buf, const char *fmt, va_list arg_ptr)
+{
+ int count, chars, c, width, radix, d, i;
+ int *int_ptr;
+ long *long_ptr;
+ short *short_ptr;
+ char *char_ptr;
+ unsigned char f;
+ char neg, assign, ok, size;
+ long n;
+ char map[256], end;
+ double dx, dd, *dbl_ptr;
+ float *flt_ptr;
+ int exp;
+ char eneg;
+
+ count = 0;
+ chars = 0;
+ c = 0;
+ while ((f = *fmt) != 0)
+ {
+ if (WHITE(f))
+ {
+ do
+ {
+ ++fmt;
+ f = *fmt;
+ }
+ while (WHITE(f));
+ do
+ {
+ c = *buf++;
+ if (!c)
+ {
+ if (!f || count)
+ return count;
+ else
+ return EOF;
+ } else
+ ++chars;
+ }
+ while (WHITE(c));
+ UNGETC();
+ } else if (f != '%')
+ {
+ NEXT(c);
+ if (c != f)
+ return count;
+ ++fmt;
+ } else
+ {
+ assign = TRUE;
+ width = INT_MAX;
+ char_ptr = NULL;
+ ++fmt;
+ if (*fmt == '*')
+ {
+ assign = FALSE;
+ ++fmt;
+ }
+ if (isdigit(*fmt))
+ {
+ width = 0;
+ while (isdigit(*fmt))
+ width = width * 10 + (*fmt++ - '0');
+ if (!width)
+ width = INT_MAX;
+ }
+ size = 0;
+ if (*fmt == 'h' || *fmt == 'l')
+ size = *fmt++;
+ f = *fmt;
+ switch (f)
+ {
+ case 'c':
+ if (width == INT_MAX)
+ width = 1;
+ if (assign)
+ char_ptr = va_arg(arg_ptr, char *);
+ while (width > 0)
+ {
+ --width;
+ NEXT(c);
+ if (assign)
+ {
+ *char_ptr++ = (char) c;
+ ++count;
+ }
+ }
+ break;
+ case '[':
+ memset(map, 0, 256);
+ end = 0;
+ ++fmt;
+ if (*fmt == '^')
+ {
+ ++fmt;
+ end = 1;
+ }
+ i = 0;
+ for (;;)
+ {
+ f = (unsigned char) *fmt;
+ switch (f)
+ {
+ case 0:
+ /* avoid skipping past 0 */
+ --fmt;
+ NEXT(c);
+ goto string;
+ case ']':
+ if (i > 0)
+ {
+ NEXT(c);
+ goto string;
+ }
+ /* no break */
+ default:
+ if (fmt[1] == '-' && fmt[2]
+ && f < (unsigned char)fmt[2])
+ {
+ memset(map + f, 1, (unsigned char)fmt[2] - f);
+ fmt += 2;
+ }
+ else
+ map[f] = 1;
+ break;
+ }
+ ++fmt;
+ ++i;
+ }
+ case 's':
+ memset(map, 0, 256);
+ map[' '] = 1;
+ map['\n'] = 1;
+ map['\r'] = 1;
+ map['\t'] = 1;
+ end = 1;
+ do
+ {
+ NEXT(c);
+ }
+ while (WHITE(c));
+ string:
+ if (assign)
+ char_ptr = va_arg(arg_ptr, char *);
+ while (width > 0 && map[(unsigned char) c] != end)
+ {
+ --width;
+ if (assign)
+ *char_ptr++ = (char) c;
+ c = *buf++;
+ if (!c)
+ break;
+ else
+ ++chars;
+ }
+ if (assign)
+ {
+ *char_ptr = 0;
+ ++count;
+ }
+ if (!c)
+ return count;
+ else
+ UNGETC();
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ neg = ok = FALSE;
+ dx = 0.0;
+ do
+ {
+ NEXT(c);
+ }
+ while (WHITE(c));
+ if (c == '+')
+ {
+ NEXT(c);
+ --width;
+ } else if (c == '-')
+ {
+ neg = TRUE;
+ NEXT(c);
+ --width;
+ }
+ while (width > 0 && isdigit(c))
+ {
+ --width;
+ dx = dx * 10.0 + (double) (c - '0');
+ ok = TRUE;
+ c = *buf++;
+ if (!c)
+ break;
+ else
+ ++chars;
+ }
+ if (width > 0 && c == '.')
+ {
+ --width;
+ dd = 10.0;
+ NEXT(c);
+ while (width > 0 && isdigit(c))
+ {
+ --width;
+ dx += (double) (c - '0') / dd;
+ dd *= 10.0;
+ ok = TRUE;
+ c = *buf++;
+ if (!c)
+ break;
+ else
+ ++chars;
+ }
+ }
+ if (!ok)
+ return count;
+ if (width > 0 && (c == 'e' || c == 'E'))
+ {
+ eneg = FALSE;
+ exp = 0;
+ NEXT(c);
+ --width;
+ if (width > 0 && c == '+')
+ {
+ NEXT(c);
+ --width;
+ } else if (width > 0 && c == '-')
+ {
+ eneg = TRUE;
+ NEXT(c);
+ --width;
+ }
+ if (!(width > 0 && isdigit(c)))
+ {
+ UNGETC();
+ return count;
+ }
+ while (width > 0 && isdigit(c))
+ {
+ --width;
+ exp = exp * 10 + (c - '0');
+ c = *buf++;
+ if (!c)
+ break;
+ else
+ ++chars;
+ }
+ if (eneg)
+ exp = -exp;
+ while (exp > 0)
+ {
+ dx *= 10.0;
+ --exp;
+ }
+ while (exp < 0)
+ {
+ dx /= 10.0;
+ ++exp;
+ }
+ }
+ if (assign)
+ {
+ if (neg)
+ dx = -dx;
+ if (size == 'l')
+ {
+ dbl_ptr = va_arg(arg_ptr, double *);
+ *dbl_ptr = dx;
+ }
+ else
+ {
+ flt_ptr = va_arg(arg_ptr, float *);
+ *flt_ptr = (float)dx;
+ }
+ ++count;
+ }
+ if (!c)
+ return count;
+ else
+ UNGETC();
+ break;
+ case 'i':
+ neg = FALSE;
+ radix = 10;
+ do
+ {
+ NEXT(c);
+ }
+ while (WHITE(c));
+ if (!(width > 0 && c == '0'))
+ goto scan_complete_number;
+ NEXT(c);
+ --width;
+ if (width > 0 && (c == 'x' || c == 'X'))
+ {
+ NEXT(c);
+ radix = 16;
+ --width;
+ }
+ else if (width > 0 && (c >= '0' && c <= '7'))
+ radix = 8;
+ goto scan_unsigned_number;
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ do
+ {
+ NEXT(c);
+ }
+ while (WHITE(c));
+ switch (f)
+ {
+ case 'o':
+ radix = 8;
+ break;
+ case 'x':
+ case 'X':
+ radix = 16;
+ break;
+ default:
+ radix = 10;
+ break;
+ }
+ scan_complete_number:
+ neg = FALSE;
+ if (width > 0 && c == '+')
+ {
+ NEXT(c);
+ --width;
+ }
+ else if (width > 0 && c == '-' && radix == 10)
+ {
+ neg = TRUE;
+ NEXT(c);
+ --width;
+ }
+ scan_unsigned_number:
+ n = 0;
+ ok = FALSE;
+ while (width > 0)
+ {
+ --width;
+ if (isdigit(c))
+ d = c - '0';
+ else if (isupper(c))
+ d = c - 'A' + 10;
+ else if (islower(c))
+ d = c - 'a' + 10;
+ else
+ break;
+ if (d < 0 || d >= radix)
+ break;
+ ok = TRUE;
+ n = n * radix + d;
+ c = *buf++;
+ if (!c)
+ break;
+ else
+ ++chars;
+ }
+ if (!ok)
+ return count;
+ if (assign)
+ {
+ if (neg)
+ n = -n;
+ switch (size)
+ {
+ case 'h':
+ short_ptr = va_arg(arg_ptr, short *);
+ *short_ptr = (short) n;
+ break;
+ case 'l':
+ long_ptr = va_arg(arg_ptr, long *);
+ *long_ptr = (long) n;
+ break;
+ default:
+ int_ptr = va_arg(arg_ptr, int *);
+ *int_ptr = (int) n;
+ }
+ ++count;
+ }
+ if (!c)
+ return count;
+ else
+ UNGETC();
+ break;
+ case 'n':
+ if (assign)
+ {
+ int_ptr = va_arg(arg_ptr, int *);
+ *int_ptr = chars;
+ ++count;
+ }
+ break;
+ default:
+ if (!f) /* % at end of string */
+ return count;
+ NEXT(c);
+ if (c != f)
+ return count;
+ break;
+ }
+ ++fmt;
+ }
+ }
+ return count;
+}
+#endif /* HAVE_VSSCANF */
diff --git a/Utilities/cmpdcurses/pdcurses/scr_dump.c b/Utilities/cmpdcurses/pdcurses/scr_dump.c
new file mode 100644
index 0000000..d9105bd
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/scr_dump.c
@@ -0,0 +1,217 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+scr_dump
+--------
+
+### Synopsis
+
+ int putwin(WINDOW *win, FILE *filep);
+ WINDOW *getwin(FILE *filep);
+ int scr_dump(const char *filename);
+ int scr_init(const char *filename);
+ int scr_restore(const char *filename);
+ int scr_set(const char *filename);
+
+### Description
+
+ getwin() reads window-related data previously stored in a file by
+ putwin(). It then creates and initialises a new window using that
+ data.
+
+ putwin() writes all data associated with a window into a file, using
+ an unspecified format. This information can be retrieved later using
+ getwin().
+
+ scr_dump() writes the current contents of the virtual screen to the
+ file named by filename in an unspecified format.
+
+ scr_restore() function sets the virtual screen to the contents of the
+ file named by filename, which must have been written using
+ scr_dump(). The next refresh operation restores the screen to the way
+ it looked in the dump file.
+
+ In PDCurses, scr_init() does nothing, and scr_set() is a synonym for
+ scr_restore(). Also, scr_dump() and scr_restore() save and load from
+ curscr. This differs from some other implementations, where
+ scr_init() works with curscr, and scr_restore() works with newscr;
+ but the effect should be the same. (PDCurses has no newscr.)
+
+### Return Value
+
+ On successful completion, getwin() returns a pointer to the window it
+ created. Otherwise, it returns a null pointer. Other functions return
+ OK or ERR.
+
+### Portability
+ X/Open ncurses NetBSD
+ putwin Y Y Y
+ getwin Y Y Y
+ scr_dump Y Y -
+ scr_init Y Y -
+ scr_restore Y Y -
+ scr_set Y Y -
+
+**man-end****************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#define DUMPVER 1 /* Should be updated whenever the WINDOW struct is
+ changed */
+
+int putwin(WINDOW *win, FILE *filep)
+{
+ static const char *marker = "PDC";
+ static const unsigned char version = DUMPVER;
+
+ PDC_LOG(("putwin() - called\n"));
+
+ /* write the marker and the WINDOW struct */
+
+ if (filep && fwrite(marker, strlen(marker), 1, filep)
+ && fwrite(&version, 1, 1, filep)
+ && fwrite(win, sizeof(WINDOW), 1, filep))
+ {
+ int i;
+
+ /* write each line */
+
+ for (i = 0; i < win->_maxy && win->_y[i]; i++)
+ if (!fwrite(win->_y[i], win->_maxx * sizeof(chtype), 1, filep))
+ return ERR;
+
+ return OK;
+ }
+
+ return ERR;
+}
+
+WINDOW *getwin(FILE *filep)
+{
+ WINDOW *win;
+ char marker[4];
+ int i, nlines, ncols;
+
+ PDC_LOG(("getwin() - called\n"));
+
+ win = malloc(sizeof(WINDOW));
+ if (!win)
+ return (WINDOW *)NULL;
+
+ /* check for the marker, and load the WINDOW struct */
+
+ if (!filep || !fread(marker, 4, 1, filep) || strncmp(marker, "PDC", 3)
+ || marker[3] != DUMPVER || !fread(win, sizeof(WINDOW), 1, filep))
+ {
+ free(win);
+ return (WINDOW *)NULL;
+ }
+
+ nlines = win->_maxy;
+ ncols = win->_maxx;
+
+ /* allocate the line pointer array */
+
+ win->_y = malloc(nlines * sizeof(chtype *));
+ if (!win->_y)
+ {
+ free(win);
+ return (WINDOW *)NULL;
+ }
+
+ /* allocate the minchng and maxchng arrays */
+
+ win->_firstch = malloc(nlines * sizeof(int));
+ if (!win->_firstch)
+ {
+ free(win->_y);
+ free(win);
+ return (WINDOW *)NULL;
+ }
+
+ win->_lastch = malloc(nlines * sizeof(int));
+ if (!win->_lastch)
+ {
+ free(win->_firstch);
+ free(win->_y);
+ free(win);
+ return (WINDOW *)NULL;
+ }
+
+ /* allocate the lines */
+
+ win = PDC_makelines(win);
+ if (!win)
+ return (WINDOW *)NULL;
+
+ /* read them */
+
+ for (i = 0; i < nlines; i++)
+ {
+ if (!fread(win->_y[i], ncols * sizeof(chtype), 1, filep))
+ {
+ delwin(win);
+ return (WINDOW *)NULL;
+ }
+ }
+
+ touchwin(win);
+
+ return win;
+}
+
+int scr_dump(const char *filename)
+{
+ FILE *filep;
+
+ PDC_LOG(("scr_dump() - called: filename %s\n", filename));
+
+ if (filename && (filep = fopen(filename, "wb")) != NULL)
+ {
+ int result = putwin(curscr, filep);
+ fclose(filep);
+ return result;
+ }
+
+ return ERR;
+}
+
+int scr_init(const char *filename)
+{
+ PDC_LOG(("scr_init() - called: filename %s\n", filename));
+
+ return OK;
+}
+
+int scr_restore(const char *filename)
+{
+ FILE *filep;
+
+ PDC_LOG(("scr_restore() - called: filename %s\n", filename));
+
+ if (filename && (filep = fopen(filename, "rb")) != NULL)
+ {
+ WINDOW *replacement = getwin(filep);
+ fclose(filep);
+
+ if (replacement)
+ {
+ int result = overwrite(replacement, curscr);
+ delwin(replacement);
+ return result;
+ }
+ }
+
+ return ERR;
+}
+
+int scr_set(const char *filename)
+{
+ PDC_LOG(("scr_set() - called: filename %s\n", filename));
+
+ return scr_restore(filename);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/scroll.c b/Utilities/cmpdcurses/pdcurses/scroll.c
new file mode 100644
index 0000000..ffe8d0d
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/scroll.c
@@ -0,0 +1,101 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+scroll
+------
+
+### Synopsis
+
+ int scroll(WINDOW *win);
+ int scrl(int n);
+ int wscrl(WINDOW *win, int n);
+
+### Description
+
+ scroll() causes the window to scroll up one line. This involves
+ moving the lines in the window data strcture.
+
+ With a positive n, scrl() and wscrl() scroll the window up n lines
+ (line i + n becomes i); otherwise they scroll the window down n
+ lines.
+
+ For these functions to work, scrolling must be enabled via
+ scrollok(). Note also that scrolling is not allowed if the supplied
+ window is a pad.
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ scroll Y Y Y
+ scrl Y Y Y
+ wscrl Y Y Y
+
+**man-end****************************************************************/
+
+int wscrl(WINDOW *win, int n)
+{
+ int i, l, dir, start, end;
+ chtype blank, *temp;
+
+ /* Check if window scrolls. Valid for window AND pad */
+
+ if (!win || !win->_scroll || !n)
+ return ERR;
+
+ blank = win->_bkgd;
+
+ if (n > 0)
+ {
+ start = win->_tmarg;
+ end = win->_bmarg;
+ dir = 1;
+ }
+ else
+ {
+ start = win->_bmarg;
+ end = win->_tmarg;
+ dir = -1;
+ }
+
+ for (l = 0; l < (n * dir); l++)
+ {
+ temp = win->_y[start];
+
+ /* re-arrange line pointers */
+
+ for (i = start; i != end; i += dir)
+ win->_y[i] = win->_y[i + dir];
+
+ win->_y[end] = temp;
+
+ /* make a blank line */
+
+ for (i = 0; i < win->_maxx; i++)
+ *temp++ = blank;
+ }
+
+ touchline(win, win->_tmarg, win->_bmarg - win->_tmarg + 1);
+
+ PDC_sync(win);
+ return OK;
+}
+
+int scrl(int n)
+{
+ PDC_LOG(("scrl() - called\n"));
+
+ return wscrl(stdscr, n);
+}
+
+int scroll(WINDOW *win)
+{
+ PDC_LOG(("scroll() - called\n"));
+
+ return wscrl(win, 1);
+}
diff --git a/Utilities/cmpdcurses/pdcurses/slk.c b/Utilities/cmpdcurses/pdcurses/slk.c
new file mode 100644
index 0000000..4fdfee1
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/slk.c
@@ -0,0 +1,671 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+slk
+---
+
+### Synopsis
+
+ int slk_init(int fmt);
+ int slk_set(int labnum, const char *label, int justify);
+ int slk_refresh(void);
+ int slk_noutrefresh(void);
+ char *slk_label(int labnum);
+ int slk_clear(void);
+ int slk_restore(void);
+ int slk_touch(void);
+ int slk_attron(const chtype attrs);
+ int slk_attr_on(const attr_t attrs, void *opts);
+ int slk_attrset(const chtype attrs);
+ int slk_attr_set(const attr_t attrs, short color_pair, void *opts);
+ int slk_attroff(const chtype attrs);
+ int slk_attr_off(const attr_t attrs, void *opts);
+ int slk_color(short color_pair);
+
+ int slk_wset(int labnum, const wchar_t *label, int justify);
+
+ int PDC_mouse_in_slk(int y, int x);
+ void PDC_slk_free(void);
+ void PDC_slk_initialize(void);
+
+ wchar_t *slk_wlabel(int labnum)
+
+### Description
+
+ These functions manipulate a window that contain Soft Label Keys
+ (SLK). To use the SLK functions, a call to slk_init() must be made
+ BEFORE initscr() or newterm(). slk_init() removes 1 or 2 lines from
+ the useable screen, depending on the format selected.
+
+ The line(s) removed from the screen are used as a separate window, in
+ which SLKs are displayed.
+
+ slk_init() requires a single parameter which describes the format of
+ the SLKs as follows:
+
+ 0 3-2-3 format
+ 1 4-4 format
+ 2 4-4-4 format (ncurses extension)
+ 3 4-4-4 format with index line (ncurses extension)
+ 2 lines used
+ 55 5-5 format (pdcurses format)
+
+ slk_refresh(), slk_noutrefresh() and slk_touch() are analogous to
+ refresh(), noutrefresh() and touch().
+
+### Return Value
+
+ All functions return OK on success and ERR on error.
+
+### Portability
+ X/Open ncurses NetBSD
+ slk_init Y Y Y
+ slk_set Y Y Y
+ slk_refresh Y Y Y
+ slk_noutrefresh Y Y Y
+ slk_label Y Y Y
+ slk_clear Y Y Y
+ slk_restore Y Y Y
+ slk_touch Y Y Y
+ slk_attron Y Y Y
+ slk_attrset Y Y Y
+ slk_attroff Y Y Y
+ slk_attr_on Y Y Y
+ slk_attr_set Y Y Y
+ slk_attr_off Y Y Y
+ slk_wset Y Y Y
+ PDC_mouse_in_slk - - -
+ PDC_slk_free - - -
+ PDC_slk_initialize - - -
+ slk_wlabel - - -
+
+**man-end****************************************************************/
+
+#include <stdlib.h>
+
+enum { LABEL_NORMAL = 8, LABEL_EXTENDED = 10, LABEL_NCURSES_EXTENDED = 12 };
+
+static int label_length = 0;
+static int labels = 0;
+static int label_fmt = 0;
+static int label_line = 0;
+static bool hidden = FALSE;
+
+static struct SLK {
+ chtype label[32];
+ int len;
+ int format;
+ int start_col;
+} *slk = (struct SLK *)NULL;
+
+/* slk_init() is the slk initialization routine.
+ This must be called before initscr().
+
+ label_fmt = 0, 1 or 55.
+ 0 = 3-2-3 format
+ 1 = 4 - 4 format
+ 2 = 4-4-4 format (ncurses extension for PC 12 function keys)
+ 3 = 4-4-4 format (ncurses extension for PC 12 function keys -
+ with index line)
+ 55 = 5 - 5 format (extended for PC, 10 function keys) */
+
+int slk_init(int fmt)
+{
+ PDC_LOG(("slk_init() - called\n"));
+
+ if (SP)
+ return ERR;
+
+ switch (fmt)
+ {
+ case 0: /* 3 - 2 - 3 */
+ labels = LABEL_NORMAL;
+ break;
+
+ case 1: /* 4 - 4 */
+ labels = LABEL_NORMAL;
+ break;
+
+ case 2: /* 4 4 4 */
+ labels = LABEL_NCURSES_EXTENDED;
+ break;
+
+ case 3: /* 4 4 4 with index */
+ labels = LABEL_NCURSES_EXTENDED;
+ break;
+
+ case 55: /* 5 - 5 */
+ labels = LABEL_EXTENDED;
+ break;
+
+ default:
+ return ERR;
+ }
+
+ label_fmt = fmt;
+
+ slk = calloc(labels, sizeof(struct SLK));
+
+ if (!slk)
+ labels = 0;
+
+ return slk ? OK : ERR;
+}
+
+/* draw a single button */
+
+static void _drawone(int num)
+{
+ int i, col, slen;
+
+ if (hidden)
+ return;
+
+ slen = slk[num].len;
+
+ switch (slk[num].format)
+ {
+ case 0: /* LEFT */
+ col = 0;
+ break;
+
+ case 1: /* CENTER */
+ col = (label_length - slen) / 2;
+
+ if (col + slen > label_length)
+ --col;
+ break;
+
+ default: /* RIGHT */
+ col = label_length - slen;
+ }
+
+ wmove(SP->slk_winptr, label_line, slk[num].start_col);
+
+ for (i = 0; i < label_length; ++i)
+ waddch(SP->slk_winptr, (i >= col && i < (col + slen)) ?
+ slk[num].label[i - col] : ' ');
+}
+
+/* redraw each button */
+
+static void _redraw(void)
+{
+ int i;
+
+ for (i = 0; i < labels; ++i)
+ _drawone(i);
+}
+
+/* slk_set() Used to set a slk label to a string.
+
+ labnum = 1 - 8 (or 10) (number of the label)
+ label = string (8 or 7 bytes total), or NULL
+ justify = 0 : left, 1 : center, 2 : right */
+
+int slk_set(int labnum, const char *label, int justify)
+{
+#ifdef PDC_WIDE
+ wchar_t wlabel[32];
+
+ PDC_mbstowcs(wlabel, label, 31);
+ return slk_wset(labnum, wlabel, justify);
+#else
+ PDC_LOG(("slk_set() - called\n"));
+
+ if (labnum < 1 || labnum > labels || justify < 0 || justify > 2)
+ return ERR;
+
+ labnum--;
+
+ if (!label || !(*label))
+ {
+ /* Clear the label */
+
+ *slk[labnum].label = 0;
+ slk[labnum].format = 0;
+ slk[labnum].len = 0;
+ }
+ else
+ {
+ int i, j = 0;
+
+ /* Skip leading spaces */
+
+ while (label[j] == ' ')
+ j++;
+
+ /* Copy it */
+
+ for (i = 0; i < label_length; i++)
+ {
+ chtype ch = label[i + j];
+
+ slk[labnum].label[i] = ch;
+
+ if (!ch)
+ break;
+ }
+
+ /* Drop trailing spaces */
+
+ while ((i + j) && (label[i + j - 1] == ' '))
+ i--;
+
+ slk[labnum].label[i] = 0;
+ slk[labnum].format = justify;
+ slk[labnum].len = i;
+ }
+
+ _drawone(labnum);
+
+ return OK;
+#endif
+}
+
+int slk_refresh(void)
+{
+ PDC_LOG(("slk_refresh() - called\n"));
+
+ return (slk_noutrefresh() == ERR) ? ERR : doupdate();
+}
+
+int slk_noutrefresh(void)
+{
+ PDC_LOG(("slk_noutrefresh() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ return wnoutrefresh(SP->slk_winptr);
+}
+
+char *slk_label(int labnum)
+{
+ static char temp[33];
+#ifdef PDC_WIDE
+ wchar_t *wtemp = slk_wlabel(labnum);
+
+ PDC_wcstombs(temp, wtemp, 32);
+#else
+ chtype *p;
+ int i;
+
+ PDC_LOG(("slk_label() - called\n"));
+
+ if (labnum < 1 || labnum > labels)
+ return (char *)0;
+
+ for (i = 0, p = slk[labnum - 1].label; *p; i++)
+ temp[i] = *p++;
+
+ temp[i] = '\0';
+#endif
+ return temp;
+}
+
+int slk_clear(void)
+{
+ PDC_LOG(("slk_clear() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ hidden = TRUE;
+ werase(SP->slk_winptr);
+ return wrefresh(SP->slk_winptr);
+}
+
+int slk_restore(void)
+{
+ PDC_LOG(("slk_restore() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ hidden = FALSE;
+ _redraw();
+ return wrefresh(SP->slk_winptr);
+}
+
+int slk_touch(void)
+{
+ PDC_LOG(("slk_touch() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ return touchwin(SP->slk_winptr);
+}
+
+int slk_attron(const chtype attrs)
+{
+ int rc;
+
+ PDC_LOG(("slk_attron() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ rc = wattron(SP->slk_winptr, attrs);
+ _redraw();
+
+ return rc;
+}
+
+int slk_attr_on(const attr_t attrs, void *opts)
+{
+ PDC_LOG(("slk_attr_on() - called\n"));
+
+ return slk_attron(attrs);
+}
+
+int slk_attroff(const chtype attrs)
+{
+ int rc;
+
+ PDC_LOG(("slk_attroff() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ rc = wattroff(SP->slk_winptr, attrs);
+ _redraw();
+
+ return rc;
+}
+
+int slk_attr_off(const attr_t attrs, void *opts)
+{
+ PDC_LOG(("slk_attr_off() - called\n"));
+
+ return slk_attroff(attrs);
+}
+
+int slk_attrset(const chtype attrs)
+{
+ int rc;
+
+ PDC_LOG(("slk_attrset() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ rc = wattrset(SP->slk_winptr, attrs);
+ _redraw();
+
+ return rc;
+}
+
+int slk_color(short color_pair)
+{
+ int rc;
+
+ PDC_LOG(("slk_color() - called\n"));
+
+ if (!SP)
+ return ERR;
+
+ rc = wcolor_set(SP->slk_winptr, color_pair, NULL);
+ _redraw();
+
+ return rc;
+}
+
+int slk_attr_set(const attr_t attrs, short color_pair, void *opts)
+{
+ PDC_LOG(("slk_attr_set() - called\n"));
+
+ return slk_attrset(attrs | COLOR_PAIR(color_pair));
+}
+
+static void _slk_calc(void)
+{
+ int i, center, col = 0;
+ label_length = COLS / labels;
+
+ if (label_length > 31)
+ label_length = 31;
+
+ switch (label_fmt)
+ {
+ case 0: /* 3 - 2 - 3 F-Key layout */
+
+ --label_length;
+
+ slk[0].start_col = col;
+ slk[1].start_col = (col += label_length);
+ slk[2].start_col = (col += label_length);
+
+ center = COLS / 2;
+
+ slk[3].start_col = center - label_length + 1;
+ slk[4].start_col = center + 1;
+
+ col = COLS - (label_length * 3) + 1;
+
+ slk[5].start_col = col;
+ slk[6].start_col = (col += label_length);
+ slk[7].start_col = (col += label_length);
+ break;
+
+ case 1: /* 4 - 4 F-Key layout */
+
+ for (i = 0; i < 8; i++)
+ {
+ slk[i].start_col = col;
+ col += label_length;
+
+ if (i == 3)
+ col = COLS - (label_length * 4) + 1;
+ }
+
+ break;
+
+ case 2: /* 4 4 4 F-Key layout */
+ case 3: /* 4 4 4 F-Key layout with index */
+
+ for (i = 0; i < 4; i++)
+ {
+ slk[i].start_col = col;
+ col += label_length;
+ }
+
+ center = COLS / 2;
+
+ slk[4].start_col = center - (label_length * 2) + 1;
+ slk[5].start_col = center - label_length + 1;
+ slk[6].start_col = center + 1;
+ slk[7].start_col = center + label_length + 1;
+
+ col = COLS - (label_length * 4) + 1;
+
+ for (i = 8; i < 12; i++)
+ {
+ slk[i].start_col = col;
+ col += label_length;
+ }
+
+ break;
+
+ default: /* 5 - 5 F-Key layout */
+
+ for (i = 0; i < 10; i++)
+ {
+ slk[i].start_col = col;
+ col += label_length;
+
+ if (i == 4)
+ col = COLS - (label_length * 5) + 1;
+ }
+ }
+
+ --label_length;
+
+ /* make sure labels are all in window */
+
+ _redraw();
+}
+
+void PDC_slk_initialize(void)
+{
+ if (slk)
+ {
+ if (label_fmt == 3)
+ {
+ SP->slklines = 2;
+ label_line = 1;
+ }
+ else
+ SP->slklines = 1;
+
+ if (!SP->slk_winptr)
+ {
+ SP->slk_winptr = newwin(SP->slklines, COLS,
+ LINES - SP->slklines, 0);
+ if (!SP->slk_winptr)
+ return;
+
+ wattrset(SP->slk_winptr, A_REVERSE);
+ }
+
+ _slk_calc();
+
+ /* if we have an index line, display it now */
+
+ if (label_fmt == 3)
+ {
+ chtype save_attr;
+ int i;
+
+ save_attr = SP->slk_winptr->_attrs;
+ wattrset(SP->slk_winptr, A_NORMAL);
+ wmove(SP->slk_winptr, 0, 0);
+ whline(SP->slk_winptr, 0, COLS);
+
+ for (i = 0; i < labels; i++)
+ mvwprintw(SP->slk_winptr, 0, slk[i].start_col, "F%d", i + 1);
+
+ SP->slk_winptr->_attrs = save_attr;
+ }
+
+ touchwin(SP->slk_winptr);
+ }
+}
+
+void PDC_slk_free(void)
+{
+ if (slk)
+ {
+ if (SP->slk_winptr)
+ {
+ delwin(SP->slk_winptr);
+ SP->slk_winptr = (WINDOW *)NULL;
+ }
+
+ free(slk);
+ slk = (struct SLK *)NULL;
+
+ label_length = 0;
+ labels = 0;
+ label_fmt = 0;
+ label_line = 0;
+ hidden = FALSE;
+ }
+}
+
+int PDC_mouse_in_slk(int y, int x)
+{
+ int i;
+
+ PDC_LOG(("PDC_mouse_in_slk() - called: y->%d x->%d\n", y, x));
+
+ /* If the line on which the mouse was clicked is NOT the last line
+ of the screen, we are not interested in it. */
+
+ if (!slk || !SP->slk_winptr || (y != SP->slk_winptr->_begy + label_line))
+ return 0;
+
+ for (i = 0; i < labels; i++)
+ if (x >= slk[i].start_col && x < (slk[i].start_col + label_length))
+ return i + 1;
+
+ return 0;
+}
+
+#ifdef PDC_WIDE
+int slk_wset(int labnum, const wchar_t *label, int justify)
+{
+ PDC_LOG(("slk_wset() - called\n"));
+
+ if (labnum < 1 || labnum > labels || justify < 0 || justify > 2)
+ return ERR;
+
+ labnum--;
+
+ if (!label || !(*label))
+ {
+ /* Clear the label */
+
+ *slk[labnum].label = 0;
+ slk[labnum].format = 0;
+ slk[labnum].len = 0;
+ }
+ else
+ {
+ int i, j = 0;
+
+ /* Skip leading spaces */
+
+ while (label[j] == L' ')
+ j++;
+
+ /* Copy it */
+
+ for (i = 0; i < label_length; i++)
+ {
+ chtype ch = label[i + j];
+
+ slk[labnum].label[i] = ch;
+
+ if (!ch)
+ break;
+ }
+
+ /* Drop trailing spaces */
+
+ while ((i + j) && (label[i + j - 1] == L' '))
+ i--;
+
+ slk[labnum].label[i] = 0;
+ slk[labnum].format = justify;
+ slk[labnum].len = i;
+ }
+
+ _drawone(labnum);
+
+ return OK;
+}
+
+wchar_t *slk_wlabel(int labnum)
+{
+ static wchar_t temp[33];
+ chtype *p;
+ int i;
+
+ PDC_LOG(("slk_wlabel() - called\n"));
+
+ if (labnum < 1 || labnum > labels)
+ return (wchar_t *)0;
+
+ for (i = 0, p = slk[labnum - 1].label; *p; i++)
+ temp[i] = *p++;
+
+ temp[i] = '\0';
+
+ return temp;
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/termattr.c b/Utilities/cmpdcurses/pdcurses/termattr.c
new file mode 100644
index 0000000..afb143d
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/termattr.c
@@ -0,0 +1,172 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+termattr
+--------
+
+### Synopsis
+
+ int baudrate(void);
+ char erasechar(void);
+ bool has_ic(void);
+ bool has_il(void);
+ char killchar(void);
+ char *longname(void);
+ chtype termattrs(void);
+ attr_t term_attrs(void);
+ char *termname(void);
+
+ int erasewchar(wchar_t *ch);
+ int killwchar(wchar_t *ch);
+
+ char wordchar(void);
+
+### Description
+
+ baudrate() is supposed to return the output speed of the terminal. In
+ PDCurses, it simply returns INT_MAX.
+
+ has_ic and has_il() return TRUE. These functions have meaning in some
+ other implementations of curses.
+
+ erasechar() and killchar() return ^H and ^U, respectively -- the
+ ERASE and KILL characters. In other curses implementations, these may
+ vary by terminal type. erasewchar() and killwchar() are the wide-
+ character versions; they take a pointer to a location in which to
+ store the character, and return OK or ERR.
+
+ longname() returns a pointer to a static area containing a verbose
+ description of the current terminal. The maximum length of the string
+ is 128 characters. It is defined only after the call to initscr() or
+ newterm().
+
+ termname() returns a pointer to a static area containing a short
+ description of the current terminal (14 characters).
+
+ termattrs() returns a logical OR of all video attributes supported by
+ the terminal.
+
+ wordchar() is a PDCurses extension of the concept behind the
+ functions erasechar() and killchar(), returning the "delete word"
+ character, ^W.
+
+### Portability
+ X/Open ncurses NetBSD
+ baudrate Y Y Y
+ erasechar Y Y Y
+ has_ic Y Y Y
+ has_il Y Y Y
+ killchar Y Y Y
+ longname Y Y Y
+ termattrs Y Y Y
+ termname Y Y Y
+ erasewchar Y Y Y
+ killwchar Y Y Y
+ term_attrs Y Y Y
+ wordchar - - -
+
+**man-end****************************************************************/
+
+#include <string.h>
+#include <limits.h>
+
+int baudrate(void)
+{
+ PDC_LOG(("baudrate() - called\n"));
+
+ return INT_MAX;
+}
+
+char erasechar(void)
+{
+ PDC_LOG(("erasechar() - called\n"));
+
+ return _ECHAR; /* character delete char (^H) */
+}
+
+bool has_ic(void)
+{
+ PDC_LOG(("has_ic() - called\n"));
+
+ return TRUE;
+}
+
+bool has_il(void)
+{
+ PDC_LOG(("has_il() - called\n"));
+
+ return TRUE;
+}
+
+char killchar(void)
+{
+ PDC_LOG(("killchar() - called\n"));
+
+ return _DLCHAR; /* line delete char (^U) */
+}
+
+char *longname(void)
+{
+ PDC_LOG(("longname() - called\n"));
+
+ return ttytype + 9; /* skip "pdcurses|" */
+}
+
+chtype termattrs(void)
+{
+ PDC_LOG(("termattrs() - called\n"));
+
+ return SP ? SP->termattrs : (chtype)0;
+}
+
+attr_t term_attrs(void)
+{
+ PDC_LOG(("term_attrs() - called\n"));
+
+ return SP ? SP->termattrs : (attr_t)0;
+}
+
+char *termname(void)
+{
+ static char _termname[14] = "pdcurses";
+
+ PDC_LOG(("termname() - called\n"));
+
+ return _termname;
+}
+
+char wordchar(void)
+{
+ PDC_LOG(("wordchar() - called\n"));
+
+ return _DWCHAR; /* word delete char */
+}
+
+#ifdef PDC_WIDE
+int erasewchar(wchar_t *ch)
+{
+ PDC_LOG(("erasewchar() - called\n"));
+
+ if (!ch)
+ return ERR;
+
+ *ch = (wchar_t)_ECHAR;
+
+ return OK;
+}
+
+int killwchar(wchar_t *ch)
+{
+ PDC_LOG(("killwchar() - called\n"));
+
+ if (!ch)
+ return ERR;
+
+ *ch = (wchar_t)_DLCHAR;
+
+ return OK;
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/touch.c b/Utilities/cmpdcurses/pdcurses/touch.c
new file mode 100644
index 0000000..e1b7c60
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/touch.c
@@ -0,0 +1,199 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+touch
+-----
+
+### Synopsis
+
+ int touchwin(WINDOW *win);
+ int touchline(WINDOW *win, int start, int count);
+ int untouchwin(WINDOW *win);
+ int wtouchln(WINDOW *win, int y, int n, int changed);
+ bool is_linetouched(WINDOW *win, int line);
+ bool is_wintouched(WINDOW *win);
+
+ int touchoverlap(const WINDOW *win1, WINDOW *win2);
+
+### Description
+
+ touchwin() and touchline() throw away all information about which
+ parts of the window have been touched, pretending that the entire
+ window has been drawn on. This is sometimes necessary when using
+ overlapping windows, since a change to one window will affect the
+ other window, but the records of which lines have been changed in the
+ other window will not reflect the change.
+
+ untouchwin() marks all lines in the window as unchanged since the
+ last call to wrefresh().
+
+ wtouchln() makes n lines in the window, starting at line y, look as
+ if they have (changed == 1) or have not (changed == 0) been changed
+ since the last call to wrefresh().
+
+ is_linetouched() returns TRUE if the specified line in the specified
+ window has been changed since the last call to wrefresh().
+
+ is_wintouched() returns TRUE if the specified window has been changed
+ since the last call to wrefresh().
+
+ touchoverlap(win1, win2) marks the portion of win2 which overlaps
+ with win1 as modified.
+
+### Return Value
+
+ All functions return OK on success and ERR on error except
+ is_wintouched() and is_linetouched().
+
+### Portability
+ X/Open ncurses NetBSD
+ touchwin Y Y Y
+ touchline Y Y Y
+ untouchwin Y Y Y
+ wtouchln Y Y Y
+ is_linetouched Y Y Y
+ is_wintouched Y Y Y
+ touchoverlap - - Y
+
+**man-end****************************************************************/
+
+int touchwin(WINDOW *win)
+{
+ int i;
+
+ PDC_LOG(("touchwin() - called: Win=%x\n", win));
+
+ if (!win)
+ return ERR;
+
+ for (i = 0; i < win->_maxy; i++)
+ {
+ win->_firstch[i] = 0;
+ win->_lastch[i] = win->_maxx - 1;
+ }
+
+ return OK;
+}
+
+int touchline(WINDOW *win, int start, int count)
+{
+ int i;
+
+ PDC_LOG(("touchline() - called: win=%p start %d count %d\n",
+ win, start, count));
+
+ if (!win || start > win->_maxy || start + count > win->_maxy)
+ return ERR;
+
+ for (i = start; i < start + count; i++)
+ {
+ win->_firstch[i] = 0;
+ win->_lastch[i] = win->_maxx - 1;
+ }
+
+ return OK;
+}
+
+int untouchwin(WINDOW *win)
+{
+ int i;
+
+ PDC_LOG(("untouchwin() - called: win=%p", win));
+
+ if (!win)
+ return ERR;
+
+ for (i = 0; i < win->_maxy; i++)
+ {
+ win->_firstch[i] = _NO_CHANGE;
+ win->_lastch[i] = _NO_CHANGE;
+ }
+
+ return OK;
+}
+
+int wtouchln(WINDOW *win, int y, int n, int changed)
+{
+ int i;
+
+ PDC_LOG(("wtouchln() - called: win=%p y=%d n=%d changed=%d\n",
+ win, y, n, changed));
+
+ if (!win || y > win->_maxy || y + n > win->_maxy)
+ return ERR;
+
+ for (i = y; i < y + n; i++)
+ {
+ if (changed)
+ {
+ win->_firstch[i] = 0;
+ win->_lastch[i] = win->_maxx - 1;
+ }
+ else
+ {
+ win->_firstch[i] = _NO_CHANGE;
+ win->_lastch[i] = _NO_CHANGE;
+ }
+ }
+
+ return OK;
+}
+
+bool is_linetouched(WINDOW *win, int line)
+{
+ PDC_LOG(("is_linetouched() - called: win=%p line=%d\n", win, line));
+
+ if (!win || line > win->_maxy || line < 0)
+ return FALSE;
+
+ return (win->_firstch[line] != _NO_CHANGE) ? TRUE : FALSE;
+}
+
+bool is_wintouched(WINDOW *win)
+{
+ int i;
+
+ PDC_LOG(("is_wintouched() - called: win=%p\n", win));
+
+ if (win)
+ for (i = 0; i < win->_maxy; i++)
+ if (win->_firstch[i] != _NO_CHANGE)
+ return TRUE;
+
+ return FALSE;
+}
+
+int touchoverlap(const WINDOW *win1, WINDOW *win2)
+{
+ int y, endy, endx, starty, startx;
+
+ PDC_LOG(("touchoverlap() - called: win1=%p win2=%p\n", win1, win2));
+
+ if (!win1 || !win2)
+ return ERR;
+
+ starty = max(win1->_begy, win2->_begy);
+ startx = max(win1->_begx, win2->_begx);
+ endy = min(win1->_maxy + win1->_begy, win2->_maxy + win2->_begy);
+ endx = min(win1->_maxx + win1->_begx, win2->_maxx + win2->_begx);
+
+ if (starty >= endy || startx >= endx)
+ return OK;
+
+ starty -= win2->_begy;
+ startx -= win2->_begx;
+ endy -= win2->_begy;
+ endx -= win2->_begx;
+ endx -= 1;
+
+ for (y = starty; y < endy; y++)
+ {
+ win2->_firstch[y] = startx;
+ win2->_lastch[y] = endx;
+ }
+
+ return OK;
+}
diff --git a/Utilities/cmpdcurses/pdcurses/util.c b/Utilities/cmpdcurses/pdcurses/util.c
new file mode 100644
index 0000000..2d29306
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/util.c
@@ -0,0 +1,308 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+util
+----
+
+### Synopsis
+
+ char *unctrl(chtype c);
+ void filter(void);
+ void use_env(bool x);
+ int delay_output(int ms);
+
+ int getcchar(const cchar_t *wcval, wchar_t *wch, attr_t *attrs,
+ short *color_pair, void *opts);
+ int setcchar(cchar_t *wcval, const wchar_t *wch, const attr_t attrs,
+ short color_pair, const void *opts);
+ wchar_t *wunctrl(cchar_t *wc);
+
+ int PDC_mbtowc(wchar_t *pwc, const char *s, size_t n);
+ size_t PDC_mbstowcs(wchar_t *dest, const char *src, size_t n);
+ size_t PDC_wcstombs(char *dest, const wchar_t *src, size_t n);
+
+### Description
+
+ unctrl() expands the text portion of the chtype c into a printable
+ string. Control characters are changed to the "^X" notation; others
+ are passed through. wunctrl() is the wide-character version of the
+ function.
+
+ filter() and use_env() are no-ops in PDCurses.
+
+ delay_output() inserts an ms millisecond pause in output.
+
+ getcchar() works in two modes: When wch is not NULL, it reads the
+ cchar_t pointed to by wcval and stores the attributes in attrs, the
+ color pair in color_pair, and the text in the wide-character string
+ wch. When wch is NULL, getcchar() merely returns the number of wide
+ characters in wcval. In either mode, the opts argument is unused.
+
+ setcchar constructs a cchar_t at wcval from the wide-character text
+ at wch, the attributes in attr and the color pair in color_pair. The
+ opts argument is unused.
+
+ Currently, the length returned by getcchar() is always 1 or 0.
+ Similarly, setcchar() will only take the first wide character from
+ wch, and ignore any others that it "should" take (i.e., combining
+ characters). Nor will it correctly handle any character outside the
+ basic multilingual plane (UCS-2).
+
+### Return Value
+
+ wunctrl() returns NULL on failure. delay_output() always returns OK.
+
+ getcchar() returns the number of wide characters wcval points to when
+ wch is NULL; when it's not, getcchar() returns OK or ERR.
+
+ setcchar() returns OK or ERR.
+
+### Portability
+ X/Open ncurses NetBSD
+ unctrl Y Y Y
+ filter Y Y Y
+ use_env Y Y Y
+ delay_output Y Y Y
+ getcchar Y Y Y
+ setcchar Y Y Y
+ wunctrl Y Y Y
+ PDC_mbtowc - - -
+ PDC_mbstowcs - - -
+ PDC_wcstombs - - -
+
+**man-end****************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+char *unctrl(chtype c)
+{
+ static char strbuf[3] = {0, 0, 0};
+
+ chtype ic;
+
+ PDC_LOG(("unctrl() - called\n"));
+
+ ic = c & A_CHARTEXT;
+
+ if (ic >= 0x20 && ic != 0x7f) /* normal characters */
+ {
+ strbuf[0] = (char)ic;
+ strbuf[1] = '\0';
+ return strbuf;
+ }
+
+ strbuf[0] = '^'; /* '^' prefix */
+
+ if (ic == 0x7f) /* 0x7f == DEL */
+ strbuf[1] = '?';
+ else /* other control */
+ strbuf[1] = (char)(ic + '@');
+
+ return strbuf;
+}
+
+void filter(void)
+{
+ PDC_LOG(("filter() - called\n"));
+}
+
+void use_env(bool x)
+{
+ PDC_LOG(("use_env() - called: x %d\n", x));
+}
+
+int delay_output(int ms)
+{
+ PDC_LOG(("delay_output() - called: ms %d\n", ms));
+
+ return napms(ms);
+}
+
+#ifdef PDC_WIDE
+int getcchar(const cchar_t *wcval, wchar_t *wch, attr_t *attrs,
+ short *color_pair, void *opts)
+{
+ if (!wcval)
+ return ERR;
+
+ if (wch)
+ {
+ if (!attrs || !color_pair)
+ return ERR;
+
+ *wch = (*wcval & A_CHARTEXT);
+ *attrs = (*wcval & (A_ATTRIBUTES & ~A_COLOR));
+ *color_pair = PAIR_NUMBER(*wcval & A_COLOR);
+
+ if (*wch)
+ *++wch = L'\0';
+
+ return OK;
+ }
+ else
+ return ((*wcval & A_CHARTEXT) != L'\0');
+}
+
+int setcchar(cchar_t *wcval, const wchar_t *wch, const attr_t attrs,
+ short color_pair, const void *opts)
+{
+ if (!wcval || !wch)
+ return ERR;
+
+ *wcval = *wch | attrs | COLOR_PAIR(color_pair);
+
+ return OK;
+}
+
+wchar_t *wunctrl(cchar_t *wc)
+{
+ static wchar_t strbuf[3] = {0, 0, 0};
+
+ cchar_t ic;
+
+ PDC_LOG(("wunctrl() - called\n"));
+
+ if (!wc)
+ return NULL;
+
+ ic = *wc & A_CHARTEXT;
+
+ if (ic >= 0x20 && ic != 0x7f) /* normal characters */
+ {
+ strbuf[0] = (wchar_t)ic;
+ strbuf[1] = L'\0';
+ return strbuf;
+ }
+
+ strbuf[0] = '^'; /* '^' prefix */
+
+ if (ic == 0x7f) /* 0x7f == DEL */
+ strbuf[1] = '?';
+ else /* other control */
+ strbuf[1] = (wchar_t)(ic + '@');
+
+ return strbuf;
+}
+
+int PDC_mbtowc(wchar_t *pwc, const char *s, size_t n)
+{
+# ifdef PDC_FORCE_UTF8
+ wchar_t key;
+ int i = -1;
+ const unsigned char *string;
+
+ if (!s || (n < 1))
+ return -1;
+
+ if (!*s)
+ return 0;
+
+ string = (const unsigned char *)s;
+
+ key = string[0];
+
+ /* Simplistic UTF-8 decoder -- only does the BMP, minimal validation */
+
+ if (key & 0x80)
+ {
+ if ((key & 0xe0) == 0xc0)
+ {
+ if (1 < n)
+ {
+ key = ((key & 0x1f) << 6) | (string[1] & 0x3f);
+ i = 2;
+ }
+ }
+ else if ((key & 0xe0) == 0xe0)
+ {
+ if (2 < n)
+ {
+ key = ((key & 0x0f) << 12) | ((string[1] & 0x3f) << 6) |
+ (string[2] & 0x3f);
+ i = 3;
+ }
+ }
+ }
+ else
+ i = 1;
+
+ if (i)
+ *pwc = key;
+
+ return i;
+# else
+ return mbtowc(pwc, s, n);
+# endif
+}
+
+size_t PDC_mbstowcs(wchar_t *dest, const char *src, size_t n)
+{
+# ifdef PDC_FORCE_UTF8
+ size_t i = 0, len;
+
+ if (!src || !dest)
+ return 0;
+
+ len = strlen(src);
+
+ while (*src && i < n)
+ {
+ int retval = PDC_mbtowc(dest + i, src, len);
+
+ if (retval < 1)
+ return -1;
+
+ src += retval;
+ len -= retval;
+ i++;
+ }
+# else
+ size_t i = mbstowcs(dest, src, n);
+# endif
+ dest[i] = 0;
+ return i;
+}
+
+size_t PDC_wcstombs(char *dest, const wchar_t *src, size_t n)
+{
+# ifdef PDC_FORCE_UTF8
+ size_t i = 0;
+
+ if (!src || !dest)
+ return 0;
+
+ while (*src && i < n)
+ {
+ chtype code = *src++;
+
+ if (code < 0x80)
+ {
+ dest[i] = code;
+ i++;
+ }
+ else
+ if (code < 0x800)
+ {
+ dest[i] = ((code & 0x07c0) >> 6) | 0xc0;
+ dest[i + 1] = (code & 0x003f) | 0x80;
+ i += 2;
+ }
+ else
+ {
+ dest[i] = ((code & 0xf000) >> 12) | 0xe0;
+ dest[i + 1] = ((code & 0x0fc0) >> 6) | 0x80;
+ dest[i + 2] = (code & 0x003f) | 0x80;
+ i += 3;
+ }
+ }
+# else
+ size_t i = wcstombs(dest, src, n);
+# endif
+ dest[i] = '\0';
+ return i;
+}
+#endif
diff --git a/Utilities/cmpdcurses/pdcurses/window.c b/Utilities/cmpdcurses/pdcurses/window.c
new file mode 100644
index 0000000..2eb294e
--- /dev/null
+++ b/Utilities/cmpdcurses/pdcurses/window.c
@@ -0,0 +1,582 @@
+/* PDCurses */
+
+#include <curspriv.h>
+
+/*man-start**************************************************************
+
+window
+------
+
+### Synopsis
+
+ WINDOW *newwin(int nlines, int ncols, int begy, int begx);
+ WINDOW *derwin(WINDOW* orig, int nlines, int ncols,
+ int begy, int begx);
+ WINDOW *subwin(WINDOW* orig, int nlines, int ncols,
+ int begy, int begx);
+ WINDOW *dupwin(WINDOW *win);
+ int delwin(WINDOW *win);
+ int mvwin(WINDOW *win, int y, int x);
+ int mvderwin(WINDOW *win, int pary, int parx);
+ int syncok(WINDOW *win, bool bf);
+ void wsyncup(WINDOW *win);
+ void wcursyncup(WINDOW *win);
+ void wsyncdown(WINDOW *win);
+
+ WINDOW *resize_window(WINDOW *win, int nlines, int ncols);
+ int wresize(WINDOW *win, int nlines, int ncols);
+ WINDOW *PDC_makelines(WINDOW *win);
+ WINDOW *PDC_makenew(int nlines, int ncols, int begy, int begx);
+ void PDC_sync(WINDOW *win);
+
+### Description
+
+ newwin() creates a new window with the given number of lines, nlines
+ and columns, ncols. The upper left corner of the window is at line
+ begy, column begx. If nlines is zero, it defaults to LINES - begy;
+ ncols to COLS - begx. Create a new full-screen window by calling
+ newwin(0, 0, 0, 0).
+
+ delwin() deletes the named window, freeing all associated memory. In
+ the case of overlapping windows, subwindows should be deleted before
+ the main window.
+
+ mvwin() moves the window so that the upper left-hand corner is at
+ position (y,x). If the move would cause the window to be off the
+ screen, it is an error and the window is not moved. Moving subwindows
+ is allowed.
+
+ subwin() creates a new subwindow within a window. The dimensions of
+ the subwindow are nlines lines and ncols columns. The subwindow is at
+ position (begy, begx) on the screen. This position is relative to the
+ screen, and not to the window orig. Changes made to either window
+ will affect both. When using this routine, you will often need to
+ call touchwin() before calling wrefresh().
+
+ derwin() is the same as subwin(), except that begy and begx are
+ relative to the origin of the window orig rather than the screen.
+ There is no difference between subwindows and derived windows.
+
+ mvderwin() moves a derived window (or subwindow) inside its parent
+ window. The screen-relative parameters of the window are not changed.
+ This routine is used to display different parts of the parent window
+ at the same physical position on the screen.
+
+ dupwin() creates an exact duplicate of the window win.
+
+ wsyncup() causes a touchwin() of all of the window's parents.
+
+ If wsyncok() is called with a second argument of TRUE, this causes a
+ wsyncup() to be called every time the window is changed.
+
+ wcursyncup() causes the current cursor position of all of a window's
+ ancestors to reflect the current cursor position of the current
+ window.
+
+ wsyncdown() causes a touchwin() of the current window if any of its
+ parent's windows have been touched.
+
+ resize_window() allows the user to resize an existing window. It
+ returns the pointer to the new window, or NULL on failure.
+
+ wresize() is an ncurses-compatible wrapper for resize_window(). Note
+ that, unlike ncurses, it will NOT process any subwindows of the
+ window. (However, you still can call it _on_ subwindows.) It returns
+ OK or ERR.
+
+ PDC_makenew() allocates all data for a new WINDOW * except the actual
+ lines themselves. If it's unable to allocate memory for the window
+ structure, it will free all allocated memory and return a NULL
+ pointer.
+
+ PDC_makelines() allocates the memory for the lines.
+
+ PDC_sync() handles wrefresh() and wsyncup() calls when a window is
+ changed.
+
+### Return Value
+
+ newwin(), subwin(), derwin() and dupwin() return a pointer to the new
+ window, or NULL on failure. delwin(), mvwin(), mvderwin() and
+ syncok() return OK or ERR. wsyncup(), wcursyncup() and wsyncdown()
+ return nothing.
+
+### Errors
+
+ It is an error to call resize_window() before calling initscr().
+ Also, an error will be generated if we fail to create a newly sized
+ replacement window for curscr, or stdscr. This could happen when
+ increasing the window size. NOTE: If this happens, the previously
+ successfully allocated windows are left alone; i.e., the resize is
+ NOT cancelled for those windows.
+
+### Portability
+ X/Open ncurses NetBSD
+ newwin Y Y Y
+ delwin Y Y Y
+ mvwin Y Y Y
+ subwin Y Y Y
+ derwin Y Y Y
+ mvderwin Y Y Y
+ dupwin Y Y Y
+ wsyncup Y Y Y
+ syncok Y Y Y
+ wcursyncup Y Y Y
+ wsyncdown Y Y Y
+ wresize - Y Y
+ resize_window - - -
+ PDC_makelines - - -
+ PDC_makenew - - -
+ PDC_sync - - -
+
+**man-end****************************************************************/
+
+#include <stdlib.h>
+
+WINDOW *PDC_makenew(int nlines, int ncols, int begy, int begx)
+{
+ WINDOW *win;
+
+ PDC_LOG(("PDC_makenew() - called: lines %d cols %d begy %d begx %d\n",
+ nlines, ncols, begy, begx));
+
+ /* allocate the window structure itself */
+
+ win = calloc(1, sizeof(WINDOW));
+ if (!win)
+ return win;
+
+ /* allocate the line pointer array */
+
+ win->_y = malloc(nlines * sizeof(chtype *));
+ if (!win->_y)
+ {
+ free(win);
+ return (WINDOW *)NULL;
+ }
+
+ /* allocate the minchng and maxchng arrays */
+
+ win->_firstch = malloc(nlines * sizeof(int));
+ if (!win->_firstch)
+ {
+ free(win->_y);
+ free(win);
+ return (WINDOW *)NULL;
+ }
+
+ win->_lastch = malloc(nlines * sizeof(int));
+ if (!win->_lastch)
+ {
+ free(win->_firstch);
+ free(win->_y);
+ free(win);
+ return (WINDOW *)NULL;
+ }
+
+ /* initialize window variables */
+
+ win->_maxy = nlines; /* real max screen size */
+ win->_maxx = ncols; /* real max screen size */
+ win->_begy = begy;
+ win->_begx = begx;
+ win->_bkgd = ' '; /* wrs 4/10/93 -- initialize background to blank */
+ win->_clear = (bool) ((nlines == LINES) && (ncols == COLS));
+ win->_bmarg = nlines - 1;
+ win->_parx = win->_pary = -1;
+
+ /* init to say window all changed */
+
+ touchwin(win);
+
+ return win;
+}
+
+WINDOW *PDC_makelines(WINDOW *win)
+{
+ int i, j, nlines, ncols;
+
+ PDC_LOG(("PDC_makelines() - called\n"));
+
+ if (!win)
+ return (WINDOW *)NULL;
+
+ nlines = win->_maxy;
+ ncols = win->_maxx;
+
+ for (i = 0; i < nlines; i++)
+ {
+ win->_y[i] = malloc(ncols * sizeof(chtype));
+ if (!win->_y[i])
+ {
+ /* if error, free all the data */
+
+ for (j = 0; j < i; j++)
+ free(win->_y[j]);
+
+ free(win->_firstch);
+ free(win->_lastch);
+ free(win->_y);
+ free(win);
+
+ return (WINDOW *)NULL;
+ }
+ }
+
+ return win;
+}
+
+void PDC_sync(WINDOW *win)
+{
+ PDC_LOG(("PDC_sync() - called:\n"));
+
+ if (win->_immed)
+ wrefresh(win);
+ if (win->_sync)
+ wsyncup(win);
+}
+
+WINDOW *newwin(int nlines, int ncols, int begy, int begx)
+{
+ WINDOW *win;
+
+ PDC_LOG(("newwin() - called:lines=%d cols=%d begy=%d begx=%d\n",
+ nlines, ncols, begy, begx));
+
+ if (!nlines)
+ nlines = LINES - begy;
+ if (!ncols)
+ ncols = COLS - begx;
+
+ if (!SP || begy + nlines > SP->lines || begx + ncols > SP->cols)
+ return (WINDOW *)NULL;
+
+ win = PDC_makenew(nlines, ncols, begy, begx);
+ if (win)
+ win = PDC_makelines(win);
+
+ if (win)
+ werase(win);
+
+ return win;
+}
+
+int delwin(WINDOW *win)
+{
+ int i;
+
+ PDC_LOG(("delwin() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ /* subwindows use parents' lines */
+
+ if (!(win->_flags & (_SUBWIN|_SUBPAD)))
+ for (i = 0; i < win->_maxy && win->_y[i]; i++)
+ if (win->_y[i])
+ free(win->_y[i]);
+
+ free(win->_firstch);
+ free(win->_lastch);
+ free(win->_y);
+ free(win);
+
+ return OK;
+}
+
+int mvwin(WINDOW *win, int y, int x)
+{
+ PDC_LOG(("mvwin() - called\n"));
+
+ if (!win || (y + win->_maxy > LINES || y < 0)
+ || (x + win->_maxx > COLS || x < 0))
+ return ERR;
+
+ win->_begy = y;
+ win->_begx = x;
+ touchwin(win);
+
+ return OK;
+}
+
+WINDOW *subwin(WINDOW *orig, int nlines, int ncols, int begy, int begx)
+{
+ WINDOW *win;
+ int i, j, k;
+
+ PDC_LOG(("subwin() - called: lines %d cols %d begy %d begx %d\n",
+ nlines, ncols, begy, begx));
+
+ /* make sure window fits inside the original one */
+
+ if (!orig || (begy < orig->_begy) || (begx < orig->_begx) ||
+ (begy + nlines) > (orig->_begy + orig->_maxy) ||
+ (begx + ncols) > (orig->_begx + orig->_maxx))
+ return (WINDOW *)NULL;
+
+ j = begy - orig->_begy;
+ k = begx - orig->_begx;
+
+ if (!nlines)
+ nlines = orig->_maxy - 1 - j;
+ if (!ncols)
+ ncols = orig->_maxx - 1 - k;
+
+ win = PDC_makenew(nlines, ncols, begy, begx);
+ if (!win)
+ return (WINDOW *)NULL;
+
+ /* initialize window variables */
+
+ win->_attrs = orig->_attrs;
+ win->_bkgd = orig->_bkgd;
+ win->_leaveit = orig->_leaveit;
+ win->_scroll = orig->_scroll;
+ win->_nodelay = orig->_nodelay;
+ win->_delayms = orig->_delayms;
+ win->_use_keypad = orig->_use_keypad;
+ win->_immed = orig->_immed;
+ win->_sync = orig->_sync;
+ win->_pary = j;
+ win->_parx = k;
+ win->_parent = orig;
+
+ for (i = 0; i < nlines; i++, j++)
+ win->_y[i] = orig->_y[j] + k;
+
+ win->_flags |= _SUBWIN;
+
+ return win;
+}
+
+WINDOW *derwin(WINDOW *orig, int nlines, int ncols, int begy, int begx)
+{
+ return subwin(orig, nlines, ncols, begy + orig->_begy, begx + orig->_begx);
+}
+
+int mvderwin(WINDOW *win, int pary, int parx)
+{
+ int i, j;
+ WINDOW *mypar;
+
+ if (!win || !(win->_parent))
+ return ERR;
+
+ mypar = win->_parent;
+
+ if (pary < 0 || parx < 0 || (pary + win->_maxy) > mypar->_maxy ||
+ (parx + win->_maxx) > mypar->_maxx)
+ return ERR;
+
+ j = pary;
+
+ for (i = 0; i < win->_maxy; i++)
+ win->_y[i] = (mypar->_y[j++]) + parx;
+
+ win->_pary = pary;
+ win->_parx = parx;
+
+ return OK;
+}
+
+WINDOW *dupwin(WINDOW *win)
+{
+ WINDOW *new;
+ chtype *ptr, *ptr1;
+ int nlines, ncols, begy, begx, i;
+
+ if (!win)
+ return (WINDOW *)NULL;
+
+ nlines = win->_maxy;
+ ncols = win->_maxx;
+ begy = win->_begy;
+ begx = win->_begx;
+
+ new = PDC_makenew(nlines, ncols, begy, begx);
+ if (new)
+ new = PDC_makelines(new);
+
+ if (!new)
+ return (WINDOW *)NULL;
+
+ /* copy the contents of win into new */
+
+ for (i = 0; i < nlines; i++)
+ {
+ for (ptr = new->_y[i], ptr1 = win->_y[i];
+ ptr < new->_y[i] + ncols; ptr++, ptr1++)
+ *ptr = *ptr1;
+
+ new->_firstch[i] = 0;
+ new->_lastch[i] = ncols - 1;
+ }
+
+ new->_curx = win->_curx;
+ new->_cury = win->_cury;
+ new->_maxy = win->_maxy;
+ new->_maxx = win->_maxx;
+ new->_begy = win->_begy;
+ new->_begx = win->_begx;
+ new->_flags = win->_flags;
+ new->_attrs = win->_attrs;
+ new->_clear = win->_clear;
+ new->_leaveit = win->_leaveit;
+ new->_scroll = win->_scroll;
+ new->_nodelay = win->_nodelay;
+ new->_delayms = win->_delayms;
+ new->_use_keypad = win->_use_keypad;
+ new->_tmarg = win->_tmarg;
+ new->_bmarg = win->_bmarg;
+ new->_parx = win->_parx;
+ new->_pary = win->_pary;
+ new->_parent = win->_parent;
+ new->_bkgd = win->_bkgd;
+ new->_flags = win->_flags;
+
+ return new;
+}
+
+WINDOW *resize_window(WINDOW *win, int nlines, int ncols)
+{
+ WINDOW *new;
+ int i, save_cury, save_curx, new_begy, new_begx;
+
+ PDC_LOG(("resize_window() - called: nlines %d ncols %d\n",
+ nlines, ncols));
+
+ if (!win || !SP)
+ return (WINDOW *)NULL;
+
+ if (win->_flags & _SUBPAD)
+ {
+ new = subpad(win->_parent, nlines, ncols, win->_begy, win->_begx);
+ if (!new)
+ return (WINDOW *)NULL;
+ }
+ else if (win->_flags & _SUBWIN)
+ {
+ new = subwin(win->_parent, nlines, ncols, win->_begy, win->_begx);
+ if (!new)
+ return (WINDOW *)NULL;
+ }
+ else
+ {
+ if (win == SP->slk_winptr)
+ {
+ new_begy = SP->lines - SP->slklines;
+ new_begx = 0;
+ }
+ else
+ {
+ new_begy = win->_begy;
+ new_begx = win->_begx;
+ }
+
+ new = PDC_makenew(nlines, ncols, new_begy, new_begx);
+ if (!new)
+ return (WINDOW *)NULL;
+ }
+
+ save_curx = min(win->_curx, (new->_maxx - 1));
+ save_cury = min(win->_cury, (new->_maxy - 1));
+
+ if (!(win->_flags & (_SUBPAD|_SUBWIN)))
+ {
+ new = PDC_makelines(new);
+ if (!new)
+ return (WINDOW *)NULL;
+
+ new->_bkgd = win->_bkgd;
+ werase(new);
+
+ copywin(win, new, 0, 0, 0, 0, min(win->_maxy, new->_maxy) - 1,
+ min(win->_maxx, new->_maxx) - 1, FALSE);
+
+ for (i = 0; i < win->_maxy && win->_y[i]; i++)
+ if (win->_y[i])
+ free(win->_y[i]);
+ }
+
+ new->_flags = win->_flags;
+ new->_attrs = win->_attrs;
+ new->_clear = win->_clear;
+ new->_leaveit = win->_leaveit;
+ new->_scroll = win->_scroll;
+ new->_nodelay = win->_nodelay;
+ new->_delayms = win->_delayms;
+ new->_use_keypad = win->_use_keypad;
+ new->_tmarg = (win->_tmarg > new->_maxy - 1) ? 0 : win->_tmarg;
+ new->_bmarg = (win->_bmarg == win->_maxy - 1) ?
+ new->_maxy - 1 : min(win->_bmarg, (new->_maxy - 1));
+ new->_parent = win->_parent;
+ new->_immed = win->_immed;
+ new->_sync = win->_sync;
+ new->_bkgd = win->_bkgd;
+
+ new->_curx = save_curx;
+ new->_cury = save_cury;
+
+ free(win->_firstch);
+ free(win->_lastch);
+ free(win->_y);
+
+ *win = *new;
+ free(new);
+
+ return win;
+}
+
+int wresize(WINDOW *win, int nlines, int ncols)
+{
+ return (resize_window(win, nlines, ncols) ? OK : ERR);
+}
+
+void wsyncup(WINDOW *win)
+{
+ WINDOW *tmp;
+
+ PDC_LOG(("wsyncup() - called\n"));
+
+ for (tmp = win; tmp; tmp = tmp->_parent)
+ touchwin(tmp);
+}
+
+int syncok(WINDOW *win, bool bf)
+{
+ PDC_LOG(("syncok() - called\n"));
+
+ if (!win)
+ return ERR;
+
+ win->_sync = bf;
+
+ return OK;
+}
+
+void wcursyncup(WINDOW *win)
+{
+ WINDOW *tmp;
+
+ PDC_LOG(("wcursyncup() - called\n"));
+
+ for (tmp = win; tmp && tmp->_parent; tmp = tmp->_parent)
+ wmove(tmp->_parent, tmp->_pary + tmp->_cury, tmp->_parx + tmp->_curx);
+}
+
+void wsyncdown(WINDOW *win)
+{
+ WINDOW *tmp;
+
+ PDC_LOG(("wsyncdown() - called\n"));
+
+ for (tmp = win; tmp; tmp = tmp->_parent)
+ {
+ if (is_wintouched(tmp))
+ {
+ touchwin(win);
+ break;
+ }
+ }
+}
diff --git a/Utilities/cmpdcurses/wincon/README.md b/Utilities/cmpdcurses/wincon/README.md
new file mode 100644
index 0000000..6192afb
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/README.md
@@ -0,0 +1,76 @@
+PDCurses for Windows console
+============================
+
+This directory contains PDCurses source code files specific to the
+Microsoft Windows console. Although historically called "Win32", this
+port can just as easily be built for 64-bit systems. Windows 95 through
+Windows 10 are covered. (Some features require later versions.)
+
+
+Building
+--------
+
+- Choose the appropriate makefile for your compiler:
+
+ Makefile - GCC (MinGW or Cygnus)
+ Makefile.bcc - Borland C++
+ Makefile.vc - Microsoft Visual C++
+ Makefile.wcc - Watcom
+
+- Optionally, you can build in a different directory than the platform
+ directory by setting PDCURSES_SRCDIR to point to the directory where
+ you unpacked PDCurses, and changing to your target directory:
+
+ set PDCURSES_SRCDIR=c:\pdcurses
+
+- Build it:
+
+ make -f makefilename
+
+ (For Watcom, use "wmake" instead of "make"; for MSVC, "nmake"; for
+ MinGW, "mingw32-make".) You'll get the library (pdcurses.lib or .a,
+ depending on your compiler) and a lot of object files.
+
+ You can also give the optional parameter "WIDE=Y", to build the
+ library with wide-character (Unicode) support:
+
+ wmake -f Makefile.wcc WIDE=Y
+
+ When built this way, the library is not compatible with Windows 9x,
+ unless you also link with the Microsoft Layer for Unicode (not
+ tested).
+
+ Another option, "UTF8=Y", makes PDCurses ignore the system locale, and
+ treat all narrow-character strings as UTF-8. This option has no effect
+ unless WIDE=Y is also set. Use it to get around the poor support for
+ UTF-8 in the Windows console:
+
+ make -f Makefile.bcc WIDE=Y UTF8=Y
+
+ You can also use the optional parameter "DLL=Y" with Visual C++,
+ MinGW or Cygwin, to build the library as a DLL:
+
+ nmake -f Makefile.vc WIDE=Y DLL=Y
+
+ When you build the library as a Windows DLL, you must always define
+ PDC_DLL_BUILD when linking against it. (Or, if you only want to use
+ the DLL, you could add this definition to your curses.h.)
+
+ Add the target "demos" to build the sample programs.
+
+- If your build stops with errors about PCONSOLE_SCREEN_BUFFER_INFOEX,
+ add the parameter "INFOEX=N" to your make command line and try again.
+ (This will happen with older compile environments.)
+
+
+Distribution Status
+-------------------
+
+The files in this directory are released to the public domain.
+
+
+Acknowledgements
+----------------
+
+Windows console port was originally provided by Chris Szurgot
+<szurgot@itribe.net>
diff --git a/Utilities/cmpdcurses/wincon/pdcclip.c b/Utilities/cmpdcurses/wincon/pdcclip.c
new file mode 100644
index 0000000..7402212
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/pdcclip.c
@@ -0,0 +1,149 @@
+/* PDCurses */
+
+#include "pdcwin.h"
+
+#include <string.h>
+
+/*man-start**************************************************************
+
+clipboard
+---------
+
+### Synopsis
+
+ int PDC_getclipboard(char **contents, long *length);
+ int PDC_setclipboard(const char *contents, long length);
+ int PDC_freeclipboard(char *contents);
+ int PDC_clearclipboard(void);
+
+### Description
+
+ PDC_getclipboard() gets the textual contents of the system's
+ clipboard. This function returns the contents of the clipboard in the
+ contents argument. It is the responsibility of the caller to free the
+ memory returned, via PDC_freeclipboard(). The length of the clipboard
+ contents is returned in the length argument.
+
+ PDC_setclipboard copies the supplied text into the system's
+ clipboard, emptying the clipboard prior to the copy.
+
+ PDC_clearclipboard() clears the internal clipboard.
+
+### Return Values
+
+ indicator of success/failure of call.
+ PDC_CLIP_SUCCESS the call was successful
+ PDC_CLIP_MEMORY_ERROR unable to allocate sufficient memory for
+ the clipboard contents
+ PDC_CLIP_EMPTY the clipboard contains no text
+ PDC_CLIP_ACCESS_ERROR no clipboard support
+
+### Portability
+ X/Open ncurses NetBSD
+ PDC_getclipboard - - -
+ PDC_setclipboard - - -
+ PDC_freeclipboard - - -
+ PDC_clearclipboard - - -
+
+**man-end****************************************************************/
+
+#ifdef PDC_WIDE
+# define PDC_TEXT CF_UNICODETEXT
+#else
+# define PDC_TEXT CF_OEMTEXT
+#endif
+
+int PDC_getclipboard(char **contents, long *length)
+{
+ HANDLE handle;
+ long len;
+
+ PDC_LOG(("PDC_getclipboard() - called\n"));
+
+ if (!OpenClipboard(NULL))
+ return PDC_CLIP_ACCESS_ERROR;
+
+ if ((handle = GetClipboardData(PDC_TEXT)) == NULL)
+ {
+ CloseClipboard();
+ return PDC_CLIP_EMPTY;
+ }
+
+#ifdef PDC_WIDE
+ len = wcslen((wchar_t *)handle) * 3;
+#else
+ len = strlen((char *)handle);
+#endif
+ *contents = (char *)GlobalAlloc(GMEM_FIXED, len + 1);
+
+ if (!*contents)
+ {
+ CloseClipboard();
+ return PDC_CLIP_MEMORY_ERROR;
+ }
+
+#ifdef PDC_WIDE
+ len = PDC_wcstombs((char *)*contents, (wchar_t *)handle, len);
+#else
+ strcpy((char *)*contents, (char *)handle);
+#endif
+ *length = len;
+ CloseClipboard();
+
+ return PDC_CLIP_SUCCESS;
+}
+
+int PDC_setclipboard(const char *contents, long length)
+{
+ HGLOBAL ptr1;
+ LPTSTR ptr2;
+
+ PDC_LOG(("PDC_setclipboard() - called\n"));
+
+ if (!OpenClipboard(NULL))
+ return PDC_CLIP_ACCESS_ERROR;
+
+ ptr1 = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,
+ (length + 1) * sizeof(TCHAR));
+
+ if (!ptr1)
+ return PDC_CLIP_MEMORY_ERROR;
+
+ ptr2 = GlobalLock(ptr1);
+
+#ifdef PDC_WIDE
+ PDC_mbstowcs((wchar_t *)ptr2, contents, length);
+#else
+ memcpy((char *)ptr2, contents, length + 1);
+#endif
+ GlobalUnlock(ptr1);
+ EmptyClipboard();
+
+ if (!SetClipboardData(PDC_TEXT, ptr1))
+ {
+ GlobalFree(ptr1);
+ return PDC_CLIP_ACCESS_ERROR;
+ }
+
+ CloseClipboard();
+ GlobalFree(ptr1);
+
+ return PDC_CLIP_SUCCESS;
+}
+
+int PDC_freeclipboard(char *contents)
+{
+ PDC_LOG(("PDC_freeclipboard() - called\n"));
+
+ GlobalFree(contents);
+ return PDC_CLIP_SUCCESS;
+}
+
+int PDC_clearclipboard(void)
+{
+ PDC_LOG(("PDC_clearclipboard() - called\n"));
+
+ EmptyClipboard();
+
+ return PDC_CLIP_SUCCESS;
+}
diff --git a/Utilities/cmpdcurses/wincon/pdcdisp.c b/Utilities/cmpdcurses/wincon/pdcdisp.c
new file mode 100644
index 0000000..fdaec76
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/pdcdisp.c
@@ -0,0 +1,329 @@
+/* PDCurses */
+
+#include "pdcwin.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef PDC_WIDE
+# include "../common/acsuni.h"
+#else
+# include "../common/acs437.h"
+#endif
+
+DWORD pdc_last_blink;
+static bool blinked_off = FALSE;
+static bool in_italic = FALSE;
+
+/* position hardware cursor at (y, x) */
+
+void PDC_gotoyx(int row, int col)
+{
+ COORD coord;
+
+ PDC_LOG(("PDC_gotoyx() - called: row %d col %d from row %d col %d\n",
+ row, col, SP->cursrow, SP->curscol));
+
+ coord.X = col;
+ coord.Y = row;
+
+ SetConsoleCursorPosition(pdc_con_out, coord);
+}
+
+void _set_ansi_color(short f, short b, attr_t attr)
+{
+ char esc[64], *p;
+ short tmp, underline;
+ bool italic;
+
+ if (f < 16 && !pdc_color[f].mapped)
+ f = pdc_curstoansi[f];
+
+ if (b < 16 && !pdc_color[b].mapped)
+ b = pdc_curstoansi[b];
+
+ if (attr & A_REVERSE)
+ {
+ tmp = f;
+ f = b;
+ b = tmp;
+ }
+ attr &= SP->termattrs;
+ italic = !!(attr & A_ITALIC);
+ underline = !!(attr & A_UNDERLINE);
+
+ p = esc + sprintf(esc, "\x1b[");
+
+ if (f != pdc_oldf)
+ {
+ if (f < 8 && !pdc_color[f].mapped)
+ p += sprintf(p, "%d", f + 30);
+ else if (f < 16 && !pdc_color[f].mapped)
+ p += sprintf(p, "%d", f + 82);
+ else if (f < 256 && !pdc_color[f].mapped)
+ p += sprintf(p, "38;5;%d", f);
+ else
+ {
+ short red = DIVROUND(pdc_color[f].r * 255, 1000);
+ short green = DIVROUND(pdc_color[f].g * 255, 1000);
+ short blue = DIVROUND(pdc_color[f].b * 255, 1000);
+
+ p += sprintf(p, "38;2;%d;%d;%d", red, green, blue);
+ }
+
+ pdc_oldf = f;
+ }
+
+ if (b != pdc_oldb)
+ {
+ if (strlen(esc) > 2)
+ p += sprintf(p, ";");
+
+ if (b < 8 && !pdc_color[b].mapped)
+ p += sprintf(p, "%d", b + 40);
+ else if (b < 16 && !pdc_color[b].mapped)
+ p += sprintf(p, "%d", b + 92);
+ else if (b < 256 && !pdc_color[b].mapped)
+ p += sprintf(p, "48;5;%d", b);
+ else
+ {
+ short red = DIVROUND(pdc_color[b].r * 255, 1000);
+ short green = DIVROUND(pdc_color[b].g * 255, 1000);
+ short blue = DIVROUND(pdc_color[b].b * 255, 1000);
+
+ p += sprintf(p, "48;2;%d;%d;%d", red, green, blue);
+ }
+
+ pdc_oldb = b;
+ }
+
+ if (italic != in_italic)
+ {
+ if (strlen(esc) > 2)
+ p += sprintf(p, ";");
+
+ if (italic)
+ p += sprintf(p, "3");
+ else
+ p += sprintf(p, "23");
+
+ in_italic = italic;
+ }
+
+ if (underline != pdc_oldu)
+ {
+ if (strlen(esc) > 2)
+ p += sprintf(p, ";");
+
+ if (underline)
+ p += sprintf(p, "4");
+ else
+ p += sprintf(p, "24");
+
+ pdc_oldu = underline;
+ }
+
+ if (strlen(esc) > 2)
+ {
+ sprintf(p, "m");
+ if (!pdc_conemu)
+ SetConsoleMode(pdc_con_out, 0x0015);
+
+ WriteConsoleA(pdc_con_out, esc, strlen(esc), NULL, NULL);
+
+ if (!pdc_conemu)
+ SetConsoleMode(pdc_con_out, 0x0010);
+ }
+}
+
+void _new_packet(attr_t attr, int lineno, int x, int len, const chtype *srcp)
+{
+ int j;
+ short fore, back;
+ bool blink, ansi;
+
+ if (pdc_ansi && (lineno == (SP->lines - 1)) && ((x + len) == SP->cols))
+ {
+ len--;
+ if (len)
+ _new_packet(attr, lineno, x, len, srcp);
+ pdc_ansi = FALSE;
+ _new_packet(attr, lineno, x + len, 1, srcp + len);
+ pdc_ansi = TRUE;
+ return;
+ }
+
+ pair_content(PAIR_NUMBER(attr), &fore, &back);
+ ansi = pdc_ansi || (fore >= 16 || back >= 16);
+ blink = (SP->termattrs & A_BLINK) && (attr & A_BLINK);
+
+ if (blink)
+ {
+ attr &= ~A_BLINK;
+ if (blinked_off)
+ attr &= ~(A_UNDERLINE | A_RIGHT | A_LEFT);
+ }
+
+ if (attr & A_BOLD)
+ fore |= 8;
+ if (attr & A_BLINK)
+ back |= 8;
+
+ if (ansi)
+ {
+#ifdef PDC_WIDE
+ WCHAR buffer[512];
+#else
+ char buffer[512];
+#endif
+ for (j = 0; j < len; j++)
+ {
+ chtype ch = srcp[j];
+
+ if (ch & A_ALTCHARSET && !(ch & 0xff80))
+ {
+ ch = acs_map[ch & 0x7f];
+
+ if (pdc_wt && (ch & A_CHARTEXT) < ' ')
+ goto NONANSI;
+ }
+
+ if (blink && blinked_off)
+ ch = ' ';
+
+ buffer[j] = ch & A_CHARTEXT;
+ }
+
+ PDC_gotoyx(lineno, x);
+ _set_ansi_color(fore, back, attr);
+#ifdef PDC_WIDE
+ WriteConsoleW(pdc_con_out, buffer, len, NULL, NULL);
+#else
+ WriteConsoleA(pdc_con_out, buffer, len, NULL, NULL);
+#endif
+ }
+ else
+NONANSI:
+ {
+ CHAR_INFO buffer[512];
+ COORD bufSize, bufPos;
+ SMALL_RECT sr;
+ WORD mapped_attr;
+
+ fore = pdc_curstoreal[fore];
+ back = pdc_curstoreal[back];
+
+ if (attr & A_REVERSE)
+ mapped_attr = back | (fore << 4);
+ else
+ mapped_attr = fore | (back << 4);
+
+ if (attr & A_UNDERLINE)
+ mapped_attr |= 0x8000; /* COMMON_LVB_UNDERSCORE */
+ if (attr & A_LEFT)
+ mapped_attr |= 0x0800; /* COMMON_LVB_GRID_LVERTICAL */
+ if (attr & A_RIGHT)
+ mapped_attr |= 0x1000; /* COMMON_LVB_GRID_RVERTICAL */
+
+ for (j = 0; j < len; j++)
+ {
+ chtype ch = srcp[j];
+
+ if (ch & A_ALTCHARSET && !(ch & 0xff80))
+ ch = acs_map[ch & 0x7f];
+
+ if (blink && blinked_off)
+ ch = ' ';
+
+ buffer[j].Attributes = mapped_attr;
+ buffer[j].Char.UnicodeChar = ch & A_CHARTEXT;
+ }
+
+ bufPos.X = bufPos.Y = 0;
+ bufSize.X = len;
+ bufSize.Y = 1;
+
+ sr.Top = sr.Bottom = lineno;
+ sr.Left = x;
+ sr.Right = x + len - 1;
+
+ WriteConsoleOutput(pdc_con_out, buffer, bufSize, bufPos, &sr);
+ }
+}
+
+/* update the given physical line to look like the corresponding line in
+ curscr */
+
+void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
+{
+ attr_t old_attr, attr;
+ int i, j;
+
+ PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno));
+
+ old_attr = *srcp & (A_ATTRIBUTES ^ A_ALTCHARSET);
+
+ for (i = 1, j = 1; j < len; i++, j++)
+ {
+ attr = srcp[i] & (A_ATTRIBUTES ^ A_ALTCHARSET);
+
+ if (attr != old_attr)
+ {
+ _new_packet(old_attr, lineno, x, i, srcp);
+ old_attr = attr;
+ srcp += i;
+ x += i;
+ i = 0;
+ }
+ }
+
+ _new_packet(old_attr, lineno, x, i, srcp);
+}
+
+void PDC_blink_text(void)
+{
+ CONSOLE_CURSOR_INFO cci;
+ int i, j, k;
+ bool oldvis;
+
+ GetConsoleCursorInfo(pdc_con_out, &cci);
+ oldvis = cci.bVisible;
+ if (oldvis)
+ {
+ cci.bVisible = FALSE;
+ SetConsoleCursorInfo(pdc_con_out, &cci);
+ }
+
+ if (!(SP->termattrs & A_BLINK))
+ blinked_off = FALSE;
+ else
+ blinked_off = !blinked_off;
+
+ for (i = 0; i < SP->lines; i++)
+ {
+ const chtype *srcp = curscr->_y[i];
+
+ for (j = 0; j < SP->cols; j++)
+ if (srcp[j] & A_BLINK)
+ {
+ k = j;
+ while (k < SP->cols && (srcp[k] & A_BLINK))
+ k++;
+ PDC_transform_line(i, j, k - j, srcp + j);
+ j = k;
+ }
+ }
+
+ PDC_gotoyx(SP->cursrow, SP->curscol);
+ if (oldvis)
+ {
+ cci.bVisible = TRUE;
+ SetConsoleCursorInfo(pdc_con_out, &cci);
+ }
+
+ pdc_last_blink = GetTickCount();
+}
+
+void PDC_doupdate(void)
+{
+}
diff --git a/Utilities/cmpdcurses/wincon/pdcgetsc.c b/Utilities/cmpdcurses/wincon/pdcgetsc.c
new file mode 100644
index 0000000..a8323eb
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/pdcgetsc.c
@@ -0,0 +1,42 @@
+/* PDCurses */
+
+#include "pdcwin.h"
+
+/* get the cursor size/shape */
+
+int PDC_get_cursor_mode(void)
+{
+ CONSOLE_CURSOR_INFO ci;
+
+ PDC_LOG(("PDC_get_cursor_mode() - called\n"));
+
+ GetConsoleCursorInfo(pdc_con_out, &ci);
+
+ return ci.dwSize;
+}
+
+/* return number of screen rows */
+
+int PDC_get_rows(void)
+{
+ CONSOLE_SCREEN_BUFFER_INFO scr;
+
+ PDC_LOG(("PDC_get_rows() - called\n"));
+
+ GetConsoleScreenBufferInfo(pdc_con_out, &scr);
+
+ return scr.srWindow.Bottom - scr.srWindow.Top + 1;
+}
+
+/* return width of screen/viewport */
+
+int PDC_get_columns(void)
+{
+ CONSOLE_SCREEN_BUFFER_INFO scr;
+
+ PDC_LOG(("PDC_get_columns() - called\n"));
+
+ GetConsoleScreenBufferInfo(pdc_con_out, &scr);
+
+ return scr.srWindow.Right - scr.srWindow.Left + 1;
+}
diff --git a/Utilities/cmpdcurses/wincon/pdckbd.c b/Utilities/cmpdcurses/wincon/pdckbd.c
new file mode 100644
index 0000000..12f30f0
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/pdckbd.c
@@ -0,0 +1,699 @@
+/* PDCurses */
+
+#include "pdcwin.h"
+
+/* These variables are used to store information about the next
+ Input Event. */
+
+static INPUT_RECORD save_ip;
+static MOUSE_STATUS old_mouse_status;
+static DWORD event_count = 0;
+static SHORT left_key;
+static int key_count = 0;
+static int save_press = 0;
+
+#define KEV save_ip.Event.KeyEvent
+#define MEV save_ip.Event.MouseEvent
+#define REV save_ip.Event.WindowBufferSizeEvent
+
+/************************************************************************
+ * Table for key code translation of function keys in keypad mode *
+ * These values are for strict IBM keyboard compatibles only *
+ ************************************************************************/
+
+typedef struct
+{
+ unsigned short normal;
+ unsigned short shift;
+ unsigned short control;
+ unsigned short alt;
+ unsigned short extended;
+} KPTAB;
+
+static KPTAB kptab[] =
+{
+ {0, 0, 0, 0, 0 }, /* 0 */
+ {0, 0, 0, 0, 0 }, /* 1 VK_LBUTTON */
+ {0, 0, 0, 0, 0 }, /* 2 VK_RBUTTON */
+ {0, 0, 0, 0, 0 }, /* 3 VK_CANCEL */
+ {0, 0, 0, 0, 0 }, /* 4 VK_MBUTTON */
+ {0, 0, 0, 0, 0 }, /* 5 */
+ {0, 0, 0, 0, 0 }, /* 6 */
+ {0, 0, 0, 0, 0 }, /* 7 */
+ {0x08, 0x08, 0x7F, ALT_BKSP, 0 }, /* 8 VK_BACK */
+ {0x09, KEY_BTAB, CTL_TAB, ALT_TAB, 999 }, /* 9 VK_TAB */
+ {0, 0, 0, 0, 0 }, /* 10 */
+ {0, 0, 0, 0, 0 }, /* 11 */
+ {KEY_B2, 0x35, CTL_PAD5, ALT_PAD5, 0 }, /* 12 VK_CLEAR */
+ {0x0D, 0x0D, CTL_ENTER, ALT_ENTER, 1 }, /* 13 VK_RETURN */
+ {0, 0, 0, 0, 0 }, /* 14 */
+ {0, 0, 0, 0, 0 }, /* 15 */
+ {0, 0, 0, 0, 0 }, /* 16 VK_SHIFT HANDLED SEPARATELY */
+ {0, 0, 0, 0, 0 }, /* 17 VK_CONTROL HANDLED SEPARATELY */
+ {0, 0, 0, 0, 0 }, /* 18 VK_MENU HANDLED SEPARATELY */
+ {0, 0, 0, 0, 0 }, /* 19 VK_PAUSE */
+ {0, 0, 0, 0, 0 }, /* 20 VK_CAPITAL HANDLED SEPARATELY */
+ {0, 0, 0, 0, 0 }, /* 21 VK_HANGUL */
+ {0, 0, 0, 0, 0 }, /* 22 */
+ {0, 0, 0, 0, 0 }, /* 23 VK_JUNJA */
+ {0, 0, 0, 0, 0 }, /* 24 VK_FINAL */
+ {0, 0, 0, 0, 0 }, /* 25 VK_HANJA */
+ {0, 0, 0, 0, 0 }, /* 26 */
+ {0x1B, 0x1B, 0x1B, ALT_ESC, 0 }, /* 27 VK_ESCAPE */
+ {0, 0, 0, 0, 0 }, /* 28 VK_CONVERT */
+ {0, 0, 0, 0, 0 }, /* 29 VK_NONCONVERT */
+ {0, 0, 0, 0, 0 }, /* 30 VK_ACCEPT */
+ {0, 0, 0, 0, 0 }, /* 31 VK_MODECHANGE */
+ {0x20, 0x20, 0x20, 0x20, 0 }, /* 32 VK_SPACE */
+ {KEY_A3, 0x39, CTL_PAD9, ALT_PAD9, 3 }, /* 33 VK_PRIOR */
+ {KEY_C3, 0x33, CTL_PAD3, ALT_PAD3, 4 }, /* 34 VK_NEXT */
+ {KEY_C1, 0x31, CTL_PAD1, ALT_PAD1, 5 }, /* 35 VK_END */
+ {KEY_A1, 0x37, CTL_PAD7, ALT_PAD7, 6 }, /* 36 VK_HOME */
+ {KEY_B1, 0x34, CTL_PAD4, ALT_PAD4, 7 }, /* 37 VK_LEFT */
+ {KEY_A2, 0x38, CTL_PAD8, ALT_PAD8, 8 }, /* 38 VK_UP */
+ {KEY_B3, 0x36, CTL_PAD6, ALT_PAD6, 9 }, /* 39 VK_RIGHT */
+ {KEY_C2, 0x32, CTL_PAD2, ALT_PAD2, 10 }, /* 40 VK_DOWN */
+ {0, 0, 0, 0, 0 }, /* 41 VK_SELECT */
+ {0, 0, 0, 0, 0 }, /* 42 VK_PRINT */
+ {0, 0, 0, 0, 0 }, /* 43 VK_EXECUTE */
+ {0, 0, 0, 0, 0 }, /* 44 VK_SNAPSHOT*/
+ {PAD0, 0x30, CTL_PAD0, ALT_PAD0, 11 }, /* 45 VK_INSERT */
+ {PADSTOP, 0x2E, CTL_PADSTOP, ALT_PADSTOP,12 }, /* 46 VK_DELETE */
+ {0, 0, 0, 0, 0 }, /* 47 VK_HELP */
+ {0x30, 0x29, 0, ALT_0, 0 }, /* 48 */
+ {0x31, 0x21, 0, ALT_1, 0 }, /* 49 */
+ {0x32, 0x40, 0, ALT_2, 0 }, /* 50 */
+ {0x33, 0x23, 0, ALT_3, 0 }, /* 51 */
+ {0x34, 0x24, 0, ALT_4, 0 }, /* 52 */
+ {0x35, 0x25, 0, ALT_5, 0 }, /* 53 */
+ {0x36, 0x5E, 0, ALT_6, 0 }, /* 54 */
+ {0x37, 0x26, 0, ALT_7, 0 }, /* 55 */
+ {0x38, 0x2A, 0, ALT_8, 0 }, /* 56 */
+ {0x39, 0x28, 0, ALT_9, 0 }, /* 57 */
+ {0, 0, 0, 0, 0 }, /* 58 */
+ {0, 0, 0, 0, 0 }, /* 59 */
+ {0, 0, 0, 0, 0 }, /* 60 */
+ {0, 0, 0, 0, 0 }, /* 61 */
+ {0, 0, 0, 0, 0 }, /* 62 */
+ {0, 0, 0, 0, 0 }, /* 63 */
+ {0, 0, 0, 0, 0 }, /* 64 */
+ {0x61, 0x41, 0x01, ALT_A, 0 }, /* 65 */
+ {0x62, 0x42, 0x02, ALT_B, 0 }, /* 66 */
+ {0x63, 0x43, 0x03, ALT_C, 0 }, /* 67 */
+ {0x64, 0x44, 0x04, ALT_D, 0 }, /* 68 */
+ {0x65, 0x45, 0x05, ALT_E, 0 }, /* 69 */
+ {0x66, 0x46, 0x06, ALT_F, 0 }, /* 70 */
+ {0x67, 0x47, 0x07, ALT_G, 0 }, /* 71 */
+ {0x68, 0x48, 0x08, ALT_H, 0 }, /* 72 */
+ {0x69, 0x49, 0x09, ALT_I, 0 }, /* 73 */
+ {0x6A, 0x4A, 0x0A, ALT_J, 0 }, /* 74 */
+ {0x6B, 0x4B, 0x0B, ALT_K, 0 }, /* 75 */
+ {0x6C, 0x4C, 0x0C, ALT_L, 0 }, /* 76 */
+ {0x6D, 0x4D, 0x0D, ALT_M, 0 }, /* 77 */
+ {0x6E, 0x4E, 0x0E, ALT_N, 0 }, /* 78 */
+ {0x6F, 0x4F, 0x0F, ALT_O, 0 }, /* 79 */
+ {0x70, 0x50, 0x10, ALT_P, 0 }, /* 80 */
+ {0x71, 0x51, 0x11, ALT_Q, 0 }, /* 81 */
+ {0x72, 0x52, 0x12, ALT_R, 0 }, /* 82 */
+ {0x73, 0x53, 0x13, ALT_S, 0 }, /* 83 */
+ {0x74, 0x54, 0x14, ALT_T, 0 }, /* 84 */
+ {0x75, 0x55, 0x15, ALT_U, 0 }, /* 85 */
+ {0x76, 0x56, 0x16, ALT_V, 0 }, /* 86 */
+ {0x77, 0x57, 0x17, ALT_W, 0 }, /* 87 */
+ {0x78, 0x58, 0x18, ALT_X, 0 }, /* 88 */
+ {0x79, 0x59, 0x19, ALT_Y, 0 }, /* 89 */
+ {0x7A, 0x5A, 0x1A, ALT_Z, 0 }, /* 90 */
+ {0, 0, 0, 0, 0 }, /* 91 VK_LWIN */
+ {0, 0, 0, 0, 0 }, /* 92 VK_RWIN */
+ {0, 0, 0, 0, 0 }, /* 93 VK_APPS */
+ {0, 0, 0, 0, 0 }, /* 94 */
+ {0, 0, 0, 0, 0 }, /* 95 */
+ {0x30, 0, CTL_PAD0, ALT_PAD0, 0 }, /* 96 VK_NUMPAD0 */
+ {0x31, 0, CTL_PAD1, ALT_PAD1, 0 }, /* 97 VK_NUMPAD1 */
+ {0x32, 0, CTL_PAD2, ALT_PAD2, 0 }, /* 98 VK_NUMPAD2 */
+ {0x33, 0, CTL_PAD3, ALT_PAD3, 0 }, /* 99 VK_NUMPAD3 */
+ {0x34, 0, CTL_PAD4, ALT_PAD4, 0 }, /* 100 VK_NUMPAD4 */
+ {0x35, 0, CTL_PAD5, ALT_PAD5, 0 }, /* 101 VK_NUMPAD5 */
+ {0x36, 0, CTL_PAD6, ALT_PAD6, 0 }, /* 102 VK_NUMPAD6 */
+ {0x37, 0, CTL_PAD7, ALT_PAD7, 0 }, /* 103 VK_NUMPAD7 */
+ {0x38, 0, CTL_PAD8, ALT_PAD8, 0 }, /* 104 VK_NUMPAD8 */
+ {0x39, 0, CTL_PAD9, ALT_PAD9, 0 }, /* 105 VK_NUMPAD9 */
+ {PADSTAR, SHF_PADSTAR,CTL_PADSTAR, ALT_PADSTAR,999 }, /* 106 VK_MULTIPLY*/
+ {PADPLUS, SHF_PADPLUS,CTL_PADPLUS, ALT_PADPLUS,999 }, /* 107 VK_ADD */
+ {0, 0, 0, 0, 0 }, /* 108 VK_SEPARATOR */
+ {PADMINUS, SHF_PADMINUS,CTL_PADMINUS,ALT_PADMINUS,999}, /* 109 VK_SUBTRACT*/
+ {0x2E, 0, CTL_PADSTOP, ALT_PADSTOP,0 }, /* 110 VK_DECIMAL */
+ {PADSLASH, SHF_PADSLASH,CTL_PADSLASH,ALT_PADSLASH,2 }, /* 111 VK_DIVIDE */
+ {KEY_F(1), KEY_F(13), KEY_F(25), KEY_F(37), 0 }, /* 112 VK_F1 */
+ {KEY_F(2), KEY_F(14), KEY_F(26), KEY_F(38), 0 }, /* 113 VK_F2 */
+ {KEY_F(3), KEY_F(15), KEY_F(27), KEY_F(39), 0 }, /* 114 VK_F3 */
+ {KEY_F(4), KEY_F(16), KEY_F(28), KEY_F(40), 0 }, /* 115 VK_F4 */
+ {KEY_F(5), KEY_F(17), KEY_F(29), KEY_F(41), 0 }, /* 116 VK_F5 */
+ {KEY_F(6), KEY_F(18), KEY_F(30), KEY_F(42), 0 }, /* 117 VK_F6 */
+ {KEY_F(7), KEY_F(19), KEY_F(31), KEY_F(43), 0 }, /* 118 VK_F7 */
+ {KEY_F(8), KEY_F(20), KEY_F(32), KEY_F(44), 0 }, /* 119 VK_F8 */
+ {KEY_F(9), KEY_F(21), KEY_F(33), KEY_F(45), 0 }, /* 120 VK_F9 */
+ {KEY_F(10), KEY_F(22), KEY_F(34), KEY_F(46), 0 }, /* 121 VK_F10 */
+ {KEY_F(11), KEY_F(23), KEY_F(35), KEY_F(47), 0 }, /* 122 VK_F11 */
+ {KEY_F(12), KEY_F(24), KEY_F(36), KEY_F(48), 0 }, /* 123 VK_F12 */
+
+ /* 124 through 218 */
+
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
+
+ {0x5B, 0x7B, 0x1B, ALT_LBRACKET,0 }, /* 219 */
+ {0x5C, 0x7C, 0x1C, ALT_BSLASH, 0 }, /* 220 */
+ {0x5D, 0x7D, 0x1D, ALT_RBRACKET,0 }, /* 221 */
+ {0, 0, 0x27, ALT_FQUOTE, 0 }, /* 222 */
+ {0, 0, 0, 0, 0 }, /* 223 */
+ {0, 0, 0, 0, 0 }, /* 224 */
+ {0, 0, 0, 0, 0 }, /* 225 */
+ {0, 0, 0, 0, 0 }, /* 226 */
+ {0, 0, 0, 0, 0 }, /* 227 */
+ {0, 0, 0, 0, 0 }, /* 228 */
+ {0, 0, 0, 0, 0 }, /* 229 */
+ {0, 0, 0, 0, 0 }, /* 230 */
+ {0, 0, 0, 0, 0 }, /* 231 */
+ {0, 0, 0, 0, 0 }, /* 232 */
+ {0, 0, 0, 0, 0 }, /* 233 */
+ {0, 0, 0, 0, 0 }, /* 234 */
+ {0, 0, 0, 0, 0 }, /* 235 */
+ {0, 0, 0, 0, 0 }, /* 236 */
+ {0, 0, 0, 0, 0 }, /* 237 */
+ {0, 0, 0, 0, 0 }, /* 238 */
+ {0, 0, 0, 0, 0 }, /* 239 */
+ {0, 0, 0, 0, 0 }, /* 240 */
+ {0, 0, 0, 0, 0 }, /* 241 */
+ {0, 0, 0, 0, 0 }, /* 242 */
+ {0, 0, 0, 0, 0 }, /* 243 */
+ {0, 0, 0, 0, 0 }, /* 244 */
+ {0, 0, 0, 0, 0 }, /* 245 */
+ {0, 0, 0, 0, 0 }, /* 246 */
+ {0, 0, 0, 0, 0 }, /* 247 */
+ {0, 0, 0, 0, 0 }, /* 248 */
+ {0, 0, 0, 0, 0 }, /* 249 */
+ {0, 0, 0, 0, 0 }, /* 250 */
+ {0, 0, 0, 0, 0 }, /* 251 */
+ {0, 0, 0, 0, 0 }, /* 252 */
+ {0, 0, 0, 0, 0 }, /* 253 */
+ {0, 0, 0, 0, 0 }, /* 254 */
+ {0, 0, 0, 0, 0 } /* 255 */
+};
+
+static KPTAB ext_kptab[] =
+{
+ {0, 0, 0, 0, }, /* MUST BE EMPTY */
+ {PADENTER, SHF_PADENTER, CTL_PADENTER, ALT_PADENTER}, /* 13 */
+ {PADSLASH, SHF_PADSLASH, CTL_PADSLASH, ALT_PADSLASH}, /* 111 */
+ {KEY_PPAGE, KEY_SPREVIOUS, CTL_PGUP, ALT_PGUP }, /* 33 */
+ {KEY_NPAGE, KEY_SNEXT, CTL_PGDN, ALT_PGDN }, /* 34 */
+ {KEY_END, KEY_SEND, CTL_END, ALT_END }, /* 35 */
+ {KEY_HOME, KEY_SHOME, CTL_HOME, ALT_HOME }, /* 36 */
+ {KEY_LEFT, KEY_SLEFT, CTL_LEFT, ALT_LEFT }, /* 37 */
+ {KEY_UP, KEY_SUP, CTL_UP, ALT_UP }, /* 38 */
+ {KEY_RIGHT, KEY_SRIGHT, CTL_RIGHT, ALT_RIGHT }, /* 39 */
+ {KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN }, /* 40 */
+ {KEY_IC, KEY_SIC, CTL_INS, ALT_INS }, /* 45 */
+ {KEY_DC, KEY_SDC, CTL_DEL, ALT_DEL }, /* 46 */
+ {PADSLASH, SHF_PADSLASH, CTL_PADSLASH, ALT_PADSLASH}, /* 191 */
+};
+
+/* End of kptab[] */
+
+void PDC_set_keyboard_binary(bool on)
+{
+ DWORD mode;
+
+ PDC_LOG(("PDC_set_keyboard_binary() - called\n"));
+
+ GetConsoleMode(pdc_con_in, &mode);
+ SetConsoleMode(pdc_con_in, !on ? (mode | ENABLE_PROCESSED_INPUT) :
+ (mode & ~ENABLE_PROCESSED_INPUT));
+}
+
+/* check if a key or mouse event is waiting */
+
+bool PDC_check_key(void)
+{
+ if (key_count > 0)
+ return TRUE;
+
+ GetNumberOfConsoleInputEvents(pdc_con_in, &event_count);
+
+ return (event_count != 0);
+}
+
+/* _get_key_count returns 0 if save_ip doesn't contain an event which
+ should be passed back to the user. This function filters "useless"
+ events.
+
+ The function returns the number of keys waiting. This may be > 1
+ if the repetition of real keys pressed so far are > 1.
+
+ Returns 0 on NUMLOCK, CAPSLOCK, SCROLLLOCK.
+
+ Returns 1 for SHIFT, ALT, CTRL only if no other key has been pressed
+ in between, and SP->return_key_modifiers is set; these are returned
+ on keyup.
+
+ Normal keys are returned on keydown only. The number of repetitions
+ are returned. Dead keys (diacritics) are omitted. See below for a
+ description.
+*/
+
+static int _get_key_count(void)
+{
+ int num_keys = 0, vk;
+
+ PDC_LOG(("_get_key_count() - called\n"));
+
+ vk = KEV.wVirtualKeyCode;
+
+ if (KEV.bKeyDown)
+ {
+ /* key down */
+
+ save_press = 0;
+
+ if (vk == VK_CAPITAL || vk == VK_NUMLOCK || vk == VK_SCROLL)
+ {
+ /* throw away these modifiers */
+ }
+ else if (vk == VK_SHIFT || vk == VK_CONTROL || vk == VK_MENU)
+ {
+ /* These keys are returned on keyup only. */
+
+ save_press = vk;
+ switch (vk)
+ {
+ case VK_SHIFT:
+ left_key = GetKeyState(VK_LSHIFT);
+ break;
+ case VK_CONTROL:
+ left_key = GetKeyState(VK_LCONTROL);
+ break;
+ case VK_MENU:
+ left_key = GetKeyState(VK_LMENU);
+ }
+ }
+ else
+ {
+ /* Check for diacritics. These are dead keys. Some locales
+ have modified characters like umlaut-a, which is an "a"
+ with two dots on it. In some locales you have to press a
+ special key (the dead key) immediately followed by the
+ "a" to get a composed umlaut-a. The special key may have
+ a normal meaning with different modifiers. */
+
+ if (KEV.uChar.UnicodeChar || !(MapVirtualKey(vk, 2) & 0x80000000))
+ num_keys = KEV.wRepeatCount;
+ }
+ }
+ else
+ {
+ /* key up */
+
+ /* Only modifier keys or the results of ALT-numpad entry are
+ returned on keyup */
+
+ if ((vk == VK_MENU && KEV.uChar.UnicodeChar) ||
+ ((vk == VK_SHIFT || vk == VK_CONTROL || vk == VK_MENU) &&
+ vk == save_press))
+ {
+ save_press = 0;
+ num_keys = 1;
+ }
+ }
+
+ PDC_LOG(("_get_key_count() - returning: num_keys %d\n", num_keys));
+
+ return num_keys;
+}
+
+/* _process_key_event returns -1 if the key in save_ip should be
+ ignored. Otherwise it returns the keycode which should be returned
+ by PDC_get_key(). save_ip must be a key event.
+
+ CTRL-ALT support has been disabled, when is it emitted plainly? */
+
+static int _process_key_event(void)
+{
+ int key =
+#ifdef PDC_WIDE
+ KEV.uChar.UnicodeChar;
+#else
+ KEV.uChar.AsciiChar;
+#endif
+ WORD vk = KEV.wVirtualKeyCode;
+ DWORD state = KEV.dwControlKeyState;
+
+ int idx;
+ BOOL enhanced;
+
+ SP->key_code = TRUE;
+
+ /* Save the key modifiers. Do this first to allow to detect e.g. a
+ pressed CTRL key after a hit of NUMLOCK. */
+
+ if (state & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
+ SP->key_modifiers |= PDC_KEY_MODIFIER_ALT;
+
+ if (state & SHIFT_PRESSED)
+ SP->key_modifiers |= PDC_KEY_MODIFIER_SHIFT;
+
+ if (state & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
+ SP->key_modifiers |= PDC_KEY_MODIFIER_CONTROL;
+
+ if (state & NUMLOCK_ON)
+ SP->key_modifiers |= PDC_KEY_MODIFIER_NUMLOCK;
+
+ /* Handle modifier keys hit by themselves */
+
+ switch (vk)
+ {
+ case VK_SHIFT: /* shift */
+ if (!SP->return_key_modifiers)
+ return -1;
+
+ return (left_key & 0x8000) ? KEY_SHIFT_L : KEY_SHIFT_R;
+
+ case VK_CONTROL: /* control */
+ if (!SP->return_key_modifiers)
+ return -1;
+
+ return (left_key & 0x8000) ? KEY_CONTROL_L : KEY_CONTROL_R;
+
+ case VK_MENU: /* alt */
+ if (!key)
+ {
+ if (!SP->return_key_modifiers)
+ return -1;
+
+ return (left_key & 0x8000) ? KEY_ALT_L : KEY_ALT_R;
+ }
+ }
+
+ /* The system may emit Ascii or Unicode characters depending on
+ whether ReadConsoleInputA or ReadConsoleInputW is used.
+
+ Normally, if key != 0 then the system did the translation
+ successfully. But this is not true for LEFT_ALT (different to
+ RIGHT_ALT). In case of LEFT_ALT we can get key != 0. So
+ check for this first. */
+
+ if (key && ( !(state & LEFT_ALT_PRESSED) ||
+ (state & RIGHT_ALT_PRESSED) ))
+ {
+ /* This code should catch all keys returning a printable
+ character. Characters above 0x7F should be returned as
+ positive codes. */
+
+ if (kptab[vk].extended == 0)
+ {
+ SP->key_code = FALSE;
+ return key;
+ }
+ }
+
+ /* This case happens if a functional key has been entered. */
+
+ if ((state & ENHANCED_KEY) && (kptab[vk].extended != 999))
+ {
+ enhanced = TRUE;
+ idx = kptab[vk].extended;
+ }
+ else
+ {
+ enhanced = FALSE;
+ idx = vk;
+ }
+
+ if (state & SHIFT_PRESSED)
+ key = enhanced ? ext_kptab[idx].shift : kptab[idx].shift;
+
+ else if (state & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
+ key = enhanced ? ext_kptab[idx].control : kptab[idx].control;
+
+ else if (state & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
+ key = enhanced ? ext_kptab[idx].alt : kptab[idx].alt;
+
+ else
+ key = enhanced ? ext_kptab[idx].normal : kptab[idx].normal;
+
+ if (key < KEY_CODE_YES)
+ SP->key_code = FALSE;
+
+ return key;
+}
+
+static int _process_mouse_event(void)
+{
+ static const DWORD button_mask[] = {1, 4, 2};
+ short action, shift_flags = 0;
+ int i;
+
+ save_press = 0;
+ SP->key_code = TRUE;
+
+ memset(&SP->mouse_status, 0, sizeof(MOUSE_STATUS));
+
+ /* Handle scroll wheel */
+
+ if (MEV.dwEventFlags == 4)
+ {
+ SP->mouse_status.changes = (MEV.dwButtonState & 0xFF000000) ?
+ PDC_MOUSE_WHEEL_DOWN : PDC_MOUSE_WHEEL_UP;
+
+ SP->mouse_status.x = -1;
+ SP->mouse_status.y = -1;
+
+ memset(&old_mouse_status, 0, sizeof(old_mouse_status));
+
+ return KEY_MOUSE;
+ }
+
+ if (MEV.dwEventFlags == 8)
+ {
+ SP->mouse_status.changes = (MEV.dwButtonState & 0xFF000000) ?
+ PDC_MOUSE_WHEEL_RIGHT : PDC_MOUSE_WHEEL_LEFT;
+
+ SP->mouse_status.x = -1;
+ SP->mouse_status.y = -1;
+
+ memset(&old_mouse_status, 0, sizeof(old_mouse_status));
+
+ return KEY_MOUSE;
+ }
+
+ action = (MEV.dwEventFlags == 2) ? BUTTON_DOUBLE_CLICKED :
+ ((MEV.dwEventFlags == 1) ? BUTTON_MOVED : BUTTON_PRESSED);
+
+ for (i = 0; i < 3; i++)
+ SP->mouse_status.button[i] =
+ (MEV.dwButtonState & button_mask[i]) ? action : 0;
+
+ if (action == BUTTON_PRESSED && MEV.dwButtonState & 7 && SP->mouse_wait)
+ {
+ /* Check for a click -- a PRESS followed immediately by a release */
+
+ if (!event_count)
+ {
+ napms(SP->mouse_wait);
+
+ GetNumberOfConsoleInputEvents(pdc_con_in, &event_count);
+ }
+
+ if (event_count)
+ {
+ INPUT_RECORD ip;
+ DWORD count;
+ bool have_click = FALSE;
+
+ PeekConsoleInput(pdc_con_in, &ip, 1, &count);
+
+ for (i = 0; i < 3; i++)
+ {
+ if (SP->mouse_status.button[i] == BUTTON_PRESSED &&
+ !(ip.Event.MouseEvent.dwButtonState & button_mask[i]))
+ {
+ SP->mouse_status.button[i] = BUTTON_CLICKED;
+ have_click = TRUE;
+ }
+ }
+
+ /* If a click was found, throw out the event */
+
+ if (have_click)
+ ReadConsoleInput(pdc_con_in, &ip, 1, &count);
+ }
+ }
+
+ SP->mouse_status.x = MEV.dwMousePosition.X;
+ SP->mouse_status.y = MEV.dwMousePosition.Y;
+
+ SP->mouse_status.changes = 0;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (old_mouse_status.button[i] != SP->mouse_status.button[i])
+ SP->mouse_status.changes |= (1 << i);
+
+ if (SP->mouse_status.button[i] == BUTTON_MOVED)
+ {
+ /* Discard non-moved "moves" */
+
+ if (SP->mouse_status.x == old_mouse_status.x &&
+ SP->mouse_status.y == old_mouse_status.y)
+ return -1;
+
+ /* Motion events always flag the button as changed */
+
+ SP->mouse_status.changes |= (1 << i);
+ SP->mouse_status.changes |= PDC_MOUSE_MOVED;
+ break;
+ }
+ }
+
+ old_mouse_status = SP->mouse_status;
+
+ /* Treat click events as release events for comparison purposes */
+
+ for (i = 0; i < 3; i++)
+ {
+ if (old_mouse_status.button[i] == BUTTON_CLICKED ||
+ old_mouse_status.button[i] == BUTTON_DOUBLE_CLICKED)
+ old_mouse_status.button[i] = BUTTON_RELEASED;
+ }
+
+ /* Check for SHIFT/CONTROL/ALT */
+
+ if (MEV.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))
+ shift_flags |= BUTTON_ALT;
+
+ if (MEV.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
+ shift_flags |= BUTTON_CONTROL;
+
+ if (MEV.dwControlKeyState & SHIFT_PRESSED)
+ shift_flags |= BUTTON_SHIFT;
+
+ if (shift_flags)
+ {
+ for (i = 0; i < 3; i++)
+ {
+ if (SP->mouse_status.changes & (1 << i))
+ SP->mouse_status.button[i] |= shift_flags;
+ }
+ }
+
+ return KEY_MOUSE;
+}
+
+/* return the next available key or mouse event */
+
+int PDC_get_key(void)
+{
+ SP->key_modifiers = 0L;
+
+ if (!key_count)
+ {
+ DWORD count;
+
+ ReadConsoleInput(pdc_con_in, &save_ip, 1, &count);
+ event_count--;
+
+ if (save_ip.EventType == MOUSE_EVENT ||
+ save_ip.EventType == WINDOW_BUFFER_SIZE_EVENT)
+ key_count = 1;
+ else if (save_ip.EventType == KEY_EVENT)
+ key_count = _get_key_count();
+ }
+
+ if (key_count)
+ {
+ key_count--;
+
+ switch (save_ip.EventType)
+ {
+ case KEY_EVENT:
+ return _process_key_event();
+
+ case MOUSE_EVENT:
+ return _process_mouse_event();
+
+ case WINDOW_BUFFER_SIZE_EVENT:
+ if (REV.dwSize.Y != LINES || REV.dwSize.X != COLS)
+ {
+ if (!SP->resized)
+ {
+ SP->resized = TRUE;
+ SP->key_code = TRUE;
+ return KEY_RESIZE;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+/* discard any pending keyboard or mouse input -- this is the core
+ routine for flushinp() */
+
+void PDC_flushinp(void)
+{
+ PDC_LOG(("PDC_flushinp() - called\n"));
+
+ FlushConsoleInputBuffer(pdc_con_in);
+}
+
+bool PDC_has_mouse(void)
+{
+ return TRUE;
+}
+
+int PDC_mouse_set(void)
+{
+ DWORD mode;
+
+ /* If turning on mouse input: Set ENABLE_MOUSE_INPUT, and clear
+ all other flags, except processed input mode;
+ If turning off the mouse: Set QuickEdit Mode to the status it
+ had on startup, and clear all other flags, except etc. */
+
+ GetConsoleMode(pdc_con_in, &mode);
+ mode = (mode & 1) | 0x0088;
+ SetConsoleMode(pdc_con_in, mode | (SP->_trap_mbe ?
+ ENABLE_MOUSE_INPUT : pdc_quick_edit));
+
+ memset(&old_mouse_status, 0, sizeof(old_mouse_status));
+
+ return OK;
+}
+
+int PDC_modifiers_set(void)
+{
+ return OK;
+}
diff --git a/Utilities/cmpdcurses/wincon/pdcscrn.c b/Utilities/cmpdcurses/wincon/pdcscrn.c
new file mode 100644
index 0000000..e2f4ddd
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/pdcscrn.c
@@ -0,0 +1,686 @@
+/* PDCurses */
+
+#include "pdcwin.h"
+
+#include <stdlib.h>
+
+/* Color component table */
+
+PDCCOLOR pdc_color[PDC_MAXCOL];
+
+HANDLE std_con_out = INVALID_HANDLE_VALUE;
+HANDLE pdc_con_out = INVALID_HANDLE_VALUE;
+HANDLE pdc_con_in = INVALID_HANDLE_VALUE;
+
+DWORD pdc_quick_edit;
+
+static short realtocurs[16] =
+{
+ COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED,
+ COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8,
+ COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8,
+ COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8
+};
+
+static short ansitocurs[16] =
+{
+ COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE,
+ COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE, COLOR_BLACK + 8,
+ COLOR_RED + 8, COLOR_GREEN + 8, COLOR_YELLOW + 8, COLOR_BLUE + 8,
+ COLOR_MAGENTA + 8, COLOR_CYAN + 8, COLOR_WHITE + 8
+};
+
+short pdc_curstoreal[16], pdc_curstoansi[16];
+short pdc_oldf, pdc_oldb, pdc_oldu;
+bool pdc_conemu, pdc_wt, pdc_ansi;
+
+enum { PDC_RESTORE_NONE, PDC_RESTORE_BUFFER };
+
+/* Struct for storing console registry keys, and for use with the
+ undocumented WM_SETCONSOLEINFO message. Originally by James Brown,
+ www.catch22.net. */
+
+static struct
+{
+ ULONG Length;
+ COORD ScreenBufferSize;
+ COORD WindowSize;
+ ULONG WindowPosX;
+ ULONG WindowPosY;
+
+ COORD FontSize;
+ ULONG FontFamily;
+ ULONG FontWeight;
+ WCHAR FaceName[32];
+
+ ULONG CursorSize;
+ ULONG FullScreen;
+ ULONG QuickEdit;
+ ULONG AutoPosition;
+ ULONG InsertMode;
+
+ USHORT ScreenColors;
+ USHORT PopupColors;
+ ULONG HistoryNoDup;
+ ULONG HistoryBufferSize;
+ ULONG NumberOfHistoryBuffers;
+
+ COLORREF ColorTable[16];
+
+ ULONG CodePage;
+ HWND Hwnd;
+
+ WCHAR ConsoleTitle[0x100];
+} console_info;
+
+#ifdef HAVE_NO_INFOEX
+/* Console screen buffer information (extended version) */
+typedef struct _CONSOLE_SCREEN_BUFFER_INFOEX {
+ ULONG cbSize;
+ COORD dwSize;
+ COORD dwCursorPosition;
+ WORD wAttributes;
+ SMALL_RECT srWindow;
+ COORD dwMaximumWindowSize;
+ WORD wPopupAttributes;
+ BOOL bFullscreenSupported;
+ COLORREF ColorTable[16];
+} CONSOLE_SCREEN_BUFFER_INFOEX;
+typedef CONSOLE_SCREEN_BUFFER_INFOEX *PCONSOLE_SCREEN_BUFFER_INFOEX;
+#endif
+
+typedef BOOL (WINAPI *SetConsoleScreenBufferInfoExFn)(HANDLE hConsoleOutput,
+ PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx);
+typedef BOOL (WINAPI *GetConsoleScreenBufferInfoExFn)(HANDLE hConsoleOutput,
+ PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx);
+
+static SetConsoleScreenBufferInfoExFn pSetConsoleScreenBufferInfoEx = NULL;
+static GetConsoleScreenBufferInfoExFn pGetConsoleScreenBufferInfoEx = NULL;
+
+static CONSOLE_SCREEN_BUFFER_INFO orig_scr;
+static CONSOLE_SCREEN_BUFFER_INFOEX console_infoex;
+
+static LPTOP_LEVEL_EXCEPTION_FILTER xcpt_filter;
+
+static DWORD old_console_mode = 0;
+
+static bool is_nt;
+
+static void _reset_old_colors(void)
+{
+ pdc_oldf = -1;
+ pdc_oldb = -1;
+ pdc_oldu = 0;
+}
+
+static HWND _find_console_handle(void)
+{
+ TCHAR orgtitle[1024], temptitle[1024];
+ HWND wnd;
+
+ GetConsoleTitle(orgtitle, 1024);
+
+ wsprintf(temptitle, TEXT("%d/%d"), GetTickCount(), GetCurrentProcessId());
+ SetConsoleTitle(temptitle);
+
+ Sleep(40);
+
+ wnd = FindWindow(NULL, temptitle);
+
+ SetConsoleTitle(orgtitle);
+
+ return wnd;
+}
+
+/* Undocumented console message */
+
+#define WM_SETCONSOLEINFO (WM_USER + 201)
+
+/* Wrapper around WM_SETCONSOLEINFO. We need to create the necessary
+ section (file-mapping) object in the context of the process which
+ owns the console, before posting the message. Originally by JB. */
+
+static void _set_console_info(void)
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ CONSOLE_CURSOR_INFO cci;
+ DWORD dwConsoleOwnerPid;
+ HANDLE hProcess;
+ HANDLE hSection, hDupSection;
+ PVOID ptrView;
+
+ /* Each-time initialization for console_info */
+
+ GetConsoleCursorInfo(pdc_con_out, &cci);
+ console_info.CursorSize = cci.dwSize;
+
+ GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
+ console_info.ScreenBufferSize = csbi.dwSize;
+
+ console_info.WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+ console_info.WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+
+ console_info.WindowPosX = csbi.srWindow.Left;
+ console_info.WindowPosY = csbi.srWindow.Top;
+
+ /* Open the process which "owns" the console */
+
+ GetWindowThreadProcessId(console_info.Hwnd, &dwConsoleOwnerPid);
+
+ hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
+
+ /* Create a SECTION object backed by page-file, then map a view of
+ this section into the owner process so we can write the contents
+ of the CONSOLE_INFO buffer into it */
+
+ hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE,
+ 0, sizeof(console_info), 0);
+
+ /* Copy our console structure into the section-object */
+
+ ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE|FILE_MAP_READ,
+ 0, 0, sizeof(console_info));
+
+ memcpy(ptrView, &console_info, sizeof(console_info));
+
+ UnmapViewOfFile(ptrView);
+
+ /* Map the memory into owner process */
+
+ DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+
+ /* Send console window the "update" message */
+
+ SendMessage(console_info.Hwnd, WM_SETCONSOLEINFO, (WPARAM)hDupSection, 0);
+
+ CloseHandle(hSection);
+ CloseHandle(hProcess);
+}
+
+static int _set_console_infoex(void)
+{
+ if (!pSetConsoleScreenBufferInfoEx(pdc_con_out, &console_infoex))
+ return ERR;
+
+ return OK;
+}
+
+static int _set_colors(void)
+{
+ SetConsoleTextAttribute(pdc_con_out, 7);
+ _reset_old_colors();
+
+ if (pSetConsoleScreenBufferInfoEx)
+ return _set_console_infoex();
+ else
+ {
+ _set_console_info();
+ return OK;
+ }
+}
+
+/* One-time initialization for console_info -- color table and font info
+ from the registry; other values from functions. */
+
+static void _init_console_info(void)
+{
+ DWORD scrnmode, len;
+ HKEY reghnd;
+ int i;
+
+ console_info.Hwnd = _find_console_handle();
+ console_info.Length = sizeof(console_info);
+
+ GetConsoleMode(pdc_con_in, &scrnmode);
+ console_info.QuickEdit = !!(scrnmode & 0x0040);
+ console_info.InsertMode = !!(scrnmode & 0x0020);
+
+ console_info.FullScreen = FALSE;
+ console_info.AutoPosition = 0x10000;
+ console_info.ScreenColors = SP->orig_back << 4 | SP->orig_fore;
+ console_info.PopupColors = 0xf5;
+
+ console_info.HistoryNoDup = FALSE;
+ console_info.HistoryBufferSize = 50;
+ console_info.NumberOfHistoryBuffers = 4;
+
+ console_info.CodePage = GetConsoleOutputCP();
+
+ RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Console"), 0,
+ KEY_QUERY_VALUE, &reghnd);
+
+ len = sizeof(DWORD);
+
+ /* Default color table */
+
+ for (i = 0; i < 16; i++)
+ {
+ char tname[13];
+
+ sprintf(tname, "ColorTable%02d", i);
+ RegQueryValueExA(reghnd, tname, NULL, NULL,
+ (LPBYTE)(&(console_info.ColorTable[i])), &len);
+ }
+
+ /* Font info */
+
+ RegQueryValueEx(reghnd, TEXT("FontSize"), NULL, NULL,
+ (LPBYTE)(&console_info.FontSize), &len);
+ RegQueryValueEx(reghnd, TEXT("FontFamily"), NULL, NULL,
+ (LPBYTE)(&console_info.FontFamily), &len);
+ RegQueryValueEx(reghnd, TEXT("FontWeight"), NULL, NULL,
+ (LPBYTE)(&console_info.FontWeight), &len);
+
+ len = sizeof(WCHAR) * 32;
+ RegQueryValueExW(reghnd, L"FaceName", NULL, NULL,
+ (LPBYTE)(console_info.FaceName), &len);
+
+ RegCloseKey(reghnd);
+}
+
+static int _init_console_infoex(void)
+{
+ console_infoex.cbSize = sizeof(console_infoex);
+
+ if (!pGetConsoleScreenBufferInfoEx(pdc_con_out, &console_infoex))
+ return ERR;
+
+ console_infoex.srWindow.Right++;
+ console_infoex.srWindow.Bottom++;
+
+ return OK;
+}
+
+static COLORREF *_get_colors(void)
+{
+ if (pGetConsoleScreenBufferInfoEx)
+ {
+ int status = OK;
+ if (!console_infoex.cbSize)
+ status = _init_console_infoex();
+ return (status == ERR) ? NULL :
+ (COLORREF *)(&(console_infoex.ColorTable));
+ }
+ else
+ {
+ if (!console_info.Hwnd)
+ _init_console_info();
+ return (COLORREF *)(&(console_info.ColorTable));
+ }
+}
+
+/* restore the original console buffer in the event of a crash */
+
+static LONG WINAPI _restore_console(LPEXCEPTION_POINTERS ep)
+{
+ PDC_scr_close();
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+/* restore the original console buffer on Ctrl+Break (or Ctrl+C,
+ if it gets re-enabled) */
+
+static BOOL WINAPI _ctrl_break(DWORD dwCtrlType)
+{
+ if (dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_C_EVENT)
+ PDC_scr_close();
+
+ return FALSE;
+}
+
+/* close the physical screen -- may restore the screen to its state
+ before PDC_scr_open(); miscellaneous cleanup */
+
+void PDC_scr_close(void)
+{
+ PDC_LOG(("PDC_scr_close() - called\n"));
+
+ if (SP->visibility != 1)
+ curs_set(1);
+
+ PDC_reset_shell_mode();
+
+ /* Position cursor to the bottom left of the screen. */
+
+ if (SP->_restore == PDC_RESTORE_NONE)
+ {
+ SMALL_RECT win;
+
+ win.Left = orig_scr.srWindow.Left;
+ win.Right = orig_scr.srWindow.Right;
+ win.Top = 0;
+ win.Bottom = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top;
+ SetConsoleWindowInfo(pdc_con_out, TRUE, &win);
+ PDC_gotoyx(win.Bottom, 0);
+ }
+}
+
+void PDC_scr_free(void)
+{
+ if (pdc_con_out != std_con_out)
+ {
+ CloseHandle(pdc_con_out);
+ pdc_con_out = std_con_out;
+ }
+
+ SetUnhandledExceptionFilter(xcpt_filter);
+ SetConsoleCtrlHandler(_ctrl_break, FALSE);
+}
+
+/* open the physical screen -- miscellaneous initialization, may save
+ the existing screen for later restoration */
+
+int PDC_scr_open(void)
+{
+ const char *str;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ HMODULE h_kernel;
+ BOOL result;
+ int i;
+
+ PDC_LOG(("PDC_scr_open() - called\n"));
+
+ for (i = 0; i < 16; i++)
+ {
+ pdc_curstoreal[realtocurs[i]] = i;
+ pdc_curstoansi[ansitocurs[i]] = i;
+ }
+ _reset_old_colors();
+
+ std_con_out =
+ pdc_con_out = GetStdHandle(STD_OUTPUT_HANDLE);
+ pdc_con_in = GetStdHandle(STD_INPUT_HANDLE);
+
+ if (GetFileType(pdc_con_in) != FILE_TYPE_CHAR)
+ {
+ fprintf(stderr, "\nRedirection is not supported.\n");
+ exit(1);
+ }
+
+ is_nt = !(GetVersion() & 0x80000000);
+
+ pdc_wt = !!getenv("WT_SESSION");
+ str = pdc_wt ? NULL : getenv("ConEmuANSI");
+ pdc_conemu = !!str;
+ pdc_ansi = pdc_wt ? TRUE : pdc_conemu ? !strcmp(str, "ON") : FALSE;
+
+ GetConsoleScreenBufferInfo(pdc_con_out, &csbi);
+ GetConsoleScreenBufferInfo(pdc_con_out, &orig_scr);
+ GetConsoleMode(pdc_con_in, &old_console_mode);
+
+ /* preserve QuickEdit Mode setting for use in PDC_mouse_set() when
+ the mouse is not enabled -- other console input settings are
+ cleared */
+
+ pdc_quick_edit = old_console_mode & 0x0040;
+
+ SP->mouse_wait = PDC_CLICK_PERIOD;
+ SP->audible = TRUE;
+
+ SP->termattrs = A_COLOR | A_REVERSE;
+ if (pdc_ansi)
+ SP->termattrs |= A_UNDERLINE | A_ITALIC;
+
+ SP->orig_fore = csbi.wAttributes & 0x0f;
+ SP->orig_back = (csbi.wAttributes & 0xf0) >> 4;
+
+ SP->orig_attr = TRUE;
+
+ SP->_restore = PDC_RESTORE_NONE;
+
+ if ((str = getenv("PDC_RESTORE_SCREEN")) == NULL || *str != '0')
+ {
+ /* Create a new console buffer */
+
+ pdc_con_out =
+ CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
+
+ if (pdc_con_out == INVALID_HANDLE_VALUE)
+ {
+ PDC_LOG(("PDC_scr_open() - screen buffer failure\n"));
+
+ pdc_con_out = std_con_out;
+ }
+ else
+ SP->_restore = PDC_RESTORE_BUFFER;
+ }
+
+ xcpt_filter = SetUnhandledExceptionFilter(_restore_console);
+ SetConsoleCtrlHandler(_ctrl_break, TRUE);
+
+ SP->_preserve = (getenv("PDC_PRESERVE_SCREEN") != NULL);
+
+ /* ENABLE_LVB_GRID_WORLDWIDE */
+ result = SetConsoleMode(pdc_con_out, 0x0010);
+ if (result)
+ SP->termattrs |= A_UNDERLINE | A_LEFT | A_RIGHT;
+
+ PDC_reset_prog_mode();
+
+ SP->mono = FALSE;
+
+ h_kernel = GetModuleHandleA("kernel32.dll");
+ pGetConsoleScreenBufferInfoEx =
+ (GetConsoleScreenBufferInfoExFn)GetProcAddress(h_kernel,
+ "GetConsoleScreenBufferInfoEx");
+ pSetConsoleScreenBufferInfoEx =
+ (SetConsoleScreenBufferInfoExFn)GetProcAddress(h_kernel,
+ "SetConsoleScreenBufferInfoEx");
+
+ return OK;
+}
+
+ /* Calls SetConsoleWindowInfo with the given parameters, but fits them
+ if a scoll bar shrinks the maximum possible value. The rectangle
+ must at least fit in a half-sized window. */
+
+static BOOL _fit_console_window(HANDLE con_out, CONST SMALL_RECT *rect)
+{
+ SMALL_RECT run;
+ SHORT mx, my;
+
+ if (SetConsoleWindowInfo(con_out, TRUE, rect))
+ return TRUE;
+
+ run = *rect;
+ run.Right /= 2;
+ run.Bottom /= 2;
+
+ mx = run.Right;
+ my = run.Bottom;
+
+ if (!SetConsoleWindowInfo(con_out, TRUE, &run))
+ return FALSE;
+
+ for (run.Right = rect->Right; run.Right >= mx; run.Right--)
+ if (SetConsoleWindowInfo(con_out, TRUE, &run))
+ break;
+
+ if (run.Right < mx)
+ return FALSE;
+
+ for (run.Bottom = rect->Bottom; run.Bottom >= my; run.Bottom--)
+ if (SetConsoleWindowInfo(con_out, TRUE, &run))
+ return TRUE;
+
+ return FALSE;
+}
+
+/* the core of resize_term() */
+
+int PDC_resize_screen(int nlines, int ncols)
+{
+ SMALL_RECT rect;
+ COORD size, max;
+
+ bool prog_resize = nlines || ncols;
+
+ if (!prog_resize)
+ {
+ nlines = PDC_get_rows();
+ ncols = PDC_get_columns();
+ }
+
+ if (nlines < 2 || ncols < 2)
+ return ERR;
+
+ max = GetLargestConsoleWindowSize(pdc_con_out);
+
+ rect.Left = rect.Top = 0;
+ rect.Right = ncols - 1;
+
+ if (rect.Right > max.X)
+ rect.Right = max.X;
+
+ rect.Bottom = nlines - 1;
+
+ if (rect.Bottom > max.Y)
+ rect.Bottom = max.Y;
+
+ size.X = rect.Right + 1;
+ size.Y = rect.Bottom + 1;
+
+ _fit_console_window(pdc_con_out, &rect);
+ SetConsoleScreenBufferSize(pdc_con_out, size);
+
+ if (prog_resize)
+ {
+ _fit_console_window(pdc_con_out, &rect);
+ SetConsoleScreenBufferSize(pdc_con_out, size);
+ }
+ SetConsoleActiveScreenBuffer(pdc_con_out);
+
+ PDC_flushinp();
+
+ return OK;
+}
+
+void PDC_reset_prog_mode(void)
+{
+ PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
+
+ if (pdc_con_out != std_con_out)
+ SetConsoleActiveScreenBuffer(pdc_con_out);
+ else if (is_nt)
+ {
+ COORD bufsize;
+ SMALL_RECT rect;
+
+ bufsize.X = orig_scr.srWindow.Right - orig_scr.srWindow.Left + 1;
+ bufsize.Y = orig_scr.srWindow.Bottom - orig_scr.srWindow.Top + 1;
+
+ rect.Top = rect.Left = 0;
+ rect.Bottom = bufsize.Y - 1;
+ rect.Right = bufsize.X - 1;
+
+ SetConsoleScreenBufferSize(pdc_con_out, bufsize);
+ SetConsoleWindowInfo(pdc_con_out, TRUE, &rect);
+ SetConsoleScreenBufferSize(pdc_con_out, bufsize);
+ SetConsoleActiveScreenBuffer(pdc_con_out);
+ }
+
+ PDC_mouse_set();
+}
+
+void PDC_reset_shell_mode(void)
+{
+ PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
+
+ if (pdc_con_out != std_con_out)
+ SetConsoleActiveScreenBuffer(std_con_out);
+ else if (is_nt)
+ {
+ SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
+ SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
+ SetConsoleScreenBufferSize(pdc_con_out, orig_scr.dwSize);
+ SetConsoleWindowInfo(pdc_con_out, TRUE, &orig_scr.srWindow);
+ SetConsoleActiveScreenBuffer(pdc_con_out);
+ }
+
+ SetConsoleMode(pdc_con_in, old_console_mode | 0x0080);
+}
+
+void PDC_restore_screen_mode(int i)
+{
+}
+
+void PDC_save_screen_mode(int i)
+{
+}
+
+bool PDC_can_change_color(void)
+{
+ return is_nt;
+}
+
+int PDC_color_content(short color, short *red, short *green, short *blue)
+{
+ if (color < 16 && !(pdc_conemu || pdc_wt))
+ {
+ COLORREF *color_table = _get_colors();
+
+ if (color_table)
+ {
+ DWORD col = color_table[pdc_curstoreal[color]];
+
+ *red = DIVROUND(GetRValue(col) * 1000, 255);
+ *green = DIVROUND(GetGValue(col) * 1000, 255);
+ *blue = DIVROUND(GetBValue(col) * 1000, 255);
+ }
+ else
+ return ERR;
+ }
+ else
+ {
+ if (!pdc_color[color].mapped)
+ {
+ *red = *green = *blue = -1;
+ return ERR;
+ }
+
+ *red = pdc_color[color].r;
+ *green = pdc_color[color].g;
+ *blue = pdc_color[color].b;
+ }
+
+ return OK;
+}
+
+int PDC_init_color(short color, short red, short green, short blue)
+{
+ if (red == -1 && green == -1 && blue == -1)
+ {
+ pdc_color[color].mapped = FALSE;
+ return OK;
+ }
+
+ if (color < 16 && !(pdc_conemu || pdc_wt))
+ {
+ COLORREF *color_table = _get_colors();
+
+ if (color_table)
+ {
+ color_table[pdc_curstoreal[color]] =
+ RGB(DIVROUND(red * 255, 1000),
+ DIVROUND(green * 255, 1000),
+ DIVROUND(blue * 255, 1000));
+
+ return _set_colors();
+ }
+
+ return ERR;
+ }
+ else
+ {
+ pdc_color[color].r = red;
+ pdc_color[color].g = green;
+ pdc_color[color].b = blue;
+ pdc_color[color].mapped = TRUE;
+ }
+
+ return OK;
+}
diff --git a/Utilities/cmpdcurses/wincon/pdcsetsc.c b/Utilities/cmpdcurses/wincon/pdcsetsc.c
new file mode 100644
index 0000000..a2d1b6d
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/pdcsetsc.c
@@ -0,0 +1,130 @@
+/* PDCurses */
+
+#include "pdcwin.h"
+
+/*man-start**************************************************************
+
+pdcsetsc
+--------
+
+### Synopsis
+
+ int PDC_set_blink(bool blinkon);
+ int PDC_set_bold(bool boldon);
+ void PDC_set_title(const char *title);
+
+### Description
+
+ PDC_set_blink() toggles whether the A_BLINK attribute sets an actual
+ blink mode (TRUE), or sets the background color to high intensity
+ (FALSE). The default is platform-dependent (FALSE in most cases). It
+ returns OK if it could set the state to match the given parameter,
+ ERR otherwise.
+
+ PDC_set_bold() toggles whether the A_BOLD attribute selects an actual
+ bold font (TRUE), or sets the foreground color to high intensity
+ (FALSE). It returns OK if it could set the state to match the given
+ parameter, ERR otherwise.
+
+ PDC_set_title() sets the title of the window in which the curses
+ program is running. This function may not do anything on some
+ platforms.
+
+### Portability
+ X/Open ncurses NetBSD
+ PDC_set_blink - - -
+ PDC_set_title - - -
+
+**man-end****************************************************************/
+
+int PDC_curs_set(int visibility)
+{
+ CONSOLE_CURSOR_INFO cci;
+ int ret_vis;
+
+ PDC_LOG(("PDC_curs_set() - called: visibility=%d\n", visibility));
+
+ ret_vis = SP->visibility;
+
+ if (GetConsoleCursorInfo(pdc_con_out, &cci) == FALSE)
+ return ERR;
+
+ switch(visibility)
+ {
+ case 0: /* invisible */
+ cci.bVisible = FALSE;
+ break;
+ case 2: /* highly visible */
+ cci.bVisible = TRUE;
+ cci.dwSize = 95;
+ break;
+ default: /* normal visibility */
+ cci.bVisible = TRUE;
+ cci.dwSize = SP->orig_cursor;
+ break;
+ }
+
+ if (SetConsoleCursorInfo(pdc_con_out, &cci) == FALSE)
+ return ERR;
+
+ SP->visibility = visibility;
+ return ret_vis;
+}
+
+void PDC_set_title(const char *title)
+{
+#ifdef PDC_WIDE
+ wchar_t wtitle[512];
+#endif
+ PDC_LOG(("PDC_set_title() - called:<%s>\n", title));
+
+#ifdef PDC_WIDE
+ PDC_mbstowcs(wtitle, title, 511);
+ SetConsoleTitleW(wtitle);
+#else
+ SetConsoleTitleA(title);
+#endif
+}
+
+int PDC_set_blink(bool blinkon)
+{
+ if (!SP)
+ return ERR;
+
+ if (SP->color_started)
+ {
+ COLORS = 16;
+ if (PDC_can_change_color()) /* is_nt */
+ {
+ if (pdc_conemu || SetConsoleMode(pdc_con_out, 0x0004)) /* VT */
+ COLORS = PDC_MAXCOL;
+
+ if (!pdc_conemu)
+ SetConsoleMode(pdc_con_out, 0x0010); /* LVB */
+ }
+ }
+
+ if (blinkon)
+ {
+ if (!(SP->termattrs & A_BLINK))
+ {
+ SP->termattrs |= A_BLINK;
+ pdc_last_blink = GetTickCount();
+ }
+ }
+ else
+ {
+ if (SP->termattrs & A_BLINK)
+ {
+ SP->termattrs &= ~A_BLINK;
+ PDC_blink_text();
+ }
+ }
+
+ return OK;
+}
+
+int PDC_set_bold(bool boldon)
+{
+ return boldon ? ERR : OK;
+}
diff --git a/Utilities/cmpdcurses/wincon/pdcutil.c b/Utilities/cmpdcurses/wincon/pdcutil.c
new file mode 100644
index 0000000..a40cf45
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/pdcutil.c
@@ -0,0 +1,26 @@
+/* PDCurses */
+
+#include "pdcwin.h"
+
+void PDC_beep(void)
+{
+ PDC_LOG(("PDC_beep() - called\n"));
+
+/* MessageBeep(MB_OK); */
+ MessageBeep(0XFFFFFFFF);
+}
+
+void PDC_napms(int ms)
+{
+ PDC_LOG(("PDC_napms() - called: ms=%d\n", ms));
+
+ if ((SP->termattrs & A_BLINK) && (GetTickCount() >= pdc_last_blink + 500))
+ PDC_blink_text();
+
+ Sleep(ms);
+}
+
+const char *PDC_sysname(void)
+{
+ return "Windows";
+}
diff --git a/Utilities/cmpdcurses/wincon/pdcwin.h b/Utilities/cmpdcurses/wincon/pdcwin.h
new file mode 100644
index 0000000..08d3579
--- /dev/null
+++ b/Utilities/cmpdcurses/wincon/pdcwin.h
@@ -0,0 +1,27 @@
+/* PDCurses */
+
+#if defined(PDC_WIDE) && !defined(UNICODE)
+# define UNICODE
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef MOUSE_MOVED
+#include <curspriv.h>
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
+# define _CRT_SECURE_NO_DEPRECATE 1 /* kill nonsense warnings */
+#endif
+
+typedef struct {short r, g, b; bool mapped;} PDCCOLOR;
+
+extern PDCCOLOR pdc_color[PDC_MAXCOL];
+
+extern HANDLE pdc_con_out, pdc_con_in;
+extern DWORD pdc_quick_edit;
+extern DWORD pdc_last_blink;
+extern short pdc_curstoreal[16], pdc_curstoansi[16];
+extern short pdc_oldf, pdc_oldb, pdc_oldu;
+extern bool pdc_conemu, pdc_wt, pdc_ansi;
+
+extern void PDC_blink_text(void);
diff --git a/Utilities/cmzlib/CMakeLists.txt b/Utilities/cmzlib/CMakeLists.txt
index d57cb29..42bf2c5 100644
--- a/Utilities/cmzlib/CMakeLists.txt
+++ b/Utilities/cmzlib/CMakeLists.txt
@@ -2,7 +2,7 @@ PROJECT(CMZLIB)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
diff --git a/Utilities/cmzstd/CMakeLists.txt b/Utilities/cmzstd/CMakeLists.txt
index 1997195..981e3d5 100644
--- a/Utilities/cmzstd/CMakeLists.txt
+++ b/Utilities/cmzstd/CMakeLists.txt
@@ -2,7 +2,7 @@ project(zstd C)
# Disable warnings to avoid changing 3rd party code.
if(CMAKE_C_COMPILER_ID MATCHES
- "^(GNU|Clang|AppleClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
+ "^(GNU|LCC|Clang|AppleClang|IBMClang|XLClang|XL|VisualAge|SunPro|HP|Intel|IntelLLVM|NVHPC)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")