Compare commits

..

4 Commits

Author SHA1 Message Date
Xavier Roche
7ead8d595e htsopt: type three more option fields as named enums
debug becomes hts_log_type (it already stored LOG_* values; the int
declaration was a latent type hole), savename_delayed becomes a new
hts_savename_delayed { NONE, SOFT, HARD }, and verbosedisplay becomes a
new hts_verbosedisplay { NONE, SIMPLE, FULL }. hostcontrol stays int but
its bits are now named by a new hts_hostcontrol flags enum, matching the
existing getmode/seeker/travel/htsparsejava_flags pattern.

A C enum is int-sized, so struct layout, field offsets and
sizeof(httrackp) are unchanged: no ABI break, no soname bump. The three
sscanf("%d", ...) sites that fill these fields now write through an int*
(size-identical) to keep the format type exact.

These enums are unsigned-backed (all enumerators non-negative), so the
non-negative debug comparisons (debug < level, debug > LOG_INFO, etc.)
now compile to unsigned jumps. debug is never negative, never sscanf'd
and never tested against a negative bound, so the result is unchanged;
disassembly is otherwise byte-identical bar instruction scheduling.

savename_83 is left as int on purpose: its sscanf sits in the -L parser
block whose old indentation does not round-trip through clang-format.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-06-18 18:11:19 +02:00
Xavier Roche
93f502990c Merge pull request #387 from xroche/feature/api-bool-returns
Return hts_boolean from the yes/no library functions
2026-06-18 17:38:48 +02:00
Xavier Roche
0f4b2596b2 htslib: return hts_boolean from the yes/no library functions
The exported API had many functions returning int where the int is really a
yes/no answer. Type the 14 genuinely-boolean ones as hts_boolean
(catch_url, dir_exists, is_dyntype, may_unknown, hts_findnext,
hts_findisdir/isfile/issystem, hts_has_stopped, hts_addurl, hts_resetaddurl,
hts_log, get_httptype_sized, guess_httptype_sized) and the three boolean int
parameters likewise (get_httptype_sized's flag, unescape_http_unharm's no_high,
hts_request_stop's force).

hts_boolean moves from htsopt.h to htsglobal.h so the library header, which only
forward-declares httrackp and does not include htsopt.h, can see the type.

The audit deliberately left alone the functions whose name suggests a boolean
but whose value is not 0/1: hts_is_testing returns 0..5, hts_is_exiting and
is_knowntype/is_userknowntype are tri-state, structcheck and the *_utf8 wrappers
are POSIX 0/-1, hts_findgetsize is a size, hts_main is an exit code, and
copy_htsopt returns 0 for success (a bool would read backwards). hts_setpause
and hts_is_parsing keep int params because they gate on '>= 0', not 0/1.

Not an ABI break: int -> int-sized enum is the same calling convention for both
return values (eax) and parameters, and enum<->int is implicit for callers, so
already-compiled consumers keep working. Verified by comparing per-object
disassembly against master: 39 of 45 objects byte-identical, htslib differs only
in __LINE__ immediates, and the five caller/definer objects differ only in
register allocation and return-block merging (no control-flow or value change).
make check passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-06-18 09:19:36 +02:00
Xavier Roche
4a676bb5e1 Merge pull request #386 from xroche/feature/api-boolean-enum
Type the boolean option fields as a named enum
2026-06-18 09:04:14 +02:00
10 changed files with 83 additions and 55 deletions

View File

@@ -135,7 +135,8 @@ HTSEXT_API T_SOC catch_url_init(int *port, /* 128 bytes */ char *adr) {
// returns 0 if error // returns 0 if error
// url: buffer where URL must be stored - or ip:port in case of failure // url: buffer where URL must be stored - or ip:port in case of failure
// data: 32Kb // data: 32Kb
HTSEXT_API int catch_url(T_SOC soc, char *url, char *method, char *data) { HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
char *data) {
int retour = 0; int retour = 0;
// connexion (accept) // connexion (accept)

View File

@@ -2585,7 +2585,7 @@ static int mkdir_compat(const char *pathname) {
/* path must end with "/" or with the finename (/tmp/bar/ or /tmp/bar/foo.zip) */ /* path must end with "/" or with the finename (/tmp/bar/ or /tmp/bar/foo.zip) */
/* Note: preserve errno */ /* Note: preserve errno */
HTSEXT_API int dir_exists(const char *path) { HTSEXT_API hts_boolean dir_exists(const char *path) {
const int err = errno; const int err = errno;
STRUCT_STAT st; STRUCT_STAT st;
char BIGSTK file[HTS_URLMAXSIZE * 2]; char BIGSTK file[HTS_URLMAXSIZE * 2];
@@ -3646,7 +3646,7 @@ HTSEXT_API int hts_setpause(httrackp * opt, int p) {
} }
// ask for termination // ask for termination
HTSEXT_API int hts_request_stop(httrackp * opt, int force) { HTSEXT_API int hts_request_stop(httrackp *opt, hts_boolean force) {
if (opt != NULL) { if (opt != NULL) {
hts_log_print(opt, LOG_ERROR, "Exit requested by shell or user"); hts_log_print(opt, LOG_ERROR, "Exit requested by shell or user");
hts_mutexlock(&opt->state.lock); hts_mutexlock(&opt->state.lock);
@@ -3656,7 +3656,7 @@ HTSEXT_API int hts_request_stop(httrackp * opt, int force) {
return 0; return 0;
} }
HTSEXT_API int hts_has_stopped(httrackp * opt) { HTSEXT_API hts_boolean hts_has_stopped(httrackp *opt) {
int ended; int ended;
hts_mutexlock(&opt->state.lock); hts_mutexlock(&opt->state.lock);
ended = opt->state.is_ended; ended = opt->state.is_ended;
@@ -3678,12 +3678,12 @@ HTSEXT_API int hts_has_stopped(httrackp * opt) {
//} //}
// ajout d'URL // ajout d'URL
// -1 : erreur // -1 : erreur
HTSEXT_API int hts_addurl(httrackp * opt, char **url) { HTSEXT_API hts_boolean hts_addurl(httrackp *opt, char **url) {
if (url) if (url)
opt->state._hts_addurl = url; opt->state._hts_addurl = url;
return (opt->state._hts_addurl != NULL); return (opt->state._hts_addurl != NULL);
} }
HTSEXT_API int hts_resetaddurl(httrackp * opt) { HTSEXT_API hts_boolean hts_resetaddurl(httrackp *opt) {
opt->state._hts_addurl = NULL; opt->state._hts_addurl = NULL;
return (opt->state._hts_addurl != NULL); return (opt->state._hts_addurl != NULL);
} }

View File

@@ -1991,7 +1991,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
case 'v': case 'v':
opt->verbosedisplay = 2; opt->verbosedisplay = 2;
if (isdigit((unsigned char) *(com + 1))) { if (isdigit((unsigned char) *(com + 1))) {
sscanf(com + 1, "%d", &opt->verbosedisplay); sscanf(com + 1, "%d", (int *) &opt->verbosedisplay);
while(isdigit((unsigned char) *(com + 1))) while(isdigit((unsigned char) *(com + 1)))
com++; com++;
} }
@@ -2006,7 +2006,7 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
case 'N': case 'N':
opt->savename_delayed = 2; opt->savename_delayed = 2;
if (isdigit((unsigned char) *(com + 1))) { if (isdigit((unsigned char) *(com + 1))) {
sscanf(com + 1, "%d", &opt->savename_delayed); sscanf(com + 1, "%d", (int *) &opt->savename_delayed);
while(isdigit((unsigned char) *(com + 1))) while(isdigit((unsigned char) *(com + 1)))
com++; com++;
} }

View File

@@ -242,6 +242,14 @@ Please visit our Website: http://www.httrack.com
#define HTS_NOPARAM "(none)" #define HTS_NOPARAM "(none)"
#define HTS_NOPARAM2 "\"(none)\"" #define HTS_NOPARAM2 "\"(none)\""
/* Boolean flag for option fields and API yes/no returns. An enum (not C bool)
so it stays int-sized: option fields keep the httrackp layout/ABI, and a
return type stays compatible with the int it replaces. */
#ifndef HTS_DEF_DEFSTRUCT_hts_boolean
#define HTS_DEF_DEFSTRUCT_hts_boolean
typedef enum hts_boolean { HTS_FALSE = 0, HTS_TRUE = 1 } hts_boolean;
#endif
/* Larger/smaller of two values. Macros: arguments are evaluated twice. */ /* Larger/smaller of two values. Macros: arguments are evaluated twice. */
#define maximum(A,B) ( (A) > (B) ? (A) : (B) ) #define maximum(A,B) ( (A) > (B) ? (A) : (B) )

View File

@@ -3646,8 +3646,9 @@ HTSEXT_API char *unescape_http(char *const catbuff, const size_t size, const cha
// DOES NOT DECODE %25 (part of CHAR_DELIM) // DOES NOT DECODE %25 (part of CHAR_DELIM)
// no_high & 1: decode high chars // no_high & 1: decode high chars
// no_high & 2: decode space // no_high & 2: decode space
HTSEXT_API char *unescape_http_unharm(char *const catbuff, const size_t size, HTSEXT_API char *unescape_http_unharm(char *const catbuff, const size_t size,
const char *s, const int no_high) { const char *s,
const hts_boolean no_high) {
size_t i, j; size_t i, j;
RUNTIME_TIME_CHECK_SIZE(size); RUNTIME_TIME_CHECK_SIZE(size);
@@ -3931,8 +3932,8 @@ void hts_replace(char *s, char from, char to) {
// guess a local file's mime type (e.g. fil="toto.gif" -> s="image/gif") // guess a local file's mime type (e.g. fil="toto.gif" -> s="image/gif")
// returns 1 if a type was written to s, 0 otherwise // returns 1 if a type was written to s, 0 otherwise
int guess_httptype_sized(httrackp *opt, char *s, size_t ssize, hts_boolean guess_httptype_sized(httrackp *opt, char *s, size_t ssize,
const char *fil) { const char *fil) {
return get_httptype_sized(opt, s, ssize, fil, 1); return get_httptype_sized(opt, s, ssize, fil, 1);
} }
@@ -3945,8 +3946,8 @@ void guess_httptype(httrackp * opt, char *s, const char *fil) {
// write the mime type for fil into s (capacity ssize) // write the mime type for fil into s (capacity ssize)
// flag: 1 to always return a type (the "application/..." / octet-stream // flag: 1 to always return a type (the "application/..." / octet-stream
// fallback) returns 1 if a type was written to s, 0 otherwise // fallback) returns 1 if a type was written to s, 0 otherwise
HTSEXT_API int get_httptype_sized(httrackp *opt, char *s, size_t ssize, HTSEXT_API hts_boolean get_httptype_sized(httrackp *opt, char *s, size_t ssize,
const char *fil, int flag) { const char *fil, hts_boolean flag) {
// userdef overrides get_httptype (a rule with an empty value, e.g. "--assume // userdef overrides get_httptype (a rule with an empty value, e.g. "--assume
// cgi=", matches but writes nothing: report it as "no type" like the old // cgi=", matches but writes nothing: report it as "no type" like the old
// code, whose callers tested strnotempty(s)) // code, whose callers tested strnotempty(s))
@@ -4196,7 +4197,7 @@ HTSEXT_API int is_userknowntype(httrackp * opt, const char *fil) {
// page dynamique? // page dynamique?
// is_dyntype(get_ext("foo.asp")) // is_dyntype(get_ext("foo.asp"))
HTSEXT_API int is_dyntype(const char *fil) { HTSEXT_API hts_boolean is_dyntype(const char *fil) {
int j = 0; int j = 0;
if (!fil) if (!fil)
@@ -4214,7 +4215,7 @@ HTSEXT_API int is_dyntype(const char *fil) {
// types critiques qui ne doivent pas être changés car renvoyés par des serveurs qui ne // types critiques qui ne doivent pas être changés car renvoyés par des serveurs qui ne
// connaissent pas le type // connaissent pas le type
int may_unknown(httrackp * opt, const char *st) { hts_boolean may_unknown(httrackp *opt, const char *st) {
int j = 0; int j = 0;
// types média // types média
@@ -5236,7 +5237,8 @@ HTSEXT_API int hts_uninit_module(void) {
} }
// legacy. do not use // legacy. do not use
HTSEXT_API int hts_log(httrackp * opt, const char *prefix, const char *msg) { HTSEXT_API hts_boolean hts_log(httrackp *opt, const char *prefix,
const char *msg) {
if (opt->log != NULL) { if (opt->log != NULL) {
fspc(opt, opt->log, prefix); fspc(opt, opt->log, prefix);
fprintf(opt->log, "%s" LF, msg); fprintf(opt->log, "%s" LF, msg);

View File

@@ -354,12 +354,25 @@ typedef enum hts_travel_scope {
#define HTS_TRAVEL_SCOPE_MASK 0xff /**< mask selecting the scope value */ #define HTS_TRAVEL_SCOPE_MASK 0xff /**< mask selecting the scope value */
#define HTS_TRAVEL_TEST_ALL (1 << 8) /**< also test forbidden URLs (-t) */ #define HTS_TRAVEL_TEST_ALL (1 << 8) /**< also test forbidden URLs (-t) */
/* Boolean option flag. An enum (not C bool) so the option fields stay int-sized /* Text progress display detail (opt->verbosedisplay). */
and the httrackp layout/ABI is unchanged. */ typedef enum hts_verbosedisplay {
#ifndef HTS_DEF_DEFSTRUCT_hts_boolean HTS_VERBOSE_NONE = 0, /**< no animated progress display (default) */
#define HTS_DEF_DEFSTRUCT_hts_boolean HTS_VERBOSE_SIMPLE = 1, /**< minimal single-line progress */
typedef enum hts_boolean { HTS_FALSE = 0, HTS_TRUE = 1 } hts_boolean; HTS_VERBOSE_FULL = 2 /**< full animated progress */
#endif } hts_verbosedisplay;
/* Delayed file-type resolution policy (opt->savename_delayed). */
typedef enum hts_savename_delayed {
HTS_SAVENAME_DELAYED_NONE = 0, /**< resolve the type immediately */
HTS_SAVENAME_DELAYED_SOFT = 1, /**< delay the type check when unknown */
HTS_SAVENAME_DELAYED_HARD = 2 /**< always delay the type check (default) */
} hts_savename_delayed;
/* Host-banning triggers (opt->hostcontrol bitmask). */
typedef enum hts_hostcontrol {
HTS_HOSTCONTROL_BAN_TIMEOUT = 1 << 0, /**< ban a timing-out host */
HTS_HOSTCONTROL_BAN_SLOW = 1 << 1 /**< ban a too-slow host */
} hts_hostcontrol;
#ifndef HTS_DEF_FWSTRUCT_lien_buffers #ifndef HTS_DEF_FWSTRUCT_lien_buffers
#define HTS_DEF_FWSTRUCT_lien_buffers #define HTS_DEF_FWSTRUCT_lien_buffers
@@ -393,7 +406,7 @@ struct httrackp {
hts_urlmode hts_urlmode
urlmode; /**< saved-link rewriting style (relative, absolute, etc.) */ urlmode; /**< saved-link rewriting style (relative, absolute, etc.) */
hts_boolean no_type_change; // do not change file type according to MIME hts_boolean no_type_change; // do not change file type according to MIME
int debug; /**< debug logging level */ hts_log_type debug; /**< debug logging level */
int getmode; /**< what to fetch (HTML, images, ...) bitmask */ int getmode; /**< what to fetch (HTML, images, ...) bitmask */
FILE *log; /**< informational log stream; NULL mutes it */ FILE *log; /**< informational log stream; NULL mutes it */
FILE *errlog; /**< error log stream; NULL mutes it */ FILE *errlog; /**< error log stream; NULL mutes it */
@@ -421,7 +434,7 @@ struct httrackp {
int savename_type; /**< saved-name layout (original tree, flat, ...) */ int savename_type; /**< saved-name layout (original tree, flat, ...) */
String String
savename_userdef; /**< user-defined name template (e.g. %h%p/%n%q.%t) */ savename_userdef; /**< user-defined name template (e.g. %h%p/%n%q.%t) */
int savename_delayed; // delayed type check hts_savename_delayed savename_delayed; /**< delayed type-check policy */
hts_boolean hts_boolean
delayed_cached; // delayed type check can be cached to speedup updates delayed_cached; // delayed type check can be cached to speedup updates
hts_boolean mimehtml; /**< produce a single MIME/MHTML archive */ hts_boolean mimehtml; /**< produce a single MIME/MHTML archive */
@@ -437,7 +450,7 @@ struct httrackp {
hts_boolean makestat; /**< maintain a transfer-statistics log */ hts_boolean makestat; /**< maintain a transfer-statistics log */
hts_boolean maketrack; /**< maintain an operations-statistics log */ hts_boolean maketrack; /**< maintain an operations-statistics log */
int parsejava; /**< Java/JS parsing mode; see htsparsejava_flags */ int parsejava; /**< Java/JS parsing mode; see htsparsejava_flags */
int hostcontrol; /**< drop hosts that are too slow, etc. */ int hostcontrol; /**< ban slow/timing-out hosts; see hts_hostcontrol bits */
hts_boolean errpage; /**< generate an error page on 404 and similar */ hts_boolean errpage; /**< generate an error page on 404 and similar */
hts_boolean hts_boolean
check_type; /**< probe unknown-type links (cgi/asp/dir) and follow moves check_type; /**< probe unknown-type links (cgi/asp/dir) and follow moves
@@ -462,7 +475,7 @@ struct httrackp {
parseall; /**< parse aggressively, including unknown tags with links */ parseall; /**< parse aggressively, including unknown tags with links */
hts_boolean parsedebug; /**< parser debug mode */ hts_boolean parsedebug; /**< parser debug mode */
hts_boolean norecatch; /**< do not re-fetch files the user deleted locally */ hts_boolean norecatch; /**< do not re-fetch files the user deleted locally */
int verbosedisplay; /**< animated text progress display */ hts_verbosedisplay verbosedisplay; /**< animated text progress display */
String footer; /**< footer/info line injected into pages */ String footer; /**< footer/info line injected into pages */
int maxcache; /**< in-memory cache backing limit (bytes) */ int maxcache; /**< in-memory cache backing limit (bytes) */
// int maxcache_anticipate; // maximum links to anticipate (upper bound) // int maxcache_anticipate; // maximum links to anticipate (upper bound)

View File

@@ -3722,7 +3722,8 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
//case -1: can_retry=1; break; //case -1: can_retry=1; break;
case STATUSCODE_TIMEOUT: case STATUSCODE_TIMEOUT:
if (opt->hostcontrol) { // timeout et retry épuisés if (opt->hostcontrol) { // timeout et retry épuisés
if ((opt->hostcontrol & 1) && (heap(ptr)->retry <= 0)) { if ((opt->hostcontrol & HTS_HOSTCONTROL_BAN_TIMEOUT) &&
(heap(ptr)->retry <= 0)) {
hts_log_print(opt, LOG_DEBUG, "Link banned: %s%s", urladr(), urlfil()); hts_log_print(opt, LOG_DEBUG, "Link banned: %s%s", urladr(), urlfil());
host_ban(opt, ptr, sback, jump_identification_const(urladr())); host_ban(opt, ptr, sback, jump_identification_const(urladr()));
hts_log_print(opt, LOG_DEBUG, hts_log_print(opt, LOG_DEBUG,
@@ -3735,7 +3736,7 @@ int hts_mirror_check_moved(htsmoduleStruct * str,
break; break;
case STATUSCODE_SLOW: case STATUSCODE_SLOW:
if ((opt->hostcontrol) && (heap(ptr)->retry <= 0)) { // too slow if ((opt->hostcontrol) && (heap(ptr)->retry <= 0)) { // too slow
if (opt->hostcontrol & 2) { if (opt->hostcontrol & HTS_HOSTCONTROL_BAN_SLOW) {
hts_log_print(opt, LOG_DEBUG, "Link banned: %s%s", urladr(), urlfil()); hts_log_print(opt, LOG_DEBUG, "Link banned: %s%s", urladr(), urlfil());
host_ban(opt, ptr, sback, jump_identification_const(urladr())); host_ban(opt, ptr, sback, jump_identification_const(urladr()));
hts_log_print(opt, LOG_DEBUG, hts_log_print(opt, LOG_DEBUG,

View File

@@ -1213,7 +1213,7 @@ HTSEXT_API find_handle hts_findfirst(char *path) {
return NULL; return NULL;
} }
HTSEXT_API int hts_findnext(find_handle find) { HTSEXT_API hts_boolean hts_findnext(find_handle find) {
if (find) { if (find) {
#ifdef _WIN32 #ifdef _WIN32
if ((FindNextFileA(find->handle, &find->hdata))) if ((FindNextFileA(find->handle, &find->hdata)))
@@ -1273,7 +1273,7 @@ HTSEXT_API int hts_findgetsize(find_handle find) {
return -1; return -1;
} }
HTSEXT_API int hts_findisdir(find_handle find) { HTSEXT_API hts_boolean hts_findisdir(find_handle find) {
if (find) { if (find) {
if (!hts_findissystem(find)) { if (!hts_findissystem(find)) {
#ifdef _WIN32 #ifdef _WIN32
@@ -1287,7 +1287,7 @@ HTSEXT_API int hts_findisdir(find_handle find) {
} }
return 0; return 0;
} }
HTSEXT_API int hts_findisfile(find_handle find) { HTSEXT_API hts_boolean hts_findisfile(find_handle find) {
if (find) { if (find) {
if (!hts_findissystem(find)) { if (!hts_findissystem(find)) {
#ifdef _WIN32 #ifdef _WIN32
@@ -1301,7 +1301,7 @@ HTSEXT_API int hts_findisfile(find_handle find) {
} }
return 0; return 0;
} }
HTSEXT_API int hts_findissystem(find_handle find) { HTSEXT_API hts_boolean hts_findissystem(find_handle find) {
if (find) { if (find) {
#ifdef _WIN32 #ifdef _WIN32
if (find->hdata. if (find->hdata.

View File

@@ -108,15 +108,15 @@ HTSEXT_API int hts_buildtopindex(httrackp * opt, const char *path,
// Portable directory find functions // Portable directory find functions
// Directory find functions // Directory find functions
HTSEXT_API find_handle hts_findfirst(char *path); HTSEXT_API find_handle hts_findfirst(char *path);
HTSEXT_API int hts_findnext(find_handle find); HTSEXT_API hts_boolean hts_findnext(find_handle find);
HTSEXT_API int hts_findclose(find_handle find); HTSEXT_API int hts_findclose(find_handle find);
// //
HTSEXT_API char *hts_findgetname(find_handle find); HTSEXT_API char *hts_findgetname(find_handle find);
HTSEXT_API int hts_findgetsize(find_handle find); HTSEXT_API int hts_findgetsize(find_handle find);
HTSEXT_API int hts_findisdir(find_handle find); HTSEXT_API hts_boolean hts_findisdir(find_handle find);
HTSEXT_API int hts_findisfile(find_handle find); HTSEXT_API hts_boolean hts_findisfile(find_handle find);
HTSEXT_API int hts_findissystem(find_handle find); HTSEXT_API hts_boolean hts_findissystem(find_handle find);
#endif #endif

View File

@@ -206,7 +206,8 @@ HTSEXT_API htsErrorCallback hts_get_error_callback(void);
/* Logging */ /* Logging */
/** Legacy: write prefix then msg to opt->log. Returns 0 if written, 1 if /** Legacy: write prefix then msg to opt->log. Returns 0 if written, 1 if
opt->log is NULL. Prefer hts_log_print(). */ opt->log is NULL. Prefer hts_log_print(). */
HTSEXT_API int hts_log(httrackp * opt, const char *prefix, const char *msg); HTSEXT_API hts_boolean hts_log(httrackp *opt, const char *prefix,
const char *msg);
/** printf-style log at level @p type (an hts_log_type, optionally |LOG_ERRNO). /** printf-style log at level @p type (an hts_log_type, optionally |LOG_ERRNO).
Forwards to the registered log callback, and when the level is <= opt->debug Forwards to the registered log callback, and when the level is <= opt->debug
@@ -313,7 +314,8 @@ HTSEXT_API T_SOC catch_url_init(int *port, char *adr);
"ip:port". The buffers are caller-allocated and not bounds-checked: @p data "ip:port". The buffers are caller-allocated and not bounds-checked: @p data
must be CATCH_URL_DATA_SIZE bytes, and @p url / @p method must fit the must be CATCH_URL_DATA_SIZE bytes, and @p url / @p method must fit the
captured request line. */ captured request line. */
HTSEXT_API int catch_url(T_SOC soc, char *url, char *method, char *data); HTSEXT_API hts_boolean catch_url(T_SOC soc, char *url, char *method,
char *data);
/* State */ /* State */
/** Whether the engine is parsing HTML. Returns 0 if not, otherwise the percent /** Whether the engine is parsing HTML. Returns 0 if not, otherwise the percent
@@ -334,10 +336,10 @@ HTSEXT_API int hts_is_exiting(httrackp * opt);
caller-owned, NULL-terminated array of strings; the engine stores the caller-owned, NULL-terminated array of strings; the engine stores the
pointer without copying, so the array and its strings must stay valid until pointer without copying, so the array and its strings must stay valid until
the engine consumes them. @return nonzero if a list is now set. */ the engine consumes them. @return nonzero if a list is now set. */
HTSEXT_API int hts_addurl(httrackp * opt, char **url); HTSEXT_API hts_boolean hts_addurl(httrackp *opt, char **url);
/** Clear any pending add-URL list set by hts_addurl(). Always returns 0. */ /** Clear any pending add-URL list set by hts_addurl(). Always returns 0. */
HTSEXT_API int hts_resetaddurl(httrackp * opt); HTSEXT_API hts_boolean hts_resetaddurl(httrackp *opt);
/** Apply the runtime-tunable options from @p from onto @p to, to adjust a live /** Apply the runtime-tunable options from @p from onto @p to, to adjust a live
mirror. Only fields set to a non-sentinel value are copied; the rest of @p mirror. Only fields set to a non-sentinel value are copied; the rest of @p
@@ -356,7 +358,7 @@ HTSEXT_API int hts_setpause(httrackp * opt, int);
lock, so it is safe to call from another thread). @p force is currently lock, so it is safe to call from another thread). @p force is currently
ignored. ignored.
@return 0; no-op if @p opt is NULL. */ @return 0; no-op if @p opt is NULL. */
HTSEXT_API int hts_request_stop(httrackp * opt, int force); HTSEXT_API int hts_request_stop(httrackp *opt, hts_boolean force);
/** Queue a single in-progress file, by URL, to be cancelled by the engine. /** Queue a single in-progress file, by URL, to be cancelled by the engine.
@p url is copied internally. Takes the state lock, so it is thread-safe. @p url is copied internally. Takes the state lock, so it is thread-safe.
@@ -373,7 +375,7 @@ HTSEXT_API void hts_cancel_parsing(httrackp * opt);
/** Nonzero once the mirror has fully ended. Read under the engine state lock, /** Nonzero once the mirror has fully ended. Read under the engine state lock,
so safe to poll from another thread. Wait for this before hts_free_opt(). */ so safe to poll from another thread. Wait for this before hts_free_opt(). */
HTSEXT_API int hts_has_stopped(httrackp * opt); HTSEXT_API hts_boolean hts_has_stopped(httrackp *opt);
/* Tools */ /* Tools */
/** Ensure the directory chain leading to @p path exists, creating missing /** Ensure the directory chain leading to @p path exists, creating missing
@@ -390,7 +392,7 @@ HTSEXT_API int structcheck_utf8(const char *path);
/** Whether the directory containing @p path exists. The basename is stripped /** Whether the directory containing @p path exists. The basename is stripped
first, so passing a file path tests its parent directory. @return 1 if it is first, so passing a file path tests its parent directory. @return 1 if it is
a directory, 0 otherwise. */ a directory, 0 otherwise. */
HTSEXT_API int dir_exists(const char *path); HTSEXT_API hts_boolean dir_exists(const char *path);
/** Write the HTTP reason phrase for @p statuscode into @p msg, a caller buffer /** Write the HTTP reason phrase for @p statuscode into @p msg, a caller buffer
of at least 64 bytes. For an unknown code a non-empty @p msg is kept, of at least 64 bytes. For an unknown code a non-empty @p msg is kept,
@@ -573,14 +575,15 @@ HTSEXT_API char *unescape_http(char *const catbuff, const size_t size, const cha
must-avoid escapes are kept encoded, and %25 is never decoded). @p no_high & must-avoid escapes are kept encoded, and %25 is never decoded). @p no_high &
1 also decodes high (>= 128) bytes; @p no_high & 2 also decodes an escaped 1 also decodes high (>= 128) bytes; @p no_high & 2 also decodes an escaped
space. Returns @p catbuff. */ space. Returns @p catbuff. */
HTSEXT_API char *unescape_http_unharm(char *const catbuff, const size_t size, const char *s, const int no_high); HTSEXT_API char *unescape_http_unharm(char *const catbuff, const size_t size,
const char *s, const hts_boolean no_high);
/** Determine the MIME type of local file name @p fil into @p s (capacity /** Determine the MIME type of local file name @p fil into @p s (capacity
@p ssize): user --assume rules, then ".html", then the built-in extension @p ssize): user --assume rules, then ".html", then the built-in extension
table. @p flag != 0 forces a fallback type. @return 1 if a type was written, table. @p flag != 0 forces a fallback type. @return 1 if a type was written,
0 otherwise. */ 0 otherwise. */
HTSEXT_API int get_httptype_sized(httrackp *opt, char *s, size_t ssize, HTSEXT_API hts_boolean get_httptype_sized(httrackp *opt, char *s, size_t ssize,
const char *fil, int flag); const char *fil, hts_boolean flag);
/** @deprecated Use get_httptype_sized(). Assumes @p s has at least /** @deprecated Use get_httptype_sized(). Assumes @p s has at least
HTS_MIMETYPE_SIZE capacity. */ HTS_MIMETYPE_SIZE capacity. */
@@ -600,7 +603,7 @@ HTSEXT_API int is_userknowntype(httrackp * opt, const char *fil);
/** 1 if @p fil, an extension such as "asp" or "php" (not a full filename), is a /** 1 if @p fil, an extension such as "asp" or "php" (not a full filename), is a
known dynamic-page type, else 0. */ known dynamic-page type, else 0. */
HTSEXT_API int is_dyntype(const char *fil); HTSEXT_API hts_boolean is_dyntype(const char *fil);
/** Extract the extension of @p fil (text after the last '.', stopping at '?') /** Extract the extension of @p fil (text after the last '.', stopping at '?')
into caller scratch @p catbuff (capacity @p size) and return it. Returns "" into caller scratch @p catbuff (capacity @p size) and return it. Returns ""
@@ -610,12 +613,12 @@ HTSEXT_API const char *get_ext(char *catbuff, size_t size, const char *fil);
/** 1 if MIME type @p st must not be reclassified or renamed (hypertext types /** 1 if MIME type @p st must not be reclassified or renamed (hypertext types
and a built-in keep-list of commonly mislabeled types), else 0. */ and a built-in keep-list of commonly mislabeled types), else 0. */
HTSEXT_API int may_unknown(httrackp * opt, const char *st); HTSEXT_API hts_boolean may_unknown(httrackp *opt, const char *st);
/** Guess the MIME type of local file @p fil into @p s (capacity @p ssize), /** Guess the MIME type of local file @p fil into @p s (capacity @p ssize),
always producing a type. @return 1 if a type was written. */ always producing a type. @return 1 if a type was written. */
HTSEXT_API int guess_httptype_sized(httrackp *opt, char *s, size_t ssize, HTSEXT_API hts_boolean guess_httptype_sized(httrackp *opt, char *s,
const char *fil); size_t ssize, const char *fil);
/** @deprecated Use guess_httptype_sized(). Assumes @p s has at least /** @deprecated Use guess_httptype_sized(). Assumes @p s has at least
HTS_MIMETYPE_SIZE capacity. */ HTS_MIMETYPE_SIZE capacity. */
@@ -677,7 +680,7 @@ HTSEXT_API find_handle hts_findfirst(char *path);
/** Advance to the next directory entry. Returns 1 if an entry is available, 0 /** Advance to the next directory entry. Returns 1 if an entry is available, 0
at end of directory. */ at end of directory. */
HTSEXT_API int hts_findnext(find_handle find); HTSEXT_API hts_boolean hts_findnext(find_handle find);
/** Close the iteration and free @p find. Always returns 0; NULL is accepted. */ /** Close the iteration and free @p find. Always returns 0; NULL is accepted. */
HTSEXT_API int hts_findclose(find_handle find); HTSEXT_API int hts_findclose(find_handle find);
@@ -692,16 +695,16 @@ HTSEXT_API int hts_findgetsize(find_handle find);
/** 1 if the current entry is a directory, else 0 (a system/special entry, see /** 1 if the current entry is a directory, else 0 (a system/special entry, see
hts_findissystem(), reports 0). */ hts_findissystem(), reports 0). */
HTSEXT_API int hts_findisdir(find_handle find); HTSEXT_API hts_boolean hts_findisdir(find_handle find);
/** 1 if the current entry is a regular file, else 0 (a system/special entry, /** 1 if the current entry is a regular file, else 0 (a system/special entry,
see hts_findissystem(), reports 0). */ see hts_findissystem(), reports 0). */
HTSEXT_API int hts_findisfile(find_handle find); HTSEXT_API hts_boolean hts_findisfile(find_handle find);
/** 1 if the current entry is a special/system entry to skip: "." or "..", on /** 1 if the current entry is a special/system entry to skip: "." or "..", on
POSIX also device/fifo/socket nodes, on Windows also system, hidden or POSIX also device/fifo/socket nodes, on Windows also system, hidden or
temporary entries. Else 0. */ temporary entries. Else 0. */
HTSEXT_API int hts_findissystem(find_handle find); HTSEXT_API hts_boolean hts_findissystem(find_handle find);
/* UTF-8 aware FILE API */ /* UTF-8 aware FILE API */
/* On non-Windows these macros resolve directly to the POSIX calls. On Windows /* On non-Windows these macros resolve directly to the POSIX calls. On Windows