refactor: clean narrowing conversions and harden unsigned arithmetic

Cleanup of the conversion-safety warnings exposed by enabling
-Wconversion / -Wsign-compare in the previous commit, plus guard
clauses at the few places where unsigned arithmetic could actually
misbehave.

Build:
- configure.ac drops -Wno-error=conversion and
  -Wno-error=float-conversion. Only -Wno-error=sign-conversion and
  -Wno-error=sign-compare remain, gating the ~230 sign warnings
  inherited from upstream that will be cleaned up in follow-ups.

Type / conversion fixes (no behaviour change):
- Length-like locals in command/cmd_ac.c, command/cmd_funcs.c,
  pgp/gpg.c, tools/autocomplete.c, tools/parser.c and ui/mucwin.c
  switched from int to size_t / glong (matching strlen /
  g_utf8_strlen return type) so we no longer need an (int) cast and
  loop counters / array sizes stay in their natural unsigned domain.
- g_timer_elapsed / GTimeSpan -> int casts in session.c, iq.c,
  core.c, server_events.c, window.c.
- _win_print_wrapped: indent parameter and local curx/maxx switched
  from size_t to int to match _win_indent / getcurx / getmaxx.
- Port casts (int -> unsigned short) at the libstrophe boundary in
  connection.c and session.c, each preceded by
  g_assert(port >= 0 && port <= UINT16_MAX) so the truncation is
  documented at the call-site.
- curl_off_t / fread size_t results cast at usage in http_upload.c,
  http_download.c, omemo/crypto.c.
- strtoul results cast to uint32_t in xmpp/omemo.c and omemo/omemo.c
  where device/prekey IDs are genuinely 32-bit.
- config/color.c: fg/bg/palette indices switched to `short`
  end-to-end (find_col, color_hash, find_closest_col,
  _color_pair_cache_get, cache.pairs), so the ncurses init_pair
  boundary needs at most one (short)i cast for the cache index. Also
  TODO-noted: init_extended_pair is needed for >15-bit palettes.
- xmpp/avatar.c: float arithmetic explicitly casts its int operands.
- tests/functionaltests/proftest.c: read() result handling uses
  size_t for the accumulator, _read_output returns ssize_t, and the
  buffer-shift check happens before space subtraction so the
  expression cannot underflow.

Real-risk guard clauses (the part that actually fixes bugs):
- src/ui/statusbar.c _tabs_width: `end > opened_tabs - 1` rewritten
  as `end < opened_tabs` so opened_tabs == 0 no longer underflows.
- src/ui/statusbar.c _status_bar_draw_extended_tabs: the mirror
  comparison rewritten as `end >= opened_tabs`.
- src/ui/statusbar.c status_bar_draw: replaced
  `MAX(0, getmaxx - (int)_tabs_width)` with an explicit precheck
  before subtraction.
- src/omemo/omemo.c prekey selection: prekey_index is now uint32_t
  and randomized into an unsigned buffer, so modulo with prekeys_len
  cannot yield a negative index for g_list_nth_data.
- src/omemo/crypto.c omemo_decrypt_func: PKCS#5/PKCS#7 unpadding
  reads `plaintext[plaintext_len - 1]`, which would underflow on a
  malformed empty ciphertext and read past the heap buffer. Reject
  plaintext_len == 0 before the padding peek and validate the
  padding byte against the buffer length before the unpad loop.
  Initialise plaintext = NULL so the early `goto out` cannot free
  uninitialised memory.
- src/ui/inputwin.c (4 mbrlen sites) and src/ui/window.c
  _win_print_wrapped: mbrlen() returns 0 for the null wide
  character. The existing checks rejected (size_t)-1 / -2 but
  treated 0 as a valid step, so the surrounding loops would either
  advance by SIZE_MAX (i += ch_len - 1) or spin in place
  (word_pos += 0 forever). Add `|| ch_len == 0` to each guard;
  inside the spell-check word-emission loop also fall back to a
  one-byte advance.
- Defensive `len > 0 ? len - 1 : 0` prechecks at the strlen-based
  g_strndup / loop sites in ui/console.c, plugins/c_api.c and
  plugins/python_plugins.c.
This commit is contained in:
2026-04-27 15:03:52 +03:00
parent 5459e78e82
commit 9feff00ead
28 changed files with 193 additions and 133 deletions

View File

@@ -436,11 +436,12 @@ AS_IF([test "x$enable_sanitizers" = xyes],
AS_IF([test "x$PACKAGE_STATUS" = xdevelopment],
[AM_CFLAGS="$AM_CFLAGS -Wunused -Werror"
# -Wconversion emits ~240 sign-conversion and ~84 other narrowing
# warnings across the tree (mostly inherited from upstream). Keep
# them visible in build logs but let development builds continue;
# they will be cleaned up incrementally.
AM_CFLAGS="$AM_CFLAGS -Wno-error=sign-conversion -Wno-error=conversion -Wno-error=float-conversion -Wno-error=sign-compare"])
# -Wsign-conversion and -Wsign-compare still emit ~230 warnings
# across the tree (mostly inherited from upstream). Keep them
# visible in build logs but let development builds continue;
# the plain narrowing / float-conversion categories are already
# clean and are kept as hard errors.
AM_CFLAGS="$AM_CFLAGS -Wno-error=sign-conversion -Wno-error=sign-compare"])
AS_IF([test "x$PLATFORM" = xosx],
[AM_CFLAGS="$AM_CFLAGS -Qunused-arguments"])

View File

