- Added curl_easy_getinfo typechecker.
authorMichal Marek <mmarek@suse.cz>
Tue, 18 Mar 2008 08:14:37 +0000 (08:14 +0000)
committerMichal Marek <mmarek@suse.cz>
Tue, 18 Mar 2008 08:14:37 +0000 (08:14 +0000)
- Added macros for curl_share_setopt and curl_multi_setopt to check at least
  the correct number of arguments.

CHANGES
RELEASE-NOTES
include/curl/curl.h
include/curl/typecheck-gcc.h
lib/easy.c
lib/multi.c
lib/share.c

diff --git a/CHANGES b/CHANGES
index 4a42458..f8245c6 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,12 @@
 
                                   Changelog
 
+Michal Marek (18 Mar 2008)
+- Added curl_easy_getinfo typechecker.
+
+- Added macros for curl_share_setopt and curl_multi_setopt to check at least
+  the correct number of arguments.
+
 Daniel Fandrich (13 Mar 2008)
 - Added tests 622-625 to test SFTP/SCP uploads. Test 625 was an attempt to
   reproduce the --ftp-create-dirs problem reported by Brian Ulm, but that
index 02d4c36..64e13b6 100644 (file)
@@ -17,10 +17,11 @@ This release includes the following changes:
  o the test509-style setting URL in callback is officially no longer supported
  o support a full chain of certificates in a given PKCS12 certificate
  o resumed transfers work with SFTP
- o added a type checking macro for curl_easy_setopt(), watch out for new
-   warnings in code using libcurl (needs gcc-4.3 and currently only works
-   in C mode)
- o curl_easy_setopt() uses are now checked to use three arguments
+ o added type checking macros for curl_easy_setopt() and curl_easy_getinfo(),
+   watch out for new warnings in code using libcurl (needs gcc-4.3 and
+   currently only works in C mode)
+ o curl_easy_setopt(), curl_easy_getinfo(), curl_share_setopt() and
+   curl_multi_setopt() uses are now checked to use exactly three arguments
 
 This release includes the following bugfixes:
 
index 4af7142..b4ed5d0 100644 (file)
@@ -1798,9 +1798,12 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #else
 #if defined(__STDC__) && (__STDC__ >= 1) 
 /* This preprocessor magic that replaces a call with the exact same call is
-   only done to make sure application authors use exactly three arguments
-   to this function. */
+   only done to make sure application authors pass exactly three arguments
+   to these functions. */
 #define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
+#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg)
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
 #endif /* __STDC__ >= 1 */
 #endif /* gcc >= 4.3 && !__cplusplus */
 
index c6475b7..969e2bb 100644 (file)
@@ -76,10 +76,10 @@ __extension__ ({                                                              \
     if (_curl_is_postfields_option(_curl_opt) && !_curl_is_postfields(value)) \
       _curl_easy_setopt_err_postfields();                                     \
     if ((_curl_opt) == CURLOPT_HTTPPOST &&                                    \
-            !_curl_is_ptr((value), struct curl_httppost))                     \
+            !_curl_is_arr((value), struct curl_httppost))                     \
       _curl_easy_setopt_err_curl_httpost();                                   \
     if (_curl_is_slist_option(_curl_opt) &&                                   \
-            !_curl_is_ptr((value), struct curl_slist))                        \
+            !_curl_is_arr((value), struct curl_slist))                        \
       _curl_easy_setopt_err_curl_slist();                                     \
     if ((_curl_opt) == CURLOPT_SHARE && !_curl_is_ptr((value), CURLSH))       \
       _curl_easy_setopt_err_CURLSH();                                         \
@@ -87,10 +87,37 @@ __extension__ ({                                                              \
   curl_easy_setopt(handle, _curl_opt, value);                                 \
 })
 
