mirror of
https://github.com/xroche/httrack.git
synced 2026-07-26 18:49:39 +03:00
Compare commits
1 Commits
warnfix-li
...
ci/vcpkg-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abbe806907 |
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@@ -6,9 +6,3 @@ updates:
|
||||
directory: /src
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
# Keep the workflow action pins current (they only rot manually otherwise).
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
env:
|
||||
CC: ${{ matrix.cc }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
name: build (no python3, Debian buildd)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
name: build (macOS arm64, clang)
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
name: webhttrack smoke (macOS arm64)
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -199,7 +199,7 @@ jobs:
|
||||
name: build (linux i386, gcc -m32)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -242,7 +242,7 @@ jobs:
|
||||
name: sanitize (ASan+UBSan, gcc)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -296,7 +296,7 @@ jobs:
|
||||
name: msan (MemorySanitizer, clang)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -344,7 +344,7 @@ jobs:
|
||||
name: fuzz (libFuzzer corpus replay, clang)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -383,7 +383,7 @@ jobs:
|
||||
name: build (no openssl, --disable-https)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -437,7 +437,7 @@ jobs:
|
||||
zlib1g-dev libssl-dev libbrotli-dev libzstd-dev \
|
||||
debhelper devscripts lintian fakeroot
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -468,7 +468,7 @@ jobs:
|
||||
name: distcheck (release tarball)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -493,7 +493,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -537,7 +537,7 @@ jobs:
|
||||
tests/*.test
|
||||
tools/mkdeb.sh
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install linters
|
||||
run: |
|
||||
@@ -572,7 +572,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -624,7 +624,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
# Upload findings to the repo's code-scanning dashboard.
|
||||
security-events: write
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
8
.github/workflows/windows-build.yml
vendored
8
.github/workflows/windows-build.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
env:
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}\vcpkg_cache
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive # coucal lives in src/coucal
|
||||
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
# carries the builtin-baseline, so a Dependabot bump busts it; restore-keys
|
||||
# still seeds the unchanged ports' archives, so only the bumped one rebuilds.
|
||||
- name: Cache vcpkg binary archives
|
||||
uses: actions/cache@v6
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}\vcpkg_cache
|
||||
key: vcpkg-${{ matrix.platform }}-${{ hashFiles('src/vcpkg.json') }}
|
||||
@@ -233,7 +233,7 @@ jobs:
|
||||
|
||||
- name: Upload the test logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: engine-tests-${{ matrix.platform }}-${{ matrix.configuration }}
|
||||
path: tests/*.log
|
||||
@@ -241,7 +241,7 @@ jobs:
|
||||
|
||||
- name: Upload MSBuild logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: msbuild-${{ matrix.platform }}-${{ matrix.configuration }}
|
||||
path: msbuild-*.log
|
||||
|
||||
45
configure.ac
45
configure.ac
@@ -66,11 +66,10 @@ AC_SUBST(LT_CV_OBJDIR,$lt_cv_objdir)
|
||||
AC_SUBST(VERSION_INFO)
|
||||
|
||||
### Default CFLAGS
|
||||
# No -Wdeclaration-after-statement: nothing sets -std=, so this builds as gnu17.
|
||||
DEFAULT_CFLAGS="-Wall -Wformat -Wformat-security \
|
||||
-Wmultichar -Wwrite-strings -Wcast-qual -Wcast-align \
|
||||
-Wstrict-prototypes -Wmissing-prototypes \
|
||||
-Wmissing-declarations \
|
||||
-Wmissing-declarations -Wdeclaration-after-statement \
|
||||
-Wpointer-arith -Wsequence-point -Wnested-externs \
|
||||
-D_REENTRANT"
|
||||
AC_SUBST(DEFAULT_CFLAGS)
|
||||
@@ -78,28 +77,26 @@ DEFAULT_LDFLAGS=""
|
||||
AC_SUBST(DEFAULT_LDFLAGS)
|
||||
|
||||
### Additional flags (if supported)
|
||||
# -Werror on probes: exit-status-only checks let clang's warn-on-unknown-flag through.
|
||||
AX_CHECK_COMPILE_FLAG([-Wparentheses], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wparentheses"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Winit-self], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Winit-self"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Wunused-but-set-parameter], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wunused-but-set-parameter"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Waddress], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Waddress"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Wuninitialized], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wuninitialized"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Wformat=2], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wformat=2"], [], [-Werror])
|
||||
# -Wformat-nonliteral needs -Wformat in the probe or gcc rejects it as ignored.
|
||||
AX_CHECK_COMPILE_FLAG([-Wformat-nonliteral], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wformat-nonliteral"], [], [-Werror -Wformat])
|
||||
AX_CHECK_COMPILE_FLAG([-Wmissing-parameter-type], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wmissing-parameter-type"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Wold-style-definition], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wold-style-definition"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Wignored-qualifiers], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wignored-qualifiers"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Wparentheses], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wparentheses"])
|
||||
AX_CHECK_COMPILE_FLAG([-Winit-self], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Winit-self"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wunused-but-set-parameter], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wunused-but-set-parameter"])
|
||||
AX_CHECK_COMPILE_FLAG([-Waddress], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Waddress"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wuninitialized], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wuninitialized"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wformat=2], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wformat=2"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wformat-nonliteral], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wformat-nonliteral"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wmissing-parameter-type], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wmissing-parameter-type"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wold-style-definition], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wold-style-definition"])
|
||||
AX_CHECK_COMPILE_FLAG([-Wignored-qualifiers], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Wignored-qualifiers"])
|
||||
# Make htssafe.h's pointer-dest 'warning' attribute a hard error in our build
|
||||
# (migration is at zero; a new char* dest is a regression). gcc/clang each take
|
||||
# only their own spelling; downstream keeps the plain warning, not a build break.
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=attribute-warning], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=attribute-warning"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=user-defined-warnings], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=user-defined-warnings"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-fstrict-aliasing -Wstrict-aliasing], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstrict-aliasing -Wstrict-aliasing"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=attribute-warning], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=attribute-warning"])
|
||||
AX_CHECK_COMPILE_FLAG([-Werror=user-defined-warnings], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -Werror=user-defined-warnings"])
|
||||
AX_CHECK_COMPILE_FLAG([-fstrict-aliasing -Wstrict-aliasing], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstrict-aliasing -Wstrict-aliasing"])
|
||||
AX_CHECK_COMPILE_FLAG([-fstack-protector-strong], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector-strong"],
|
||||
[AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"], [], [-Werror])], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-clash-protection"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-fcf-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fcf-protection"], [], [-Werror])
|
||||
[AX_CHECK_COMPILE_FLAG([-fstack-protector], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-protector"])])
|
||||
AX_CHECK_COMPILE_FLAG([-fstack-clash-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fstack-clash-protection"])
|
||||
AX_CHECK_COMPILE_FLAG([-fcf-protection], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -fcf-protection"])
|
||||
AX_CHECK_LINK_FLAG([-Wl,--discard-all], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--discard-all"])
|
||||
AX_CHECK_LINK_FLAG([-Wl,--no-undefined], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,--no-undefined"])
|
||||
AX_CHECK_LINK_FLAG([-Wl,-z,relro,-z,now], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -Wl,-z,relro,-z,now"])
|
||||
@@ -122,13 +119,13 @@ AC_SUBST([LIBC_FORCE_LINK])
|
||||
### PIE
|
||||
CFLAGS_PIE=""
|
||||
LDFLAGS_PIE=""
|
||||
AX_CHECK_COMPILE_FLAG([-fpie], [CFLAGS_PIE="-fpie"], [], [-Werror])
|
||||
AX_CHECK_COMPILE_FLAG([-fpie -pie], [CFLAGS_PIE="-fpie -pie"])
|
||||
AX_CHECK_LINK_FLAG([-pie], [LDFLAGS_PIE="-pie"])
|
||||
AC_SUBST([CFLAGS_PIE])
|
||||
AC_SUBST([LDFLAGS_PIE])
|
||||
|
||||
## -rdynamic must be a link flag; DEFAULT_CFLAGS (AM_CPPFLAGS) never reaches the linker.
|
||||
AX_CHECK_LINK_FLAG([-rdynamic], [DEFAULT_LDFLAGS="$DEFAULT_LDFLAGS -rdynamic"])
|
||||
## Export all symbols for backtraces
|
||||
AX_CHECK_COMPILE_FLAG([-rdynamic], [DEFAULT_CFLAGS="$DEFAULT_CFLAGS -rdynamic"])
|
||||
|
||||
### Check for -fvisibility=hidden support
|
||||
gl_VISIBILITY
|
||||
@@ -172,7 +169,7 @@ AC_CHECK_TYPE(sa_family_t, [], [AC_DEFINE([sa_family_t], [uint16_t], [sa_family_
|
||||
AX_CHECK_ALIGNED_ACCESS_REQUIRED
|
||||
|
||||
# check for various headers
|
||||
AC_CHECK_HEADERS([execinfo.h sys/ioctl.h])
|
||||
AC_CHECK_HEADERS([execinfo.h])
|
||||
|
||||
### zlib
|
||||
CHECK_ZLIB()
|
||||
|
||||
@@ -629,8 +629,8 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
||||
// File exists on disk with declared cache name (this is expected!)
|
||||
if (fexist_utf8(fconv(catbuff, sizeof(catbuff), previous_save))) { // un fichier existe déja
|
||||
// Expected size ?
|
||||
const LLint fsize = fsize_utf8(
|
||||
fconv(catbuff, sizeof(catbuff), previous_save));
|
||||
const size_t fsize =
|
||||
fsize_utf8(fconv(catbuff, sizeof(catbuff), previous_save));
|
||||
if (fsize == r.size) {
|
||||
// Target name is the previous name, and the file looks good: nothing to do!
|
||||
if (strcmp(previous_save, target_save) == 0) {
|
||||
@@ -666,8 +666,7 @@ static htsblk cache_readex_new(httrackp * opt, cache_back * cache,
|
||||
// Suppose a broken mirror, with a file being renamed: OK
|
||||
else if (fexist_utf8(fconv(catbuff, sizeof(catbuff), target_save))) {
|
||||
// Expected size ?
|
||||
const LLint fsize =
|
||||
fsize_utf8(fconv(catbuff, sizeof(catbuff), target_save));
|
||||
const size_t fsize = fsize_utf8(fconv(catbuff, sizeof(catbuff), target_save));
|
||||
|
||||
if (fsize == r.size) {
|
||||
// So far so good
|
||||
|
||||
@@ -390,10 +390,6 @@ HTSEXT_API char *hts_convertStringSystemToUTF8(const char *s, size_t size) {
|
||||
return hts_convertStringCPToUTF8(s, size, GetACP());
|
||||
}
|
||||
|
||||
HTSEXT_API char *hts_convertStringUTF8ToSystem(const char *s, size_t size) {
|
||||
return hts_convertStringCPFromUTF8(s, size, GetACP());
|
||||
}
|
||||
|
||||
HTSEXT_API void hts_argv_utf8(int *pargc, char ***pargv) {
|
||||
int wargc = 0;
|
||||
LPWSTR *const wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
|
||||
|
||||
@@ -184,12 +184,6 @@ extern LPWSTR hts_pathToUCS2(const char *path);
|
||||
**/
|
||||
HTSEXT_API char *hts_convertStringSystemToUTF8(const char *s, size_t size);
|
||||
|
||||
/**
|
||||
* Convert UTF-8 to the current system codepage. Caller frees; NULL upon error.
|
||||
* This function is WIN32 specific.
|
||||
**/
|
||||
HTSEXT_API char *hts_convertStringUTF8ToSystem(const char *s, size_t size);
|
||||
|
||||
/**
|
||||
* Replace the CRT's ANSI argv by a UTF-8 one decoded from the real UTF-16
|
||||
* command line: every char* is UTF-8 on Windows (FOPEN, STAT, ... convert at
|
||||
|
||||
@@ -696,19 +696,17 @@ int httpmirror(char *url1, httrackp * opt) {
|
||||
// copier adresse(s) dans liste des adresses
|
||||
{
|
||||
char *a = url1;
|
||||
const LLint list_sz = StringNotEmpty(opt->filelist)
|
||||
? fsize_utf8(StringBuff(opt->filelist))
|
||||
: 0;
|
||||
/* two bytes reserved per list byte; -1 makes an undoublable size refused */
|
||||
const LLint list_room =
|
||||
list_sz > 0 ? (list_sz <= INT64_MAX / 2 ? list_sz * 2 : -1) : 0;
|
||||
const size_t primary_len =
|
||||
llint_grow_size_t(8192 + strlen(url1) * 2, list_room, 0);
|
||||
int primary_len = 8192;
|
||||
|
||||
if (StringNotEmpty(opt->filelist)) {
|
||||
primary_len += max(0, fsize_utf8(StringBuff(opt->filelist)) * 2);
|
||||
}
|
||||
primary_len += (int) strlen(url1) * 2;
|
||||
|
||||
// création de la première page, qui contient les liens de base à scanner
|
||||
// c'est plus propre et plus logique que d'entrer à la main les liens dans la pile
|
||||
// on bénéficie ainsi des vérifications et des tests du robot pour les liens "primaires"
|
||||
primary = primary_len != (size_t) -1 ? (char *) malloct(primary_len) : NULL;
|
||||
primary = (char *) malloct(primary_len);
|
||||
if (!primary) {
|
||||
printf("PANIC! : Not enough memory [%d]\n", __LINE__);
|
||||
XH_extuninit;
|
||||
@@ -889,7 +887,7 @@ int httpmirror(char *url1, httrackp * opt) {
|
||||
}
|
||||
|
||||
if (filelist_buff != NULL) {
|
||||
size_t filelist_ptr = 0;
|
||||
int filelist_ptr = 0;
|
||||
int n = 0;
|
||||
char BIGSTK line[HTS_URLMAXSIZE * 2];
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
int argv_url = -1; // ==0 : utiliser cache et doit.log
|
||||
char *argv_firsturl = NULL; // utilisé pour nommage par défaut
|
||||
char *url = NULL; // URLS séparées par un espace
|
||||
size_t url_sz = 65535;
|
||||
int url_sz = 65535;
|
||||
|
||||
// the parametres
|
||||
int httrack_logmode = 3; // ONE log file
|
||||
@@ -224,22 +224,21 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
|
||||
/* create x_argvblk buffer for transformed command line */
|
||||
{
|
||||
size_t current_size = 0;
|
||||
const LLint size = fsize("config");
|
||||
size_t blk_size;
|
||||
int current_size = 0;
|
||||
int size;
|
||||
int na;
|
||||
|
||||
for(na = 0; na < argc; na++)
|
||||
current_size += strlen(argv[na]) + 1;
|
||||
/* a huge file named "config" must saturate, not wrap, the capacity */
|
||||
blk_size = llint_grow_size_t(current_size, size > 0 ? size : 0, 32768);
|
||||
x_argvblk = blk_size != (size_t) -1 ? (char *) malloct(blk_size) : NULL;
|
||||
current_size += (int) (strlen(argv[na]) + 1);
|
||||
if ((size = fsize("config")) > 0)
|
||||
current_size += size;
|
||||
x_argvblk = (char *) malloct(current_size + 32768);
|
||||
if (x_argvblk == NULL) {
|
||||
HTS_PANIC_PRINTF("Error, not enough memory");
|
||||
htsmain_free();
|
||||
return -1;
|
||||
}
|
||||
x_argvblk_size = blk_size;
|
||||
x_argvblk_size = (size_t) (current_size + 32768);
|
||||
x_argvblk[0] = '\0';
|
||||
x_ptr = 0;
|
||||
|
||||
@@ -1457,29 +1456,20 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
FILE *fp = FOPEN(argv[na], "rb");
|
||||
|
||||
if (fp != NULL) {
|
||||
size_t cl = strlen(url);
|
||||
const size_t fzs = llint_to_size_t(fz);
|
||||
const size_t capa = llint_grow_size_t(cl, fz, 8192);
|
||||
int cl = (int) strlen(url);
|
||||
|
||||
if (capa == (size_t) -1) {
|
||||
fclose(fp);
|
||||
HTS_PANIC_PRINTF("File url list too large");
|
||||
htsmain_free();
|
||||
return -1;
|
||||
}
|
||||
ensureUrlCapacity(url, url_sz, capa);
|
||||
ensureUrlCapacity(url, url_sz, cl + fz + 8192);
|
||||
if (cl > 0) { /* don't stick! (3.43) */
|
||||
url[cl] = ' ';
|
||||
cl++;
|
||||
}
|
||||
if (fread(url + cl, 1, fzs, fp) != fzs) {
|
||||
fclose(fp);
|
||||
if (fread(url + cl, 1, fz, fp) != fz) {
|
||||
HTS_PANIC_PRINTF("File url list could not be read");
|
||||
htsmain_free();
|
||||
return -1;
|
||||
}
|
||||
fclose(fp);
|
||||
*(url + cl + fzs) = '\0';
|
||||
*(url + cl + fz) = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2306,8 +2296,8 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
|
||||
|
||||
} else { // URL/filters
|
||||
char catbuff[CATBUFF_SIZE];
|
||||
const size_t urlSize = strlen(argv[na]);
|
||||
const size_t capa = strlen(url) + urlSize + 32;
|
||||
const int urlSize = (int) strlen(argv[na]);
|
||||
const int capa = (int) (strlen(url) + urlSize + 32);
|
||||
|
||||
assertf(urlSize < HTS_URLMAXSIZE);
|
||||
if (urlSize < HTS_URLMAXSIZE) {
|
||||
|
||||
@@ -336,20 +336,16 @@ typedef int INTsys;
|
||||
#endif
|
||||
|
||||
/* Socket-handle type. An unsigned integer wide enough for a Windows SOCKET;
|
||||
a plain int file descriptor on POSIX. T_SOCP is its printf conversion,
|
||||
'%' included: unsigned __int64 on Win64 must not be printed with "%d". */
|
||||
a plain int file descriptor on POSIX. */
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN64)
|
||||
|
||||
typedef unsigned __int64 T_SOC;
|
||||
#define T_SOCP "%" PRIu64
|
||||
#else
|
||||
typedef unsigned __int32 T_SOC;
|
||||
#define T_SOCP "%" PRIu32
|
||||
#endif
|
||||
#else
|
||||
typedef int T_SOC;
|
||||
#define T_SOCP "%d"
|
||||
#endif
|
||||
|
||||
/* Buffer size for a printed network address (IPv4 or IPv6, NUL included). */
|
||||
|
||||
@@ -2598,15 +2598,13 @@ void deletesoc(T_SOC soc) {
|
||||
if (closesocket(soc) != 0) {
|
||||
int err = WSAGetLastError();
|
||||
|
||||
fprintf(stderr, "* error closing socket " T_SOCP ": %s\n", soc,
|
||||
strerror(err));
|
||||
fprintf(stderr, "* error closing socket %d: %s\n", soc, strerror(err));
|
||||
}
|
||||
#else
|
||||
if (close(soc) != 0) {
|
||||
const int err = errno;
|
||||
|
||||
fprintf(stderr, "* error closing socket " T_SOCP ": %s\n", soc,
|
||||
strerror(err));
|
||||
fprintf(stderr, "* error closing socket %d: %s\n", soc, strerror(err));
|
||||
}
|
||||
#endif
|
||||
#if HTS_WIDE_DEBUG
|
||||
|
||||
15
src/htslib.h
15
src/htslib.h
@@ -607,21 +607,6 @@ static HTS_UNUSED size_t llint_to_size_t(LLint o) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Capacity for @p used bytes plus @p extra more plus @p slack spare;
|
||||
(size_t) -1 if the total exceeds (size_t) -2 or @p extra is negative
|
||||
(llint_to_size_t() would map that to a huge valid-looking size). */
|
||||
static HTS_UNUSED size_t llint_grow_size_t(size_t used, LLint extra,
|
||||
size_t slack) {
|
||||
const size_t max = (size_t) -2; /* (size_t) -1 is the error value */
|
||||
const size_t e = extra >= 0 ? llint_to_size_t(extra) : (size_t) -1;
|
||||
|
||||
if (e == (size_t) -1 || used > max || slack > max - used ||
|
||||
e > max - used - slack) {
|
||||
return (size_t) -1;
|
||||
}
|
||||
return used + e + slack;
|
||||
}
|
||||
|
||||
/* dirent() compatibility */
|
||||
#ifdef _WIN32
|
||||
/* Holds a UTF-8 d_name: MAX_PATH (260) UTF-16 units expand to <=3 bytes each.
|
||||
|
||||
@@ -4583,7 +4583,7 @@ int hts_wait_delayed(htsmoduleStruct * str, lien_adrfilsave *afs,
|
||||
/* seen as in error */
|
||||
in_error = back[b].r.statuscode;
|
||||
in_error_msg[0] = 0;
|
||||
strncatbuff(in_error_msg, back[b].r.msg, sizeof(in_error_msg) - 1);
|
||||
strncat(in_error_msg, back[b].r.msg, sizeof(in_error_msg) - 1);
|
||||
in_error_size = back[b].r.totalsize;
|
||||
/* don't break, even with "don't take error pages" switch, because we need to process the slot anyway (and cache the error) */
|
||||
}
|
||||
|
||||
@@ -116,15 +116,6 @@ static HTS_UNUSED void abortf_(const char *exp, const char *file, int line) {
|
||||
#endif
|
||||
#define HTS_IS_NOT_CHAR_BUFFER(VAR) (!HTS_IS_CHAR_BUFFER(VAR))
|
||||
|
||||
/* Source capacity for the buff() family, (size_t)-1 when unknown; sizeof of the
|
||||
TYPE keeps a decayed operand ("buf + 1") off -Wsizeof-array-decay. */
|
||||
#if (defined(__GNUC__) && !defined(__cplusplus))
|
||||
#define HTS_SIZEOF_SRC_(B) \
|
||||
(HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(__typeof__(B)))
|
||||
#else
|
||||
#define HTS_SIZEOF_SRC_(B) (HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B))
|
||||
#endif
|
||||
|
||||
/* Compile-time checks. */
|
||||
static HTS_UNUSED void htssafe_compile_time_check_(void) {
|
||||
char array[32];
|
||||
@@ -214,17 +205,19 @@ static char *strncatbuff_ptr_(char *dest, const char *src, size_t n) {
|
||||
#if (defined(__GNUC__) && !defined(__cplusplus))
|
||||
|
||||
#define strncatbuff(A, B, N) \
|
||||
__builtin_choose_expr(HTS_IS_CHAR_BUFFER(A), \
|
||||
strncat_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), N, \
|
||||
"overflow while appending '" #B \
|
||||
"' to '" #A "'", \
|
||||
__FILE__, __LINE__), \
|
||||
strncatbuff_ptr_((A), (B), (N)))
|
||||
__builtin_choose_expr( \
|
||||
HTS_IS_CHAR_BUFFER(A), \
|
||||
strncat_safe_(A, sizeof(A), B, \
|
||||
HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), N, \
|
||||
"overflow while appending '" #B "' to '" #A "'", __FILE__, \
|
||||
__LINE__), \
|
||||
strncatbuff_ptr_((A), (B), (N)))
|
||||
#else
|
||||
#define strncatbuff(A, B, N) \
|
||||
(HTS_IS_NOT_CHAR_BUFFER(A) \
|
||||
? strncat(A, B, N) \
|
||||
: strncat_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), N, \
|
||||
: strncat_safe_(A, sizeof(A), B, \
|
||||
HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), N, \
|
||||
"overflow while appending '" #B "' to '" #A "'", \
|
||||
__FILE__, __LINE__))
|
||||
#endif
|
||||
@@ -239,7 +232,9 @@ static char *strncatbuff_ptr_(char *dest, const char *src, size_t n) {
|
||||
#define strcatbuff(A, B) \
|
||||
__builtin_choose_expr( \
|
||||
HTS_IS_CHAR_BUFFER(A), \
|
||||
strncat_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), (size_t) -1, \
|
||||
strncat_safe_(A, sizeof(A), B, \
|
||||
HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), \
|
||||
(size_t) -1, \
|
||||
"overflow while appending '" #B "' to '" #A "'", __FILE__, \
|
||||
__LINE__), \
|
||||
strcatbuff_ptr_((A), (B)))
|
||||
@@ -247,7 +242,9 @@ static char *strncatbuff_ptr_(char *dest, const char *src, size_t n) {
|
||||
#define strcatbuff(A, B) \
|
||||
(HTS_IS_NOT_CHAR_BUFFER(A) \
|
||||
? strcat(A, B) \
|
||||
: strncat_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), (size_t) -1, \
|
||||
: strncat_safe_(A, sizeof(A), B, \
|
||||
HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), \
|
||||
(size_t) -1, \
|
||||
"overflow while appending '" #B "' to '" #A "'", \
|
||||
__FILE__, __LINE__))
|
||||
#endif
|
||||
@@ -260,17 +257,19 @@ static char *strncatbuff_ptr_(char *dest, const char *src, size_t n) {
|
||||
#if (defined(__GNUC__) && !defined(__cplusplus))
|
||||
|
||||
#define strcpybuff(A, B) \
|
||||
__builtin_choose_expr(HTS_IS_CHAR_BUFFER(A), \
|
||||
strcpy_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), \
|
||||
"overflow while copying '" #B "' to '" #A \
|
||||
"'", \
|
||||
__FILE__, __LINE__), \
|
||||
strcpybuff_ptr_((A), (B)))
|
||||
__builtin_choose_expr( \
|
||||
HTS_IS_CHAR_BUFFER(A), \
|
||||
strcpy_safe_(A, sizeof(A), B, \
|
||||
HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), \
|
||||
"overflow while copying '" #B "' to '" #A "'", __FILE__, \
|
||||
__LINE__), \
|
||||
strcpybuff_ptr_((A), (B)))
|
||||
#else
|
||||
#define strcpybuff(A, B) \
|
||||
(HTS_IS_NOT_CHAR_BUFFER(A) \
|
||||
? strcpy(A, B) \
|
||||
: strcpy_safe_(A, sizeof(A), B, HTS_SIZEOF_SRC_(B), \
|
||||
: strcpy_safe_(A, sizeof(A), B, \
|
||||
HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), \
|
||||
"overflow while copying '" #B "' to '" #A "'", __FILE__, \
|
||||
__LINE__))
|
||||
#endif
|
||||
@@ -287,24 +286,24 @@ static char *strncatbuff_ptr_(char *dest, const char *src, size_t n) {
|
||||
* Append characters of "B" to "A", "A" having a maximum capacity of "S".
|
||||
*/
|
||||
#define strlcatbuff(A, B, S) \
|
||||
strncat_safe_(A, S, B, HTS_SIZEOF_SRC_(B), (size_t) -1, \
|
||||
"overflow while appending '" #B "' to '" #A "'", __FILE__, \
|
||||
__LINE__)
|
||||
strncat_safe_(A, S, B, HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), \
|
||||
(size_t) -1, "overflow while appending '" #B "' to '" #A "'", \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Append at most "N" characters of "B" to "A", "A" having a maximum capacity
|
||||
* of "S".
|
||||
*/
|
||||
#define strlncatbuff(A, B, S, N) \
|
||||
strncat_safe_(A, S, B, HTS_SIZEOF_SRC_(B), N, \
|
||||
"overflow while appending '" #B "' to '" #A "'", __FILE__, \
|
||||
strncat_safe_(A, S, B, HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), \
|
||||
N, "overflow while appending '" #B "' to '" #A "'", __FILE__, \
|
||||
__LINE__)
|
||||
|
||||
/**
|
||||
* Copy characters of "B" to "A", "A" having a maximum capacity of "S".
|
||||
*/
|
||||
#define strlcpybuff(A, B, S) \
|
||||
strcpy_safe_(A, S, B, HTS_SIZEOF_SRC_(B), \
|
||||
strcpy_safe_(A, S, B, HTS_IS_NOT_CHAR_BUFFER(B) ? (size_t) -1 : sizeof(B), \
|
||||
"overflow while copying '" #B "' to '" #A "'", __FILE__, \
|
||||
__LINE__)
|
||||
|
||||
@@ -423,9 +422,7 @@ static HTS_INLINE HTS_UNUSED htsbuff htsbuff_ptr_(char *buf, size_t cap) {
|
||||
*/
|
||||
static HTS_INLINE HTS_UNUSED void htsbuff_catn(htsbuff *b, const char *s,
|
||||
size_t n) {
|
||||
/* the (size_t)-1 "no limit" sentinel would reach strnlen as a bound past
|
||||
PTRDIFF_MAX */
|
||||
const size_t add = n != (size_t) -1 ? strnlen(s, n) : strlen(s);
|
||||
const size_t add = strnlen(s, n);
|
||||
/* Overflow-safe: keep the (potentially huge) 'add' alone on one side. The
|
||||
maintained invariant len < cap makes 'cap - len' >= 1 (no underflow), so
|
||||
'add < cap - len' cannot wrap the way 'len + add < cap' could. */
|
||||
|
||||
@@ -481,28 +481,6 @@ static int string_safety_selftests(void) {
|
||||
if (strcmp(buf, "abcd") != 0)
|
||||
return 1;
|
||||
|
||||
/* A decayed source has no known capacity, so the whole tail must land; a
|
||||
sizeof(char*) capacity would abort here instead. */
|
||||
{
|
||||
char src[32] = "0123456789abcdefghij";
|
||||
char dst[32];
|
||||
|
||||
strcpybuff(dst, src + 1);
|
||||
if (strcmp(dst, "123456789abcdefghij") != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Truncating append: stops at N without aborting, what the status-message
|
||||
call sites rely on. */
|
||||
{
|
||||
char dst[10]; /* never sizeof(char*), or MSVC reads it as a pointer */
|
||||
|
||||
dst[0] = '\0';
|
||||
strncatbuff(dst, "abcdefghijkl", sizeof(dst) - 1);
|
||||
if (strcmp(dst, "abcdefghi") != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* strlcpybuff: explicit-capacity copy into a pointer destination, the form
|
||||
the migration moves toward */
|
||||
{
|
||||
@@ -909,66 +887,6 @@ static int st_charset(httrackp *opt, int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Oracle is the raw Win32 two-step this replaces, so a mis-wired direction or
|
||||
a plain copy fails whatever the machine's ACP. */
|
||||
static int st_syscharset(httrackp *opt, int argc, char **argv) {
|
||||
#ifdef _WIN32
|
||||
static const char *const utf8 = "caf\xC3\xA9 \xE2\x82\xAC"; /* "café €" */
|
||||
const UINT cp = GetACP();
|
||||
const int len = (int) strlen(utf8);
|
||||
WCHAR wide[64], round[64];
|
||||
char want[64];
|
||||
char *sys, *back, *part;
|
||||
int wn, n, lossless;
|
||||
|
||||
(void) opt;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
wn = MultiByteToWideChar(CP_UTF8, 0, utf8, len, wide,
|
||||
(int) (sizeof(wide) / sizeof(wide[0])));
|
||||
assertf(wn > 0);
|
||||
n = WideCharToMultiByte(cp, 0, wide, wn, want, (int) sizeof(want) - 1, NULL,
|
||||
NULL);
|
||||
assertf(n > 0);
|
||||
want[n] = '\0';
|
||||
/* the ACP holds the string only if its bytes decode back to the same UTF-16;
|
||||
lpUsedDefaultChar would miss a best-fit mapping (é to a bare e) */
|
||||
lossless =
|
||||
MultiByteToWideChar(cp, 0, want, n, round,
|
||||
(int) (sizeof(round) / sizeof(round[0]))) == wn &&
|
||||
memcmp(round, wide, (size_t) wn * sizeof(WCHAR)) == 0;
|
||||
|
||||
sys = hts_convertStringUTF8ToSystem(utf8, (size_t) len);
|
||||
assertf(sys != NULL);
|
||||
assertf(strcmp(sys, want) == 0);
|
||||
assertf(strlen(sys) == (size_t) n); /* NUL-terminated, nothing past it */
|
||||
/* the copy the ASCII fast path returns is a pass on a UTF-8 ACP only */
|
||||
assertf(cp == CP_UTF8 || strcmp(sys, utf8) != 0);
|
||||
/* size bounds the read: a caller-given length, not strlen() */
|
||||
part = hts_convertStringUTF8ToSystem(utf8, 3);
|
||||
assertf(part != NULL && strcmp(part, "caf") == 0);
|
||||
freet(part);
|
||||
part = hts_convertStringUTF8ToSystem(utf8, 0);
|
||||
assertf(part != NULL && *part == '\0');
|
||||
freet(part);
|
||||
if (lossless) {
|
||||
back = hts_convertStringSystemToUTF8(sys, strlen(sys));
|
||||
assertf(back != NULL);
|
||||
assertf(strcmp(back, utf8) == 0);
|
||||
freet(back);
|
||||
}
|
||||
freet(sys);
|
||||
printf("syscharset: acp=%u %s: OK\n", (unsigned) cp,
|
||||
lossless ? "round-trip" : "one-way");
|
||||
return 0;
|
||||
#else
|
||||
(void) opt;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
return 77; /* WIN32-only entry point */
|
||||
#endif
|
||||
}
|
||||
|
||||
static int st_metacharset(httrackp *opt, int argc, char **argv) {
|
||||
char *s;
|
||||
|
||||
@@ -1321,14 +1239,6 @@ static int st_strsafe(httrackp *opt, int argc, char **argv) {
|
||||
htsbuff b = htsbuff_array(small);
|
||||
|
||||
htsbuff_cat(&b, src);
|
||||
} else if (strcmp(argv[0], "overflow-src") == 0) {
|
||||
/* Array source with no NUL: its capacity still comes from sizeof(), so
|
||||
the bounded strlen aborts rather than running off the array. */
|
||||
char nonul[6]; /* never sizeof(char*), per the note above */
|
||||
char big[64];
|
||||
|
||||
memset(nonul, src[0], sizeof(nonul));
|
||||
strcpybuff(big, nonul);
|
||||
} else {
|
||||
strcpybuff(small, src);
|
||||
}
|
||||
@@ -2023,77 +1933,6 @@ static int st_fsize(httrackp *opt, int argc, char **argv) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 4GB+100KB wraps to ~108KB through an int, and needs 33 unsigned bits. A
|
||||
macro, not a static const: MSVC's C mode (/TC) rejects a const object
|
||||
used inside another object's static initializer below (C2099). */
|
||||
#define HTS_ST_GROWSIZE_OVER32 (4LL * 1024 * 1024 * 1024 + 100 * 1024)
|
||||
|
||||
/* llint_grow_size_t() sizes the buffer holding a whole -%S list file: the
|
||||
result must be the exact 64-bit sum or a clean refusal, never a short one. */
|
||||
static int st_growsize(httrackp *opt, int argc, char **argv) {
|
||||
enum { REFUSE, ACCEPT, WIDTH };
|
||||
|
||||
static const struct {
|
||||
size_t used;
|
||||
LLint extra;
|
||||
size_t slack;
|
||||
int want;
|
||||
} cases[] = {
|
||||
{0, 0, 0, ACCEPT},
|
||||
{10, 100, 8192, ACCEPT},
|
||||
{(size_t) -2 - 8, 4, 4, ACCEPT}, /* exact fit, no room to spare */
|
||||
{(size_t) -2, 0, 0, ACCEPT}, /* largest representable capacity */
|
||||
{0, -1, 0, REFUSE}, /* fsize() failure */
|
||||
/* -1 already maps to SIZE_MAX; only this exercises the negative guard */
|
||||
{0, -4096, 0, REFUSE},
|
||||
{(size_t) -1, 1, 0, REFUSE},
|
||||
{(size_t) -2, 0, 1, REFUSE}, /* slack alone overruns */
|
||||
{(size_t) -1 - 8, 4, 4, REFUSE}, /* total would be the error value */
|
||||
{(size_t) -1 - 8, 4, 8, REFUSE},
|
||||
{0, HTS_ST_GROWSIZE_OVER32, 8192,
|
||||
WIDTH}, /* 32-bit size_t can't hold these */
|
||||
{10, HTS_ST_GROWSIZE_OVER32, 8192, WIDTH},
|
||||
};
|
||||
|
||||
size_t k;
|
||||
int rc = 0;
|
||||
|
||||
(void) opt;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
for (k = 0; k < sizeof(cases) / sizeof(cases[0]); k++) {
|
||||
const size_t used = cases[k].used, slack = cases[k].slack;
|
||||
const LLint extra = cases[k].extra;
|
||||
const size_t got = llint_grow_size_t(used, extra, slack);
|
||||
const hts_boolean refused = got == (size_t) -1 ? HTS_TRUE : HTS_FALSE;
|
||||
const hts_boolean exact =
|
||||
!refused && extra >= 0 && got - used - slack == (size_t) extra;
|
||||
hts_boolean ok;
|
||||
|
||||
switch (cases[k].want) {
|
||||
case ACCEPT:
|
||||
ok = exact;
|
||||
break;
|
||||
case REFUSE:
|
||||
ok = refused;
|
||||
break;
|
||||
default:
|
||||
ok = sizeof(size_t) >= sizeof(LLint) ? exact : refused;
|
||||
break;
|
||||
}
|
||||
if (!ok) {
|
||||
fprintf(stderr,
|
||||
"growsize: grow(" LLintP ", " LLintP ", " LLintP ") = " LLintP
|
||||
" (want %s)\n",
|
||||
(LLint) used, extra, (LLint) slack, (LLint) got,
|
||||
cases[k].want == REFUSE ? "refusal" : "exact sum");
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
printf("growsize self-test %s\n", rc == 0 ? "OK" : "FAILED");
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int st_savename(httrackp *opt, int argc, char **argv) {
|
||||
lien_adrfilsave afs;
|
||||
cache_back cache;
|
||||
@@ -4893,8 +4732,6 @@ static const struct selftest_entry {
|
||||
{"mime", "<filename>", "MIME type for a filename", st_mime},
|
||||
{"charset", "<charset> <hex:..|string>",
|
||||
"convert a string to UTF-8 from a charset", st_charset},
|
||||
{"syscharset", "", "UTF-8 <-> system codepage conversion (WIN32 only)",
|
||||
st_syscharset},
|
||||
{"metacharset", "<html>", "extract the <meta> charset from an HTML page",
|
||||
st_metacharset},
|
||||
{"isutf8", "<hex:..|string>", "is the string valid UTF-8 (1/0)", st_isutf8},
|
||||
@@ -4908,8 +4745,8 @@ static const struct selftest_entry {
|
||||
{"unescape-bounds", "", "unescapers reserve the NUL byte (no 1-byte OOB)",
|
||||
st_unescape_bounds},
|
||||
{"hashtable", "<count|file>", "coucal hashtable stress test", st_hashtable},
|
||||
{"strsafe", "[overflow|overflow-buff|overflow-src [str]]",
|
||||
"bounded string-op self-test", st_strsafe},
|
||||
{"strsafe", "[overflow|overflow-buff [str]]", "bounded string-op self-test",
|
||||
st_strsafe},
|
||||
{"copyopt", "", "copy_htsopt option-copy self-test", st_copyopt},
|
||||
{"pause", "", "randomized inter-file pause target self-test", st_pause},
|
||||
{"relative", "<link> <curr-file>", "relative link between two paths",
|
||||
@@ -4939,8 +4776,6 @@ static const struct selftest_entry {
|
||||
{"sniff", "<content-type> <hex:..|text>", "MIME magic consistency",
|
||||
st_sniff},
|
||||
{"fsize", "<dir>", "file size past the 2GB signed-32-bit wrap", st_fsize},
|
||||
{"growsize", "", "buffer capacity for a 64-bit file size (no int wrap)",
|
||||
st_growsize},
|
||||
{"cache", "<dir>", "cache read/write round-trip self-test", st_cache},
|
||||
{"cacheindex", "", "cache-index (.ndx) parse must stay in bounds",
|
||||
st_cacheindex},
|
||||
|
||||
@@ -671,10 +671,10 @@ int __cdecl htsshow_loop(t_hts_callbackarg * carg, httrackp * opt, lien_back * b
|
||||
char *eps = strchr(back[i].url_adr, '/');
|
||||
int count;
|
||||
|
||||
if (ep != NULL && eps != NULL && ep < eps &&
|
||||
(count = (int) (ep - back[i].url_adr)) < 4) {
|
||||
if (ep != NULL && ep < eps
|
||||
&& (count = (int) (ep - back[i].url_adr)) < 4) {
|
||||
proto[0] = '\0';
|
||||
strncatbuff(proto, back[i].url_adr, count);
|
||||
strncat(proto, back[i].url_adr, count);
|
||||
}
|
||||
}
|
||||
snprintf(StatsBuffer[index].state, sizeof(StatsBuffer[index].state),
|
||||
|
||||
@@ -68,9 +68,6 @@ static int linput(FILE * fp, char *s, int max);
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#if (defined(__linux) && defined(HAVE_EXECINFO_H))
|
||||
#include <execinfo.h>
|
||||
@@ -188,43 +185,6 @@ static void vt_home(void) {
|
||||
printf("%s%s", VT_RESET, VT_GOTOXY("1", "0"));
|
||||
}
|
||||
|
||||
/* Last known terminal geometry; the defaults are the classic VT100 size. */
|
||||
static int term_cols = 80;
|
||||
static int term_rows = 24;
|
||||
|
||||
/* Returns HTS_TRUE if the terminal size changed since the last call. */
|
||||
static hts_boolean vt_size_refresh(void) {
|
||||
int cols = 0;
|
||||
int rows = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
const HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (console != INVALID_HANDLE_VALUE &&
|
||||
GetConsoleScreenBufferInfo(console, &info)) {
|
||||
cols = info.srWindow.Right - info.srWindow.Left + 1;
|
||||
rows = info.srWindow.Bottom - info.srWindow.Top + 1;
|
||||
}
|
||||
#elif defined(TIOCGWINSZ)
|
||||
struct winsize ws;
|
||||
|
||||
if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) == 0) {
|
||||
cols = ws.ws_col;
|
||||
rows = ws.ws_row;
|
||||
}
|
||||
#endif
|
||||
if (cols <= 0)
|
||||
cols = 80;
|
||||
if (rows <= 0)
|
||||
rows = 24;
|
||||
if (cols == term_cols && rows == term_rows)
|
||||
return HTS_FALSE;
|
||||
term_cols = cols;
|
||||
term_rows = rows;
|
||||
return HTS_TRUE;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
/*
|
||||
@@ -235,8 +195,7 @@ static hts_boolean vt_size_refresh(void) {
|
||||
#define STYLE_STATTEXT VT_UNBOLD
|
||||
#define STYLE_STATRESET VT_UNBOLD
|
||||
#define NStatsBuffer 14
|
||||
/* Rows the stats block and "Current job" take above the in-progress list. */
|
||||
#define NStatsHeaderRows 7
|
||||
#define MAX_LEN_INPROGRESS 40
|
||||
|
||||
static int use_show;
|
||||
static httrackp *global_opt = NULL;
|
||||
@@ -332,7 +291,6 @@ static int __cdecl htsshow_start(t_hts_callbackarg * carg, httrackp * opt) {
|
||||
use_show = 0;
|
||||
if (opt->verbosedisplay == HTS_VERBOSE_FULL) {
|
||||
use_show = 1;
|
||||
(void) vt_size_refresh();
|
||||
vt_clear();
|
||||
}
|
||||
return 1;
|
||||
@@ -438,10 +396,6 @@ static int __cdecl htsshow_loop(t_hts_callbackarg * carg, httrackp * opt, lien_b
|
||||
|
||||
prev_mytime = mytime;
|
||||
|
||||
/* A resize leaves stale wrapped text on screen: repaint everything. */
|
||||
if (vt_size_refresh())
|
||||
vt_clear();
|
||||
|
||||
st[0] = '\0';
|
||||
qsec2str(st, stat_time);
|
||||
vt_home();
|
||||
@@ -481,13 +435,6 @@ static int __cdecl htsshow_loop(t_hts_callbackarg * carg, httrackp * opt, lien_b
|
||||
//
|
||||
t_StatsBuffer StatsBuffer[NStatsBuffer];
|
||||
|
||||
/* Keep the frame within the terminal, or it scrolls the stats away. */
|
||||
const int nstats =
|
||||
min(NStatsBuffer, max(0, term_rows - NStatsHeaderRows));
|
||||
/* URL budget: half the width, i.e. the historical 40 at 80 columns. */
|
||||
const int maxurl =
|
||||
min((int) sizeof(StatsBuffer[0].name) - 1, max(16, term_cols / 2));
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -502,11 +449,10 @@ static int __cdecl htsshow_loop(t_hts_callbackarg * carg, httrackp * opt, lien_b
|
||||
}
|
||||
}
|
||||
for(k = 0; k < 2; k++) { // 0: lien en cours 1: autres liens
|
||||
for (j = 0; (j < 3) && (index < nstats); j++) { // passe de priorité
|
||||
for(j = 0; (j < 3) && (index < NStatsBuffer); j++) { // passe de priorité
|
||||
int _i;
|
||||
|
||||
for (_i = 0 + k; (_i < max(back_max * k, 1)) && (index < nstats);
|
||||
_i++) { // no lien
|
||||
for(_i = 0 + k; (_i < max(back_max * k, 1)) && (index < NStatsBuffer); _i++) { // no lien
|
||||
int i = (back_index + _i) % back_max; // commencer par le "premier" (l'actuel)
|
||||
|
||||
if (back[i].status >= 0) { // signifie "lien actif"
|
||||
@@ -581,14 +527,16 @@ static int __cdecl htsshow_loop(t_hts_callbackarg * carg, httrackp * opt, lien_b
|
||||
}
|
||||
}
|
||||
|
||||
if ((l = (int) strlen(s)) < maxurl)
|
||||
if ((l = (int) strlen(s)) < MAX_LEN_INPROGRESS)
|
||||
strcpybuff(StatsBuffer[index].name, s);
|
||||
else {
|
||||
// couper
|
||||
StatsBuffer[index].name[0] = '\0';
|
||||
strncatbuff(StatsBuffer[index].name, s, maxurl / 2 - 2);
|
||||
strncatbuff(StatsBuffer[index].name, s,
|
||||
MAX_LEN_INPROGRESS / 2 - 2);
|
||||
strcatbuff(StatsBuffer[index].name, "...");
|
||||
strcatbuff(StatsBuffer[index].name, s + l - maxurl / 2 + 2);
|
||||
strcatbuff(StatsBuffer[index].name,
|
||||
s + l - MAX_LEN_INPROGRESS / 2 + 2);
|
||||
}
|
||||
|
||||
if (back[i].r.totalsize >= 0) { // taille prédéfinie
|
||||
@@ -649,7 +597,7 @@ static int __cdecl htsshow_loop(t_hts_callbackarg * carg, httrackp * opt, lien_b
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nstats; i++) {
|
||||
for(i = 0; i < NStatsBuffer; i++) {
|
||||
if (strnotempty(StatsBuffer[i].state)) {
|
||||
printf(VT_CLREOL " %s - \t%s%s \t%s / \t%s", StatsBuffer[i].state,
|
||||
StatsBuffer[i].name, StatsBuffer[i].file, int2bytes(&strc,
|
||||
|
||||
@@ -2191,7 +2191,7 @@ static PT_Element PT_ReadCache__Arc_u(PT_Index index_, const char *url,
|
||||
}
|
||||
if ((pos = getArcField(index->line, 2)) != NULL) {
|
||||
r->msg[0] = '\0';
|
||||
strncatbuff(r->msg, pos, sizeof(r->msg) - 1);
|
||||
strncat(r->msg, pos, sizeof(pos) - 1);
|
||||
}
|
||||
while(linput(index->file, index->line, sizeof(index->line) - 1)
|
||||
&& index->line[0] != '\0') {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Buffer capacity for a 64-bit file size ('httrack -#test=growsize'): a -%S list
|
||||
# file past 4GB must size its buffer exactly or be refused, never wrap.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
out=$(httrack -#test=growsize)
|
||||
echo "$out"
|
||||
test "$out" == "growsize self-test OK"
|
||||
|
||||
tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_growsize.XXXXXX")
|
||||
trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM
|
||||
|
||||
echo '<html><body>hi</body></html>' >"$tmp/index.html"
|
||||
printf -- '-*/zzmarker*\n' >"$tmp/rules.txt"
|
||||
|
||||
# the rules file lands in the URL/filter string, echoed back by the banner
|
||||
run=$(httrack -O "$tmp/out" --quiet -n "-%S" "$tmp/rules.txt" \
|
||||
"file://$tmp/index.html" 2>&1) || true
|
||||
printf '%s\n' "$run" | grep -q 'zzmarker' || {
|
||||
echo "FAIL: -%S rules file was not loaded"
|
||||
printf '%s\n' "$run"
|
||||
exit 1
|
||||
}
|
||||
@@ -47,18 +47,3 @@ case "$err" in
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# An array source with no NUL must abort on the source bound rather than run
|
||||
# off the array: the array half of the source-capacity selection.
|
||||
err=$(httrack -#test=strsafe overflow-src "x" 2>&1) || true
|
||||
case "$err" in
|
||||
*"strsafe: NOT aborted"*)
|
||||
echo "unterminated source array was NOT caught" >&2
|
||||
exit 1
|
||||
;;
|
||||
*"size < sizeof_source"*) ;;
|
||||
*)
|
||||
echo "expected htssafe source-bound abort, got: $err" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# UTF-8 <-> system codepage ('httrack -#test=syscharset'), the pair an MBCS GUI
|
||||
# uses at the Win32 ANSI entry points. WIN32 only, skipped elsewhere.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
rc=0
|
||||
out=$(httrack -O /dev/null -#test=syscharset) || rc=$?
|
||||
echo "$out"
|
||||
|
||||
[ "$rc" = 77 ] && exit 77
|
||||
[ "$rc" = 0 ] || exit "$rc"
|
||||
|
||||
case "$out" in
|
||||
"syscharset: acp="*": OK") ;;
|
||||
*)
|
||||
echo "FAIL: unexpected report"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/bin/bash
|
||||
# An ARC entry's HTTP reason phrase must survive a proxytrack --convert
|
||||
# round-trip; it used to be clipped to sizeof(char*) - 1 bytes.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
dir=$(mktemp -d)
|
||||
trap 'rm -rf "$dir"' EXIT
|
||||
|
||||
printf 'HTTP/1.1 404 Not Found Here At All\r\nContent-Type: text/html\r\nLast-Modified: Wed, 01 Jan 2025 00:00:00 GMT\r\nContent-Length: 5\r\n\r\n' >"$dir/hdr"
|
||||
printf 'hello' >"$dir/body"
|
||||
alen=$(($(wc -c <"$dir/hdr") + $(wc -c <"$dir/body")))
|
||||
|
||||
# ARC 1.0: filedesc record and version block, then per entry
|
||||
# <nl> <URL-record> <nl> <headers> <body>; the record's last field is that length.
|
||||
{
|
||||
printf 'filedesc://t.arc 0.0.0.0 20250101000000 text/plain 200 - - 0 t.arc 9\n'
|
||||
printf '2 0 test\n'
|
||||
printf '\n\n'
|
||||
printf 'http://example.com/page.html 0.0.0.0 20250101000000 text/html 404 - - 0 t.arc %d\n' "$alen"
|
||||
cat "$dir/hdr" "$dir/body"
|
||||
} >"$dir/in.arc"
|
||||
|
||||
proxytrack --convert "$dir/out.arc" "$dir/in.arc" >/dev/null 2>&1
|
||||
|
||||
# HTTP/1.0 is the writer's own prefix (the input says 1.1), so a verbatim copy
|
||||
# of the input cannot satisfy this match.
|
||||
grep -aqF 'HTTP/1.0 404 Not Found Here At All' "$dir/out.arc" || {
|
||||
echo "reason phrase lost in the ARC round-trip:" >&2
|
||||
grep -a '^HTTP/' "$dir/out.arc" >&2 || echo "(no status line at all)" >&2
|
||||
exit 1
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
# #97: a terminal resize must repaint the whole screen, and the frame must
|
||||
# follow the new geometry instead of the hardcoded 80x24 one.
|
||||
set -eu
|
||||
|
||||
: "${top_srcdir:=..}"
|
||||
testdir=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=tests/testlib.sh
|
||||
. "${testdir}/testlib.sh"
|
||||
server=$(nativepath "${testdir}/local-server.py")
|
||||
root=$(nativepath "${testdir}/server-root")
|
||||
driver=$(nativepath "${testdir}/pty-resize.py")
|
||||
|
||||
if is_windows; then
|
||||
echo "no pty on Windows; skipping" >&2
|
||||
exit 77
|
||||
fi
|
||||
python=$(find_python) || ! echo "python3 not found; skipping" >&2 || exit 77
|
||||
|
||||
tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/httrack_resize.XXXXXX") || exit 1
|
||||
serverpid=
|
||||
cleanup() {
|
||||
stop_server "$serverpid"
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
trap cleanup EXIT HUP INT QUIT PIPE TERM
|
||||
|
||||
serverlog="${tmpdir}/server.log"
|
||||
: >"$serverlog"
|
||||
"$python" "$server" --root "$root" >"$serverlog" 2>&1 &
|
||||
serverpid=$!
|
||||
port=
|
||||
for _ in $(seq 1 50); do
|
||||
line=$(head -n1 "$serverlog" 2>/dev/null)
|
||||
if test "${line%% *}" == "PORT"; then
|
||||
port="${line#PORT }"
|
||||
break
|
||||
fi
|
||||
kill -0 "$serverpid" 2>/dev/null || {
|
||||
echo "server exited early: $(cat "$serverlog")"
|
||||
exit 1
|
||||
}
|
||||
sleep 0.1
|
||||
done
|
||||
test -n "$port" || {
|
||||
echo "could not discover server port"
|
||||
exit 1
|
||||
}
|
||||
|
||||
which httrack >/dev/null || {
|
||||
echo "could not find httrack"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Trickled pages under a long path: the display keeps animating while the pty is
|
||||
# resized under it, and the URL is truncated at 80 columns but not at 200.
|
||||
deep="127.0.0.1:${port}/trickle/deep/a-long-directory-segment/another-long-segment"
|
||||
out="${tmpdir}/crawl"
|
||||
mkdir "$out"
|
||||
rc=0
|
||||
# The in-progress rows show host:port, not the scheme.
|
||||
"$python" "$driver" "${tmpdir}/pty.raw" "${deep}/p" -- \
|
||||
httrack "http://${deep}/index.html" \
|
||||
-O "$out" -%v --robots=0 --disable-security-limits \
|
||||
--timeout=30 --retries=1 -c4 --max-time 60 || rc=$?
|
||||
test "$rc" -eq 0 || {
|
||||
echo "pty capture tail:"
|
||||
tail -c 600 "${tmpdir}/pty.raw" | cat -v
|
||||
exit 1
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
EXTRA_DIST = $(TESTS) crawl-test.sh run-all-tests.sh check-network.sh \
|
||||
proxy-https-server.py socks5-server.py proxy-connect-server.py \
|
||||
proxytestlib.py tls-stall-server.py warc-validate.py wacz-validate.py \
|
||||
pty-resize.py \
|
||||
local-crawl.sh local-server.py testlib.sh server.crt server.key \
|
||||
server-root/simple/basic.html server-root/simple/link.html \
|
||||
server-root/stripquery/index.html server-root/stripquery/a.html \
|
||||
@@ -64,7 +63,6 @@ TESTS = \
|
||||
01_engine-reconcile.test \
|
||||
01_engine-expandhome.test \
|
||||
01_engine-fsize.test \
|
||||
01_engine-growsize.test \
|
||||
01_engine-redirect.test \
|
||||
01_engine-longpath-io.test \
|
||||
01_engine-mirror-io.test \
|
||||
@@ -79,7 +77,6 @@ TESTS = \
|
||||
01_engine-status.test \
|
||||
01_engine-stripquery.test \
|
||||
01_engine-strsafe.test \
|
||||
01_engine-syscharset.test \
|
||||
01_engine-topindex.test \
|
||||
01_engine-urlhack.test \
|
||||
01_engine-unescape-bounds.test \
|
||||
@@ -148,7 +145,6 @@ TESTS = \
|
||||
50_local-contentcodings.test \
|
||||
51_local-update-codec.test \
|
||||
52_local-socks5.test \
|
||||
53_local-proxytrack-arc-reason.test \
|
||||
53_local-proxytrack-cache-corrupt.test \
|
||||
54_local-update-truncate-purge.test \
|
||||
55_local-chunked.test \
|
||||
@@ -171,7 +167,6 @@ TESTS = \
|
||||
73_local-warc.test \
|
||||
74_local-warc-wacz.test \
|
||||
74_local-warc-verbatim.test \
|
||||
75_engine-longpath-posix.test \
|
||||
76_cli-resize.test
|
||||
75_engine-longpath-posix.test
|
||||
|
||||
CLEANFILES = check-network_sh.cache
|
||||
|
||||
@@ -457,9 +457,6 @@ def _big_sitemap(port):
|
||||
).encode()
|
||||
|
||||
|
||||
DEEPDIR = "/trickle/deep/a-long-directory-segment/another-long-segment"
|
||||
|
||||
|
||||
class Handler(SimpleHTTPRequestHandler):
|
||||
# Quieter logging; the launcher captures httrack's own log anyway.
|
||||
def log_message(self, fmt, *args):
|
||||
@@ -1464,11 +1461,6 @@ class Handler(SimpleHTTPRequestHandler):
|
||||
def route_trickle_index(self):
|
||||
self.send_bin_index()
|
||||
|
||||
# #97: a path long enough that the CLI in-progress column truncates it at 80
|
||||
# columns but not at 200. Its own index: /trickle/ is asserted on elsewhere.
|
||||
def route_deeptrickle_index(self):
|
||||
self.send_html('\t<a href="p0.bin">p0</a>\n\t<a href="p1.bin">p1</a>\n')
|
||||
|
||||
def route_trickle_page(self):
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "application/octet-stream")
|
||||
@@ -1654,9 +1646,6 @@ class Handler(SimpleHTTPRequestHandler):
|
||||
"/trickle/p5.bin": route_trickle_page,
|
||||
"/trickle/p6.bin": route_trickle_page,
|
||||
"/trickle/p7.bin": route_trickle_page,
|
||||
DEEPDIR + "/index.html": route_deeptrickle_index,
|
||||
DEEPDIR + "/p0.bin": route_trickle_page,
|
||||
DEEPDIR + "/p1.bin": route_trickle_page,
|
||||
"/dcancel/index.html": route_dcancel_index,
|
||||
"/dcancel/p0.bin": route_dcancel_page,
|
||||
"/dcancel/p1.bin": route_dcancel_page,
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drive httrack on a pty and check the animated display follows the terminal.
|
||||
|
||||
Usage: pty-resize.py <capture-file> <long-url-prefix> -- <cmd> [args...]
|
||||
"""
|
||||
import fcntl
|
||||
import os
|
||||
import pty
|
||||
import select
|
||||
import signal
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import termios
|
||||
import time
|
||||
|
||||
CLEAR = b"\033[2J"
|
||||
FRAME = b"\033[1;1f" # every refresh homes here before painting the stats
|
||||
LIVE = b"Bytes saved"
|
||||
|
||||
|
||||
class Term:
|
||||
def __init__(self, argv, capture):
|
||||
self.capture = capture
|
||||
self.buf = bytearray()
|
||||
self.master, slave = pty.openpty()
|
||||
self.resize(24, 80)
|
||||
self.proc = subprocess.Popen(
|
||||
argv, stdin=slave, stdout=slave, stderr=slave, start_new_session=True
|
||||
)
|
||||
os.close(slave)
|
||||
|
||||
def resize(self, rows, cols):
|
||||
fcntl.ioctl(
|
||||
self.master, termios.TIOCSWINSZ, struct.pack("HHHH", rows, cols, 0, 0)
|
||||
)
|
||||
|
||||
def _read(self, timeout):
|
||||
ready, _, _ = select.select([self.master], [], [], timeout)
|
||||
if not ready:
|
||||
return b""
|
||||
try:
|
||||
return os.read(self.master, 65536)
|
||||
except OSError:
|
||||
return b""
|
||||
|
||||
def pump(self, seconds):
|
||||
"""Read for the given window; return only the bytes read during it."""
|
||||
mark = len(self.buf)
|
||||
end = time.monotonic() + seconds
|
||||
while time.monotonic() < end:
|
||||
self.buf += self._read(0.1)
|
||||
return bytes(self.buf[mark:])
|
||||
|
||||
def wait_for(self, pattern, timeout):
|
||||
mark = len(self.buf)
|
||||
end = time.monotonic() + timeout
|
||||
while time.monotonic() < end:
|
||||
self.buf += self._read(0.1)
|
||||
if pattern in bytes(self.buf[mark:]):
|
||||
return True
|
||||
if self.proc.poll() is not None:
|
||||
break
|
||||
return False
|
||||
|
||||
def alive(self):
|
||||
return self.proc.poll() is None
|
||||
|
||||
def close(self):
|
||||
if self.alive():
|
||||
os.killpg(self.proc.pid, signal.SIGKILL)
|
||||
self.proc.wait()
|
||||
os.close(self.master)
|
||||
with open(self.capture, "wb") as fp:
|
||||
fp.write(self.buf)
|
||||
|
||||
|
||||
def frame_heights(chunk):
|
||||
"""Newline count of each complete frame in the chunk."""
|
||||
return [f.count(b"\n") for f in chunk.split(FRAME)[1:-1]]
|
||||
|
||||
|
||||
def main():
|
||||
capture, long_url = sys.argv[1], sys.argv[2].encode()
|
||||
argv = sys.argv[sys.argv.index("--") + 1 :]
|
||||
term = Term(argv, capture)
|
||||
failures = []
|
||||
|
||||
def check(cond, msg):
|
||||
if not cond:
|
||||
failures.append(msg)
|
||||
return cond
|
||||
|
||||
try:
|
||||
if not check(term.wait_for(LIVE, 15), "the display never started"):
|
||||
return 1
|
||||
|
||||
# Steady state: a repaint here would mask any resize-driven one below.
|
||||
idle = term.pump(1.0)
|
||||
check(CLEAR not in idle, "repaint without a resize")
|
||||
check(long_url not in idle, "long URL not truncated at 80 columns")
|
||||
|
||||
term.resize(24, 120)
|
||||
check(term.wait_for(CLEAR, 3), "no repaint after a width-only resize")
|
||||
check(CLEAR not in term.pump(1.0), "repaint kept firing after the resize")
|
||||
|
||||
term.resize(10, 120)
|
||||
check(term.wait_for(CLEAR, 3), "no repaint after a height-only resize")
|
||||
heights = frame_heights(term.pump(1.0))
|
||||
check(heights, "no frame after the height change")
|
||||
check(
|
||||
all(h <= 9 for h in heights),
|
||||
"frame overflows a 10-row terminal: %s" % heights,
|
||||
)
|
||||
|
||||
term.resize(24, 200)
|
||||
check(term.wait_for(CLEAR, 3), "no repaint after growing the terminal")
|
||||
check(long_url in term.pump(1.0), "long URL still truncated at 200 columns")
|
||||
|
||||
check(term.alive(), "httrack died mid-run (exit %s)" % term.proc.poll())
|
||||
finally:
|
||||
term.close()
|
||||
|
||||
for msg in failures:
|
||||
print("FAIL: %s" % msg)
|
||||
return 1 if failures else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user