@@ -1879,9 +1879,9 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
}
}
int len = strlen(input);
size_t len = strlen(input);
char parsed[len + 1];
int i = 0;
size_t i = 0;
while (i < len) {
if (input[i] == ' ') {
break;

View File

@@ -1499,11 +1499,11 @@ cmd_win(ProfWin* window, const char* const command, gchar** args)
static void
_cmd_list_commands(GList* commands)
{
int maxlen = 0;
size_t maxlen = 0;
GList* curr = commands;
while (curr) {
gchar* cmd = curr->data;
int len = strlen(cmd);
size_t len = strlen(cmd);
if (len > maxlen)
maxlen = len;
curr = g_list_next(curr);
@@ -1520,7 +1520,7 @@ _cmd_list_commands(GList* commands)
cmds = g_string_new("");
count = 0;
}
g_string_append_printf(cmds, "%-*s", maxlen + 1, cmd);
g_string_append_printf(cmds, "%-*s", (int)(maxlen + 1), cmd);
curr = g_list_next(curr);
count++;
}
@@ -3799,7 +3799,7 @@ cmd_form_field(ProfWin* window, char* tag, gchar** args)
break;
}
int index = strtol(&value[3], NULL, 10);
int index = (int)strtol(&value[3], NULL, 10);
if ((index < 1) || (index > form_get_value_count(form, tag))) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);

View File

