From 92daae473e43264d86c4fd1d863d8b03fb897482 Mon Sep 17 00:00:00 2001 From: Jordan Lee Date: Mon, 23 Jun 2014 02:38:53 +0000 Subject: [PATCH] mike.dld's portability improvements to libtransmission, pt 1 --- Transmission.xcodeproj/project.pbxproj | 8 + libtransmission/Makefile.am | 7 + libtransmission/error-test.c | 95 ++++++++++++ libtransmission/error.c | 198 +++++++++++++++++++++++++ libtransmission/error.h | 178 ++++++++++++++++++++++ libtransmission/utils-test.c | 58 ++++++++ libtransmission/utils.c | 26 ++-- libtransmission/utils.h | 3 + 8 files changed, 557 insertions(+), 16 deletions(-) create mode 100644 libtransmission/error-test.c create mode 100644 libtransmission/error.c create mode 100644 libtransmission/error.h diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 7725acd41..c73e3ba08 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -458,6 +458,8 @@ BEFC1E560C07861A00B0BB3C /* completion.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E1D0C07861A00B0BB3C /* completion.c */; }; BEFC1E570C07861A00B0BB3C /* clients.h in Headers */ = {isa = PBXBuildFile; fileRef = BEFC1E1E0C07861A00B0BB3C /* clients.h */; }; BEFC1E580C07861A00B0BB3C /* clients.c in Sources */ = {isa = PBXBuildFile; fileRef = BEFC1E1F0C07861A00B0BB3C /* clients.c */; }; + C1077A4E183EB29600634C22 /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = C1077A4A183EB29600634C22 /* error.c */; }; + C1077A4F183EB29600634C22 /* error.h in Headers */ = {isa = PBXBuildFile; fileRef = C1077A4B183EB29600634C22 /* error.h */; }; D4AF3B2F0C41F7A500D46B6B /* list.c in Sources */ = {isa = PBXBuildFile; fileRef = D4AF3B2D0C41F7A500D46B6B /* list.c */; }; D4AF3B300C41F7A600D46B6B /* list.h in Headers */ = {isa = PBXBuildFile; fileRef = D4AF3B2E0C41F7A500D46B6B /* list.h */; }; E138A9780C04D88F00C5426C /* ProgressGradients.m in Sources */ = {isa = PBXBuildFile; fileRef = E138A9760C04D88F00C5426C /* ProgressGradients.m */; }; @@ -1192,6 +1194,8 @@ BEFC1E1D0C07861A00B0BB3C /* completion.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = completion.c; path = libtransmission/completion.c; sourceTree = ""; }; BEFC1E1E0C07861A00B0BB3C /* clients.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = clients.h; path = libtransmission/clients.h; sourceTree = ""; }; BEFC1E1F0C07861A00B0BB3C /* clients.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = clients.c; path = libtransmission/clients.c; sourceTree = ""; }; + C1077A4A183EB29600634C22 /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = error.c; path = libtransmission/error.c; sourceTree = ""; }; + C1077A4B183EB29600634C22 /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = error.h; path = libtransmission/error.h; sourceTree = ""; }; D4AF3B2D0C41F7A500D46B6B /* list.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = list.c; path = libtransmission/list.c; sourceTree = ""; }; D4AF3B2E0C41F7A500D46B6B /* list.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = list.h; path = libtransmission/list.h; sourceTree = ""; }; E138A9750C04D88F00C5426C /* ProgressGradients.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ProgressGradients.h; path = macosx/ProgressGradients.h; sourceTree = ""; }; @@ -1646,6 +1650,8 @@ 4D1838DC09DEC04A0047D688 /* libtransmission */ = { isa = PBXGroup; children = ( + C1077A4A183EB29600634C22 /* error.c */, + C1077A4B183EB29600634C22 /* error.h */, 4D80185710BBC0B0008A4AF2 /* magnet.c */, 4D80185810BBC0B0008A4AF2 /* magnet.h */, 4D8017E810BBC073008A4AF2 /* torrent-magnet.c */, @@ -2083,6 +2089,7 @@ A220EC5C118C8A060022B4BE /* tr-lpd.h in Headers */, A23547E311CD0B090046EAE6 /* cache.h in Headers */, A284214512DA663E00FBDDBB /* tr-udp.h in Headers */, + C1077A4F183EB29600634C22 /* error.h in Headers */, A2679295130E00A000CB7464 /* tr-utp.h in Headers */, A23F29A1132A447400E9A83B /* announcer-common.h in Headers */, A2EE726F14DCCC950093C99A /* natpmp_local.h in Headers */, @@ -2657,6 +2664,7 @@ BEFC1E3C0C07861A00B0BB3C /* platform.c in Sources */, BEFC1E460C07861A00B0BB3C /* net.c in Sources */, BEFC1E480C07861A00B0BB3C /* natpmp.c in Sources */, + C1077A4E183EB29600634C22 /* error.c in Sources */, BEFC1E4A0C07861A00B0BB3C /* metainfo.c in Sources */, BEFC1E4F0C07861A00B0BB3C /* inout.c in Sources */, BEFC1E530C07861A00B0BB3C /* fdlimit.c in Sources */, diff --git a/libtransmission/Makefile.am b/libtransmission/Makefile.am index f526bd01b..4a66d9611 100644 --- a/libtransmission/Makefile.am +++ b/libtransmission/Makefile.am @@ -28,6 +28,7 @@ libtransmission_a_SOURCES = \ completion.c \ ConvertUTF.c \ crypto.c \ + error.c \ fdlimit.c \ handshake.c \ history.c \ @@ -82,6 +83,7 @@ noinst_HEADERS = \ ConvertUTF.h \ crypto.h \ completion.h \ + error.h \ fdlimit.h \ handshake.h \ history.h \ @@ -133,6 +135,7 @@ TESTS = \ blocklist-test \ clients-test \ crypto-test \ + error-test \ history-test \ json-test \ magnet-test \ @@ -184,6 +187,10 @@ crypto_test_SOURCES = crypto-test.c $(TEST_SOURCES) crypto_test_LDADD = ${apps_ldadd} crypto_test_LDFLAGS = ${apps_ldflags} +error_test_SOURCES = error-test.c $(TEST_SOURCES) +error_test_LDADD = ${apps_ldadd} +error_test_LDFLAGS = ${apps_ldflags} + history_test_SOURCES = history-test.c $(TEST_SOURCES) history_test_LDADD = ${apps_ldadd} history_test_LDFLAGS = ${apps_ldflags} diff --git a/libtransmission/error-test.c b/libtransmission/error-test.c new file mode 100644 index 000000000..0a5e3ce21 --- /dev/null +++ b/libtransmission/error-test.c @@ -0,0 +1,95 @@ +/* + * This file Copyright (C) 2013-2014 Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + * $Id$ + */ + +#include "transmission.h" +#include "error.h" + +#include "libtransmission-test.h" + +static int +test_error_set (void) +{ + tr_error * err = NULL; + +#if 0 + + tr_error_prefix (&err, "error: "); + check (err == NULL); + +#endif /* 0 */ + + tr_error_set (&err, 1, "error: %s (%d)", "oops", 2); + check (err != NULL); + check_int_eq (1, err->code); + check_streq ("error: oops (2)", err->message); + tr_error_clear (&err); + check (err == NULL); + + tr_error_set_literal (&err, 2, "oops"); + check (err != NULL); + check_int_eq (2, err->code); + check_streq ("oops", err->message); + +#if 0 + + tr_error_prefix (&err, "error: "); + check (err != NULL); + check_int_eq (2, err->code); + check_streq ("error: oops", err->message); + +#endif /* 0 */ + + tr_error_free (err); + + return 0; +} + +static int +test_error_propagate (void) +{ + tr_error * err = NULL; + tr_error * err2 = NULL; + + tr_error_set_literal (&err, 1, "oops"); + check (err != NULL); + check_int_eq (1, err->code); + check_streq ("oops", err->message); + + tr_error_propagate (&err2, &err); + check (err2 != NULL); + check_int_eq (1, err2->code); + check_streq ("oops", err2->message); + check (err == NULL); + +#if 0 + + tr_error_propagate_prefixed (&err, &err2, "error: "); + check (err != NULL); + check_int_eq (1, err->code); + check_streq ("error: oops", err->message); + check (err2 == NULL); + + tr_error_propagate (NULL, &err); + check (err == NULL); + +#endif /* 0 */ + + tr_error_free (err2); + + return 0; +} + +int +main (void) +{ + const testFunc tests[] = { test_error_set, + test_error_propagate }; + + return runTests (tests, NUM_TESTS (tests)); +} diff --git a/libtransmission/error.c b/libtransmission/error.c new file mode 100644 index 000000000..6557b8049 --- /dev/null +++ b/libtransmission/error.c @@ -0,0 +1,198 @@ +/* + * This file Copyright (C) 2013-2014 Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + * $Id$ + */ + +#include + +#include "transmission.h" +#include "error.h" +#include "utils.h" + +tr_error * +tr_error_new (int code, + const char * message_format, + ...) +{ + tr_error * error; + va_list args; + + assert (message_format != NULL); + + va_start (args, message_format); + error = tr_error_new_valist (code, message_format, args); + va_end (args); + + return error; +} + +tr_error * +tr_error_new_literal (int code, + const char * message) +{ + tr_error * error; + + assert (message != NULL); + + error = tr_new (tr_error, 1); + error->code = code; + error->message = tr_strdup (message); + + return error; +} + +tr_error * +tr_error_new_valist (int code, + const char * message_format, + va_list args) +{ + tr_error * error; + + assert (message_format != NULL); + + error = tr_new (tr_error, 1); + error->code = code; + error->message = tr_strdup_vprintf (message_format, args); + + return error; +} + +void +tr_error_free (tr_error * error) +{ + if (error == NULL) + return; + + tr_free (error->message); + tr_free (error); +} + +void +tr_error_set (tr_error ** error, + int code, + const char * message_format, + ...) +{ + va_list args; + + if (error == NULL) + return; + + assert (*error == NULL); + assert (message_format != NULL); + + va_start (args, message_format); + *error = tr_error_new_valist (code, message_format, args); + va_end (args); +} + +void +tr_error_set_literal (tr_error ** error, + int code, + const char * message) +{ + if (error == NULL) + return; + + assert (*error == NULL); + assert (message != NULL); + + *error = tr_error_new_literal (code, message); +} + +void +tr_error_propagate (tr_error ** new_error, + tr_error ** old_error) +{ + assert (old_error != NULL); + assert (*old_error != NULL); + + if (new_error != NULL) + { + assert (*new_error == NULL); + + *new_error = *old_error; + *old_error = NULL; + } + else + { + tr_error_clear (old_error); + } +} + +void +tr_error_clear (tr_error ** error) +{ + if (error == NULL) + return; + + tr_error_free (*error); + + *error = NULL; +} + +#if 0 + +static void +error_prefix_valist (tr_error ** error, + const char * prefix_format, + va_list args) +{ + char * prefix; + char * new_message; + + assert (error != NULL); + assert (*error != NULL); + assert (prefix_format != NULL); + + prefix = tr_strdup_vprintf (prefix_format, args); + + new_message = tr_strdup_printf ("%s%s", prefix, (*error)->message); + tr_free ((*error)->message); + (*error)->message = new_message; + + tr_free (prefix); +} + +void +tr_error_prefix (tr_error ** error, + const char * prefix_format, + ...) +{ + va_list args; + + assert (prefix_format != NULL); + + if (error == NULL || *error == NULL) + return; + + va_start (args, prefix_format); + error_prefix_valist (error, prefix_format, args); + va_end (args); +} + +void +tr_error_propagate_prefixed (tr_error ** new_error, + tr_error ** old_error, + const char * prefix_format, + ...) +{ + va_list args; + + assert (prefix_format != NULL); + + tr_error_propagate (new_error, old_error); + + if (new_error == NULL) + return; + + va_start (args, prefix_format); + error_prefix_valist (new_error, prefix_format, args); + va_end (args); +} + +#endif /* 0 */ diff --git a/libtransmission/error.h b/libtransmission/error.h new file mode 100644 index 000000000..d300f6a7a --- /dev/null +++ b/libtransmission/error.h @@ -0,0 +1,178 @@ +/* + * This file Copyright (C) 2013-2014 Mnemosyne LLC + * + * It may be used under the GNU GPL versions 2 or 3 + * or any future license endorsed by Mnemosyne LLC. + * + * $Id$ + */ + +#ifndef TR_ERROR_H +#define TR_ERROR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef TR_GNUC_PRINTF + #ifdef __GNUC__ + #define TR_GNUC_PRINTF(fmt, args) __attribute__ ((format (printf, fmt, args))) + #else + #define TR_GNUC_PRINTF(fmt, args) + #endif +#endif + +/** + * @addtogroup error Error reporting + * @{ + */ + +/** @brief Structure holding error information. */ +typedef struct tr_error +{ + /** @brief Error code, platform-specific */ + int code; + /** @brief Error message */ + char * message; +} +tr_error; + +/** + * @brief Create new error object using `printf`-style formatting. + * + * @param[in] code Error code (platform-specific). + * @param[in] message_format Error message format string. + * @param[in] ... Format arguments. + * + * @return Newly allocated error object on success, `NULL` otherwise. + */ +tr_error * tr_error_new (int code, + const char * message_format, + ...) TR_GNUC_PRINTF (2, 3); + +/** + * @brief Create new error object using literal error message. + * + * @param[in] code Error code (platform-specific). + * @param[in] message Error message. + * + * @return Newly allocated error object on success, `NULL` otherwise. + */ +tr_error * tr_error_new_literal (int code, + const char * message); + +/** + * @brief Create new error object using `vprintf`-style formatting. + * + * @param[in] code Error code (platform-specific). + * @param[in] message_format Error message format string. + * @param[in] args Format arguments. + * + * @return Newly allocated error object on success, `NULL` otherwise. + */ +tr_error * tr_error_new_valist (int code, + const char * message_format, + va_list args); + +/** + * @brief Free memory used by error object. + * + * @param[in] error Error object to be freed. + */ +void tr_error_free (tr_error * error); + +/** + * @brief Create and set new error object using `printf`-style formatting. + * + * If passed pointer to error object is `NULL`, do nothing. + * + * @param[in,out] error Pointer to error object to be set. + * @param[in] code Error code (platform-specific). + * @param[in] message_format Error message format string. + * @param[in] ... Format arguments. + */ +void tr_error_set (tr_error ** error, + int code, + const char * message_format, + ...) TR_GNUC_PRINTF (3, 4); + +/** + * @brief Create and set new error object using literal error message. + * + * If passed pointer to error object is `NULL`, do nothing. + * + * @param[in,out] error Pointer to error object to be set. + * @param[in] code Error code (platform-specific). + * @param[in] message Error message. + */ +void tr_error_set_literal (tr_error ** error, + int code, + const char * message); + +/** + * @brief Propagate existing error object upwards. + * + * If passed pointer to new error object is not `NULL`, copy old error object to + * new error object and free old error object. Otherwise, just free old error + * object. + * + * @param[in,out] new_error Pointer to error object to be set. + * @param[in,out] old_error Error object to be propagated. Cleared on return. + */ +void tr_error_propagate (tr_error ** new_error, + tr_error ** old_error); + +/** + * @brief Clear error object. + * + * Free error object being pointed and set pointer to `NULL`. If passed pointer + * is `NULL`, do nothing. + * + * @param[in,out] error Pointer to error object to be cleared. + */ +void tr_error_clear (tr_error ** error); + +#if 0 + +/** + * @brief Prefix message of exising error object. + * + * If passed pointer to error object is not `NULL`, prefix its message with + * `printf`-style formatted text. Otherwise, do nothing. + * + * @param[in,out] error Pointer to error object to be set. + * @param[in] prefix_format Prefix format string. + * @param[in] ... Format arguments. + */ +void tr_error_prefix (tr_error ** error, + const char * prefix_format, + ...) TR_GNUC_PRINTF (2, 3); + +/** + * @brief Prefix message and propagate existing error object upwards. + * + * If passed pointer to new error object is not `NULL`, copy old error object to + * new error object, prefix its message with `printf`-style formatted text, and + * free old error object. Otherwise, just free old error object. + * + * @param[in,out] new_error Pointer to error object to be set. + * @param[in,out] old_error Error object to be propagated. Cleared on return. + * @param[in] prefix_format Prefix format string. + * @param[in] ... Format arguments. + */ +void tr_error_propagate_prefixed (tr_error ** new_error, + tr_error ** old_error, + const char * prefix_format, + ...) TR_GNUC_PRINTF (3, 4); + +#endif /* 0 */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libtransmission/utils-test.c b/libtransmission/utils-test.c index 57179969e..9f33e8b15 100644 --- a/libtransmission/utils-test.c +++ b/libtransmission/utils-test.c @@ -421,6 +421,63 @@ test_cryptoRand (void) return 0; } +static char * +test_strdup_printf_valist (const char * fmt, ...) +{ + va_list args; + char * ret; + + va_start (args, fmt); + ret = tr_strdup_vprintf (fmt, args); + va_end (args); + + return ret; +} + +static int +test_strdup_printf (void) +{ + char * s, * s2, * s3; + + s = tr_strdup_printf ("%s", "test"); + check_streq ("test", s); + tr_free (s); + + s = tr_strdup_printf ("%d %s %c %u", -1, "0", '1', 2); + check_streq ("-1 0 1 2", s); + tr_free (s); + + s3 = tr_malloc0 (4098); + memset (s3, '-', 4097); + s3[2047] = 't'; + s3[2048] = 'e'; + s3[2049] = 's'; + s3[2050] = 't'; + + s2 = tr_malloc0 (4096); + memset (s2, '-', 4095); + s2[2047] = '%'; + s2[2048] = 's'; + + s = tr_strdup_printf (s2, "test"); + check_streq (s3, s); + tr_free (s); + + tr_free (s2); + + s = tr_strdup_printf ("%s", s3); + check_streq (s3, s); + tr_free (s); + + tr_free (s3); + + s = test_strdup_printf_valist ("\n-%s-%s-%s-\n", "\r", "\t", "\b"); + check_streq ("\n-\r-\t-\b-\n", s); + tr_free (s); + + return 0; +} + int main (void) { @@ -434,6 +491,7 @@ main (void) test_memmem, test_numbers, test_strip_positional_args, + test_strdup_printf, test_strstrip, test_truncd, test_url, diff --git a/libtransmission/utils.c b/libtransmission/utils.c index 413639633..41ccc8571 100644 --- a/libtransmission/utils.c +++ b/libtransmission/utils.c @@ -24,7 +24,6 @@ #include /* DBL_EPSILON */ #include /* localeconv () */ #include /* pow (), fabs (), floor () */ -#include #include #include #include /* strerror (), memset (), memmem () */ @@ -602,28 +601,23 @@ tr_strdup_printf (const char * fmt, ...) { va_list ap; char * ret; - size_t len; - char statbuf[2048]; va_start (ap, fmt); - len = evutil_vsnprintf (statbuf, sizeof (statbuf), fmt, ap); + ret = tr_strdup_vprintf (fmt, ap); va_end (ap); - if (len < sizeof (statbuf)) - { - ret = tr_strndup (statbuf, len); - } - else - { - ret = tr_new (char, len + 1); - va_start (ap, fmt); - evutil_vsnprintf (ret, len + 1, fmt, ap); - va_end (ap); - } - return ret; } +char * +tr_strdup_vprintf (const char * fmt, + va_list args) +{ + struct evbuffer * buf = evbuffer_new (); + evbuffer_add_vprintf (buf, fmt, args); + return evbuffer_free_to_str (buf); +} + const char* tr_strerror (int i) { diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 0ae3edccf..4c9947687 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -11,6 +11,7 @@ #define TR_UTILS_H 1 #include +#include #include /* size_t */ #include /* time_t */ @@ -267,6 +268,8 @@ void tr_quickfindFirstK (void * base, size_t nmemb, size_t size, */ char* tr_strdup_printf (const char * fmt, ...) TR_GNUC_PRINTF (1, 2) TR_GNUC_MALLOC; +char * tr_strdup_vprintf (const char * fmt, + va_list args) TR_GNUC_MALLOC; /** * @brief Translate a block of bytes into base64