diff -Nru swirc-3.4.3/CHANGELOG.md swirc-3.4.4/CHANGELOG.md --- swirc-3.4.3/CHANGELOG.md 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/CHANGELOG.md 2023-07-29 13:02:03.000000000 +0000 @@ -1,6 +1,23 @@ # Change Log # All notable changes to this project will be documented in this file. +## [3.4.4] - 2023-07-29 ## +- **Added** a man page that describes how to write themes. +- **Added** and made use of a pointer validation function. +- **Added** improved unicode support in the **printtext** and **readline** modules. +- **Added** usage of a binary search algorithm. +- **Added** validation of nicknames before they go into the names hash + table. +- **Allowed** the names htbl modify API to alter names even if the list is + incomplete. (But only in ICB mode.) +- **Changed** the file suffix for theme files from `.the` to + `.thm`. (`.the` looks too much like the English word "the".) +- **Closed** an open stream before exit +- **Defined** noreturn for C++ in `fallbackattrs.h` +- **Fixed** hardcoded function names in error messages +- **Fixed** unchecked return values +- And more... + ## [3.4.3] - 2023-03-10 ## - **Added** code improvements: - **Added** constructors/destructors diff -Nru swirc-3.4.3/configure swirc-3.4.4/configure --- swirc-3.4.3/configure 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/configure 2023-07-29 13:02:03.000000000 +0000 @@ -6,6 +6,7 @@ MAKE_DEF_FILE=options.mk +. "posixshell/check_etext.sh" . "posixshell/check_strcasestr.sh" . "posixshell/fix_cflags.sh" . "posixshell/link_with_gnu_libidn.sh" @@ -106,6 +107,7 @@ ;; esac +check_etext check_strcasestr if [ ${_fuzz_mode} -eq 1 ]; then diff -Nru swirc-3.4.3/debian/changelog swirc-3.4.4/debian/changelog --- swirc-3.4.3/debian/changelog 2023-03-10 16:17:52.000000000 +0000 +++ swirc-3.4.4/debian/changelog 2023-07-29 13:51:17.000000000 +0000 @@ -1,3 +1,9 @@ +swirc (3.4.4-1) unstable; urgency=medium + + * New upstream version. + + -- Markus Uhlin Sat, 29 Jul 2023 15:51:17 +0200 + swirc (3.4.3-1) unstable; urgency=medium * New upstream version. diff -Nru swirc-3.4.3/debian/control swirc-3.4.4/debian/control --- swirc-3.4.3/debian/control 2023-03-10 16:17:52.000000000 +0000 +++ swirc-3.4.4/debian/control 2023-07-29 13:51:17.000000000 +0000 @@ -8,11 +8,11 @@ libcmocka-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev | libcurl4-nss-dev, libhunspell-dev, - libidn-dev | libidn11-dev, + libidn-dev, libncurses-dev, libnotify-dev, libssl-dev -Standards-Version: 4.6.1.0 +Standards-Version: 4.6.2.0 Homepage: https://www.nifty-networks.net/swirc/ Vcs-Browser: https://github.com/uhlin/swirc Vcs-Git: https://github.com/uhlin/swirc.git diff -Nru swirc-3.4.3/install.mk swirc-3.4.4/install.mk --- swirc-3.4.3/install.mk 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/install.mk 2023-07-29 13:02:03.000000000 +0000 @@ -2,7 +2,8 @@ INSTALL_DEPS = src/swirc.1\ swirc\ swirc-royal.png\ - swirc.conf.5 + swirc.conf.5\ + swirc.theme.5 LC_MSGS = po/de/swirc.mo\ po/fi/swirc.mo\ po/fr/swirc.mo\ @@ -29,6 +30,7 @@ $(INSTALL) -m 0755 swirc $(DEST_PROGRAM) $(INSTALL) -m 0444 src/swirc.1 $(DEST_MANUAL) $(INSTALL) -m 0444 swirc.conf.5 $(DEST_CONFMAN) + $(INSTALL) -m 0444 swirc.theme.5 $(DEST_CONFMAN) $(INSTALL) -m 0444 swirc-royal.png $(DEST_LOGO) $(INSTALL) -m 0644 po/de/swirc.mo $(DEST_LC_MSGS)de/LC_MESSAGES $(INSTALL) -m 0644 po/fi/swirc.mo $(DEST_LC_MSGS)fi/LC_MESSAGES @@ -43,4 +45,5 @@ $(INSTALL) -m 0755 swirc $(DEST_PROGRAM) $(INSTALL) -m 0444 src/swirc.1 $(DEST_MANUAL) $(INSTALL) -m 0444 swirc.conf.5 $(DEST_CONFMAN) + $(INSTALL) -m 0444 swirc.theme.5 $(DEST_CONFMAN) $(INSTALL) -m 0444 swirc-royal.png $(DEST_LOGO) diff -Nru swirc-3.4.3/Makefile.vc swirc-3.4.4/Makefile.vc --- swirc-3.4.3/Makefile.vc 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/Makefile.vc 2023-07-29 13:02:03.000000000 +0000 @@ -16,7 +16,7 @@ # Locale location LOCLOC = LC_MESSAGES\swirc.mo -PRODUCT_VERSION = 3.4.3 +PRODUCT_VERSION = 3.4.4 REVISION = all: main diff -Nru swirc-3.4.3/po/de/swirc.po swirc-3.4.4/po/de/swirc.po --- swirc-3.4.3/po/de/swirc.po 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/po/de/swirc.po 2023-07-29 13:02:03.000000000 +0000 @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: swirc 3.4.3\n" +"Project-Id-Version: swirc 3.4.4\n" "Report-Msgid-Bugs-To: https://github.com/uhlin/swirc/issues\n" "POT-Creation-Date: 2023-03-09 12:51+0100\n" "PO-Revision-Date: 2023-03-09 13:21+0100\n" diff -Nru swirc-3.4.3/po/fi/swirc.po swirc-3.4.4/po/fi/swirc.po --- swirc-3.4.3/po/fi/swirc.po 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/po/fi/swirc.po 2023-07-29 13:02:03.000000000 +0000 @@ -5,10 +5,10 @@ # msgid "" msgstr "" -"Project-Id-Version: swirc 3.4.3\n" +"Project-Id-Version: swirc 3.4.4\n" "Report-Msgid-Bugs-To: https://github.com/uhlin/swirc/issues\n" "POT-Creation-Date: 2023-03-09 12:51+0100\n" -"PO-Revision-Date: 2023-03-09 13:15+0100\n" +"PO-Revision-Date: 2023-07-29 12:27+0200\n" "Last-Translator: Markus Uhlin \n" "Language-Team: Finnish \n" "Language: fi\n" @@ -127,17 +127,19 @@ #: ../src/include/commandhelp.h:44 msgid "usage: /away [reason]" -msgstr "" +msgstr "käyttö: /away [syy]" #: ../src/include/commandhelp.h:46 msgid "" "Marks yourself as being away (with a reason). If the reason is omitted\n" "you will be marked as no longer being away." msgstr "" +"Merkitsee itsesi poissa (syyn kanssa). Jos syy jätetään pois, sinut\n" +"merkitään et ole enää poissa." #: ../src/include/commandhelp.h:52 msgid "usage: /ban " -msgstr "" +msgstr "käyttö: /ban " #: ../src/include/commandhelp.h:54 msgid "" @@ -145,10 +147,14 @@ "matches the provided mask from joining the channel. Wildcards are okay\n" "and the active window must be an IRC channel." msgstr "" +"Asettaa kanavakiellon, joka estää kaikkia käyttäjiä, joiden\n" +"'nick!user@host' vastaa annettua maskia, liittymästä\n" +"kanavaan. Jokerimerkit ovat kunnossa ja aktiivisen ikkunan on oltava\n" +"IRC kanava." #: ../src/include/commandhelp.h:61 msgid "usage: /banlist [channel]" -msgstr "" +msgstr "käyttö: /banlist [kanava]" #: ../src/include/commandhelp.h:63 msgid "" @@ -156,26 +162,29 @@ "the active window is an IRC channel, Swirc will output the banlist for\n" "that channel." msgstr "" +"Näyttää kanavan banlistin. Jos kanavaargumentti jätetään tyhjäksi ja\n" +"aktiivinen ikkuna on IRC kanava, Swirc tulostaa kyseisen kanavan\n" +"banlistin." #: ../src/include/commandhelp.h:70 msgid "usage: /beep " -msgstr "" +msgstr "käyttö: /beep " #: ../src/include/commandhelp.h:72 msgid "Send beeps. (ICB only)" -msgstr "" +msgstr "Lähetä piippaukset. (Vain ICB)" #: ../src/include/commandhelp.h:77 msgid "usage: /boot " -msgstr "" +msgstr "käyttö: /boot " #: ../src/include/commandhelp.h:79 msgid "Kick a user out of your group. (ICB only)" -msgstr "" +msgstr "Potkaise käyttäjä ryhmästäsi. (Vain ICB)" #: ../src/include/commandhelp.h:84 msgid "usage: /chanserv <[service hostname | --]> [...]" -msgstr "" +msgstr "käyttö: /chanserv <[palvelun isäntänimi | --]> [...]" #: ../src/include/commandhelp.h:86 msgid "" @@ -183,30 +192,37 @@ "argument equals to '--', then the value of setting 'chanserv_host' is\n" "used as a service hostname." msgstr "" +"Kommunikoi IRC verkkosi kanavapalvelun kanssa. Jos aloitusargumentti\n" +"on '--', palvelun isäntänimenä käytetään asetuksen 'chanserv_host'\n" +"arvoa." #: ../src/include/commandhelp.h:97 msgid "usage: /cap [ls | list]" -msgstr "" +msgstr "käyttö: /cap [ls | list]" #: ../src/include/commandhelp.h:99 msgid "" "Lists the (IRCv3) capabilities supported by the server and/or the\n" "capabilities associated with the active connection." msgstr "" +"Luetteloi palvelimen tukemat IRCv3 ominaisuudet ja/tai aktiiviseen\n" +"yhteyteen liittyvät ominaisuudet." #: ../src/include/commandhelp.h:105 msgid "usage: /cleartoasts" -msgstr "" +msgstr "käyttö: /cleartoasts" #: ../src/include/commandhelp.h:107 msgid "" "On Windows Swirc sends toast notifications. By running this command\n" "all notifications associated with Swirc will be cleared." msgstr "" +"Windowsissa Swirc lähettää toast-ilmoituksia. Suorittamalla tämän\n" +"komennon kaikki Swirciin liittyvät ilmoitukset tyhjennetään." #: ../src/include/commandhelp.h:113 msgid "usage: /close" -msgstr "" +msgstr "käyttö: /close" #: ../src/include/commandhelp.h:115 msgid "" diff -Nru swirc-3.4.3/po/fr/swirc.po swirc-3.4.4/po/fr/swirc.po --- swirc-3.4.3/po/fr/swirc.po 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/po/fr/swirc.po 2023-07-29 13:02:03.000000000 +0000 @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: swirc 3.4.3\n" +"Project-Id-Version: swirc 3.4.4\n" "Report-Msgid-Bugs-To: https://github.com/uhlin/swirc/issues\n" "POT-Creation-Date: 2023-03-09 12:51+0100\n" "PO-Revision-Date: 2023-03-09 13:09+0100\n" diff -Nru swirc-3.4.3/po/sv/swirc.po swirc-3.4.4/po/sv/swirc.po --- swirc-3.4.3/po/sv/swirc.po 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/po/sv/swirc.po 2023-07-29 13:02:03.000000000 +0000 @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: swirc 3.4.3\n" +"Project-Id-Version: swirc 3.4.4\n" "Report-Msgid-Bugs-To: https://github.com/uhlin/swirc/issues\n" "POT-Creation-Date: 2023-03-09 12:51+0100\n" "PO-Revision-Date: 2023-03-09 13:01+0100\n" diff -Nru swirc-3.4.3/posixshell/check_etext.sh swirc-3.4.4/posixshell/check_etext.sh --- swirc-3.4.3/posixshell/check_etext.sh 1970-01-01 00:00:00.000000000 +0000 +++ swirc-3.4.4/posixshell/check_etext.sh 2023-07-29 13:02:03.000000000 +0000 @@ -0,0 +1,69 @@ +####################################################### +# +# Check whether the etext segment is usable +# +# Copyright (c) 2023 Markus Uhlin. All rights reserved. +# + +check_etext () { + local _tmpfile _srcfile _out + local _val=1 + + printf "creating temp file..." + _tmpfile=$(mktemp) || { echo "error"; exit 1; } + echo "ok" + + _srcfile="${_tmpfile}.c" + _out="${_tmpfile}.out" + cat <"$_srcfile" +#include + +int global; + +static int +valid(const void *ptr) +{ + extern char etext; + return (ptr != NULL && ((const char *) ptr) > &etext); +} + +int +main(void) +{ + int local; + + if (valid(&local) && valid(&global)) + return 99; + return 1; +} +EOF + + if [ ! -f "$_srcfile" ]; then + echo "failed to create $_srcfile" + exit 1 + fi + + printf "checking whether the etext segment is usable..." + + ${CC} ${CFLAGS} -Werror "$_srcfile" -o "$_out" ${LDFLAGS} \ + >/dev/null 2>&1 + if [ $? -eq 0 ]; then + eval "$_out" + _val=$? + fi + + if [ ${_val} -eq 99 ]; then + echo "yes" + cat <>$MAKE_DEF_FILE +CFLAGS += -DHAVE_ETEXT_SEGMENT=1 +CXXFLAGS += -DHAVE_ETEXT_SEGMENT=1 +EOF + else + echo "no" + fi + + echo "cleaning..." + test -f "$_tmpfile" && rm -f "$_tmpfile" + test -f "$_srcfile" && rm -f "$_srcfile" + test -f "$_out" && rm -f "$_out" +} diff -Nru swirc-3.4.3/README.md swirc-3.4.4/README.md --- swirc-3.4.3/README.md 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/README.md 2023-07-29 13:02:03.000000000 +0000 @@ -47,33 +47,34 @@ Swirc currently depends on: * [Curl](https://curl.haxx.se/libcurl/) +* [GNOME libnotify](https://wiki.gnome.org/) +* [GNU gettext](https://www.gnu.org/software/gettext/) +* [GNU libiconv](https://www.gnu.org/software/libiconv/) * [GNU libidn](https://www.gnu.org/software/libidn/) +* [Hunspell](https://hunspell.github.io/) * [Ncurses](https://www.gnu.org/software/ncurses/ncurses.html) with wide character support * [OpenSSL toolkit](https://www.openssl.org/) Which means that on for example a Debian GNU/Linux system you need to -install 4 packages before building: +install these packages before building: - # apt install libcurl4-openssl-dev libidn11-dev libncursesw5-dev libssl-dev + # apt install gettext libcurl4-openssl-dev libhunspell-dev libidn11-dev libncursesw5-dev libssl-dev And on Mac OS X, provided that [Homebrew](http://brew.sh/) is installed, issue: + $ brew install hunspell $ brew install libressl -#### FreeBSD #### +Prompts that begin with a hash(#) symbolizes that the command shall be +executed as root, while prompts that begin with a dollar sign ($) +symbolizes that the command shall be executed as a normal user. - # pkg install curl libidn +#### Void Linux #### -#### NetBSD #### - - # pkgin install curl libidn ncursesw - -#### Void GNU/Linux #### - - # xbps-install -S libcurl-devel libressl-devel ncurses-devel libidn-devel + # xbps-install -S gettext-devel hunspell-devel libcurl-devel libidn-devel libnotify-devel ncurses-devel openssl-devel ### Building for the UNIX environment ### diff -Nru swirc-3.4.3/SECURITY.md swirc-3.4.4/SECURITY.md --- swirc-3.4.3/SECURITY.md 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/SECURITY.md 2023-07-29 13:02:03.000000000 +0000 @@ -4,6 +4,8 @@ | Version | Supported | | ------- | ------------------ | +| 3.4.4 | :heavy_check_mark: | +| 3.4.3 | :heavy_check_mark: | | 3.4.2 | :heavy_check_mark: | | < 3.4.2 | :x: | diff -Nru swirc-3.4.3/src/commands/connect.c swirc-3.4.4/src/commands/connect.c --- swirc-3.4.3/src/commands/connect.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/commands/connect.c 2023-07-29 13:02:03.000000000 +0000 @@ -643,7 +643,7 @@ set_ssl_off(); - if (strings_match(dcopy, "") || is_whiteSpace(dcopy)) { + if (strings_match(dcopy, "") || is_whitespace(dcopy)) { print_and_free("/connect: missing arguments", dcopy); return; } else if ((feeds_written = strFeed(dcopy, 1)) == 1) { diff -Nru swirc-3.4.3/src/commands/ignore.h swirc-3.4.4/src/commands/ignore.h --- swirc-3.4.3/src/commands/ignore.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/commands/ignore.h 2023-07-29 13:02:03.000000000 +0000 @@ -4,11 +4,11 @@ #define MAXIGNORES 101 __SWIRC_BEGIN_DECLS -void cmd_ignore(const char *) PTR_ARGS_NONNULL; -void cmd_unignore(const char *) PTR_ARGS_NONNULL; +void cmd_ignore(const char *) NONNULL; +void cmd_unignore(const char *) NONNULL; bool is_in_ignore_list(const char *, const char *, const char *); -bool is_valid_regex(const char *, char **) PTR_ARGS_NONNULL; +bool is_valid_regex(const char *, char **) NONNULL; __SWIRC_END_DECLS #endif diff -Nru swirc-3.4.3/src/commands/sasl.cpp swirc-3.4.4/src/commands/sasl.cpp --- swirc-3.4.3/src/commands/sasl.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/commands/sasl.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -30,6 +30,15 @@ #include "base64.h" #include "common.h" +/* + * Certain low-level functions from the OpenSSL toolkit that we use in + * this file have been flagged deprecated in OpenSSL 3.0. They aren't + * deprecated in LibreSSL. Some redesign of this file is certainly + * needed in order to use the new API. But I haven't investigated it + * closer yet nor if it's possible to accomplish the same effect using + * the new higher level API. Suppress for now... + */ +#define OPENSSL_API_COMPAT 10101 #include #include diff -Nru swirc-3.4.3/src/commands/sasl-scram-sha.cpp swirc-3.4.4/src/commands/sasl-scram-sha.cpp --- swirc-3.4.3/src/commands/sasl-scram-sha.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/commands/sasl-scram-sha.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -80,7 +80,7 @@ volatile bool g_sasl_scram_sha_got_first_msg = false; -static char *complete_nonce = NULL; +static STRING complete_nonce = NULL; static char nonce[64] = { '\0' }; static unsigned char signature_expected[EVP_MAX_MD_SIZE] = { '\0' }; @@ -90,7 +90,7 @@ /*lint -sem(get_salted_password, r_null) */ static void -generate_and_store_nonce() +generate_and_store_nonce(void) { static const char legal_index[] = "!\"#$%&'()*+-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" @@ -111,11 +111,11 @@ #endif nonce[ARRAY_SIZE(nonce) - 1] = '\0'; - debug("generate_and_store_nonce: nonce: %s", nonce); + debug("%s: nonce: %s", __func__, nonce); } -static const char * -get_encoded_msg(const char *source) +static CSTRING +get_encoded_msg(CSTRING source) { static char encoded_msg[4096] = { '\0' }; @@ -129,9 +129,9 @@ int sasl_scram_sha_send_client_first_msg(void) { - char *msg; - const char *encoded_msg; - const char *username = Config("sasl_username"); + CSTRING encoded_msg; + CSTRING username = Config("sasl_username"); + STRING msg; if (!is_valid_username(username)) return -1; @@ -151,9 +151,9 @@ /* C: c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0, p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ= */ int -sasl_scram_sha_send_client_final_msg(const char *proof) +sasl_scram_sha_send_client_final_msg(CSTRING proof) { - char *cli_final_msg; + STRING cli_final_msg; size_t size; std::string str("c=biws,r="); @@ -172,15 +172,15 @@ return -1; } - debug("sasl_scram_sha_send_client_final_msg: C: %s", cli_final_msg); + debug("%s: C: %s", __func__, cli_final_msg); delete[] cli_final_msg; return 0; } -static char * -get_decoded_msg(const char *source, int *outlen) noexcept +static STRING +get_decoded_msg(CSTRING source, int *outlen) noexcept { - char *decoded_msg = NULL; + STRING decoded_msg = NULL; int length_needed = b64_decode(source, NULL, 0); if (length_needed < 0) @@ -204,24 +204,27 @@ /* S: r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0, s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096 */ static int -get_sfm_components(const char *msg, unsigned char **salt, int *saltlen, +get_sfm_components(CSTRING msg, unsigned char **salt, int *saltlen, int *iter) { + STRING decoded_msg = NULL; bool ok = false; - char *decoded_msg = NULL; *salt = NULL; *saltlen = 0; *iter = PKCS5_DEFAULT_ITER; try { + char *cp, *b64salt; + size_t n; + if ((decoded_msg = get_decoded_msg(msg, NULL)) == NULL) { throw std::runtime_error("unable to get decoded " "message"); } - debug("get_sfm_components: S: %s", decoded_msg); - char *cp = decoded_msg; + debug("%s: S: %s", __func__, decoded_msg); + cp = decoded_msg; if (strncmp(cp, "r=", 2) != STRINGS_MATCH) throw std::runtime_error("expected nonce"); @@ -231,7 +234,7 @@ if (strncmp(cp, nonce, strlen(nonce)) != STRINGS_MATCH) throw std::runtime_error("nonce mismatch"); - size_t n = strcspn(cp, ","); + n = strcspn(cp, ","); cp[n] = '\0'; free(complete_nonce); complete_nonce = sw_strdup(cp); @@ -243,11 +246,10 @@ cp += 3; n = strcspn(cp, ","); cp[n] = '\0'; - char *b64salt = sw_strdup(cp); + b64salt = sw_strdup(cp); cp[n] = ','; - *salt = - reinterpret_cast(get_decoded_msg(b64salt, - saltlen)); + *salt = reinterpret_cast + (get_decoded_msg(b64salt, saltlen)); free(b64salt); if (*salt == NULL) @@ -267,7 +269,7 @@ *salt = NULL; *saltlen = 0; *iter = PKCS5_DEFAULT_ITER; - err_log(0, "get_sfm_components: %s", e.what()); + err_log(0, "%s: %s", __func__, e.what()); } if (decoded_msg) @@ -285,7 +287,7 @@ unsigned char *out = NULL; try { - const char *pass; + CSTRING pass; if (*outsize = EVP_MD_size(EVP_sha256()), *outsize < 0) { throw std::runtime_error("message digest size " @@ -305,10 +307,10 @@ } catch (const std::runtime_error &e) { *outsize = 0; delete[] out; - err_log(0, "get_salted_password: %s", e.what()); + err_log(0, "%s: %s", __func__, e.what()); return NULL; } catch (const std::bad_alloc &e) { - err_exit(ENOMEM, "get_salted_password: %s", e.what()); + err_exit(ENOMEM, "%s: %s", __func__, e.what()); /* NOTREACHED */ } catch (...) { sw_assert_not_reached(); @@ -326,10 +328,10 @@ return 0; } -static char * +static STRING get_client_first_msg_bare() noexcept { - char *msg_bare; + STRING msg_bare; size_t size; std::string str("n="); @@ -344,10 +346,10 @@ return msg_bare; } -static char * +static STRING get_client_final_msg_wo_proof() noexcept { - char *msg_wo_proof; + STRING msg_wo_proof; size_t size; std::string str("c=biws,r="); @@ -367,10 +369,10 @@ * client-final-message-without-proof */ static unsigned char * -get_auth_msg(const char *b64msg, size_t *auth_msg_len) +get_auth_msg(CSTRING b64msg, size_t *auth_msg_len) { - char *msg_bare, *msg_wo_proof, *serv_first_msg; - char *out; + STRING msg_bare, msg_wo_proof, serv_first_msg; + STRING out; msg_bare = get_client_first_msg_bare(); msg_wo_proof = get_client_final_msg_wo_proof(); @@ -387,7 +389,7 @@ } int -sasl_scram_sha_handle_serv_first_msg(const char *msg) +sasl_scram_sha_handle_serv_first_msg(CSTRING msg) { char proof[EVP_MAX_MD_SIZE] = { '\0' }; int iter = PKCS5_DEFAULT_ITER; @@ -474,10 +476,10 @@ * S: v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4= */ int -sasl_scram_sha_handle_serv_final_msg(const char *msg) +sasl_scram_sha_handle_serv_final_msg(CSTRING msg) { + STRING decoded_msg = NULL; bool signature_ok = false; - char *decoded_msg = NULL; try { char *cp; @@ -490,8 +492,7 @@ throw std::runtime_error("expected server signature"); } - debug("sasl_scram_sha_handle_serv_final_msg: S: %s", - decoded_msg); + debug("%s: S: %s", __func__, decoded_msg); cp = decoded_msg; cp += 2; @@ -509,8 +510,7 @@ delete[] signature; } catch (const std::runtime_error &e) { delete[] decoded_msg; - err_log(0, "sasl_scram_sha_handle_serv_final_msg: %s", - e.what()); + err_log(0, "%s: %s", __func__, e.what()); return -1; } diff -Nru swirc-3.4.3/src/commands/sasl-scram-sha.h swirc-3.4.4/src/commands/sasl-scram-sha.h --- swirc-3.4.3/src/commands/sasl-scram-sha.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/commands/sasl-scram-sha.h 2023-07-29 13:02:03.000000000 +0000 @@ -5,10 +5,10 @@ extern volatile bool g_sasl_scram_sha_got_first_msg; int sasl_scram_sha_send_client_first_msg(void); -int sasl_scram_sha_send_client_final_msg(const char *proof); +int sasl_scram_sha_send_client_final_msg(CSTRING proof); -int sasl_scram_sha_handle_serv_first_msg(const char *); -int sasl_scram_sha_handle_serv_final_msg(const char *); +int sasl_scram_sha_handle_serv_first_msg(CSTRING); +int sasl_scram_sha_handle_serv_final_msg(CSTRING); __SWIRC_END_DECLS #endif diff -Nru swirc-3.4.3/src/commands/servlist.h swirc-3.4.4/src/commands/servlist.h --- swirc-3.4.3/src/commands/servlist.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/commands/servlist.h 2023-07-29 13:02:03.000000000 +0000 @@ -2,7 +2,7 @@ #define CMD_SERVLIST_H __SWIRC_BEGIN_DECLS -void cmd_servlist(const char *) PTR_ARGS_NONNULL; +void cmd_servlist(const char *) NONNULL; __SWIRC_END_DECLS #endif diff -Nru swirc-3.4.3/src/commands/squery.h swirc-3.4.4/src/commands/squery.h --- swirc-3.4.3/src/commands/squery.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/commands/squery.h 2023-07-29 13:02:03.000000000 +0000 @@ -2,7 +2,7 @@ #define CMD_SQUERY_H __SWIRC_BEGIN_DECLS -void cmd_squery(const char *) PTR_ARGS_NONNULL; +void cmd_squery(const char *) NONNULL; __SWIRC_END_DECLS #endif diff -Nru swirc-3.4.3/src/commands/theme.c swirc-3.4.4/src/commands/theme.c --- swirc-3.4.3/src/commands/theme.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/commands/theme.c 2023-07-29 13:02:03.000000000 +0000 @@ -63,18 +63,20 @@ "install bx", "install nano", "install superkod", + "install weechat", "list-remote", "set ", "set bx", "set nano", "set superkod", + "set weechat", }; static THEME_INFO theme_info_array[MAX_NO_THEMES]; -static void free_theme_info(PTHEME_INFO) PTR_ARGS_NONNULL; -static void install_theme(const char *) PTR_ARGS_NONNULL; -static void set_theme(const char *) PTR_ARGS_NONNULL; +static void free_theme_info(PTHEME_INFO) NONNULL; +static void install_theme(const char *) NONNULL; +static void set_theme(const char *) NONNULL; static bool is_instruction_ok(const char *instruction) @@ -491,12 +493,13 @@ } if (strings_match(instruction, "install")) { - if (theme_is_in_db(name)) + if (isValid(name) && theme_is_in_db(name)) install_theme(name); } else if (strings_match(instruction, "list-remote")) { list_remote(); } else if (strings_match(instruction, "set")) { - if (strings_match(name, "default") || theme_is_in_db(name)) + if (isValid(name) && (strings_match(name, "default") || + theme_is_in_db(name))) set_theme(name); } else { sw_assert_not_reached(); diff -Nru swirc-3.4.3/src/config.cpp swirc-3.4.4/src/config.cpp --- swirc-3.4.3/src/config.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/config.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -211,7 +211,7 @@ hash_table[hashval] = item; } -static void hUndef(PCONF_HTBL_ENTRY) PTR_ARGS_NONNULL; +static void hUndef(PCONF_HTBL_ENTRY) NONNULL; static void hUndef(PCONF_HTBL_ENTRY entry) diff -Nru swirc-3.4.3/src/crypt.cpp swirc-3.4.4/src/crypt.cpp --- swirc-3.4.3/src/crypt.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/crypt.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ /* crypt.cpp - Copyright (C) 2022 Markus Uhlin. All rights reserved. + Copyright (C) 2022, 2023 Markus Uhlin. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -109,8 +109,7 @@ if (crypt_get_key_and_iv(password, &crypt_ctx) == -1) { throw std::runtime_error("unable to get key/iv"); } else if ((cipher_ctx = EVP_CIPHER_CTX_new()) == NULL) { - err_exit(ENOMEM, "crypt_decrypt_str: " - "EVP_CIPHER_CTX_new"); + err_exit(ENOMEM, "%s: EVP_CIPHER_CTX_new", __func__); } else if (!EVP_DecryptInit_ex(cipher_ctx, get_encrypt_alg(), NULL, addrof(crypt_ctx.key[0]), addrof(crypt_ctx.iv[0]))) { throw std::runtime_error("evp decrypt initialization " @@ -131,8 +130,8 @@ } decdat_len += rem_bytes; - debug("crypt_decrypt_str: decdat_len: %d", decdat_len); - debug("crypt_decrypt_str: decdat_size: %d", decdat_size); + debug("%s: decdat_len: %d", __func__, decdat_len); + debug("%s: decdat_size: %d", __func__, decdat_size); EVP_CIPHER_CTX_free(cipher_ctx); cipher_ctx = NULL; @@ -143,10 +142,10 @@ memcpy(out_str, decdat, static_cast(decdat_len)); } catch (const std::runtime_error &e) { error = true; - err_log(0, "crypt_decrypt_str: %s", e.what()); + err_log(0, "%s: %s", __func__, e.what()); } catch (...) { error = true; - err_log(0, "crypt_decrypt_str: %s", "unknown exception!"); + err_log(0, "%s: %s", __func__, "unknown exception!"); } clean_up(cipher_ctx, &crypt_ctx, decdat, static_cast @@ -193,8 +192,7 @@ } else if (crypt_get_key_and_iv(password, &crypt_ctx) == -1) { throw std::runtime_error("unable to get key/iv"); } else if ((cipher_ctx = EVP_CIPHER_CTX_new()) == NULL) { - err_exit(ENOMEM, "crypt_encrypt_str: " - "EVP_CIPHER_CTX_new"); + err_exit(ENOMEM, "%s: EVP_CIPHER_CTX_new", __func__); } else if (!EVP_EncryptInit_ex(cipher_ctx, get_encrypt_alg(), NULL, addrof(crypt_ctx.key[0]), addrof(crypt_ctx.iv[0]))) { throw std::runtime_error("evp encrypt initialization " @@ -215,8 +213,8 @@ } encdat_len += rem_bytes; - debug("crypt_encrypt_str: encdat_len: %d", encdat_len); - debug("crypt_encrypt_str: encdat_size: %d", encdat_size); + debug("%s: encdat_len: %d", __func__, encdat_len); + debug("%s: encdat_size: %d", __func__, encdat_size); EVP_CIPHER_CTX_free(cipher_ctx); cipher_ctx = NULL; @@ -231,10 +229,10 @@ throw std::runtime_error("base64 error"); } catch (const std::runtime_error &e) { error = true; - err_log(0, "crypt_encrypt_str: %s", e.what()); + err_log(0, "%s: %s", __func__, e.what()); } catch (...) { error = true; - err_log(0, "crypt_encrypt_str: %s", "unknown exception!"); + err_log(0, "%s: %s", __func__, "unknown exception!"); } clean_up(cipher_ctx, &crypt_ctx, encdat, static_cast diff -Nru swirc-3.4.3/src/dataClassify.c swirc-3.4.4/src/dataClassify.c --- swirc-3.4.3/src/dataClassify.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/dataClassify.c 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ /* Data classification utilities - Copyright (C) 2012-2022 Markus Uhlin. All rights reserved. + Copyright (C) 2012-2023 Markus Uhlin. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -34,10 +34,10 @@ #include "dataClassify.h" #include "strHand.h" +static const size_t hostname_len_max = 255; static const size_t nickname_len_max = 45; -static const size_t username_len_max = 100; static const size_t real_name_len_max = 60; -static const size_t hostname_len_max = 255; +static const size_t username_len_max = 100; bool is_alphabetic(const char *string) @@ -53,28 +53,89 @@ return true; } +/* + * Chinese, Japanese and Korean + */ bool -is_numeric(const char *string) +is_cjk(const wchar_t wc) { - if (string == NULL || *string == '\0') + static const RANGE array[] = { + { 0x2E80, 0x2EFF, "CJK Radicals Supplement" }, + { 0x2F00, 0x2FDF, "Kangxi Radicals" }, + { 0x3000, 0x303F, "CJK Symbols and Punctuation" }, + { 0x30A0, 0x30FF, "Katakana" }, + { 0x3100, 0x312F, "Bopomofo" }, + { 0x31A0, 0x31BF, "Bopomofo Extended" }, + { 0x31C0, 0x31EF, "CJK Strokes" }, + { 0x31F0, 0x31FF, "Katakana Phonetic Extensions" }, + { 0x3200, 0x32FF, "Enclosed CJK Letters and Months" }, + { 0x3300, 0x33FF, "CJK Compatibility" }, + { 0x3400, 0x4DBF, "CJK Unified Ideographs Extension A" }, + { 0x4E00, 0x9FFF, "CJK Unified Ideographs" }, + { 0xA000, 0xA48F, "Yi Syllables" }, + { 0xA490, 0xA4CF, "Yi Radicals" }, + { 0xF900, 0xFAFF, "CJK Compatibility Ideographs" }, + { 0xFE30, 0xFE4F, "CJK Compatibility Forms" }, + + { 0x20000, 0x2A6DF, "CJK Unified Ideographs Extension B" }, + { 0x2A700, 0x2B739, "CJK Unified Ideographs Extension C" }, + { 0x2B740, 0x2B81D, "CJK Unified Ideographs Extension D" }, + { 0x2B820, 0x2CEA1, "CJK Unified Ideographs Extension E" }, + { 0x2F800, 0x2FA1F, "CJK Compatibility Ideographs Supplement" }, + }; + static const size_t mid = ARRAY_SIZE(array) / 2; + + if (wc < array[0].start) return false; - for (const char *p = &string[0]; *p != '\0'; p++) { - if (!sw_isdigit(*p)) - return false; + for (const RANGE *rp = &array[wc < array[mid].start ? 0 : mid]; + rp < &array[ARRAY_SIZE(array)]; + rp++) { + if (wc >= rp->start && wc <= rp->stop) + return true; } - return true; + return false; } bool -is_whiteSpace(const char *string) +is_combined(const wchar_t wc) +{ + static const RANGE array[] = { + { 0x0300, 0x036F, "Combining Diacritical Marks" }, + { 0x1AB0, 0x1AFF, "Combining Diacritical Marks Extended" }, // stop 0x1ACE? + { 0x1DC0, 0x1DFF, "Combining Diacritical Marks Supplement" }, + { 0x20D0, 0x20FF, "Combining Diacritical Marks for Symbols" }, // stop 0x20F0? + { 0xFE20, 0xFE2F, "Combining Half Marks" }, + }; + + for (const RANGE *rp = &array[0]; + rp < &array[ARRAY_SIZE(array)]; + rp++) { + if (wc >= rp->start && wc <= rp->stop) + return true; + } + + return false; +} + +bool +is_irc_channel(const char *name) +{ + if (name == NULL || *name == '\0') + return false; + + return (*name == '&' || *name == '#' || *name == '+' || *name == '!'); +} + +bool +is_numeric(const char *string) { if (string == NULL || *string == '\0') return false; for (const char *p = &string[0]; *p != '\0'; p++) { - if (!sw_isspace(*p)) + if (!sw_isdigit(*p)) return false; } @@ -82,12 +143,21 @@ } bool -is_irc_channel(const char *name) +is_valid_hostname(const char *hostname) { - if (name == NULL || *name == '\0') + static const char host_chars[] = + "abcdefghijklmnopqrstuvwxyz.0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ:"; + + if (hostname == NULL || *hostname == '\0' || + xstrnlen(hostname, hostname_len_max + 1) > hostname_len_max) return false; - return (*name == '&' || *name == '#' || *name == '+' || *name == '!'); + for (const char *ccp = &hostname[0]; *ccp != '\0'; ccp++) { + if (strchr(host_chars, *ccp) == NULL) + return false; + } + + return true; } bool @@ -110,6 +180,21 @@ } bool +is_valid_real_name(const char *real_name) +{ + if (real_name == NULL || *real_name == '\0' || + xstrnlen(real_name, real_name_len_max + 1) > real_name_len_max) + return false; + + for (const char *ccp = &real_name[0]; *ccp != '\0'; ccp++) { + if (!sw_isprint(*ccp)) + return false; + } + + return true; +} + +bool is_valid_username(const char *username) { static const char legal_index[] = @@ -129,34 +214,61 @@ } bool -is_valid_real_name(const char *real_name) +is_whitespace(const char *string) { - if (real_name == NULL || *real_name == '\0' || - xstrnlen(real_name, real_name_len_max + 1) > real_name_len_max) + if (string == NULL || *string == '\0') return false; - for (const char *ccp = &real_name[0]; *ccp != '\0'; ccp++) { - if (!sw_isprint(*ccp)) + for (const char *p = &string[0]; *p != '\0'; p++) { + if (!sw_isspace(*p)) return false; } return true; } -bool -is_valid_hostname(const char *hostname) +/* + * Determines the number of column positions required to display a + * wide character. + * + * Specifically written to be used in the printtext and readline + * modules. + * + * Test the 'wc' using iswprint() initially. (This is done elsewhere + * so we don't want to do it twice...) + */ +int +xwcwidth(const wchar_t wc, const int fwlen) { - static const char host_chars[] = - "abcdefghijklmnopqrstuvwxyz.0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ:"; + static const RANGE fullwidth[] = { + { 0xFF01, 0xFF5E, "Fullwidth ASCII variants" }, + { 0xFF5F, 0xFF60, "Fullwidth brackets" }, + { 0xFFE0, 0xFFE6, "Fullwidth symbol variants" }, + { 0x1F600, 0x1F64F, "Emoticons" }, + }; + + if (wc >= 0x20 && wc <= 0xFF) + return 1; + else if (wc < 0x20 || is_combined(wc)) + return 0; + for (const RANGE *rp = &fullwidth[0]; + rp < &fullwidth[ARRAY_SIZE(fullwidth)]; + rp++) { + if (wc >= rp->start && wc <= rp->stop) + return fwlen; + } + return (is_cjk(wc) ? fwlen : 1); +} - if (hostname == NULL || *hostname == '\0' || - xstrnlen(hostname, hostname_len_max + 1) > hostname_len_max) - return false; +int +xwcswidth(const wchar_t *str, const int fwlen) +{ + const wchar_t *ptr = str; + int width = 0; - for (const char *ccp = &hostname[0]; *ccp != '\0'; ccp++) { - if (strchr(host_chars, *ccp) == NULL) - return false; + while (*ptr) { + width += xwcwidth(*ptr, fwlen); + ptr++; } - - return true; + return width; } diff -Nru swirc-3.4.3/src/dataClassify.h swirc-3.4.4/src/dataClassify.h --- swirc-3.4.3/src/dataClassify.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/dataClassify.h 2023-07-29 13:02:03.000000000 +0000 @@ -1,15 +1,26 @@ #ifndef DATA_CLASSIFY_H #define DATA_CLASSIFY_H +typedef struct tagRANGE { + wchar_t start; + wchar_t stop; + CSTRING comment; +} RANGE, *PRANGE; + __SWIRC_BEGIN_DECLS bool is_alphabetic(const char *); -bool is_numeric(const char *); -bool is_whiteSpace(const char *); +bool is_cjk(const wchar_t); +bool is_combined(const wchar_t); bool is_irc_channel(const char *); +bool is_numeric(const char *); +bool is_valid_hostname(const char *); bool is_valid_nickname(const char *); -bool is_valid_username(const char *); bool is_valid_real_name(const char *); -bool is_valid_hostname(const char *); +bool is_valid_username(const char *); +bool is_whitespace(const char *); + +int xwcwidth(const wchar_t, const int); +int xwcswidth(const wchar_t *, const int) NONNULL; __SWIRC_END_DECLS /* Inline function definitions @@ -31,6 +42,21 @@ return (*data == '\0'); } +#ifndef _lint +static SW_INLINE bool +isValid(const void *ptr) +{ +#if defined(HAVE_ETEXT_SEGMENT) + extern char etext; + return (ptr != NULL && ((const char *) ptr) > &etext); +#else + return (ptr != NULL); +#endif +} +#else +#define isValid(_ptr) ((_ptr) != NULL) +#endif + #include #include #include /* EOF */ diff -Nru swirc-3.4.3/src/events/channel.cpp swirc-3.4.4/src/events/channel.cpp --- swirc-3.4.3/src/events/channel.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/events/channel.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -355,7 +355,7 @@ } static void maintain_channel_stats(const char *, const char *) - PTR_ARGS_NONNULL; + NONNULL; /* * Example input: +vvv nick1 nick2 nick3 @@ -507,6 +507,10 @@ COLOR2, nick, NORMAL); maintain_channel_stats(channel, next_token_copy); + } else if (strings_match_ignore_case(nick, "NickServ") && + strings_match_ignore_case(channel, g_my_nickname)) { + if (net_send("MODE %s", g_my_nickname) < 0) + throw std::runtime_error("cannot send"); } else { throw std::runtime_error("unhandled else branch"); } diff -Nru swirc-3.4.3/src/events/names.cpp swirc-3.4.4/src/events/names.cpp --- swirc-3.4.3/src/events/names.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/events/names.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -54,8 +54,8 @@ ****************************************************************/ struct hInstall_context { - char *channel; - char *nick; + STRING channel; + STRING nick; bool is_owner; bool is_superop; @@ -75,7 +75,7 @@ /* null */; } - hInstall_context(char *p_channel, char *p_nick, const char c) + hInstall_context(STRING p_channel, STRING p_nick, const char c) : channel(p_channel) , nick(p_nick) , is_owner(c == '~') @@ -103,7 +103,7 @@ ****************************************************************/ static void -add_match(PTEXTBUF matches, const char *user) +add_match(PTEXTBUF matches, CSTRING user) { static chararray_t msg = "get_list_of_matching_channel_users: " "textBuf_ins_next"; @@ -119,7 +119,7 @@ } static inline bool -already_is_in_names_hash(const char *nick, PIRC_WINDOW window) +already_is_in_names_hash(CSTRING nick, PIRC_WINDOW window) { for (PNAMES names = window->names_hash[hash(nick)]; names != NULL; @@ -131,6 +131,35 @@ return false; } +/* + * Non-strict checking. + * But we cannot allow: + * ~&@%+ + */ +static inline bool +name_chars_ok(CSTRING name) +{ + static chararray_t chars = + "!#$'()*,-./0123456789:;<=>?" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" + "abcdefghijklmnopqrstuvwxyz{|}"; + + for (const char *cp = name; *cp != '\0'; cp++) { + if (strchr(chars, *cp) == NULL) + return false; + } + + return true; +} + +static inline bool +name_len_ok(CSTRING name) +{ + static const size_t maxlen = 45; + + return (xstrnlen(name, maxlen + 1) <= maxlen); +} + static int hInstall(const struct hInstall_context *ctx) { @@ -141,16 +170,22 @@ if (ctx == NULL || ctx->channel == NULL) { return ERR; } else if ((window = window_by_label(ctx->channel)) == NULL) { - debug("events/names.cpp: hInstall: cannot find window " - "labelled \"%s\"", ctx->channel); + debug("%s: %s: cannot find window labelled \"%s\"", __FILE__, + __func__, ctx->channel); return ERR; } else if (ctx->nick == NULL || strings_match(ctx->nick, "")) { - debug("events/names.cpp: hInstall: no nickname (channel=%s)", + debug("%s: %s: no nickname (channel=%s)", __FILE__, __func__, ctx->channel); return ERR; + } else if (!name_len_ok(ctx->nick)) { + debug("%s: %s: name too long!", __FILE__, __func__); + return ERR; + } else if (!name_chars_ok(ctx->nick)) { + debug("%s: %s: name is invalid", __FILE__, __func__); + return ERR; } else if (already_is_in_names_hash(ctx->nick, window)) { - debug("events/names.cpp: hInstall: busy nickname: " - "\"%s\" (channel=%s)", ctx->nick, ctx->channel); + debug("%s: %s: busy nickname: \"%s\" (channel=%s)", __FILE__, + __func__, ctx->nick, ctx->channel); return ERR; } @@ -216,19 +251,19 @@ free(entry); } -static char * +static STRING get_bold_int(const int i) { return strdup_printf("%c%d%c", BOLD, i, BOLD); } static void -output_statistics(PRINTTEXT_CONTEXT ctx, const char *channel, +output_statistics(PRINTTEXT_CONTEXT ctx, CSTRING channel, const IRC_WINDOW *window) { - char *str; - char *num_total; - char *num_ops, *num_halfops, *num_voices, *num_normal; + STRING str; + STRING num_total; + STRING num_ops, num_halfops, num_voices, num_normal; str = strdup_printf("%s%s%s%c%s", LEFT_BRKT, COLOR1, channel, NORMAL, RIGHT_BRKT); @@ -278,7 +313,7 @@ * usage: /stats [channel] */ void -cmd_stats(const char *data) +cmd_stats(CSTRING data) { PIRC_WINDOW win; PRINTTEXT_CONTEXT ptext_ctx; @@ -308,7 +343,7 @@ } PTEXTBUF -get_list_of_matching_channel_users(const char *chan, const char *search_var) +get_list_of_matching_channel_users(CSTRING chan, CSTRING search_var) { PIRC_WINDOW window; PTEXTBUF matches; @@ -355,7 +390,7 @@ } PNAMES -event_names_htbl_lookup(const char *nick, const char *channel) +event_names_htbl_lookup(CSTRING nick, CSTRING channel) { PIRC_WINDOW window; PNAMES names; @@ -375,15 +410,15 @@ } int -event_names_htbl_insert(const char *nick, const char *channel) +event_names_htbl_insert(CSTRING nick, CSTRING channel) { if (nick == NULL || strings_match(nick, "")) return ERR; struct hInstall_context ctx; /* calls constructor */ - ctx.channel = const_cast(channel); - ctx.nick = const_cast(nick); + ctx.channel = const_cast(channel); + ctx.nick = const_cast(nick); if (hInstall(&ctx) == ERR) return ERR; @@ -393,7 +428,7 @@ } int -event_names_htbl_remove(const char *nick, const char *channel) +event_names_htbl_remove(CSTRING nick, CSTRING channel) { PIRC_WINDOW window; PNAMES names; @@ -431,8 +466,8 @@ try { PIRC_WINDOW win = NULL; - char *channel, *eof_msg; - char *state = const_cast(""); + STRING channel, eof_msg; + STRING state = const_cast(""); if (strFeed(compo->params, 2) != 2) throw std::runtime_error("strFeed"); @@ -507,13 +542,13 @@ void event_names(struct irc_message_compo *compo) { - char *names_copy = NULL; + STRING names_copy = NULL; try { PIRC_WINDOW win = NULL; - char *chan_type, *channel, *names; - char *state1 = const_cast(""); - char *state2 = const_cast(""); + STRING chan_type, channel, names; + STRING state1 = const_cast(""); + STRING state2 = const_cast(""); if (strFeed(compo->params, 3) != 3) throw std::runtime_error("strFeed"); @@ -554,7 +589,7 @@ } for (char *cp = &names_copy[0];; cp = NULL) { - char *token, *nick; + STRING token, nick; if ((token = strtok_r(cp, " ", &state2)) == NULL) break; diff -Nru swirc-3.4.3/src/events/names.h swirc-3.4.4/src/events/names.h --- swirc-3.4.3/src/events/names.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/events/names.h 2023-07-29 13:02:03.000000000 +0000 @@ -8,18 +8,18 @@ /*lint -sem(get_list_of_matching_channel_users, r_null) */ -void cmd_stats(const char *); -PTEXTBUF get_list_of_matching_channel_users(const char *chan, - const char *search_var); +void cmd_stats(CSTRING); +PTEXTBUF get_list_of_matching_channel_users(CSTRING chan, + CSTRING search_var); void event_names_init(void); void event_names_deinit(void); /*lint -sem(event_names_htbl_lookup, r_null) */ -PNAMES event_names_htbl_lookup(const char *nick, const char *channel); -int event_names_htbl_insert(const char *nick, const char *channel); -int event_names_htbl_remove(const char *nick, const char *channel); +PNAMES event_names_htbl_lookup(CSTRING nick, CSTRING channel); +int event_names_htbl_insert(CSTRING nick, CSTRING channel); +int event_names_htbl_remove(CSTRING nick, CSTRING channel); void event_eof_names(struct irc_message_compo *); void event_names(struct irc_message_compo *); void event_names_htbl_remove_all(PIRC_WINDOW); diff -Nru swirc-3.4.3/src/events/names-htbl-modify.cpp swirc-3.4.4/src/events/names-htbl-modify.cpp --- swirc-3.4.3/src/events/names-htbl-modify.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/events/names-htbl-modify.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ /* names-htbl-modify.cpp - Copyright (C) 2022 Markus Uhlin. All rights reserved. + Copyright (C) 2022-2023 Markus Uhlin. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -30,6 +30,7 @@ #include "common.h" #include "../libUtils.h" +#include "../main.h" #include "../nicklist.h" #include "../strHand.h" #include "../window.h" @@ -43,7 +44,7 @@ { if (nick == NULL || strings_match(nick, "") || (window = window_by_label(channel)) == NULL || - !window->received_names) /* XXX */ + (!window->received_names && !g_icb_mode)) /* XXX */ return ERR; return OK; } diff -Nru swirc-3.4.3/src/events/privmsg.cpp swirc-3.4.4/src/events/privmsg.cpp --- swirc-3.4.3/src/events/privmsg.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/events/privmsg.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -63,8 +63,8 @@ #include "swircpaths.h" #endif -static bool shouldHighlightMessage_case1(const char *) PTR_ARGS_NONNULL; -static bool shouldHighlightMessage_case2(const char *) PTR_ARGS_NONNULL; +static bool shouldHighlightMessage_case1(const char *) NONNULL; +static bool shouldHighlightMessage_case2(const char *) NONNULL; static void acknowledge_ctcp_request(const char *cmd, const struct special_msg_context *ctx) @@ -217,7 +217,7 @@ get_message(const wchar_t *s1, const wchar_t *s2, const wchar_t *s3, const wchar_t *s4, const wchar_t *s5) { - static wchar_t message[1001] = { '\0' }; + static wchar_t message[1001] = { L'\0' }; (void) wmemset(message, 0L, ARRAY_SIZE(message)); diff -Nru swirc-3.4.3/src/events/servlist.h swirc-3.4.4/src/events/servlist.h --- swirc-3.4.3/src/events/servlist.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/events/servlist.h 2023-07-29 13:02:03.000000000 +0000 @@ -2,8 +2,8 @@ #define SWIRC_EVENT_SERVLIST_H __SWIRC_BEGIN_DECLS -void event_servlist(struct irc_message_compo *) PTR_ARGS_NONNULL; -void event_servlistEnd(struct irc_message_compo *) PTR_ARGS_NONNULL; +void event_servlist(struct irc_message_compo *) NONNULL; +void event_servlistEnd(struct irc_message_compo *) NONNULL; __SWIRC_END_DECLS #endif diff -Nru swirc-3.4.3/src/events/wallops.h swirc-3.4.4/src/events/wallops.h --- swirc-3.4.3/src/events/wallops.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/events/wallops.h 2023-07-29 13:02:03.000000000 +0000 @@ -2,7 +2,7 @@ #define WALLOPS_H __SWIRC_BEGIN_DECLS -void event_wallops(struct irc_message_compo *) PTR_ARGS_NONNULL; +void event_wallops(struct irc_message_compo *) NONNULL; __SWIRC_END_DECLS #endif diff -Nru swirc-3.4.3/src/include/fallbackattrs.h swirc-3.4.4/src/include/fallbackattrs.h --- swirc-3.4.3/src/include/fallbackattrs.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/include/fallbackattrs.h 2023-07-29 13:02:03.000000000 +0000 @@ -1,10 +1,14 @@ #define DOES_NOT_WRITE_GLOBAL_DATA -#define NO_SIDE_EFFECT -#define PRINTFLIKE(arg_no) -#define PTR_ARGS_NONNULL -#define SW_INLINE inline +#define NONNULL + #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define NORETURN _Noreturn +#elif defined(__cplusplus) && __cplusplus >= 201103L +#define NORETURN [[noreturn]] #else #define NORETURN #endif + +#define NO_SIDE_EFFECT +#define PRINTFLIKE(arg_no) +#define SW_INLINE inline diff -Nru swirc-3.4.3/src/include/gnuattrs.h swirc-3.4.4/src/include/gnuattrs.h --- swirc-3.4.3/src/include/gnuattrs.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/include/gnuattrs.h 2023-07-29 13:02:03.000000000 +0000 @@ -1,6 +1,6 @@ #define DOES_NOT_WRITE_GLOBAL_DATA __attribute__((pure)) +#define NONNULL __attribute__((nonnull)) +#define NORETURN __attribute__((noreturn)) #define NO_SIDE_EFFECT __attribute__((const)) #define PRINTFLIKE(arg_no) __attribute__((format(printf, arg_no, arg_no + 1))) -#define PTR_ARGS_NONNULL __attribute__((nonnull)) #define SW_INLINE inline -#define NORETURN __attribute__((noreturn)) diff -Nru swirc-3.4.3/src/include/sunattrs.h swirc-3.4.4/src/include/sunattrs.h --- swirc-3.4.3/src/include/sunattrs.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/include/sunattrs.h 2023-07-29 13:02:03.000000000 +0000 @@ -45,7 +45,7 @@ */ #define NO_SIDE_EFFECT __attribute__((const)) +#define NONNULL +#define NORETURN __attribute__((noreturn)) #define PRINTFLIKE(arg_no) -#define PTR_ARGS_NONNULL #define SW_INLINE inline -#define NORETURN __attribute__((noreturn)) diff -Nru swirc-3.4.3/src/include/winattrs.h swirc-3.4.4/src/include/winattrs.h --- swirc-3.4.3/src/include/winattrs.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/include/winattrs.h 2023-07-29 13:02:03.000000000 +0000 @@ -1,6 +1,6 @@ #define DOES_NOT_WRITE_GLOBAL_DATA +#define NONNULL +#define NORETURN __declspec(noreturn) #define NO_SIDE_EFFECT #define PRINTFLIKE(arg_no) -#define PTR_ARGS_NONNULL #define SW_INLINE __inline -#define NORETURN __declspec(noreturn) diff -Nru swirc-3.4.3/src/io-loop.c swirc-3.4.4/src/io-loop.c --- swirc-3.4.3/src/io-loop.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/io-loop.c 2023-07-29 13:02:03.000000000 +0000 @@ -292,7 +292,7 @@ if ((bytes_convert = xmbstowcs(g_push_back_buf, element->text, size - 1)) == g_conversion_failed) (void) wmemset(g_push_back_buf, 0L, size); - else if (bytes_convert == (size - 1)) + else if (bytes_convert >= (size - 1)) g_push_back_buf[size - 1] = 0L; } @@ -310,7 +310,7 @@ if ((bytes_convert = xmbstowcs(g_push_back_buf, element->text, size - 1)) == g_conversion_failed) (void) wmemset(g_push_back_buf, 0L, size); - else if (bytes_convert == (size - 1)) + else if (bytes_convert >= (size - 1)) g_push_back_buf[size - 1] = 0L; if (element != textBuf_head(history)) element = element->prev; diff -Nru swirc-3.4.3/src/irc.c swirc-3.4.4/src/irc.c --- swirc-3.4.3/src/irc.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/irc.c 2023-07-29 13:02:03.000000000 +0000 @@ -274,6 +274,16 @@ SortMsgCompo(const char *); static void FreeMsgCompo(struct irc_message_compo *); +static int +cmp_fn(const void *vp1, const void *vp2) +{ + const struct numeric_events_tag *evt1, *evt2; + + evt1 = vp1; + evt2 = vp2; + return strcmp(evt1->numeric_event, evt2->numeric_event); +} + /** * Initialize irc module */ @@ -281,6 +291,7 @@ irc_init(void) { char *nickname; + static bool is_sorted = false; if (g_cmdline_opts->nickname) irc_set_my_nickname(g_cmdline_opts->nickname); @@ -292,6 +303,12 @@ else err_quit("%s: no nickname", __func__); event_names_init(); + + if (!is_sorted) { + qsort(numeric_events, ARRAY_SIZE(numeric_events), + sizeof numeric_events[0], cmp_fn); + is_sorted = true; + } } /** @@ -547,29 +564,33 @@ static int handle_numeric_event(struct irc_message_compo *compo) { - for (struct numeric_events_tag *sp = &numeric_events[0]; - sp < &numeric_events[ARRAY_SIZE(numeric_events)]; sp++) { - if (strings_match(sp->numeric_event, compo->command)) { - if (sp->event_handler != NULL) { - sp->event_handler(compo); + struct numeric_events_tag *evt, key; + + key.numeric_event = compo->command; + key.official_name = NULL; + key.window = NO_WINDOW; + key.ext_bits = 0; + key.event_handler = NULL; + + if ((evt = bsearch(&key, numeric_events, ARRAY_SIZE(numeric_events), + sizeof numeric_events[0], cmp_fn)) != NULL) { + if (evt->event_handler != NULL) { + evt->event_handler(compo); + } else { + if (evt->window == STATUS_WINDOW) { + irc_extract_msg(compo, g_status_window, + evt->ext_bits, + !strncmp(evt->official_name, "ERR_", 4)); + } else if (evt->window == ACTIVE_WINDOW) { + irc_extract_msg(compo, g_active_window, + evt->ext_bits, + !strncmp(evt->official_name, "ERR_", 4)); } else { - if (sp->window == STATUS_WINDOW) { - irc_extract_msg(compo, g_status_window, - sp->ext_bits, - !strncmp(sp->official_name, "ERR_", - 4)); - } else if (sp->window == ACTIVE_WINDOW) { - irc_extract_msg(compo, g_active_window, - sp->ext_bits, - !strncmp(sp->official_name, "ERR_", - 4)); - } else { - sw_assert_not_reached(); - } + sw_assert_not_reached(); } - - return 0; } + + return 0; } return -1; diff -Nru swirc-3.4.3/src/libUtils.h swirc-3.4.4/src/libUtils.h --- swirc-3.4.3/src/libUtils.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/libUtils.h 2023-07-29 13:02:03.000000000 +0000 @@ -21,7 +21,7 @@ bool bool_false(const char *str); bool bool_true(const char *str); bool getval_strtol(const char *str, const long int lo, const long int hi, - long int *val) PTR_ARGS_NONNULL; + long int *val) NONNULL; bool time_format_ok(const char *); char rot13_byte(char); char *rot13_str(char *); diff -Nru swirc-3.4.3/src/log.c swirc-3.4.4/src/log.c --- swirc-3.4.3/src/log.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/log.c 2023-07-29 13:02:03.000000000 +0000 @@ -46,8 +46,8 @@ const char g_log_filesuffix[] = ".txt"; -static const char *get_modified_server_host(const char *) PTR_ARGS_NONNULL; -static const char *get_logtype(const char *) PTR_ARGS_NONNULL; +static const char *get_modified_server_host(const char *) NONNULL; +static const char *get_logtype(const char *) NONNULL; static const char * get_date(void) diff -Nru swirc-3.4.3/src/main.cpp swirc-3.4.4/src/main.cpp --- swirc-3.4.3/src/main.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/main.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -54,6 +54,7 @@ #include "assertAPI.h" #include "curses-funcs.h" #include "cursesInit.h" +#include "dataClassify.h" #include "errHand.h" #include "i18n.h" #include "io-loop.h" @@ -84,7 +85,7 @@ /* Things with external linkage ============================ */ -chararray_t g_swircVersion = "v3.4.3"; +chararray_t g_swircVersion = "v3.4.4"; chararray_t g_swircYear = "2012-2023"; chararray_t g_swircAuthor = "Markus Uhlin"; chararray_t g_swircWebAddr = "https://www.nifty-networks.net/swirc/"; @@ -737,6 +738,12 @@ nestHome_deinit(); term_deinit(); + if (isValid(g_dev_null)) { + if (fclose(g_dev_null) != 0) + err_ret("fclose"); + else + g_dev_null = NULL; + } cmdline_options_destroy(); puts("- Exit Success! -"); return (EXIT_SUCCESS); @@ -801,12 +808,31 @@ void redir_stderr(void) { - g_stderr_fd = dup(fileno(stderr)); - (void) dup2(fileno(g_dev_null), fileno(stderr)); + const bool is_valid_fd = (g_stderr_fd != -1); + + if (is_valid_fd) + err_log(EBUSY, "%s: valid file descriptor", __func__); + else if (!isValid(g_dev_null)) + err_log(EFAULT, "%s: dev null not open", __func__); + else if ((g_stderr_fd = dup(fileno(stderr))) == -1) + err_sys("%s: dup() error", __func__); + else if (dup2(fileno(g_dev_null), fileno(stderr)) == -1) + err_sys("%s: dup2() error", __func__); + else + return; } void restore_stderr(void) { - (void) dup2(g_stderr_fd, fileno(stderr)); + const bool is_valid_fd = (g_stderr_fd != -1); + + if (!is_valid_fd) + err_log(EBADF, "%s", __func__); + else if (dup2(g_stderr_fd, fileno(stderr)) == -1) + err_sys("%s: dup2() error", __func__); + else if (close(g_stderr_fd) != 0) + err_log(errno, "%s: close() error", __func__); + else + g_stderr_fd = -1; } diff -Nru swirc-3.4.3/src/nestHome.c swirc-3.4.4/src/nestHome.c --- swirc-3.4.3/src/nestHome.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/nestHome.c 2023-07-29 13:02:03.000000000 +0000 @@ -73,7 +73,7 @@ char *g_log_dir = NULL; const char g_config_filesuffix[] = ".conf"; -const char g_theme_filesuffix[] = ".the"; +const char g_theme_filesuffix[] = ".thm"; char *g_config_file = NULL; char *g_theme_file = NULL; diff -Nru swirc-3.4.3/src/net-unix.c swirc-3.4.4/src/net-unix.c --- swirc-3.4.3/src/net-unix.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/net-unix.c 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ /* Networking for UNIX - Copyright (C) 2014-2021 Markus Uhlin. All rights reserved. + Copyright (C) 2014-2023 Markus Uhlin. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -90,7 +90,7 @@ if (g_socket == INVALID_SOCKET) return -1; else if (fmt == NULL) - err_exit(EINVAL, "net_send_plain"); + err_exit(EINVAL, "%s", __func__); else if (strings_match(fmt, "")) return 0; @@ -131,16 +131,16 @@ if ((errno = pthread_create(&thread, NULL, do_connect_wrapper, server)) != 0) - err_sys("net_do_connect_detached: pthread_create"); + err_sys("%s: pthread_create", __func__); else if ((errno = pthread_detach(thread)) != 0) - err_sys("net_do_connect_detached: pthread_detach"); + err_sys("%s: pthread_detach", __func__); } void net_listen_thread_join(void) { if ((errno = pthread_join(listen_thread_id, NULL)) != 0) - err_sys("net_listen_thread_join: pthread_join"); + err_sys("%s: pthread_join", __func__); } /*lint -sem(listen_thread_fn, r_null) */ @@ -167,9 +167,9 @@ { if ((errno = pthread_create(&listen_thread_id, NULL, listen_thread_fn, NULL)) != 0) - err_sys("net_spawn_listen_thread: pthread_create"); + err_sys("%s: pthread_create", __func__); else if ((errno = pthread_detach(listen_thread_id)) != 0) - err_sys("net_spawn_listen_thread: pthread_detach"); + err_sys("%s: pthread_detach", __func__); } /* ---------------------------------------------------------------------- */ @@ -185,7 +185,7 @@ errno = 0; if (setsockopt(g_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv) != 0) - err_log(errno, "net_set_recv_timeout: setsockopt"); + err_log(errno, "%s: setsockopt", __func__); } void @@ -199,5 +199,5 @@ errno = 0; if (setsockopt(g_socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv) != 0) - err_log(errno, "net_set_send_timeout: setsockopt"); + err_log(errno, "%s: setsockopt", __func__); } diff -Nru swirc-3.4.3/src/net-w32.c swirc-3.4.4/src/net-w32.c --- swirc-3.4.3/src/net-w32.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/net-w32.c 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ /* Networking for WIN32 - Copyright (C) 2014-2022 Markus Uhlin. All rights reserved. + Copyright (C) 2014-2023 Markus Uhlin. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -103,7 +103,7 @@ if (g_socket == INVALID_SOCKET) return -1; else if (fmt == NULL) - err_exit(EINVAL, "net_send_plain"); + err_exit(EINVAL, "%s", __func__); else if (strings_match(fmt, "")) return 0; @@ -142,7 +142,7 @@ errno = 0; if (_beginthread(do_connect_wrapper, 0, server) == g_beginthread_failed) - err_sys("net_do_connect_detached: _beginthread"); + err_sys("%s: _beginthread", __func__); } void @@ -174,7 +174,7 @@ { if ((listen_thread_id = _beginthread(listen_thread_fn, 0, NULL)) == g_beginthread_failed) - err_sys("net_spawn_listen_thread: _beginthread"); + err_sys("%s: _beginthread", __func__); } /* ---------------------------------------------------------------------- */ @@ -187,7 +187,7 @@ if (setsockopt(g_socket, SOL_SOCKET, SO_RCVTIMEO, ((char *) &timeout_milliseconds), optlen) != 0) - err_log(0, "net_set_recv_timeout: setsockopt"); + err_log(0, "%s: setsockopt", __func__); } void @@ -198,5 +198,5 @@ if (setsockopt(g_socket, SOL_SOCKET, SO_SNDTIMEO, ((char *) &timeout_milliseconds), optlen) != 0) - err_log(0, "net_set_send_timeout: setsockopt"); + err_log(0, "%s: setsockopt", __func__); } diff -Nru swirc-3.4.3/src/network.cpp swirc-3.4.4/src/network.cpp --- swirc-3.4.3/src/network.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/network.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -160,9 +160,9 @@ ****************************************************************/ static void send_icb_login_packet(const struct network_connect_context *) - PTR_ARGS_NONNULL; + NONNULL; static void send_reg_cmds(const struct network_connect_context *) - PTR_ARGS_NONNULL; + NONNULL; static void check_conn_fail() @@ -770,8 +770,8 @@ winsock_deinit(); #endif irc_deinit(); - free(recvbuf); - free(message_concat); + free_and_null(&recvbuf); + free_and_null(&message_concat); printtext(&ptext_ctx, "%s", _("Disconnected")); (void) atomic_swap_bool(&g_irc_listening, false); } diff -Nru swirc-3.4.3/src/network.h swirc-3.4.4/src/network.h --- swirc-3.4.3/src/network.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/network.h 2023-07-29 13:02:03.000000000 +0000 @@ -41,8 +41,8 @@ char *nickname; }; -typedef PTR_ARGS_NONNULL int (*NET_SEND_FN)(const char *, ...) PRINTFLIKE(1); -typedef PTR_ARGS_NONNULL int (*NET_RECV_FN)(struct network_recv_context *, char *, int); +typedef NONNULL int (*NET_SEND_FN)(const char *, ...) PRINTFLIKE(1); +typedef NONNULL int (*NET_RECV_FN)(struct network_recv_context *, char *, int); typedef enum { CONNECTION_ESTABLISHED, diff -Nru swirc-3.4.3/src/printtext.cpp swirc-3.4.4/src/printtext.cpp --- swirc-3.4.3/src/printtext.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/printtext.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -259,8 +259,7 @@ * * ****************************************************************/ -static size_t get_mb_strlen(CSTRING) PTR_ARGS_NONNULL; -static char *get_buffer(CSTRING) PTR_ARGS_NONNULL; +static char *get_buffer(CSTRING) NONNULL; static void addmbs(WINDOW *win, const unsigned char *mbs) @@ -699,7 +698,7 @@ WADDCH(win, '\n'); *insert_count = 0; - if (rep_count != NULL) + if (isValid(rep_count)) (*rep_count) ++; } @@ -759,7 +758,7 @@ } else if (!start_on_a_new_row((*insert_count) + ctx->diff + 1, ctx->win)) { addmbs(ctx->win, mbs); - (*insert_count) ++; + (*insert_count) += xwcwidth(ctx->wc, 2); // XXX } else { /* * Start on a new row @@ -778,7 +777,7 @@ if (ctx->wc != L' ') { addmbs(ctx->win, mbs); - (*insert_count) ++; + (*insert_count) += xwcwidth(ctx->wc, 2); } } @@ -823,45 +822,27 @@ } } -/** - * Get multibyte string length - */ -static size_t -get_mb_strlen(CSTRING s) -{ - const size_t ERR_CASE1 = static_cast(-1); - const size_t ERR_CASE2 = static_cast(-2); - size_t idx = 0; - size_t len = 0; - - while (true) { - const size_t ret = mbrlen(&s[idx], MB_CUR_MAX, NULL); - - if (ret == ERR_CASE1 || ret == ERR_CASE2) { - return strlen(s); - } else if (ret == 0) { - break; - } else { - idx += ret; - len += 1; - } - } - - return len; -} - static void set_indent(int *indent, CSTRING fmt, ...) { - va_list ap; char *str = NULL; + size_t bytes_convert; + va_list ap; + wchar_t wcs[400] = { L'\0' }; va_start(ap, fmt); str = strdup_vprintf(fmt, ap); va_end(ap); - *indent = static_cast(get_mb_strlen(squeeze_text_deco(str))); + bytes_convert = xmbstowcs(addrof(wcs[0]), squeeze_text_deco(str), + ARRAY_SIZE(wcs) - 1); + wcs[ARRAY_SIZE(wcs) - 1] = L'\0'; free(str); + if (bytes_convert == g_conversion_failed) { + *indent = 0; + return; + } + *indent = xwcswidth(addrof(wcs[0]), 2); } /** @@ -1069,7 +1050,7 @@ throw std::runtime_error("conversion failed"); } - if (bytes_convert == (size - 1)) + if (bytes_convert >= (size - 1)) out[size - 1] = 0L; if (xsetlocale(LC_CTYPE, original_locale) == NULL) { err_log(EPERM, "%s: cannot restore original " @@ -1405,25 +1386,22 @@ get_buffer(CSTRING orig) { #ifdef HAVE_LIBICONV +#if defined(__cplusplus) && __cplusplus >= 201103L +#define fromcode_pb(_str) fromcode.emplace_back(_str) +#else +#define fromcode_pb(_str) fromcode.push_back(_str) +#endif #define UTF8_MAXBYTE 4 if (!config_bool("iconv_conversion", false)) return sw_strdup(orig); std::list fromcode; -#if defined(__cplusplus) && __cplusplus >= 201103L - fromcode.emplace_back("UTF-8"); - fromcode.emplace_back("ISO-8859-1"); - fromcode.emplace_back("ISO-8859-15"); - fromcode.emplace_back("WINDOWS-1251"); - fromcode.emplace_back("WINDOWS-1252"); -#else - fromcode.push_back("UTF-8"); - fromcode.push_back("ISO-8859-1"); - fromcode.push_back("ISO-8859-15"); - fromcode.push_back("WINDOWS-1251"); - fromcode.push_back("WINDOWS-1252"); -#endif + fromcode_pb("UTF-8"); + fromcode_pb("ISO-8859-1"); + fromcode_pb("ISO-8859-15"); + fromcode_pb("WINDOWS-1251"); + fromcode_pb("WINDOWS-1252"); for (const std::string &x : fromcode) { char *in, *orig_copy, *out, *out_p; @@ -1502,7 +1480,7 @@ err_sys("%s: init_once", __func__); #endif - if (rep_count) + if (isValid(rep_count)) *rep_count = 0; if (pwin == NULL || buf == NULL) err_exit(EINVAL, "%s", __func__); @@ -1552,8 +1530,21 @@ wchar_t *wcp = NULL; if (wc == L' ' && (wcp = wcschr(wc_bufp + 1, L' ')) != - NULL) - diff = (wcp - wc_bufp); + NULL) { + static wchar_t str[4096] = { L'\0' }; + static const ptrdiff_t ARSZ = static_cast + (ARRAY_SIZE(str)); + + if ((diff = (wcp - wc_bufp)) > ARSZ - 1) + diff = ARSZ - 1; + sw_assert(diff > 0); + (void) wcsncpy(str, wc_bufp, diff); + str[diff] = L'\0'; + if ((diff = xwcswidth(wcspbrk(str, + L"\035\002\003\017\026\037") ? + squeeze_text_deco_wide(str) : str, 2)) < 0) + diff = 0; + } struct case_default_context def_ctx(pwin, wc, !wcscmp(wc_bufp + 1, L""), indent, max_lines, diff); case_default(&def_ctx, rep_count, &lines_count, diff -Nru swirc-3.4.3/src/printtext.h swirc-3.4.4/src/printtext.h --- swirc-3.4.3/src/printtext.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/printtext.h 2023-07-29 13:02:03.000000000 +0000 @@ -90,7 +90,7 @@ void printtext_puts(WINDOW *, CSTRING buf, int indent, int, int *); void printtext_set_color(WINDOW *, bool *, short int, short int); void set_timestamp(char *dest, size_t destsize, - const struct irc_message_compo *) PTR_ARGS_NONNULL; + const struct irc_message_compo *) NONNULL; void vprinttext(PPRINTTEXT_CONTEXT, CSTRING fmt, va_list); __SWIRC_END_DECLS diff -Nru swirc-3.4.3/src/readlineAPI.c swirc-3.4.4/src/readlineAPI.c --- swirc-3.4.3/src/readlineAPI.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/readlineAPI.c 2023-07-29 13:02:03.000000000 +0000 @@ -33,11 +33,13 @@ #include #include "assertAPI.h" +#include "dataClassify.h" #include "errHand.h" #include "libUtils.h" #include "printtext.h" #include "readline.h" #include "readlineAPI.h" +#include "strHand.h" #define WATTR_ON(win, attrs) ((void) wattr_on(win, attrs, NULL)) #define WATTR_OFF(win, attrs) ((void) wattr_off(win, attrs, NULL)) @@ -181,6 +183,38 @@ } /** + * Readline error handling + * (Formatted version) + */ +NORETURN void +readline_ferror(int error, CSTRING fmt, ...) +{ + PRINTTEXT_CONTEXT ctx; + char out[900] = { '\0' }; + char strerrbuf[MAXERROR] = { '\0' }; + va_list ap; + + va_start(ap, fmt); +#if defined(UNIX) + (void) vsnprintf(out, sizeof out, fmt, ap); +#elif defined(WIN32) + (void) vsnprintf_s(out, sizeof out, _TRUNCATE, fmt, ap); +#endif + va_end(ap); + + if (error) { + (void) sw_strcat(out, ": ", sizeof out); + (void) sw_strcat(out, xstrerror(error, strerrbuf, MAXERROR), + sizeof out); + } + + printtext_context_init(&ctx, g_status_window, TYPE_SPEC1_FAILURE, true); + printtext(&ctx, "non-fatal: %s", out); + g_readline_loop = false; + longjmp(g_readline_loc_info, READLINE_RESTART); +} + +/** * Add a character at given position * * @param win Window @@ -198,12 +232,12 @@ if (wmove(win, row, col) == ERR) { free_and_null(&mbs); mutex_unlock(&g_puts_mutex); - readline_error(0, "readline_mvwaddch: wmove"); + readline_ferror(0, "%s: wmove", __func__); } else if (!is_text_decoration(wc)) { if (waddnstr(win, mbs, -1) == ERR) { free_and_null(&mbs); mutex_unlock(&g_puts_mutex); - readline_error(0, "readline_mvwaddch: waddnstr"); + readline_ferror(0, "%s: waddnstr", __func__); } } else { add_complex_char(win, *mbs); @@ -229,7 +263,7 @@ if (waddnstr(win, mbs, -1) == ERR) { free_and_null(&mbs); mutex_unlock(&g_puts_mutex); - readline_error(EIO, "readline_waddch: waddnstr"); + readline_ferror(EIO, "%s: waddnstr", __func__); /* NOTREACHED */ } } else { @@ -275,12 +309,12 @@ if (wmove(win, row, col) == ERR) { free_and_null(&mbs); mutex_unlock(&g_puts_mutex); - readline_error(0, "readline_mvwinsch: wmove"); + readline_ferror(0, "%s: wmove", __func__); } else if (!is_text_decoration(wc)) { if (winsnstr(win, mbs, size_to_int(strlen(mbs) + 1)) == ERR) { free_and_null(&mbs); mutex_unlock(&g_puts_mutex); - readline_error(0, "readline_mvwinsch: winsnstr"); + readline_ferror(0, "%s: winsnstr", __func__); } } else { ins_complex_char(win, *mbs); @@ -306,7 +340,7 @@ if (winsnstr(win, mbs, size_to_int(strlen(mbs) + 1)) == ERR) { free_and_null(&mbs); mutex_unlock(&g_puts_mutex); - readline_error(EIO, "readline_winsch: winsnstr"); + readline_ferror(EIO, "%s: winsnstr", __func__); /* NOTREACHED */ } } else { @@ -333,3 +367,24 @@ for (const wchar_t *ptr = &s[i - 1]; ptr >= &s[0]; ptr--) readline_winsch(win, *ptr); } + +int +readline_wcwidth(const wchar_t wc, const int fwlen) +{ + if (is_text_decoration(wc)) + return 1; + return xwcwidth(wc, fwlen); +} + +int +readline_wcswidth(const wchar_t *str, const int fwlen) +{ + const wchar_t *ptr = str; + int width = 0; + + while (*ptr) { + width += readline_wcwidth(*ptr, fwlen); + ptr++; + } + return width; +} diff -Nru swirc-3.4.3/src/readlineAPI.h swirc-3.4.4/src/readlineAPI.h --- swirc-3.4.3/src/readlineAPI.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/readlineAPI.h 2023-07-29 13:02:03.000000000 +0000 @@ -8,22 +8,28 @@ #elif WIN32 #include "pdcurses/curses.h" #else -#error "Cannot determine curses header file!" +#error Cannot determine Curses header file! #endif -/*lint -sem(readline_error, r_no) doesn't return because of longjmp() */ +//lint -printf(2, readline_ferror) +//lint -sem(readline_error, r_no) doesn't return because of longjmp() +//lint -sem(readline_ferror, r_no) likewise __SWIRC_BEGIN_DECLS NORETURN void readline_error(int, CSTRING); +NORETURN void readline_ferror(int, CSTRING, ...) PRINTFLIKE(2); void readline_mvwaddch(WINDOW *, int row, int col, wint_t); void readline_mvwinsch(WINDOW *, int row, int col, wint_t); void readline_waddch(WINDOW *, wint_t); void readline_waddnstr(WINDOW *, const wchar_t *, ptrdiff_t) - PTR_ARGS_NONNULL; + NONNULL; void readline_winsch(WINDOW *, wint_t); void readline_winsnstr(WINDOW *, const wchar_t *, ptrdiff_t) - PTR_ARGS_NONNULL; + NONNULL; + +int readline_wcwidth(const wchar_t, const int); +int readline_wcswidth(const wchar_t *, const int); __SWIRC_END_DECLS #endif diff -Nru swirc-3.4.3/src/readline.c swirc-3.4.4/src/readline.c --- swirc-3.4.3/src/readline.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/readline.c 2023-07-29 13:02:03.000000000 +0000 @@ -57,6 +57,16 @@ #include "commands/misc.h" +/* + * Full-width length, i.e. the number of column positions required to + * display a full width wide character. (Windows behaves differently.) + */ +#if defined(UNIX) +#define FWLEN 2 +#elif defined(WIN32) +#define FWLEN 1 +#endif + /**************************************************************** * * * -------------- Objects with external linkage -------------- * @@ -147,12 +157,31 @@ mutex_unlock(&g_puts_mutex); if (ret == ERR) - readline_error(0, "write_cmdprompt: werase"); + readline_ferror(0, "%s: werase", __func__); printtext_puts(win, prompt, -1, -1, NULL); UNUSED_PARAM(size); } +static int +get_subtrahend(const volatile struct readline_session_context *ctx, + const int diff) +{ + const wchar_t *ptr; + int i, j; + + i = j = 0; + ptr = addrof(ctx->buffer[ctx->bufpos - 1]); + + while (i < diff && ptr >= addrof(ctx->buffer[0])) { + i += readline_wcwidth(*ptr, FWLEN); + j++; + ptr--; + } + + return j; +} + /** * When swapping between panels: computes the new window entry. */ @@ -160,24 +189,26 @@ compute_new_window_entry(const volatile struct readline_session_context *ctx, bool fwd) { - int bufindex, diff; - wchar_t *str1, *str2; + const wchar_t *str1, *str2; + int bufindex, diff; if (fwd) { diff = (COLS / 2); - bufindex = int_diff(ctx->bufpos, diff); + bufindex = int_diff(ctx->bufpos, get_subtrahend(ctx, diff)); - if ((COLS % 2) == 0) - bufindex += 1; + if (bufindex < 0) + readline_ferror(ERANGE, "%s", __func__); str1 = &ctx->buffer[bufindex]; str2 = &ctx->buffer[ctx->bufpos]; } else { diff = int_diff(COLS / 2, ctx->prompt_size); + bufindex = int_diff(ctx->bufpos, get_subtrahend(ctx, diff)); - if ((bufindex = int_diff(ctx->bufpos, diff)) < 0) { - readline_error(ERANGE, "compute_new_window_entry"); - /* NOTREACHED */ + if (bufindex < 0) { + printtext_print("warn", "%s: bufindex=%d", __func__, + bufindex); + bufindex = 0; } str1 = &ctx->buffer[bufindex]; @@ -226,54 +257,65 @@ static void case_key_backspace(volatile struct readline_session_context *ctx) { - int ret[3]; + int ret[2] = { OK }; + int width; + struct current_cursor_pos yx; if (ctx->bufpos == 0) { term_beep(); return; } + if (loLim_isset(ctx->act, ctx->prompt_size)) magic_swap_panels(ctx, false); + yx = term_get_pos(ctx->act); + if (ctx->insert_mode) { wchar_t *ptr; + width = readline_wcwidth(ctx->buffer[ctx->bufpos - 1], FWLEN); ptr = &ctx->buffer[ctx->bufpos--]; (void) wmemmove(ptr - 1, ptr, wcslen(ptr)); ctx->buffer[--ctx->numins] = 0L; mutex_lock(&g_puts_mutex); - ret[0] = wmove(ctx->act, term_get_pos(ctx->act).cury, - term_get_pos(ctx->act).curx - 1); - ret[1] = wdelch(ctx->act); - ret[2] = wclrtoeol(ctx->act); + if (width > 0) { + ctx->vispos -= width; + ret[0] = wmove(ctx->act, yx.cury, yx.curx - width); + ret[1] = wclrtoeol(ctx->act); + } mutex_unlock(&g_puts_mutex); if (ret[0] == ERR) - readline_error(EIO, "case_key_backspace: wmove"); + readline_ferror(EIO, "%s: wmove", __func__); else if (ret[1] == ERR) - readline_error(EIO, "case_key_backspace: wdelch"); - else if (ret[2] == ERR) - readline_error(EIO, "case_key_backspace: wclrtoeol"); + readline_ferror(EIO, "%s: wclrtoeol", __func__); - readline_winsnstr(ctx->act, &ctx->buffer[ctx->bufpos], -1); + if (width > 0) { + readline_winsnstr(ctx->act, &ctx->buffer[ctx->bufpos], + -1); + } } else { /* * Not insert mode */ + width = readline_wcwidth(ctx->buffer[ctx->bufpos - 1], FWLEN); ctx->buffer[--ctx->bufpos] = 0L; ctx->numins--; mutex_lock(&g_puts_mutex); - ret[0] = wmove(ctx->act, term_get_pos(ctx->act).cury, - term_get_pos(ctx->act).curx - 1); - ret[1] = wdelch(ctx->act); + if (width > 0) { + ctx->vispos -= width; + ret[0] = wmove(ctx->act, yx.cury, yx.curx - width); + ret[1] = wclrtoeol(ctx->act); + } mutex_unlock(&g_puts_mutex); if (ret[0] == ERR) - readline_error(EIO, "case_key_backspace: wmove"); + readline_ferror(EIO, "%s: wmove", __func__); else if (ret[1] == ERR) - readline_error(EIO, "case_key_backspace: wdelch"); + readline_ferror(EIO, "%s: wclrtoeol", __func__); } mutex_lock(&g_puts_mutex); @@ -306,9 +348,9 @@ mutex_unlock(&g_puts_mutex); if (ret[0] == ERR) - readline_error(EIO, "case_key_dc: wdelch"); + readline_ferror(EIO, "%s: wdelch", __func__); else if (ret[1] == ERR) - readline_error(EIO, "case_key_dc: wclrtoeol"); + readline_ferror(EIO, "%s: wclrtoeol", __func__); readline_winsnstr(ctx->act, &ctx->buffer[ctx->bufpos], -1); @@ -323,6 +365,7 @@ static void case_key_left(volatile struct readline_session_context *ctx) { + int width; struct current_cursor_pos yx; if (ctx->bufpos == 0) { @@ -334,14 +377,16 @@ magic_swap_panels(ctx, false); mutex_lock(&g_puts_mutex); - ctx->bufpos--; - yx = term_get_pos(ctx->act); - if (wmove(ctx->act, yx.cury, yx.curx - 1) == ERR) { - mutex_unlock(&g_puts_mutex); - readline_error(EIO, "wmove"); - /* NOTREACHED */ + if ((width = readline_wcwidth(ctx->buffer[--ctx->bufpos], FWLEN)) > 0) { + ctx->vispos -= width; + yx = term_get_pos(ctx->act); + if (wmove(ctx->act, yx.cury, yx.curx - width) == ERR) { + mutex_unlock(&g_puts_mutex); + readline_error(EIO, "wmove"); + /* NOTREACHED */ + } + (void) wrefresh(ctx->act); } - (void) wrefresh(ctx->act); mutex_unlock(&g_puts_mutex); } @@ -351,6 +396,7 @@ static void case_key_right(volatile struct readline_session_context *ctx) { + int width; struct current_cursor_pos yx; if (!ctx->insert_mode) { @@ -362,14 +408,16 @@ magic_swap_panels(ctx, true); mutex_lock(&g_puts_mutex); - ctx->bufpos++; - yx = term_get_pos(ctx->act); - if (wmove(ctx->act, yx.cury, yx.curx + 1) == ERR) { - mutex_unlock(&g_puts_mutex); - readline_error(EIO, "wmove"); - /* NOTREACHED */ + if ((width = readline_wcwidth(ctx->buffer[ctx->bufpos++], FWLEN)) > 0) { + ctx->vispos += width; + yx = term_get_pos(ctx->act); + if (wmove(ctx->act, yx.cury, yx.curx + width) == ERR) { + mutex_unlock(&g_puts_mutex); + readline_error(EIO, "wmove"); + /* NOTREACHED */ + } + (void) wrefresh(ctx->act); } - (void) wrefresh(ctx->act); mutex_unlock(&g_puts_mutex); } @@ -394,10 +442,10 @@ if ((bytes_convert = wcstombs(out, buf, size - 1)) == g_conversion_failed) { - err_log(errno, "finalize_out_string: wcstombs"); + err_log(errno, "%s: wcstombs", __func__); BZERO(out, size); return xrealloc(out, 1); - } else if (bytes_convert == (size - 1)) { + } else if (bytes_convert >= (size - 1)) { out[size - 1] = '\0'; } @@ -419,7 +467,7 @@ if (WideCharToMultiByte(CP_UTF8, 0, buf, -1, out, size, NULL, NULL) > 0) return xrealloc(out, strlen(out) + 1); - err_log(errno, "finalize_out_string: WideCharToMultiByte"); + err_log(errno, "%s: WideCharToMultiByte", __func__); BZERO(out, size); return xrealloc(out, 1); } @@ -451,15 +499,19 @@ handle_key(volatile struct readline_session_context *ctx, wint_t wc, bool check_reset) { + int width; + if (ctx->no_bufspc) { term_beep(); return; } + if (hiLim_isset(ctx->act)) magic_swap_panels(ctx, true); + width = readline_wcwidth(wc, FWLEN); + if (ctx->insert_mode) { - int ret; - wchar_t *ptr; + wchar_t *ptr; ptr = &ctx->buffer[ctx->bufpos]; (void) wmemmove(ptr + 1, ptr, wcslen(ptr)); @@ -467,20 +519,28 @@ ctx->bufpos++; ctx->numins++; + ctx->vispos += width; readline_winsch(ctx->act, wc); - mutex_lock(&g_puts_mutex); - ret = wmove(ctx->act, term_get_pos(ctx->act).cury, - term_get_pos(ctx->act).curx + 1); - mutex_unlock(&g_puts_mutex); + if (width > 0) { + int ret; + struct current_cursor_pos yx; + + yx = term_get_pos(ctx->act); + + mutex_lock(&g_puts_mutex); + ret = wmove(ctx->act, yx.cury, yx.curx + width); + mutex_unlock(&g_puts_mutex); - if (ret == ERR) - readline_error(0, "handle_key: wmove"); + if (ret == ERR) + readline_error(0, "handle_key: wmove"); + } } else { ctx->buffer[ctx->bufpos] = wc; ctx->bufpos++; ctx->numins++; + ctx->vispos += width; readline_waddch(ctx->act, wc); } @@ -526,11 +586,12 @@ ctx->buffer = xcalloc(g_readline_bufsize + 1, sizeof(wchar_t)); ctx->bufpos = 0; ctx->insert_mode = false; - ctx->numins = 0; ctx->no_bufspc = false; + ctx->numins = 0; ctx->prompt = sw_strdup(prompt); ctx->prompt_size = (int) strlen(squeeze_text_deco(prompt_copy)); ctx->tc = readline_tab_comp_ctx_new(); + ctx->vispos = 0; free(prompt_copy); @@ -783,7 +844,7 @@ session_destroy(ctx); return NULL; default: - if (iswprint(wc)) + if (iswprint(wc) && !is_combined(wc)) handle_key(ctx, wc, true); break; } @@ -879,13 +940,22 @@ switch (setjmp(g_readline_loc_info)) { case READLINE_PROCESS: - g_readline_loop = true; - g_resize_requested = false; - g_suggs_mode = false; - g_hist_next = false; - g_hist_prev = false; + g_hist_next = false; + g_hist_prev = false; + g_readline_loop = true; + g_resize_requested = false; + g_suggs_mode = false; ctx = new_session(prompt); return process(ctx); + case READLINE_RESTART: + debug("%s: restarting...", __func__); + break; + case READLINE_TERMINATE: + debug("%s: terminating...", __func__); + break; + default: + sw_assert_not_reached(); + break; } session_destroy(ctx); @@ -923,7 +993,7 @@ "WHEEL")) report_wheel_events(); else - err_log(EINVAL, "readline_mouse_init: 'mouse_events'"); + err_log(EINVAL, "%s: 'mouse_events'", __func__); } else { (void) mousemask(0, NULL); } diff -Nru swirc-3.4.3/src/readline.h swirc-3.4.4/src/readline.h --- swirc-3.4.3/src/readline.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/readline.h 2023-07-29 13:02:03.000000000 +0000 @@ -8,7 +8,7 @@ #elif WIN32 #include "pdcurses/panel.h" #else -#error "Cannot determine panel header file!" +#error Cannot determine Panel header file! #endif #include /* want type jmp_buf */ @@ -73,6 +73,7 @@ int bufpos; int numins; int prompt_size; + int vispos; // visual position wchar_t *buffer; }; diff -Nru swirc-3.4.3/src/sig-unix.c swirc-3.4.4/src/sig-unix.c --- swirc-3.4.3/src/sig-unix.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/sig-unix.c 2023-07-29 13:02:03.000000000 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2012-2022 Markus Uhlin. All rights reserved. */ +/* Copyright (C) 2012-2023 Markus Uhlin. All rights reserved. */ #include "common.h" @@ -92,7 +92,7 @@ (void) sigaddset(&set, ssp->num); } if ((errno = pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0) - err_sys("block_signals: pthread_sigmask"); + err_sys("%s: pthread_sigmask", __func__); } bool @@ -106,7 +106,7 @@ act.sa_flags = 0; if (pthread_sigmask(SIG_SETMASK, &set, NULL) != 0) { - err_ret("sighand_init: SIG_SETMASK"); + err_ret("%s: SIG_SETMASK", __func__); return false; } @@ -118,8 +118,8 @@ else act.sa_handler = signal_handler; if (sigaction(ssp->num, &act, NULL) != 0) { - err_ret("sighand_init: sigaction failed on signal %d " - "(%s)", ssp->num, ssp->num_str); + err_ret("%s: sigaction failed on signal %d (%s)", + __func__, ssp->num, ssp->num_str); return false; } } @@ -127,7 +127,7 @@ (void) sigemptyset(&set); if (pthread_sigmask(SIG_SETMASK, &set, NULL) != 0) { - err_ret("sighand_init: SIG_SETMASK"); + err_ret("%s: SIG_SETMASK", __func__); return false; } diff -Nru swirc-3.4.3/src/spell.cpp swirc-3.4.4/src/spell.cpp --- swirc-3.4.3/src/spell.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/spell.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -61,7 +61,7 @@ bool g_suggs_mode = false; #ifdef HAVE_HUNSPELL -static Hunhandle *hh = nullptr; +static Hunhandle *pHunspell = nullptr; static std::vector *rl_suggs = nullptr; static std::vector::iterator suggs_it; static std::wstring rl_word; @@ -90,7 +90,8 @@ if (li->lang_and_territory == nullptr || li->codeset == nullptr) { free_locale_info(li); throw std::runtime_error("get locale info error"); - } else if ((encoding = Hunspell_get_dic_encoding(hh)) == nullptr) { + } else if ((encoding = Hunspell_get_dic_encoding(pHunspell)) == + nullptr) { free_locale_info(li); throw std::runtime_error("get dic encoding error"); } @@ -175,11 +176,11 @@ } } - if (hh) - Hunspell_destroy(hh); + if (pHunspell) + Hunspell_destroy(pHunspell); redir_stderr(); - if ((hh = Hunspell_create(aff.c_str(), dic.c_str())) == nullptr) + if ((pHunspell = Hunspell_create(aff.c_str(), dic.c_str())) == nullptr) printtext_print("err", "%s: error", __func__); restore_stderr(); } @@ -189,9 +190,9 @@ { g_suggs_mode = false; - if (hh) - Hunspell_destroy(hh); - hh = nullptr; + if (pHunspell) + Hunspell_destroy(pHunspell); + pHunspell = nullptr; } void @@ -239,7 +240,7 @@ return nullptr; else if (mbs) { if (strcmp(mbs, "") == STRINGS_MATCH || - (nsuggs = Hunspell_suggest(hh, &list, mbs)) < 1) + (nsuggs = Hunspell_suggest(pHunspell, &list, mbs)) < 1) return nullptr; } else if (wcs) { char *word; @@ -249,7 +250,7 @@ return nullptr; if ((word = get_mbs(wcs)) == nullptr || - (nsuggs = Hunspell_suggest(hh, &list, word)) < 1) { + (nsuggs = Hunspell_suggest(pHunspell, &list, word)) < 1) { free(word); return nullptr; } @@ -273,7 +274,7 @@ } } - Hunspell_free_list(hh, &list, nsuggs); + Hunspell_free_list(pHunspell, &list, nsuggs); return suggs; } @@ -312,10 +313,10 @@ bool spell_word(const char *word) { - if (hh == nullptr || word == nullptr || + if (pHunspell == nullptr || word == nullptr || strcmp(word, "") == STRINGS_MATCH) return false; - return (Hunspell_spell(hh, word) != 0 ? true : false); + return (Hunspell_spell(pHunspell, word) != 0 ? true : false); } static void @@ -427,7 +428,7 @@ bool ret; char *mbs; - if (hh == nullptr || word == nullptr || + if (pHunspell == nullptr || word == nullptr || wcscmp(word, L"") == STRINGS_MATCH || wcslen(word) > MAXWORDLEN) return false; @@ -435,7 +436,7 @@ if ((mbs = get_mbs(word)) == nullptr) return false; - ret = (Hunspell_spell(hh, mbs) != 0 ? true : false); + ret = (Hunspell_spell(pHunspell, mbs) != 0 ? true : false); free(mbs); return ret; diff -Nru swirc-3.4.3/src/squeeze_text_deco.cpp swirc-3.4.4/src/squeeze_text_deco.cpp --- swirc-3.4.3/src/squeeze_text_deco.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/squeeze_text_deco.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ /* squeeze_text_deco.cpp - Copyright (C) 2022 Markus Uhlin. All rights reserved. + Copyright (C) 2022-2023 Markus Uhlin. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -29,12 +29,20 @@ #include "common.h" +#include + #include "assertAPI.h" #include "dataClassify.h" #include "errHand.h" #include "printtext.h" #include "strHand.h" +#if defined(UNIX) +#define PRINT_SIZE "%zu" +#elif defined(WIN32) +#define PRINT_SIZE "%Iu" +#endif + static const char reject[] = TXT_BLINK TXT_BOLD @@ -178,3 +186,43 @@ buffer[j] = '\0'; return buffer; } + +wchar_t * +squeeze_text_deco_wide(wchar_t *buffer) +{ + char str_copy[4096] = { '\0' }; + size_t buflen, newlen, num; + std::string str(""); + std::wstring wstr(L""); + + if (buffer == NULL) + err_exit(EINVAL, "%s", __func__); + else if (wcscmp(buffer, L"") == STRINGS_MATCH) + return buffer; + + buflen = wcslen(buffer); + newlen = num = 0; + + try { + (void) wstr.assign(buffer); + (void) str.assign(wstr.begin(), wstr.end()); + + strncpy(str_copy, str.c_str(), sizeof str_copy - 1); + str_copy[sizeof str_copy - 1] = '\0'; + + (void) str.assign(squeeze_text_deco(str_copy)); + (void) wstr.assign(str.begin(), str.end()); + + newlen = wstr.size(); + num = (newlen < buflen ? newlen : buflen); + + wmemcpy(buffer, wstr.data(), num); + buffer[num] = L'\0'; + } catch (...) { + err_log(0, "%s: fatal error", __func__); + err_log(0, "buflen: " PRINT_SIZE, buflen); + err_log(0, "newlen: " PRINT_SIZE, newlen); + } + + return buffer; +} diff -Nru swirc-3.4.3/src/squeeze_text_deco.h swirc-3.4.4/src/squeeze_text_deco.h --- swirc-3.4.3/src/squeeze_text_deco.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/squeeze_text_deco.h 2023-07-29 13:02:03.000000000 +0000 @@ -3,6 +3,7 @@ __SWIRC_BEGIN_DECLS char *squeeze_text_deco(char *); +wchar_t *squeeze_text_deco_wide(wchar_t *); __SWIRC_END_DECLS #endif diff -Nru swirc-3.4.3/src/strdup_printf.c swirc-3.4.4/src/strdup_printf.c --- swirc-3.4.3/src/strdup_printf.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/strdup_printf.c 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ /* Duplicate a printf style format string - Copyright (C) 2012-2021 Markus Uhlin. All rights reserved. + Copyright (C) 2012-2023 Markus Uhlin. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -88,21 +88,20 @@ #if defined(UNIX) if ((errno = pthread_once(&init_done, mutex_init)) != 0) - err_sys("strdup_vprintf: pthread_once"); + err_sys("%s: pthread_once", __func__); #elif defined(WIN32) if ((errno = init_once(&init_done, mutex_init)) != 0) - err_sys("strdup_vprintf: init_once"); + err_sys("%s: init_once", __func__); #endif mutex_lock(&mutex); if ((size = get_size(fmt, ap)) < 0) - err_exit(ENOSYS, "strdup_vprintf: get_size"); - else - size += 1; + err_exit(ENOSYS, "%s: get_size", __func__); + size += 1; if ((buffer = malloc(size)) == NULL) { - err_exit(ENOMEM, "strdup_vprintf: malloc (allocating %d bytes)", + err_exit(ENOMEM, "%s: malloc (allocating %d bytes)", __func__, size); } @@ -110,10 +109,10 @@ #if defined(UNIX) if ((n_print = vsnprintf(buffer, size, fmt, ap)) < 0 || n_print >= size) - err_sys("strdup_vprintf: vsnprintf() returned %d", n_print); + err_sys("%s: vsnprintf() returned %d", __func__, n_print); #elif defined(WIN32) if ((n_print = vsnprintf_s(buffer, size, size - 1, fmt, ap)) < 0) - err_sys("strdup_vprintf: vsnprintf_s() returned %d", n_print); + err_sys("%s: vsnprintf_s() returned %d", __func__, n_print); #endif mutex_unlock(&mutex); diff -Nru swirc-3.4.3/src/swirc.1 swirc-3.4.4/src/swirc.1 --- swirc-3.4.3/src/swirc.1 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/swirc.1 2023-07-29 13:02:03.000000000 +0000 @@ -1,7 +1,7 @@ .\" .\" Public domain .\" -.Dd February 5, 2023 +.Dd April 27, 2023 .Dt SWIRC 1 .Os .Sh NAME @@ -163,7 +163,7 @@ .It Pa ~/.swirc/swirc.conf .Nm configuration file -.It Pa ~/.swirc/default.the +.It Pa ~/.swirc/default.thm .Nm default theme .It Pa ~/.swirc/log/error.log diff -Nru swirc-3.4.3/src/swirc.exe.manifest swirc-3.4.4/src/swirc.exe.manifest --- swirc-3.4.3/src/swirc.exe.manifest 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/swirc.exe.manifest 2023-07-29 13:02:03.000000000 +0000 @@ -16,7 +16,7 @@ type="win32" name="SDT.Swirc.Swirc" processorArchitecture="*" - version="3.4.3.0" /> + version="3.4.4.0" /> Curses IRC client diff -Nru swirc-3.4.3/src/swirc.rc swirc-3.4.4/src/swirc.rc --- swirc-3.4.3/src/swirc.rc 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/swirc.rc 2023-07-29 13:02:03.000000000 +0000 @@ -3,8 +3,8 @@ LANGUAGE 0, 0 -#define VER 3,4,3,0 -#define VER_STR "3.4.3\0" +#define VER 3,4,4,0 +#define VER_STR "3.4.4\0" 1 VERSIONINFO FILEVERSION VER diff -Nru swirc-3.4.3/src/terminal.h swirc-3.4.4/src/terminal.h --- swirc-3.4.3/src/terminal.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/terminal.h 2023-07-29 13:02:03.000000000 +0000 @@ -48,7 +48,7 @@ void term_beep(void); struct current_cursor_pos - term_get_pos(WINDOW *) PTR_ARGS_NONNULL; + term_get_pos(WINDOW *) NONNULL; bool term_is_too_small(void); PANEL *term_new_panel(int rows, int cols, int start_row, int start_col); void term_remove_panel(PANEL *); diff -Nru swirc-3.4.3/src/theme.c swirc-3.4.4/src/theme.c --- swirc-3.4.3/src/theme.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/theme.c 2023-07-29 13:02:03.000000000 +0000 @@ -36,7 +36,7 @@ #elif WIN32 #include "pdcurses/curses.h" #else -#error "Cannot determine curses header file!" +#error Cannot determine Curses header file! #endif #include "errHand.h" @@ -177,7 +177,7 @@ hash_table[hashval] = item; } -static void hUndef(PTHEME_HTBL_ENTRY) PTR_ARGS_NONNULL; +static void hUndef(PTHEME_HTBL_ENTRY) NONNULL; static void hUndef(PTHEME_HTBL_ENTRY entry) diff -Nru swirc-3.4.3/src/tls-server.cpp swirc-3.4.4/src/tls-server.cpp --- swirc-3.4.3/src/tls-server.cpp 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/tls-server.cpp 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ /* TLS server - Copyright (C) 2021-2022 Markus Uhlin. All rights reserved. + Copyright (C) 2021-2023 Markus Uhlin. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -29,6 +29,10 @@ #include "common.h" +/* + * OpenSSL 1.1.1 API compat + */ +#define OPENSSL_API_COMPAT 10101 #include #include #include diff -Nru swirc-3.4.3/src/window.c swirc-3.4.4/src/window.c --- swirc-3.4.3/src/window.c 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/window.c 2023-07-29 13:02:03.000000000 +0000 @@ -291,7 +291,7 @@ return entry; } -static void hUndef(PIRC_WINDOW) PTR_ARGS_NONNULL; +static void hUndef(PIRC_WINDOW) NONNULL; static void hUndef(PIRC_WINDOW entry) diff -Nru swirc-3.4.3/src/window.h swirc-3.4.4/src/window.h --- swirc-3.4.3/src/window.h 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/src/window.h 2023-07-29 13:02:03.000000000 +0000 @@ -8,7 +8,7 @@ #elif WIN32 #include "pdcurses/panel.h" #else -#error "Cannot determine panel header file!" +#error Cannot determine Panel header file! #endif #include "textBuffer.h" diff -Nru swirc-3.4.3/swirc.theme.5 swirc-3.4.4/swirc.theme.5 --- swirc-3.4.3/swirc.theme.5 1970-01-01 00:00:00.000000000 +0000 +++ swirc-3.4.4/swirc.theme.5 2023-07-29 13:02:03.000000000 +0000 @@ -0,0 +1,243 @@ +.\" -*- mode: nroff; -*- +.\" +.\" Copyright 2023 Markus Uhlin. All rights reserved. +.\" +.Dd April 27, 2023 +.Dt SWIRC.THEME 5 +.Os +.Sh NAME +.Nm swirc.theme +.Nd how to write themes for swirc +.Sh DESCRIPTION +This manual page is the ultimate reference to consult when writing +themes to +.Xr swirc 1 . +.Sh TEXT DECORATION +.Bl -column " " "Hex" "Octal" "Appearance" -offset indent +.It Sy "What" Ta Sy "Hex" Ta Sy "Octal" Ta Sy "Appearance" +.It "Blink" Ta "1d" Ta "035" Ta "^]" +.It "Bold" Ta "02" Ta "002" Ta "^B" +.It "Color" Ta "03" Ta "003" Ta "^C" +.It "Normal" Ta "0f" Ta "017" Ta "^O" +.It "Reverse" Ta "16" Ta "026" Ta "^V" +.It "Underline" Ta "1f" Ta "037" Ta "^_" +.El +.Pp +Example usage: +.Bd -literal -offset indent -compact +blabla ^Bbold text^B blabla +blabla ^Vreversed text^V blabla +blabla ^_underlined text^_ blabla +.Ed +.Pp +Always use the +.Em literal +control characters because else it won't work! +.Pp +Blink is a no operation because it's annoying. +.Sh COLORS +.Bl -column "Number" " " "" -offset indent +.It Sy "Number" Ta Sy "Name" Ta Sy "" +.It "00" Ta "white" Ta "" +.It "01" Ta "black" Ta "" +.It "02" Ta "blue" Ta "(navy)" +.It "03" Ta "green" Ta "" +.It "04" Ta "red" Ta "" +.It "05" Ta "brown" Ta "(maroon)" +.It "06" Ta "purple" Ta "" +.It "07" Ta "orange" Ta "(olive)" +.It "08" Ta "yellow" Ta "" +.It "09" Ta "lt.green" Ta "(lime)" +.It "10" Ta "teal" Ta "(a kinda green/blue cyan)" +.It "11" Ta "lt.cyan" Ta "(cyan ?) (aqua)" +.It "12" Ta "lt.blue" Ta "(royal)" +.It "13" Ta "pink" Ta "(light purple) (fuchsia)" +.It "14" Ta "grey" Ta "" +.It "15" Ta "lt.grey" Ta "(silver)" +.El +.Pp +For the colors 16-99 see the output of the command +.Sy "/colormap" . +Enough color pairs must've been initialized. +(193 color pairs are too few for the colors 16-99 to be used as +backgrounds.) +.Pp +The syntax of the color attribute in text has the format ^CN[,M]. +N will be the text (foreground) color and M the background color. +A background color (M) is optional and is not always included. +.Pp +N and M can maximally be two digits long. +Although the colors +.Brq 0,1,2,...,9 +are supported you are highly encouraged to use +.Brq 00,01,02,...,09 . +.Pp +A plain ^C can be used to turn the color effect off. +While typing ^O will make sure ALL the text effects gets resetted. +For example: +.Bd -literal -offset indent -compact +blabla ^C05,02red text on blue background^C blabla +blabla ^C09green text^O blabla +.Ed +.Pp +Of course settings can start with colored text and a closing ^C is not +essential. +.Sh SETTING TYPES +See +.Xr swirc.conf 5 . +.Sh SETTINGS +.Bl -tag -width Ds +.\" ---------------------------------------- +.\" TERM BACKGROUND +.\" ---------------------------------------- +.It Sy term_background Pq Em int +Which background color (0-15) is this theme written for? +.Bd -literal -offset indent -compact +0 = white +1 = black +.Ed +.\" ---------------------------------------- +.\" TERM ENABLE COLORS +.\" ---------------------------------------- +.It Sy term_enable_colors Pq Em bool +Enable colors (yes/no)? +.\" ---------------------------------------- +.\" TERM USE DEFAULT COLORS +.\" ---------------------------------------- +.It Sy term_use_default_colors Pq Em bool +Use terminal's default colors? +I.e. call +.Xr use_default_colors 3 . +.\" ---------------------------------------- +.\" COLOR3 / COLOR4 +.\" ---------------------------------------- +.It Sy color3 , color4 Pq Em string +Colors used in uncategorized contexts. +Must begin with ^C. +.\" ---------------------------------------- +.\" GFX FAILURE/SUCCESS/WARNING +.\" ---------------------------------------- +.It Sy gfx_failure , gfx_success , gfx_warning Pq Em string +Used in contexts where to flag failures, successes and warnings +respectively. +.\" ---------------------------------------- +.\" LEFT/RIGHT-BRACKET +.\" ---------------------------------------- +.It Sy left_bracket , right_bracket Pq Em string +Left and right bracket. +Frequently used. +.\" ---------------------------------------- +.\" LOGO COLOR +.\" ---------------------------------------- +.It Sy logo_color Pq Em string +Swirc ASCII logo color displayed at startup. +(Must begin with ^C.) +.\" ---------------------------------------- +.\" NICK S1/S2 +.\" ---------------------------------------- +.It Sy nick_s1 , nick_s2 Pq Em string +When you or another user types something the nickname will be enclosed +by s1 and s2. +.\" ---------------------------------------- +.\" NICKLIST ... +.\" ---------------------------------------- +.It Sy nicklist_my_nick_color , nicklist_nick_color , nicklist_privilege_color , nicklist_vline_color Pq Em int +Nicklist decoration. +All of these settings are of type +.Em int +(0-99) thus ^C is not needed and should not be used. +.\" ---------------------------------------- +.\" NOTICE COLOR1/COLOR2 +.\" ---------------------------------------- +.It Sy notice_color1 , notice_color2 Pq Em string +Notice colors. +^C should be used. +.\" ---------------------------------------- +.\" NOTICE LB/RB/SEP +.\" ---------------------------------------- +.It Sy notice_lb , notice_rb , notice_sep Pq Em string +Notice left/right bracket and separator +.\" ---------------------------------------- +.\" NOTICE INNER B1/B2 +.\" ---------------------------------------- +.It Sy notice_inner_b1 , notice_inner_b2 Pq Em string +Notice inner bracket 1 and 2. +(I.e. left and right.) +.\" ---------------------------------------- +.\" PRIMARY/SECONDARY COLOR +.\" ---------------------------------------- +.It Sy primary_color , secondary_color Pq Em string +Primary and secondary color for the theme. +Frequently used. +(Begin with ^C.) +.\" ---------------------------------------- +.\" SLOGAN +.\" ---------------------------------------- +.It Sy slogan Pq Em string +Swirc slogan displayed in the statusbar. +.\" ---------------------------------------- +.\" SPECIFIER 1,2,3 +.\" ---------------------------------------- +.It Sy specifier1 , specifier2 , specifier3 Pq Em string +Specifiers used in various contexts. +Number 1 is frequently used. +.\" ---------------------------------------- +.\" STATUSBAR BG/FG +.\" ---------------------------------------- +.It Sy statusbar_bg , statusbar_fg Pq Em string +Statusbar background and foreground. +Valid values are +.Sy black , red , green , yellow , blue , magenta , cyan , white . +.\" ---------------------------------------- +.\" STATUSBAR LB/RB/SPEC +.\" ---------------------------------------- +.It Sy statusbar_leftBracket , statusbar_rightBracket , statusbar_spec Pq Em string +Statusbar left/right bracket and specifier. +.\" ---------------------------------------- +.\" TIME FORMAT +.\" ---------------------------------------- +.It Sy time_format Pq Em string +Time format passed to +.Xr strftime 3 . +.\" ---------------------------------------- +.\" TITLEBAR BG/FG +.\" ---------------------------------------- +.It Sy titlebar_bg , titlebar_fg Pq Em string +Titlebar background and foreground. +Valid values are +.Sy black , red , green , yellow , blue , magenta , cyan , white . +.\" ---------------------------------------- +.\" WHOIS ... +.\" ---------------------------------------- +.It Sy whois_acc Pq Em string +.It Sy whois_away Pq Em string +.It Sy whois_bot Pq Em string +.It Sy whois_cert Pq Em string +.It Sy whois_channels Pq Em string +.It Sy whois_conn Pq Em string +.It Sy whois_host Pq Em string +.It Sy whois_idle Pq Em string +.It Sy whois_ircName Pq Em string +.It Sy whois_ircOp Pq Em string +.It Sy whois_modes Pq Em string +.It Sy whois_server Pq Em string +.It Sy whois_service Pq Em string +.It Sy whois_ssl Pq Em string +.El +.Sh FILES +.Bl -tag -width " " -compact +.It Pa ~/.swirc/default.thm +default theme +.El +.Sh SEE ALSO +.Xr swirc 1 , Xr swirc.conf 5 +.Sh AUTHORS +This manual page was written by +.An Markus Uhlin +.Aq Mt markus.uhlin@bredband.net +.Sh CAVEATS +If you want to give color to +.Em numbers +be sure to use +.Em two +digits for N nor M! diff -Nru swirc-3.4.3/Swirc.wxs swirc-3.4.4/Swirc.wxs --- swirc-3.4.3/Swirc.wxs 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/Swirc.wxs 2023-07-29 13:02:03.000000000 +0000 @@ -13,9 +13,9 @@ Id="A3532170-8CC9-47BF-A0F6-5CB3F3341F12" Language="1033" Manufacturer="Swirc Development Team" - Name="Swirc 3.4.3" + Name="Swirc 3.4.4" UpgradeCode="4899E3ED-B314-4402-8E66-A2AB1B4632DE" - Version="3.4.3.0"> + Version="3.4.4.0"> diff -Nru swirc-3.4.3/tests/is_cjk.c swirc-3.4.4/tests/is_cjk.c --- swirc-3.4.3/tests/is_cjk.c 1970-01-01 00:00:00.000000000 +0000 +++ swirc-3.4.4/tests/is_cjk.c 2023-07-29 13:02:03.000000000 +0000 @@ -0,0 +1,52 @@ +#include "common.h" + +#include +#ifdef UNIT_TESTING +#undef UNIT_TESTING +#endif +#include + +#include "dataClassify.h" + +static void +returnsTrue_test1(void **state) +{ + wchar_t wc; + wchar_t *ptr = &wc; + + *ptr = L'一'; + assert_true(*ptr == 0x4e00); + assert_true(is_cjk(*ptr)); + for (int i = 0; i < 10; i++) { + (*ptr)++; + assert_true(is_cjk(*ptr)); + } + UNUSED_PARAM(state); +} + +static void +returnsTrue_test2(void **state) +{ + wchar_t wc; + wchar_t *ptr = &wc; + + *ptr = L'俿'; + assert_true(*ptr == 0x4fff); + assert_true(is_cjk(*ptr)); + for (int i = 0; i < 10; i++) { + (*ptr)++; + assert_true(is_cjk(*ptr)); + } + UNUSED_PARAM(state); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(returnsTrue_test1), + cmocka_unit_test(returnsTrue_test2), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff -Nru swirc-3.4.3/tests/isValid.c swirc-3.4.4/tests/isValid.c --- swirc-3.4.3/tests/isValid.c 1970-01-01 00:00:00.000000000 +0000 +++ swirc-3.4.4/tests/isValid.c 2023-07-29 13:02:03.000000000 +0000 @@ -0,0 +1,110 @@ +#include "common.h" + +#include +#ifdef UNIT_TESTING +#undef UNIT_TESTING +#endif +#include + +#include "dataClassify.h" + +#ifndef HAVE_ETEXT_SEGMENT +#pragma message("Etext segment not present") +#endif + +#define yesno(_b) ((_b) ? "yes" : "no") + +int main(void); + +int global; + +static bool bval; + +static void +isValid_ptrToLocal(void **state) +{ + int local; + + print_message("pointer to local var valid? %s\n", + yesno(isValid(&local))); + UNUSED_PARAM(state); +} + +static void +isValid_ptrToGlobal(void **state) +{ + print_message("pointer to global var valid? %s\n", + yesno(isValid(&global))); + UNUSED_PARAM(state); +} + +static void +isValid_ptrToFn(void **state) +{ + print_message("pointer to function valid? %s\n", + yesno(isValid((void *)main))); + UNUSED_PARAM(state); +} + +static void +isValid_ptrToHeap(void **state) +{ + int *ip = malloc(sizeof *ip); + + print_message("pointer to heap valid? %s\n", yesno(isValid(ip))); + print_message("pointer to end of allocated heap valid? %s\n", + yesno(isValid(++ip))); + free(--ip); + print_message("pointer to freed heap valid? %s\n", yesno(isValid(ip))); + UNUSED_PARAM(state); +} + +static void +isValid_nullPtr(void **state) +{ + bval = isValid(NULL); + print_message("null pointer valid? %s\n", yesno(bval)); + assert_false(bval); + UNUSED_PARAM(state); +} + +static void +isValid_unusualLoc(void **state) +{ + bval = isValid((void *)6); + print_message("unusual location valid? %s\n", yesno(bval)); + UNUSED_PARAM(state); +} + +static void +isValid_emptyStr(void **state) +{ + bval = isValid(""); + print_message("empty string valid? %s\n", yesno(bval)); + UNUSED_PARAM(state); +} + +static void +isValid_fixedStr(void **state) +{ + bval = isValid("foo"); + print_message("fixed string valid? %s\n", yesno(bval)); + UNUSED_PARAM(state); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(isValid_ptrToLocal), + cmocka_unit_test(isValid_ptrToGlobal), + cmocka_unit_test(isValid_ptrToFn), + cmocka_unit_test(isValid_ptrToHeap), + cmocka_unit_test(isValid_nullPtr), + cmocka_unit_test(isValid_unusualLoc), + cmocka_unit_test(isValid_emptyStr), + cmocka_unit_test(isValid_fixedStr), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff -Nru swirc-3.4.3/tests/run swirc-3.4.4/tests/run --- swirc-3.4.3/tests/run 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/tests/run 2023-07-29 13:02:03.000000000 +0000 @@ -16,7 +16,9 @@ icb_send_pm int_diff int_sum +isValid is_alphabetic +is_cjk is_numeric printtext_convert_wc realloc_strcat @@ -24,6 +26,7 @@ size_product squeeze squeeze_text_deco +squeeze_text_deco_wide strColor strFeed strToLower @@ -38,6 +41,7 @@ trim write_to_stream xstrnlen +xwcswidth " for test in $TESTS; do diff -Nru swirc-3.4.3/tests/squeeze_text_deco_wide.c swirc-3.4.4/tests/squeeze_text_deco_wide.c --- swirc-3.4.3/tests/squeeze_text_deco_wide.c 1970-01-01 00:00:00.000000000 +0000 +++ swirc-3.4.4/tests/squeeze_text_deco_wide.c 2023-07-29 13:02:03.000000000 +0000 @@ -0,0 +1,48 @@ +#include "common.h" + +#include +#include + +#include "printtext.h" + +static wchar_t buf[300] = { L'\0' }; + +static void +canSqueezeTextDecoration_test1(void **state) +{ + swprintf(buf, ARRAY_SIZE(buf), L"%c1,2,3,test", COLOR); + squeeze_text_deco_wide(buf); + assert_true(wcscmp(buf, L",3,test") == 0); + UNUSED_PARAM(state); +} + +static void +canSqueezeTextDecoration_test2(void **state) +{ + swprintf(buf, ARRAY_SIZE(buf), L"%c1,234", COLOR); + squeeze_text_deco_wide(buf); + assert_true(wcscmp(buf, L"4") == 0); + UNUSED_PARAM(state); +} + +static void +canSqueezeTextDecoration_test3(void **state) +{ + swprintf(buf, ARRAY_SIZE(buf), L"%c1,1%c2,22foo%c33,3bar", + COLOR, COLOR, COLOR); + squeeze_text_deco_wide(buf); + assert_true(wcscmp(buf, L"foobar") == 0); + UNUSED_PARAM(state); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(canSqueezeTextDecoration_test1), + cmocka_unit_test(canSqueezeTextDecoration_test2), + cmocka_unit_test(canSqueezeTextDecoration_test3), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff -Nru swirc-3.4.3/tests/tests.mk swirc-3.4.4/tests/tests.mk --- swirc-3.4.3/tests/tests.mk 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/tests/tests.mk 2023-07-29 13:02:03.000000000 +0000 @@ -15,7 +15,9 @@ icb_send_pm.run\ int_diff.run\ int_sum.run\ + isValid.run\ is_alphabetic.run\ + is_cjk.run\ is_numeric.run\ printtext_convert_wc.run\ realloc_strcat.run\ @@ -23,6 +25,7 @@ size_product.run\ squeeze.run\ squeeze_text_deco.run\ + squeeze_text_deco_wide.run\ strColor.run\ strFeed.run\ strToLower.run\ @@ -36,4 +39,5 @@ sw_wcscpy.run\ trim.run\ write_to_stream.run\ - xstrnlen.run + xstrnlen.run\ + xwcswidth.run diff -Nru swirc-3.4.3/tests/xwcswidth.c swirc-3.4.4/tests/xwcswidth.c --- swirc-3.4.3/tests/xwcswidth.c 1970-01-01 00:00:00.000000000 +0000 +++ swirc-3.4.4/tests/xwcswidth.c 2023-07-29 13:02:03.000000000 +0000 @@ -0,0 +1,42 @@ +#include "common.h" + +#include +#ifdef UNIT_TESTING +#undef UNIT_TESTING +#endif +#include + +#include "dataClassify.h" + +static int expected = -1; + +static void +test1(void **state) +{ + const wchar_t str[] = L"Ӽe̲̅v̲̅o̲̅l̲̅u̲̅t̲̅i̲̅o̲̅ɳ̲̅ᕗ"; + + expected = 11; + assert_true(xwcswidth(str, 2) == expected); + UNUSED_PARAM(state); +} + +static void +test2(void **state) +{ + const wchar_t str[] = L"你a好b世c界"; + + expected = 11; + assert_true(xwcswidth(str, 2) == expected); + UNUSED_PARAM(state); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test1), + cmocka_unit_test(test2), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff -Nru swirc-3.4.3/VERSION_INFO swirc-3.4.4/VERSION_INFO --- swirc-3.4.3/VERSION_INFO 2023-03-10 15:22:58.000000000 +0000 +++ swirc-3.4.4/VERSION_INFO 2023-07-29 13:02:03.000000000 +0000 @@ -1,5 +1,5 @@ MAJOR_VERSION=3 MINOR_VERSION=4 -PATCHLEVEL=3 +PATCHLEVEL=4 VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${PATCHLEVEL}