@@ -33,7 +33,7 @@ static struct color_pair_cache
{
struct
{
int16_t fg, bg;
short fg, bg;
}* pairs;
int size;
int capacity;
@@ -315,14 +315,18 @@ color_distance(const struct color_def* a, const struct color_def* b)
return h * h + s * s + l * l;
}
static int
/* Indices into the 256-colour palette and ncurses palette IDs are
* 16-bit (the size_t-or-short distinction in ncurses init_pair).
* Use `short` end-to-end so the caller boundaries don't need casts.
*/
static short
find_closest_col(int h, int s, int l)
{
struct color_def a = { h, s, l, NULL };
int min = 0;
struct color_def a = { (uint16_t)h, (uint8_t)s, (uint8_t)l, NULL };
short min = 0;
int dmin = color_distance(&a, &color_names[0]);
for (int i = 1; i < COLOR_NAME_SIZE; i++) {
for (short i = 1; i < COLOR_NAME_SIZE; i++) {
int d = color_distance(&a, &color_names[i]);
if (d < dmin) {
dmin = d;
@@ -332,8 +336,8 @@ find_closest_col(int h, int s, int l)
return min;
}
static int
find_col(const char* col_name, int n)
static short
find_col(const char* col_name, size_t n)
{
char name[32] = { 0 };
@@ -343,9 +347,9 @@ find_col(const char* col_name, int n)
* blue.
*/
if (n >= (int)sizeof(name)) {
if (n >= sizeof(name)) {
/* truncate */
log_error("Color: <%s,%d> bigger than %zu", col_name, n, sizeof(name));
log_error("Color: <%s,%zu> bigger than %zu", col_name, n, sizeof(name));
n = sizeof(name) - 1;
}
memcpy(name, col_name, n);
@@ -354,7 +358,7 @@ find_col(const char* col_name, int n)
return -1;
}
for (int i = 0; i < COLOR_NAME_SIZE; i++) {
for (short i = 0; i < COLOR_NAME_SIZE; i++) {
if (g_ascii_strcasecmp(name, color_names[i].name) == 0) {
return i;
}
@@ -363,13 +367,13 @@ find_col(const char* col_name, int n)
return COL_ERR;
}
static int
static short
color_hash(const char* str, color_profile profile)
{
GChecksum* cs = NULL;
guint8 buf[256] = { 0 };
gsize len = 256;
int rc = -1; /* default ncurse color */
short rc = -1; /* default ncurse color */
cs = g_checksum_new(G_CHECKSUM_SHA1);
if (!cs)
@@ -438,7 +442,7 @@ color_pair_cache_reset(void)
}
static int
_color_pair_cache_get(int fg, int bg)
_color_pair_cache_get(short fg, short bg)
{
if (COLORS < 256) {
if (fg > 7 || bg > 7) {
@@ -463,10 +467,13 @@ _color_pair_cache_get(int fg, int bg)
}
int i = cache.size;
// TODO: init_pair uses 15-bit palette indices. Terminals exposing
// extended colour palettes (>32767) need init_extended_pair here.
// Upstream-inherited limitation.
cache.pairs[i].fg = fg;
cache.pairs[i].bg = bg;
/* (re-)define the new pair in curses */
init_pair(i, fg, bg);
init_pair((short)i, fg, bg);
cache.size++;
@@ -485,8 +492,8 @@ _color_pair_cache_get(int fg, int bg)
int
color_pair_cache_hash_str(const char* str, color_profile profile)
{
int fg = color_hash(str, profile);
int bg = -1;
short fg = color_hash(str, profile);
short bg = -1;
auto_char char* bkgnd = theme_get_bkgnd();
if (bkgnd) {
@@ -506,7 +513,7 @@ int
color_pair_cache_get(const char* pair_name)
{
const char* sep;
int fg, bg;
short fg, bg;
sep = strchr(pair_name, '_');
if (!sep) {
@@ -514,7 +521,7 @@ color_pair_cache_get(const char* pair_name)
return -1;
}
fg = find_col(pair_name, sep - pair_name);
fg = find_col(pair_name, (size_t)(sep - pair_name));
bg = find_col(sep + 1, strlen(sep));
if (fg == COL_ERR || bg == COL_ERR) {
log_error("Color: bad color name %s", pair_name);

View File

@@ -154,7 +154,7 @@ sv_ev_roster_received(void)
GDateTime* lastdt = g_date_time_new_from_timeval_utc(&lasttv);
GTimeSpan diff_micros = g_date_time_difference(nowdt, lastdt);
diff_secs = (diff_micros / 1000) / 1000;
diff_secs = (int)((diff_micros / 1000) / 1000);
g_date_time_unref(lastdt);
}
g_date_time_unref(nowdt);

View File

@@ -233,7 +233,7 @@ omemo_decrypt_func(signal_buffer** output, int cipher, const uint8_t* key, size_
{
int ret = SG_SUCCESS;
gcry_cipher_hd_t hd;
unsigned char* plaintext;
unsigned char* plaintext = NULL;
size_t plaintext_len;
int mode;
int algo;
@@ -268,6 +268,13 @@ omemo_decrypt_func(signal_buffer** output, int cipher, const uint8_t* key, size_
}
plaintext_len = ciphertext_len;
// PKCS#5/PKCS#7 padding requires at least one byte of plaintext;
// reject malformed empty ciphertext before any plaintext[len - 1]
// access could underflow / read out-of-bounds.
if (plaintext_len == 0) {
ret = SG_ERR_INVAL;
goto out;
}
plaintext = malloc(plaintext_len);
gcry_cipher_decrypt(hd, plaintext, plaintext_len, ciphertext, ciphertext_len);
@@ -279,6 +286,12 @@ omemo_decrypt_func(signal_buffer** output, int cipher, const uint8_t* key, size_
assert(FALSE);
}
// padding byte must address bytes that exist in plaintext.
if (padding == 0 || (size_t)padding > plaintext_len) {
ret = SG_ERR_UNKNOWN;
goto out;
}
for (int i = 0; i < padding; i++) {
if (plaintext[plaintext_len - 1 - i] != padding) {
ret = SG_ERR_UNKNOWN;
@@ -401,7 +414,7 @@ aes256gcm_crypt_file(FILE* in, FILE* out, off_t file_size,
unsigned char buffer[AES256_GCM_BUFFER_SIZE];
int bytes = 0;
size_t bytes = 0;
off_t bytes_read = 0, bytes_available = 0, read_size = 0;
while (bytes_read < file_size) {
bytes_available = file_size - bytes_read;
@@ -416,8 +429,8 @@ aes256gcm_crypt_file(FILE* in, FILE* out, off_t file_size,
read_size = AES256_GCM_BUFFER_SIZE;
}
bytes = fread(buffer, 1, read_size, in);
bytes_read += bytes;
bytes = fread(buffer, 1, (size_t)read_size, in);
bytes_read += (off_t)bytes;
if (encrypt) {
res = gcry_cipher_encrypt(hd, buffer, bytes, NULL, 0);

View File

@@ -708,14 +708,17 @@ omemo_start_device_session(const char* const jid, uint32_t device_id,
goto out;
}
int prekey_index;
uint32_t prekey_index;
size_t prekeys_len = g_list_length(prekeys);
if (prekeys_len == 0) {
log_error("[OMEMO] No prekeys found for %s device %d", jid, device_id);
goto out;
}
gcry_randomize(&prekey_index, sizeof(int), GCRY_STRONG_RANDOM);
prekey_index %= prekeys_len;
// Use an unsigned type so the modulo below is unsigned and cannot
// produce a negative index (gcry_randomize writes random bytes,
// including the sign bit of a signed int).
gcry_randomize(&prekey_index, sizeof(prekey_index), GCRY_STRONG_RANDOM);
prekey_index %= (uint32_t)prekeys_len;
omemo_key_t* prekey = g_list_nth_data(prekeys, prekey_index);
curve_decode_point(&prekey_public, prekey->data, prekey->length, omemo_ctx.signal);
@@ -1453,8 +1456,8 @@ _omemo_fingerprint_decode(const char* const fingerprint, size_t* len)
continue;
}
output[j] = g_ascii_xdigit_value(fingerprint[i++]) << 4;
output[j] |= g_ascii_xdigit_value(fingerprint[i++]);
output[j] = (unsigned char)(g_ascii_xdigit_value(fingerprint[i++]) << 4);
output[j] |= (unsigned char)g_ascii_xdigit_value(fingerprint[i++]);
j++;
}
@@ -1744,7 +1747,7 @@ _load_identity(void)
log_info("[OMEMO] Loading OMEMO identity");
/* Device ID */
omemo_ctx.device_id = g_key_file_get_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_DEVICE_ID, &error);
omemo_ctx.device_id = (uint32_t)g_key_file_get_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_DEVICE_ID, &error);
if (error != NULL) {
log_error("[OMEMO] cannot load device id: %s", error->message);
return FALSE;
@@ -1752,7 +1755,7 @@ _load_identity(void)
log_debug("[OMEMO] device id: %d", omemo_ctx.device_id);
/* Registration ID */
omemo_ctx.registration_id = g_key_file_get_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_REGISTRATION_ID, &error);
omemo_ctx.registration_id = (uint32_t)g_key_file_get_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_REGISTRATION_ID, &error);
if (error != NULL) {
log_error("[OMEMO] cannot load registration id: %s", error->message);
return FALSE;
@@ -1793,7 +1796,7 @@ _load_identity(void)
keys = g_key_file_get_keys(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_PREKEYS, NULL, NULL);
if (keys) {
for (i = 0; keys[i] != NULL; i++) {
uint32_t id = strtoul(keys[i], NULL, 10);
uint32_t id = (uint32_t)strtoul(keys[i], NULL, 10);
if (id > omemo_ctx.max_pre_key_id) {
omemo_ctx.max_pre_key_id = id;
}
@@ -1822,7 +1825,7 @@ _load_identity(void)
auto_guchar guchar* signed_pre_key = g_base64_decode(signed_pre_key_b64, &signed_pre_key_len);
signal_buffer* buffer = signal_buffer_create(signed_pre_key, signed_pre_key_len);
g_hash_table_insert(omemo_ctx.signed_pre_key_store, GINT_TO_POINTER(strtoul(keys[i], NULL, 10)), buffer);
omemo_ctx.signed_pre_key_id = strtoul(keys[i], NULL, 10);
omemo_ctx.signed_pre_key_id = (uint32_t)strtoul(keys[i], NULL, 10);
}
g_strfreev(keys);
}
@@ -1863,7 +1866,7 @@ _load_trust(void)
size_t key_len;
auto_guchar guchar* key = g_base64_decode(key_b64, &key_len);
signal_buffer* buffer = signal_buffer_create(key, key_len);
uint32_t device_id = strtoul(keys[j], NULL, 10);
uint32_t device_id = (uint32_t)strtoul(keys[j], NULL, 10);
g_hash_table_insert(trusted, GINT_TO_POINTER(device_id), buffer);
}
}
@@ -1889,7 +1892,7 @@ _load_sessions(void)
auto_gcharv gchar** keys = g_key_file_get_keys(omemo_ctx.sessions.keyfile, groups[i], NULL, NULL);
for (int j = 0; keys[j] != NULL; j++) {
uint32_t id = strtoul(keys[j], NULL, 10);
uint32_t id = (uint32_t)strtoul(keys[j], NULL, 10);
auto_gchar gchar* record_b64 = g_key_file_get_string(omemo_ctx.sessions.keyfile, groups[i], keys[j], NULL);
size_t record_len;
auto_guchar guchar* record = g_base64_decode(record_b64, &record_len);
@@ -1919,7 +1922,7 @@ _load_known_devices(void)
auto_gcharv gchar** keys = g_key_file_get_keys(omemo_ctx.knowndevices.keyfile, groups[i], NULL, NULL);
for (int j = 0; keys[j] != NULL; j++) {
uint32_t device_id = strtoul(keys[j], NULL, 10);
uint32_t device_id = (uint32_t)strtoul(keys[j], NULL, 10);
auto_gchar gchar* fingerprint = g_key_file_get_string(omemo_ctx.knowndevices.keyfile, groups[i], keys[j], NULL);
g_hash_table_insert(known_identities, strdup(fingerprint), GINT_TO_POINTER(device_id));
}

View File

@@ -687,8 +687,8 @@ p_gpg_format_fp_str(gchar* fp)
}
GString* format = g_string_new("");
int len = strlen(fp);
for (int i = 0; i < len; i++) {
size_t len = strlen(fp);
for (size_t i = 0; i < len; i++) {
g_string_append_c(format, fp[i]);
if (((i + 1) % 4 == 0) && (i + 1 < len)) {
g_string_append_c(format, ' ');

View File

@@ -506,7 +506,8 @@ c_api_init(void)
static char*
_c_plugin_name(const char* filename)
{
auto_gchar gchar* name = g_strndup(filename, strlen(filename) - 1);
size_t flen = strlen(filename);
auto_gchar gchar* name = g_strndup(filename, flen > 0 ? flen - 1 : 0);
gchar* result = g_strdup_printf("%sso", name);
return result;

View File

@@ -94,7 +94,8 @@ python_plugin_create(const char* const filename)
if (p_module) {
p_module = PyImport_ReloadModule(p_module);
} else {
gchar* module_name = g_strndup(filename, strlen(filename) - 3);
size_t flen = strlen(filename);
gchar* module_name = g_strndup(filename, flen > 3 ? flen - 3 : 0);
p_module = PyImport_ImportModule(module_name);
if (p_module) {
g_hash_table_insert(loaded_modules, strdup(filename), p_module);
@@ -856,7 +857,8 @@ static void
_python_undefined_error(ProfPlugin* plugin, char* hook, char* type)
{
GString* err_msg = g_string_new("Plugin error - ");
auto_gchar gchar* module_name = g_strndup(plugin->name, strlen(plugin->name) - 2);
size_t nlen = strlen(plugin->name);
auto_gchar gchar* module_name = g_strndup(plugin->name, nlen > 2 ? nlen - 2 : 0);
g_string_append(err_msg, module_name);
g_string_append(err_msg, hook);
g_string_append(err_msg, "(): return value undefined, expected ");
@@ -870,7 +872,8 @@ static void
_python_type_error(ProfPlugin* plugin, char* hook, char* type)
{
GString* err_msg = g_string_new("Plugin error - ");
auto_gchar gchar* module_name = g_strndup(plugin->name, strlen(plugin->name) - 2);
size_t nlen = strlen(plugin->name);
auto_gchar gchar* module_name = g_strndup(plugin->name, nlen > 2 ? nlen - 2 : 0);
g_string_append(err_msg, module_name);
g_string_append(err_msg, hook);
g_string_append(err_msg, "(): incorrect return type, expected ");

View File

@@ -290,7 +290,7 @@ autocomplete_complete(Autocomplete ac, const gchar* search_str, gboolean quote,
static char*
_autocomplete_param_common(const char* const input, char* command, autocomplete_func func, Autocomplete ac, gboolean quote, gboolean previous, void* context)
{
int len;
size_t len;
auto_gchar gchar* command_cpy = g_strdup_printf("%s ", command);
if (!command_cpy) {
return NULL;
@@ -299,14 +299,14 @@ _autocomplete_param_common(const char* const input, char* command, autocomplete_
len = strlen(command_cpy);
if (strncmp(input, command_cpy, len) == 0) {
int inp_len = strlen(input);
size_t inp_len = strlen(input);
auto_char char* found = NULL;
auto_char char* prefix = malloc(inp_len + 1);
if (!prefix) {
return NULL;
}
for (int i = len; i < inp_len; i++) {
for (size_t i = len; i < inp_len; i++) {
prefix[i - len] = input[i];
}

View File

@@ -54,7 +54,7 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot
unsigned int dlperc = 0;
if (dltotal != 0) {
dlperc = (100 * dlnow) / dltotal;
dlperc = (unsigned int)((100 * dlnow) / dltotal);
}
if (!download->silent) {

View File

@@ -62,7 +62,7 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot
unsigned int ulperc = 0;
if (ultotal != 0) {
ulperc = (100 * ulnow) / ultotal;
ulperc = (unsigned int)((100 * ulnow) / ultotal);
}
gchar* msg = NULL;

View File

@@ -28,7 +28,7 @@ _parse_args_helper(const char* const inp, int min, int max, gboolean* result, gb
auto_char char* copy = strdup(inp);
g_strstrip(copy);
int inp_size = g_utf8_strlen(copy, -1);
glong inp_size = g_utf8_strlen(copy, -1);
gboolean in_token = FALSE;
gboolean in_freetext = FALSE;
gboolean in_quotes = FALSE;
@@ -37,7 +37,7 @@ _parse_args_helper(const char* const inp, int min, int max, gboolean* result, gb
GSList* tokens = NULL;
// add tokens to GSList
for (int i = 0; i < inp_size; i++) {
for (glong i = 0; i < inp_size; i++) {
gchar* curr_ch = g_utf8_offset_to_pointer(copy, i);
gunichar curr_uni = g_utf8_get_char(curr_ch);
@@ -231,10 +231,10 @@ gchar**
parse_args_as_one(const char* const inp, int min, int max, gboolean* result)
{
gchar** args = g_malloc0(2 * sizeof(*args));
int length = g_utf8_strlen(inp, -1);
glong length = g_utf8_strlen(inp, -1);
gchar* space = g_utf8_strchr(inp, length, ' ');
if (space) {
int sub_length = g_utf8_strlen(space, -1);
glong sub_length = g_utf8_strlen(space, -1);
if (sub_length > 1) {
args[0] = g_strdup(space + 1);
*result = TRUE;
@@ -253,14 +253,14 @@ parse_args_as_one(const char* const inp, int min, int max, gboolean* result)
int
count_tokens(const char* const string)
{
int length = g_utf8_strlen(string, -1);
glong length = g_utf8_strlen(string, -1);
gboolean in_quotes = FALSE;
int num_tokens = 0;
// include first token
num_tokens++;
for (int i = 0; i < length; i++) {
for (glong i = 0; i < length; i++) {
gchar* curr_ch = g_utf8_offset_to_pointer(string, i);
gunichar curr_uni = g_utf8_get_char(curr_ch);
@@ -298,14 +298,14 @@ char*
get_start(const char* const string, int tokens)
{
GString* result = g_string_new("");
int length = g_utf8_strlen(string, -1);
glong length = g_utf8_strlen(string, -1);
gboolean in_quotes = FALSE;
int num_tokens = 0;
// include first token
num_tokens++;
for (int i = 0; i < length; i++) {
for (glong i = 0; i < length; i++) {
gchar* curr_ch = g_utf8_offset_to_pointer(string, i);
gunichar curr_uni = g_utf8_get_char(curr_ch);

View File

@@ -92,8 +92,11 @@ cons_show_help(const char* const cmd, CommandHelp* help)
win_println(console, THEME_HELP_HEADER, "-", "%s", &cmd[1]);
win_print(console, THEME_HELP_HEADER, "-", "");
size_t i;
for (i = 0; i < strlen(cmd) - 1; i++) {
win_append(console, THEME_HELP_HEADER, "-");
size_t cmd_len = strlen(cmd);
if (cmd_len > 0) {
for (i = 0; i < cmd_len - 1; i++) {
win_append(console, THEME_HELP_HEADER, "-");
}
}
win_appendln(console, THEME_HELP_HEADER, "");
cons_show("");
@@ -115,7 +118,7 @@ cons_show_help(const char* const cmd, CommandHelp* help)
cons_show("");
win_println(console, THEME_HELP_HEADER, "-", "Arguments");
for (i = 0; help->args[i][0] != NULL; i++) {
win_println_indent(console, maxlen + 3, "%-*s: %s", (int)(maxlen + 1), help->args[i][0], help->args[i][1]);
win_println_indent(console, (int)(maxlen + 3), "%-*s: %s", (int)(maxlen + 1), help->args[i][0], help->args[i][1]);
}
}

View File

@@ -166,7 +166,7 @@ ui_get_idle_time(void)
// if no libxss or xss idle time failed, use profanity idle time
#endif
gdouble seconds_elapsed = g_timer_elapsed(ui_idle_time, NULL);
unsigned long ms_elapsed = seconds_elapsed * 1000.0;
unsigned long ms_elapsed = (unsigned long)(seconds_elapsed * 1000.0);
return ms_elapsed;
}

View File

@@ -385,7 +385,10 @@ _inp_write(char* line, int offset)
char retc[PROF_MB_CUR_MAX] = { 0 };
size_t ch_len = mbrlen(c, MB_CUR_MAX, NULL);
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) {
// ch_len == 0 means mbrlen consumed the null wide character;
// skipping it here keeps `i += ch_len - 1` below from
// underflowing to SIZE_MAX.
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) {
waddch(inp_win, ' ');
continue;
}
@@ -409,7 +412,9 @@ _inp_write(char* line, int offset)
size_t end = start + ch_len;
while (line[end] != '\0') {
size_t next_ch_len = mbrlen(&line[end], MB_CUR_MAX, NULL);
if (next_ch_len == (size_t)-2 || next_ch_len == (size_t)-1)
// ch_len == 0 means embedded NUL — stop, otherwise
// `end += next_ch_len` loops forever.
if (next_ch_len == (size_t)-2 || next_ch_len == (size_t)-1 || next_ch_len == 0)
break;
gunichar next_uc = g_utf8_get_char(&line[end]);
if (!g_unichar_isalnum(next_uc) && next_uc != '\'')
@@ -428,7 +433,13 @@ _inp_write(char* line, int offset)
size_t word_pos = start;
while (word_pos < end) {
size_t cur_ch_len = mbrlen(&line[word_pos], MB_CUR_MAX, NULL);
waddnstr(inp_win, &line[word_pos], cur_ch_len);
// Defensive: invalid or zero-length step would loop
// forever; advance one byte and continue.
if (cur_ch_len == (size_t)-2 || cur_ch_len == (size_t)-1 || cur_ch_len == 0) {
word_pos++;
continue;
}
waddnstr(inp_win, &line[word_pos], (int)cur_ch_len);
word_pos += cur_ch_len;
}
@@ -441,7 +452,7 @@ _inp_write(char* line, int offset)
}
}
waddnstr(inp_win, c, ch_len);
waddnstr(inp_win, c, (int)ch_len);
}
wmove(inp_win, 0, col);
@@ -494,11 +505,13 @@ _inp_offset_to_col(char* str, int offset)
while (i < offset && str[i] != '\0') {
gunichar uni = g_utf8_get_char(&str[i]);
size_t ch_len = mbrlen(&str[i], MB_CUR_MAX, NULL);
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) {
// ch_len == 0 (embedded NUL) would freeze the loop on the same
// byte; treat it like an invalid step.
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) {
i++;
continue;
}
i += ch_len;
i += (int)ch_len;
col++;
if (g_unichar_iswide(uni)) {
col++;

View File

@@ -382,7 +382,7 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co
auto_gchar gchar* mynick_str = g_utf8_substring(message, pos, pos + mynick_len);
win_append_highlight(window, THEME_ROOMMENTION_TERM, "%s", mynick_str);
last_pos = pos + mynick_len;
last_pos = pos + (int)mynick_len;
curr = g_slist_next(curr);
}
@@ -400,8 +400,8 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co
gint
_cmp_trigger_weight(gconstpointer a, gconstpointer b)
{
int alen = strlen((char*)a);
int blen = strlen((char*)b);
size_t alen = strlen((char*)a);
size_t blen = strlen((char*)b);
if (alen > blen)
return -1;
@@ -438,10 +438,10 @@ _mucwin_print_triggers(ProfWin* window, const char* const message, GList* trigge
}
// found, replace vars if earlier than previous
int trigger_pos = trigger_ptr - message_lower;
int trigger_pos = (int)(trigger_ptr - message_lower);
if (first_trigger_pos == -1 || trigger_pos < first_trigger_pos) {
first_trigger_pos = trigger_pos;
first_trigger_len = strlen(trigger_lower);
first_trigger_len = (int)strlen(trigger_lower);
}
curr = g_list_next(curr);

View File

@@ -304,8 +304,13 @@ _status_bar_draw_tabs(guint pos)
gboolean is_static = g_strcmp0(tabmode, "dynamic") != 0;
_get_range_bounds(&start, &end, is_static);
// if the result of the calc is negative we take 0
pos = MAX(0, (getmaxx(stdscr) - (int)_tabs_width(start, end)));
guint tabs_w = _tabs_width(start, end);
int max_x = getmaxx(stdscr);
if (max_x > 0 && (guint)max_x > tabs_w) {
pos = (guint)max_x - tabs_w;
} else {
pos = 0;
}
pos = _status_bar_draw_extended_tabs(pos, TRUE, start, end, is_static);
@@ -392,7 +397,9 @@ _status_bar_draw_extended_tabs(guint pos, gboolean prefix, guint start, guint en
if (prefix && start < 2) {
return pos;
}
if (!prefix && end > opened_tabs - 1) {
// Guard against underflow when opened_tabs == 0 (reachable if the
// earlier `opened_tabs <= max_tabs` early-return no longer holds).
if (!prefix && end >= opened_tabs) {
return pos;
}
gboolean is_current = is_static && statusbar->current_tab > max_tabs;
@@ -504,7 +511,7 @@ _status_bar_draw_time(guint pos)
int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
int time_attrs = theme_attrs(THEME_STATUS_TIME);
size_t len = strlen(statusbar->time);
guint len = (guint)strlen(statusbar->time);
wattron(statusbar_win, bracket_attrs);
mvwaddch(statusbar_win, 0, pos, '[');
pos++;
@@ -599,7 +606,7 @@ _tabs_width(guint start, guint end)
guint opened_tabs = g_hash_table_size(statusbar->tabs);
int width = start < 2 ? 1 : 4;
width += end > opened_tabs - 1 ? 0 : 3;
width += (end < opened_tabs) ? 3 : 0;
if (show_name && show_number) {
for (guint i = start; i <= end; i++) {

View File

@@ -224,7 +224,7 @@ _title_bar_draw(void)
auto_gchar gchar* title = win_get_title(current);
mvwprintw(win, 0, 0, " %s", title);
pos = strlen(title) + 1;
pos = (int)strlen(title) + 1;
// presence is written from the right side
// calculate it first so we have a maxposition
@@ -596,7 +596,7 @@ _show_contact_presence(ProfChatWin* chatwin, int pos, int maxpos)
}
if (resource && prefs_get_boolean(PREF_RESOURCE_TITLE)) {
int needed = strlen(resource) + 1;
int needed = (int)strlen(resource) + 1;
if (pos + needed < maxpos) {
wprintw(win, "/");
wprintw(win, "%s", resource);

View File

@@ -75,7 +75,7 @@ static void
_win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* timestamp, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message_id, const char* const message, ...);
static void _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDateTime* time,
int flags, theme_item_t theme_item, const char* const from, const char* const message, DeliveryReceipt* receipt);
static void _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pad_indent);
static void _win_print_wrapped(WINDOW* win, const char* const message, int indent, int pad_indent);
// Helper: clamp a subwindow width to a sane range [1, cols-1] if possible
static int
@@ -1048,11 +1048,11 @@ win_show_contact(ProfWin* window, PContact contact)
GTimeSpan span = g_date_time_difference(now, last_activity);
g_date_time_unref(now);
int hours = span / G_TIME_SPAN_HOUR;
int hours = (int)(span / G_TIME_SPAN_HOUR);
span = span - hours * G_TIME_SPAN_HOUR;
int minutes = span / G_TIME_SPAN_MINUTE;
int minutes = (int)(span / G_TIME_SPAN_MINUTE);
span = span - minutes * G_TIME_SPAN_MINUTE;
int seconds = span / G_TIME_SPAN_SECOND;
int seconds = (int)(span / G_TIME_SPAN_SECOND);
if (hours > 0) {
win_append(window, presence_colour, ", idle %dh%dm%ds", hours, minutes, seconds);
@@ -1173,11 +1173,11 @@ win_show_info(ProfWin* window, PContact contact)
GDateTime* now = g_date_time_new_now_local();
GTimeSpan span = g_date_time_difference(now, last_activity);
int hours = span / G_TIME_SPAN_HOUR;
int hours = (int)(span / G_TIME_SPAN_HOUR);
span = span - hours * G_TIME_SPAN_HOUR;
int minutes = span / G_TIME_SPAN_MINUTE;
int minutes = (int)(span / G_TIME_SPAN_MINUTE);
span = span - minutes * G_TIME_SPAN_MINUTE;
int seconds = span / G_TIME_SPAN_SECOND;
int seconds = (int)(span / G_TIME_SPAN_SECOND);
if (hours > 0) {
win_println(window, THEME_DEFAULT, "-", "Last activity: %dh%dm%ds", hours, minutes, seconds);
@@ -1846,7 +1846,7 @@ _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDat
gboolean me_message = FALSE;
int offset = 0;
int colour = theme_attrs(THEME_ME);
size_t indent = 0;
int indent = 0;
auto_gchar gchar* time_pref = NULL;
switch (window->type) {
@@ -1879,7 +1879,7 @@ _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDat
assert(date_fmt != NULL);
if (strlen(date_fmt) != 0) {
indent = 3 + strlen(date_fmt);
indent = 3 + (int)strlen(date_fmt);
}
if ((flags & NO_DATE) == 0) {
@@ -1975,7 +1975,7 @@ _win_indent(WINDOW* win, int size)
}
static void
_win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pad_indent)
_win_print_wrapped(WINDOW* win, const char* const message, int indent, int pad_indent)
{
int starty = getcury(win);
int wordi = 0;
@@ -2002,7 +2002,8 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa
int wordlen = 0;
while (*curr_ch != ' ' && *curr_ch != '\n' && *curr_ch != '\0') {
size_t ch_len = mbrlen(curr_ch, MB_CUR_MAX, NULL);
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) {
// 0 / invalid step: advance one byte to avoid spinning.
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) {
curr_ch++;
continue;
}
@@ -2015,9 +2016,9 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa
word[wordi] = '\0';
wordlen = utf8_display_len(word);
size_t curx = (size_t)getcurx(win);
int curx = getcurx(win);
int cury;
size_t maxx = getmaxx(win);
int maxx = getmaxx(win);
// wrap required
if (curx + wordlen > maxx) {
@@ -2027,7 +2028,7 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa
if (wordlen > linelen) {
gchar* word_ch = g_utf8_offset_to_pointer(word, 0);
while (*word_ch != '\0') {
curx = (size_t)getcurx(win);
curx = getcurx(win);
cury = getcury(win);
gboolean firstline = cury == starty;
@@ -2048,7 +2049,7 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa
// newline and print word
} else {
waddch(win, '\n');
curx = (size_t)getcurx(win);
curx = getcurx(win);
cury = getcury(win);
gboolean firstline = cury == starty;
@@ -2063,7 +2064,7 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa
// no wrap required
} else {
curx = (size_t)getcurx(win);
curx = getcurx(win);
cury = getcury(win);
gboolean firstline = cury == starty;

View File

@@ -97,12 +97,12 @@ avatar_set(const char* path)
int h = gdk_pixbuf_get_height(pixbuf);
if (w >= h && w > MAX_PIXEL) {
int dest_height = (int)((float)MAX_PIXEL / w * h);
int dest_height = (int)((float)MAX_PIXEL / (float)w * (float)h);
GdkPixbuf* new_pixbuf = gdk_pixbuf_scale_simple(pixbuf, MAX_PIXEL, dest_height, GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = new_pixbuf;
} else if (h > w && w > MAX_PIXEL) {
int dest_width = (int)((float)MAX_PIXEL / h * w);
int dest_width = (int)((float)MAX_PIXEL / (float)h * (float)w);
GdkPixbuf* new_pixbuf = gdk_pixbuf_scale_simple(pixbuf, dest_width, MAX_PIXEL, GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = new_pixbuf;

View File

@@ -245,10 +245,13 @@ connection_connect(const char* const jid, const char* const passwd, const char*
_conn_apply_settings(jid, passwd, tls_policy, auth_policy);
// TCP ports are 16-bit; the account-layer validator must enforce this
// range before we reach libstrophe.
g_assert(port >= 0 && port <= UINT16_MAX);
int connect_status = xmpp_connect_client(
conn.xmpp_conn,
altdomain,
port,
(unsigned short)port,
_connection_handler,
conn.xmpp_ctx);
@@ -503,10 +506,11 @@ connection_register(const char* const altdomain, int port, const char* const tls
reg->username = strdup(username);
reg->password = strdup(password);
g_assert(port >= 0 && port <= UINT16_MAX);
int connect_status = xmpp_connect_raw(
conn.xmpp_conn,
altdomain,
port,
(unsigned short)port,
_register_handler,
reg);
@@ -1018,7 +1022,8 @@ _connection_handler(xmpp_conn_t* const xmpp_conn, const xmpp_conn_event_t status
gchar* host;
int port;
if (stream_error && stream_error->stanza && _get_other_host(stream_error->stanza, &host, &port)) {
session_reconnect(host, port);
g_assert(port >= 0 && port <= UINT16_MAX);
session_reconnect(host, (unsigned short)port);
log_debug("Connection handler: Forcing a re-connect to \"%s\"", host);
conn.conn_status = JABBER_RECONNECT;
return;

View File

@@ -384,7 +384,7 @@ iq_autoping_check(void)
}
gdouble elapsed = g_timer_elapsed(autoping_time, NULL);
gint seconds_elapsed = elapsed * 1.0;
gint seconds_elapsed = (gint)elapsed;
gint timeout = prefs_get_autoping_timeout();
if (timeout > 0 && seconds_elapsed >= timeout) {
cons_show("Autoping response timed out after %u seconds.", timeout);
@@ -1138,7 +1138,7 @@ _room_list_id_handler(xmpp_stanza_t* const stanza, void* const userdata)
if (item_name) {
item_name_lower = g_utf8_strdown(item_name, -1);
}
if ((item_jid_lower) && ((glob == NULL) || ((g_pattern_match(glob, strlen(item_jid_lower), item_jid_lower, NULL)) || (item_name_lower && g_pattern_match(glob, strlen(item_name_lower), item_name_lower, NULL))))) {
if ((item_jid_lower) && ((glob == NULL) || ((g_pattern_match(glob, (guint)strlen(item_jid_lower), item_jid_lower, NULL)) || (item_name_lower && g_pattern_match(glob, (guint)strlen(item_name_lower), item_name_lower, NULL))))) {
if (glob) {
matched = TRUE;
@@ -1394,7 +1394,7 @@ _manual_pong_id_handler(xmpp_stanza_t* const stanza, void* const userdata)
GDateTime* now = g_date_time_new_now_local();
GTimeSpan elapsed = g_date_time_difference(now, sent);
int elapsed_millis = elapsed / 1000;
int elapsed_millis = (int)(elapsed / 1000);
g_date_time_unref(now);
@@ -1781,7 +1781,7 @@ _last_activity_get_handler(xmpp_stanza_t* const stanza)
}
if (prefs_get_boolean(PREF_LASTACTIVITY)) {
int idls_secs = ui_get_idle_time() / 1000;
int idls_secs = (int)(ui_get_idle_time() / 1000);
char str[50];
sprintf(str, "%d", idls_secs);

View File

@@ -1640,7 +1640,7 @@ _ox_openpgp_signcrypt(xmpp_ctx_t* ctx, const char* const to, const char* const t
char rpad_data[randnr];
for (int i = 0; i < randnr; i++) {
int rchar = (rand() % 52) + 65;
rpad_data[i] = rchar;
rpad_data[i] = (char)rchar;
}
rpad_data[randnr - 1] = '\0';

View File

@@ -194,7 +194,7 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* cons
goto out;
}
uint32_t device_id = strtoul(++device_id_str, NULL, 10);
uint32_t device_id = (uint32_t)strtoul(++device_id_str, NULL, 10);
log_debug("[OMEMO] omemo_start_device_session_handle_bundle: %d", device_id);
xmpp_stanza_t* item = xmpp_stanza_get_child_by_name(items, "item");
@@ -227,7 +227,7 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* cons
continue;
}
key->id = strtoul(prekey_id_text, NULL, 10);
key->id = (uint32_t)strtoul(prekey_id_text, NULL, 10);
xmpp_stanza_t* prekey_text = xmpp_stanza_get_children(prekey);
if (!prekey_text) {
@@ -257,7 +257,7 @@ omemo_start_device_session_handle_bundle(xmpp_stanza_t* const stanza, void* cons
goto out;
}
uint32_t signed_prekey_id = strtoul(signed_prekey_id_text, NULL, 10);
uint32_t signed_prekey_id = (uint32_t)strtoul(signed_prekey_id_text, NULL, 10);
xmpp_stanza_t* signed_prekey_text = xmpp_stanza_get_children(signed_prekey);
if (!signed_prekey_text) {
goto out;
@@ -358,7 +358,7 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_erro
*error = OMEMO_ERR_OTHER;
return NULL;
}
uint32_t sid = strtoul(sid_text, NULL, 10);
uint32_t sid = (uint32_t)strtoul(sid_text, NULL, 10);
xmpp_stanza_t* iv = xmpp_stanza_get_child_by_name(header, "iv");
if (!iv) {
@@ -403,7 +403,7 @@ omemo_receive_message(xmpp_stanza_t* const stanza, gboolean* trusted, omemo_erro
}
const char* rid_text = xmpp_stanza_get_attribute(key_stanza, "rid");
key->device_id = strtoul(rid_text, NULL, 10);
key->device_id = (uint32_t)strtoul(rid_text, NULL, 10);
if (!key->device_id) {
free(key);
continue;

View File

@@ -243,7 +243,7 @@ session_process_events(void)
case JABBER_DISCONNECTED:
reconnect_sec = prefs_get_reconnect();
if ((reconnect_sec != 0) && reconnect_timer) {
int elapsed_sec = g_timer_elapsed(reconnect_timer, NULL);
int elapsed_sec = (int)g_timer_elapsed(reconnect_timer, NULL);
if (elapsed_sec > reconnect_sec) {
log_debug("[CONNDBG] session_process_events: auto-reconnect triggered after %d seconds (threshold=%d)",
elapsed_sec, reconnect_sec);
@@ -437,7 +437,7 @@ session_check_autoaway(void)
auto_gchar gchar* message = prefs_get_string(PREF_AUTOAWAY_MESSAGE);
connection_set_presence_msg(message);
if (prefs_get_boolean(PREF_LASTACTIVITY)) {
cl_ev_presence_send(RESOURCE_AWAY, idle_ms / 1000);
cl_ev_presence_send(RESOURCE_AWAY, (int)(idle_ms / 1000));
} else {
cl_ev_presence_send(RESOURCE_AWAY, 0);
}
@@ -456,7 +456,7 @@ session_check_autoaway(void)
// send current presence with last activity
connection_set_presence_msg(curr_status);
cl_ev_presence_send(curr_presence, idle_ms / 1000);
cl_ev_presence_send(curr_presence, (int)(idle_ms / 1000));
}
}
break;
@@ -479,7 +479,7 @@ session_check_autoaway(void)
auto_gchar gchar* message = prefs_get_string(PREF_AUTOXA_MESSAGE);
connection_set_presence_msg(message);
if (prefs_get_boolean(PREF_LASTACTIVITY)) {
cl_ev_presence_send(RESOURCE_XA, idle_ms / 1000);
cl_ev_presence_send(RESOURCE_XA, (int)(idle_ms / 1000));
} else {
cl_ev_presence_send(RESOURCE_XA, 0);
}
@@ -560,7 +560,8 @@ session_reconnect_now(void)
port = reconnect.altport;
} else {
server = account->server;
port = account->port;
g_assert(account->port >= 0 && account->port <= UINT16_MAX);
port = (unsigned short)account->port;
}
log_debug("Attempting reconnect with account %s", account->name);

View File

@@ -194,34 +194,36 @@ sleep_ms(int ms)
* Read available data from fd into output_buffer with timeout.
* Returns number of bytes read, 0 on timeout, -1 on error.
*/
static int
static ssize_t
_read_output(int timeout_ms)
{
fd_set readfds;
struct timeval tv;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
tv.tv_sec = timeout_ms / MS_TO_US;
tv.tv_usec = (timeout_ms % MS_TO_US) * MS_TO_US;
int ret = select(fd + 1, &readfds, NULL, NULL, &tv);
if (ret <= 0) {
return ret;
}
size_t space = OUTPUT_BUF_SIZE - output_len - 1;
if (space <= 0) {
/* Check size before subtracting so OUTPUT_BUF_SIZE - output_len - 1
* never goes negative / underflows. Reserves one byte for the
* trailing NUL. */
if (output_len >= OUTPUT_BUF_SIZE - 1) {
/* Buffer full, shift content */
memmove(output_buffer, output_buffer + OUTPUT_BUF_SIZE/2, OUTPUT_BUF_SIZE/2);
output_len = OUTPUT_BUF_SIZE/2;
space = OUTPUT_BUF_SIZE - output_len - 1;
}
size_t space = OUTPUT_BUF_SIZE - output_len - 1;
ssize_t n = read(fd, output_buffer + output_len, space);
if (n > 0) {
output_len += n;
output_len += (size_t)n;
output_buffer[output_len] = '\0';
}
return n;