+/* wraps curl_easy_getinfo() with typechecking */
+/* FIXME: don't allow const pointers */
+#define curl_easy_getinfo(handle, info, arg)                                  \
+__extension__ ({                                                              \
+  __typeof__ (info) _curl_info = info;                                        \
+  if (__builtin_constant_p(_curl_info)) {                                     \
+    if (_curl_is_string_info(_curl_info) && !_curl_is_arr((arg), char *))     \
+      _curl_easy_getinfo_err_string();                                        \
+    if (_curl_is_long_info(_curl_info) && !_curl_is_arr((arg), long))         \
+      _curl_easy_getinfo_err_long();                                          \
+    if (_curl_is_double_info(_curl_info) && !_curl_is_arr((arg), double))     \
+      _curl_easy_getinfo_err_double();                                        \
+    if (_curl_is_slist_info(_curl_info) &&                                    \
+           !_curl_is_arr((arg), struct curl_slist *))                         \
+      _curl_easy_getinfo_err_curl_slist();                                    \
+  }                                                                           \
+  curl_easy_getinfo(handle, _curl_info, arg);                                 \
+})
+
+/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(),
+ * for now just make sure that the functions are called with three
+ * arguments
+ */
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+
+
 /* the actual warnings, triggered by calling the _curl_easy_setopt_err*
  * functions */
 
-/* To define a new warning, use _CURL_WARNING(identifier, "message"); */
+/* To define a new warning, use _CURL_WARNING(identifier, "message") */
 #define _CURL_WARNING(id, message)                                            \
   static void __attribute__((warning(message))) __attribute__((unused))       \
   __attribute__((noinline)) id(void) { __asm__(""); }
@@ -136,7 +163,16 @@ _CURL_WARNING(_curl_easy_setopt_err_curl_slist,
 _CURL_WARNING(_curl_easy_setopt_err_CURLSH,
   "curl_easy_setopt expects a CURLSH* argument for this option")
 
-/* groups of options that take the same type of argument */
+_CURL_WARNING(_curl_easy_getinfo_err_string,
+  "curl_easy_getinfo expects a pointer to char * for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_long,
+  "curl_easy_getinfo expects a pointer to long for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_double,
+  "curl_easy_getinfo expects a pointer to double for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
+  "curl_easy_getinfo expects a pointer to struct curl_slist * for this info")
+
+/* groups of curl_easy_setops options that take the same type of argument */
 
 /* To add a new option to one of the groups, just add
  *   (option) == CURLOPT_SOMETHING
@@ -230,13 +266,34 @@ _CURL_WARNING(_curl_easy_setopt_err_CURLSH,
    (option) == CURLOPT_TELNETOPTIONS ||                                       \
    0)
 
+/* groups of curl_easy_getinfo infos that take the same type of argument */
+
+/* evaluates to true if info expects a pointer to char * argument */
+#define _curl_is_string_info(info)                                            \
+  (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG)
+
+/* evaluates to true if info expects a pointer to long argument */
+#define _curl_is_long_info(info)                                              \
+  (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE)
+
+/* evaluates to true if info expects a pointer to double argument */
+#define _curl_is_double_info(info)                                            \
+  (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST)
+
+/* evaluates to true if info expects a pointer to struct curl_slist * argument */
+#define _curl_is_slist_info(info)                                             \
+  (CURLINFO_SLIST < (info))
+
+
 /* typecheck helpers -- check whether given expression has requested type*/
 
-/* For pointers, you can use the _curl_is_ptr macro, otherwise define a new
- * macro. Search for __builtin_types_compatible_p in the GCC manual.  NOTE:
- * these macros MUST NOT EVALUATE their arguments! The argument is the actual
- * expression passed to the curl_easy_setopt macro. This means that you can
- * only apply the sizeof and __typeof__ operators, no == or whatsoever.
+/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros,
+ * otherwise define a new macro. Search for __builtin_types_compatible_p
+ * in the GCC manual.
+ * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is
+ * the actual expression passed to the curl_easy_setopt macro. This
+ * means that you can only apply the sizeof and __typeof__ operators, no
+ * == or whatsoever.
  */
 
 /* XXX: should evaluate to true iff expr is a pointer */
index 018aeab..cfa6c41 100644 (file)
@@ -548,6 +548,7 @@ void Curl_easy_initHandleData(struct SessionHandle *data)
  * curl_easy_getinfo() is an external interface that allows an app to retrieve
  * information from a performed transfer and similar.
  */
+#undef curl_easy_getinfo
 CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
 {
   va_list arg;
index a29b6a0..73e8e7e 100644 (file)
@@ -1778,6 +1778,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
   return result;
 }
 
+#undef curl_multi_setopt
 CURLMcode curl_multi_setopt(CURLM *multi_handle,
                             CURLMoption option, ...)
 {
index eb2ee78..3a5f072 100644 (file)
@@ -46,6 +46,7 @@ curl_share_init(void)
   return share;
 }
 
+#undef curl_share_setopt
 CURLSHcode
 curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
 {