Author: aconway
Date: Fri Jun  6 00:31:21 2014
New Revision: 1600797

URL: http://svn.apache.org/r1600797
Log:
NO-JIRA: Error handling mechanism for dispatch.

errno-like error handling mechanism for dispatch but thread safe and
includes printf-style string error message.

See comments in error.h for details.

Added error handling to qd_message_check and additional logging
in message.c and agent.c.

New code should use this mechanism where appropriate, old code
can be refactored as we go.

Added:
    qpid/dispatch/trunk/src/error.c   (with props)
    qpid/dispatch/trunk/src/static_assert.h
      - copied, changed from r1600796, 
qpid/dispatch/trunk/include/qpid/dispatch/error.h
Modified:
    qpid/dispatch/trunk/CMakeLists.txt
    qpid/dispatch/trunk/include/qpid/dispatch/error.h
    qpid/dispatch/trunk/src/agent.c
    qpid/dispatch/trunk/src/dispatch.c
    qpid/dispatch/trunk/src/message.c

Modified: qpid/dispatch/trunk/CMakeLists.txt
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/CMakeLists.txt?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/CMakeLists.txt (original)
+++ qpid/dispatch/trunk/CMakeLists.txt Fri Jun  6 00:31:21 2014
@@ -115,6 +115,7 @@ set(server_SOURCES
     src/amqp.c
     src/bitmask.c
     src/buffer.c
+    src/error.c
     src/compose.c
     src/config.c
     src/connection_manager.c

Modified: qpid/dispatch/trunk/include/qpid/dispatch/error.h
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/include/qpid/dispatch/error.h?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/include/qpid/dispatch/error.h (original)
+++ qpid/dispatch/trunk/include/qpid/dispatch/error.h Fri Jun  6 00:31:21 2014
@@ -8,9 +8,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *   http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,11 +19,52 @@
  * under the License.
  */
 
+/** @file
+ * Thread-safe error handling mechansim for dispatch.
+ *
+ * Functions that detect an error should return qd_error_t.
+ *
+ * Implementation of such functions should first call qd_error_clear()
+ * to clear any previous error and on detecting an error do:
+ *     return qd_error(code, "printf format", ...)
+ *
+ * The caller can check the error code and message with
+ * qd_error_code() and qd_error_message().
+ *
+ *
+ */
+// NOTE: If you modify this enum, you must update error_names in error.c
 typedef enum {
     QD_ERROR_NONE = 0,
     QD_ERROR_NOT_FOUND,
     QD_ERROR_ALREADY_EXISTS,
-    QD_ERROR_ALLOC
+    QD_ERROR_ALLOC,
+    QD_ERROR_MESSAGE,           ///< Error parsing a message.
+
+    QD_ERROR_COUNT              ///< Not an error, marks the end of the enum
 } qd_error_t;
 
+/**
+ * Store thread-local error code and message.
+ *@param code Error code. If 0 this is equivalent to calling qd_error_clear()
+ *@param fmt printf-stlye format.
+ *@return code
+ */
+qd_error_t qd_error(qd_error_t code, const char *fmt, ...);
+
+/**
+ * Clear thread-local error code and message.
+ */
+void qd_error_clear();
+
+/**
+ * @return Thread local error message. Includes text for error code.
+ */
+const char* qd_error_message();
+
+/**
+ *@return Thread local error code
+ */
+qd_error_t qd_error_code();
+
 #endif

Modified: qpid/dispatch/trunk/src/agent.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/agent.c?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/agent.c (original)
+++ qpid/dispatch/trunk/src/agent.c Fri Jun  6 00:31:21 2014
@@ -82,6 +82,9 @@ typedef enum {
     QD_DISCOVER_OPERATIONS
 } qd_discover_t;
 
+// Convenience for logging, expects agent to be defined.
+#define LOG(LEVEL, MSG, ...) qd_log(agent->log_source, QD_LOG_##LEVEL, MSG, 
##__VA_ARGS__)
+
 
 static const char *AGENT_ADDRESS       = "$management";
 static const char *STATUS_CODE         = "statusCode";
@@ -520,7 +523,7 @@ static void qd_agent_process_agent_query
             const char *class_name = (const char*) 
qd_hash_key_by_handle(cls->hash_handle);
 
             //
-            // If entityType was provided to restrict the result, check to see 
if the 
+            // If entityType was provided to restrict the result, check to see 
if the
             // class is in the restricted set.
             //
             if (etype && !qd_field_iterator_equal(qd_parse_raw(etype), 
(unsigned char*) class_name))
@@ -592,23 +595,28 @@ static void qd_agent_process_request(qd_
     //
     // Parse the message through the body and exit if the message is not well 
formed.
     //
-    if (!qd_message_check(msg, QD_DEPTH_BODY))
-        return;
+    if (!qd_message_check(msg, QD_DEPTH_BODY)) {
+       LOG(ERROR, "Bad request: %s", qd_error_message());
+       return;
+    }
 
     //
     // Get an iterator for the application-properties.  Exit if the message 
has none.
     //
     qd_field_iterator_t *ap = qd_message_field_iterator(msg, 
QD_FIELD_APPLICATION_PROPERTIES);
-    if (ap == 0)
-        return;
+    if (ap == 0) {
+       LOG(ERROR, "Bad request: no application-properties");
+       return;
+    }
 
     //
     // Get an iterator for the reply-to.  Exit if not found.
     //
     qd_field_iterator_t *reply_to = qd_message_field_iterator(msg, 
QD_FIELD_REPLY_TO);
-    if (reply_to == 0)
+    if (reply_to == 0) {
+       LOG(ERROR, "Bad request: no reply-to");
         return;
-
+    }
     //
     // Try to get a map-view of the application-properties.
     //
@@ -616,6 +624,7 @@ static void qd_agent_process_request(qd_
     if (map == 0) {
         qd_field_iterator_free(ap);
         qd_field_iterator_free(reply_to);
+       LOG(ERROR, "Bad request: application-properties not a map");
         return;
     }
 
@@ -626,6 +635,7 @@ static void qd_agent_process_request(qd_
         qd_field_iterator_free(ap);
         qd_field_iterator_free(reply_to);
         qd_parse_free(map);
+       LOG(ERROR, "Bad request: application-properties not a map");
         return;
     }
 
@@ -885,4 +895,3 @@ void *qd_agent_raise_event(qd_dispatch_t
 {
     return 0;
 }
-

Modified: qpid/dispatch/trunk/src/dispatch.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/dispatch.c?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/dispatch.c (original)
+++ qpid/dispatch/trunk/src/dispatch.c Fri Jun  6 00:31:21 2014
@@ -42,7 +42,7 @@ void            qd_router_setup_late(qd_
 void            qd_router_free(qd_router_t *router);
 qd_agent_t     *qd_agent(qd_dispatch_t *qd);
 void            qd_agent_free(qd_agent_t *agent);
-
+void            qd_error_initialize();
 
 static const char *CONF_CONTAINER   = "container";
 static const char *CONF_ROUTER      = "router";
@@ -56,7 +56,8 @@ qd_dispatch_t *qd_dispatch(const char *p
 
     // alloc and log has to be initialized before any module.
     qd_alloc_initialize();
-    qd_log_initialize(); 
+    qd_log_initialize();
+    qd_error_initialize();
 
     qd->router_area = strdup("0");
     qd->router_id   = strdup("0");

Added: qpid/dispatch/trunk/src/error.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/error.c?rev=1600797&view=auto
==============================================================================
--- qpid/dispatch/trunk/src/error.c (added)
+++ qpid/dispatch/trunk/src/error.c Fri Jun  6 00:31:21 2014
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <qpid/dispatch/error.h>
+#include <qpid/dispatch/log.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include "static_assert.h"
+
+static const char *error_names[] = {
+ "No Error",
+ "Not found",
+ "Already exists",
+ "Allocation",
+ "Invalid message"
+};
+
+STATIC_ASSERT(sizeof(error_names)/sizeof(error_names[0]) == QD_ERROR_COUNT, 
error_names_wrong_size);
+
+#define ERROR_MAX 512
+
+static __thread char error_message[ERROR_MAX];
+static __thread qd_error_t error_code = 0;
+static qd_log_source_t* log_source = 0;
+
+void qd_error_initialize() {
+    log_source = qd_log_source("ERROR");
+}
+
+qd_error_t qd_error(qd_error_t code, const char *fmt, ...) {
+    error_code = code;
+    if (code) {
+       int i = 0;
+       if (code < QD_ERROR_COUNT)
+           i = snprintf(error_message, ERROR_MAX,"%s: ", error_names[code]);
+       else
+           i = snprintf(error_message, ERROR_MAX, "%d: ", code);
+       va_list arglist;
+       va_start(arglist, fmt);
+       vsnprintf(error_message+i, ERROR_MAX-i, fmt, arglist);
+       va_end(arglist);
+       qd_log(log_source, QD_LOG_TRACE, "%s", qd_error_message());
+       return code;
+    }
+    else
+       qd_error_clear();
+    return 0;
+}
+
+void qd_error_clear() {
+    error_code = 0;
+    error_message[0] = '\0';
+}
+
+const char* qd_error_message() {
+    return error_message;
+}
+
+qd_error_t qd_error_code() {
+    return error_code;
+}

Propchange: qpid/dispatch/trunk/src/error.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: qpid/dispatch/trunk/src/error.c
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: qpid/dispatch/trunk/src/message.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/message.c?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/message.c (original)
+++ qpid/dispatch/trunk/src/message.c Fri Jun  6 00:31:21 2014
@@ -18,6 +18,7 @@
  */
 
 #include <qpid/dispatch/ctools.h>
+#include <qpid/dispatch/error.h>
 #include <qpid/dispatch/amqp.h>
 #include <qpid/dispatch/threading.h>
 #include <qpid/dispatch/iterator.h>
@@ -27,6 +28,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <stdio.h>
+#include <limits.h>
 
 static const unsigned char * const MSG_HDR_LONG                 = (unsigned 
char*) "\x00\x80\x00\x00\x00\x00\x00\x00\x00\x70";
 static const unsigned char * const MSG_HDR_SHORT                = (unsigned 
char*) "\x00\x53\x70";
@@ -64,6 +66,7 @@ void qd_message_initialize() {
 
 int qd_message_repr_len() { return qd_log_max_len(); }
 
+// Quote non-printable characters suitable for log messages. Output in buffer.
 static int quote(char* bytes, int n, char* buffer, int len) {
     int i = 0;
     for (char* p = bytes; p < bytes+n && i < len; ++p) {
@@ -78,29 +81,36 @@ static int quote(char* bytes, int n, cha
     return i;
 }
 
-/* TODO aconway 2014-05-13: more detailed message representation. */
-char* qd_message_repr(qd_message_t *msg, char* buffer, size_t len) {
-    qd_message_check(msg, QD_DEPTH_BODY);
+/** Copy a message field for use in log messages. Output in buffer. */
+static int copy_field(qd_message_t *msg,  int field, int max, char *pre, char 
*post, char *buffer, size_t len) {
+    qd_field_iterator_t* iter =        qd_message_field_iterator(msg, field);
     int i = 0;
-    --len;                     /* Save space for final '\0' */
-    i += snprintf(buffer+i, len-i, "Message(%p){to=", msg);
-    qd_field_iterator_t* iter =        0;
-    iter = qd_message_field_iterator(msg, QD_FIELD_TO);
     if (iter) {
-       i += qd_field_iterator_ncopy(iter, (unsigned char*)buffer+i, len-i);
-       qd_field_iterator_free(iter);
-    }
-    iter = qd_message_field_iterator(msg, QD_FIELD_BODY);
-    if (iter) {
-       i += snprintf(buffer+i, len-i, " body='");
-       char body[8];           /* Initial bytes of body */
-       int bytes = qd_field_iterator_ncopy(iter, (unsigned char*)body, 
sizeof(body));
-       i += quote(body, bytes, buffer+i, len-i);
-       i += snprintf(buffer+i, len-i, "'");
+       i += snprintf(buffer+i, len-i, "%s", pre);
+       qd_field_iterator_reset(iter);
+       for (int j = 0; !qd_field_iterator_end(iter) && i < len && j < max; 
++j) {
+           char byte = qd_field_iterator_octet(iter);
+           i += quote(&byte, 1, buffer+i, len-i);
+       }
+       i += snprintf(buffer+i, len-i, "%s", post);
     }
-    i += snprintf(buffer+i, len-i, "}");
+    return i;
+}
+
+static const char REPR_END[] = "}\0";
+
+/* TODO aconway 2014-05-13: more detailed message representation. */
+char* qd_message_repr(qd_message_t *msg, char* buffer, size_t len) {
+    int i = 0;
+    len -= sizeof(REPR_END);   /* Save space for ending */
+    i += snprintf(buffer+i, len-i, "Message(%p){", msg);
+    if (!qd_message_check(msg, QD_DEPTH_BODY))
+       i += snprintf(buffer+i, len-i, "<%s>", qd_error_message());
+    i += copy_field(msg, QD_FIELD_TO, INT_MAX, " to='", "'", buffer+i, len-i);
+    i += copy_field(msg, QD_FIELD_REPLY_TO, INT_MAX, " reply-to='", "'", 
buffer+i, len-i);
+    i += copy_field(msg, QD_FIELD_BODY, 16, " body='", "'", buffer+i, len-i);
     assert(i <= len);
-    buffer[i] = '\0';
+    strcat(buffer, REPR_END);  /* We saved space at the beginning. */
     return buffer;
 }
 
@@ -705,8 +715,10 @@ void qd_message_send(qd_message_t *in_ms
         // Start by making sure that we've parsed the message sections through
         // the message annotations
         //
-        if (!qd_message_check(in_msg, QD_DEPTH_MESSAGE_ANNOTATIONS))
+        if (!qd_message_check(in_msg, QD_DEPTH_MESSAGE_ANNOTATIONS)) {
+           qd_log(log_source, QD_LOG_ERROR, "Cannot send: %s", 
qd_error_message);
             return;
+       }
 
         //
         // Send header if present
@@ -777,15 +789,18 @@ static int qd_check_field_LH(qd_message_
 }
 
 
-static int qd_message_check_LH(qd_message_content_t *content, 
qd_message_depth_t depth)
+static bool qd_message_check_LH(qd_message_content_t *content, 
qd_message_depth_t depth)
 {
+    qd_error_clear();
     qd_buffer_t *buffer  = DEQ_HEAD(content->buffers);
 
-    if (!buffer)
-        return 0; // Invalid - No data in the message
+    if (!buffer) {
+       qd_error(QD_ERROR_MESSAGE, "No data");
+       return false;
+    }
 
     if (depth <= content->parse_depth)
-        return 1; // We've already parsed at least this deep
+        return true; // We've already parsed at least this deep
 
     if (content->parse_buffer == 0) {
         content->parse_buffer = buffer;
@@ -793,52 +808,62 @@ static int qd_message_check_LH(qd_messag
     }
 
     if (depth == QD_DEPTH_NONE)
-        return 1;
+        return true;
 
     //
     // MESSAGE HEADER
     //
     if (0 == qd_check_field_LH(content, QD_DEPTH_HEADER,
-                               MSG_HDR_LONG, MSG_HDR_SHORT, TAGS_LIST, 
&content->section_message_header, 0))
-        return 0;
+                               MSG_HDR_LONG, MSG_HDR_SHORT, TAGS_LIST, 
&content->section_message_header, 0)) {
+       qd_error(QD_ERROR_MESSAGE, "Invalid header");
+           return false;
+    }
     if (depth == QD_DEPTH_HEADER)
-        return 1;
+        return true;
 
     //
     // DELIVERY ANNOTATION
     //
     if (0 == qd_check_field_LH(content, QD_DEPTH_DELIVERY_ANNOTATIONS,
-                               DELIVERY_ANNOTATION_LONG, 
DELIVERY_ANNOTATION_SHORT, TAGS_MAP, &content->section_delivery_annotation, 0))
-        return 0;
+                               DELIVERY_ANNOTATION_LONG, 
DELIVERY_ANNOTATION_SHORT, TAGS_MAP, &content->section_delivery_annotation, 0)) 
{
+       qd_error(QD_ERROR_MESSAGE, "Invalid delivery-annotations");
+       return false;
+    }
     if (depth == QD_DEPTH_DELIVERY_ANNOTATIONS)
-        return 1;
+        return true;
 
     //
     // MESSAGE ANNOTATION
     //
     if (0 == qd_check_field_LH(content, QD_DEPTH_MESSAGE_ANNOTATIONS,
-                               MESSAGE_ANNOTATION_LONG, 
MESSAGE_ANNOTATION_SHORT, TAGS_MAP, &content->section_message_annotation, 0))
-        return 0;
+                               MESSAGE_ANNOTATION_LONG, 
MESSAGE_ANNOTATION_SHORT, TAGS_MAP, &content->section_message_annotation, 0)) {
+       qd_error(QD_ERROR_MESSAGE, "Invalid annotations");
+       return false;
+    }
     if (depth == QD_DEPTH_MESSAGE_ANNOTATIONS)
-        return 1;
+        return true;
 
     //
     // PROPERTIES
     //
     if (0 == qd_check_field_LH(content, QD_DEPTH_PROPERTIES,
-                               PROPERTIES_LONG, PROPERTIES_SHORT, TAGS_LIST, 
&content->section_message_properties, 0))
-        return 0;
+                               PROPERTIES_LONG, PROPERTIES_SHORT, TAGS_LIST, 
&content->section_message_properties, 0)) {
+       qd_error(QD_ERROR_MESSAGE, "Invalid message properties");
+       return false;
+    }
     if (depth == QD_DEPTH_PROPERTIES)
-        return 1;
+        return true;
 
     //
     // APPLICATION PROPERTIES
     //
     if (0 == qd_check_field_LH(content, QD_DEPTH_APPLICATION_PROPERTIES,
-                               APPLICATION_PROPERTIES_LONG, 
APPLICATION_PROPERTIES_SHORT, TAGS_MAP, 
&content->section_application_properties, 0))
-        return 0;
+                               APPLICATION_PROPERTIES_LONG, 
APPLICATION_PROPERTIES_SHORT, TAGS_MAP, 
&content->section_application_properties, 0)) {
+       qd_error(QD_ERROR_MESSAGE, "Invalid application-properties");
+       return false;
+    }
     if (depth == QD_DEPTH_APPLICATION_PROPERTIES)
-        return 1;
+        return true;
 
     //
     // BODY
@@ -847,25 +872,34 @@ static int qd_message_check_LH(qd_messag
     // be parsed to BODY-depth.
     //
     if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
-                               BODY_DATA_LONG, BODY_DATA_SHORT, TAGS_BINARY, 
&content->section_body, 1))
-        return 0;
+                               BODY_DATA_LONG, BODY_DATA_SHORT, TAGS_BINARY, 
&content->section_body, 1)) {
+       qd_error(QD_ERROR_MESSAGE, "Invalid body data");
+       return false;
+    }
     if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
-                               BODY_SEQUENCE_LONG, BODY_SEQUENCE_SHORT, 
TAGS_LIST, &content->section_body, 1))
-        return 0;
+                               BODY_SEQUENCE_LONG, BODY_SEQUENCE_SHORT, 
TAGS_LIST, &content->section_body, 1)) {
+       qd_error(QD_ERROR_MESSAGE, "Invalid body sequence");
+       return false;
+    }
     if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
-                               BODY_VALUE_LONG, BODY_VALUE_SHORT, TAGS_ANY, 
&content->section_body, 0))
-        return 0;
+                               BODY_VALUE_LONG, BODY_VALUE_SHORT, TAGS_ANY, 
&content->section_body, 0)) {
+       qd_error(QD_ERROR_MESSAGE, "Invalid body value");
+       return false;
+    }
     if (depth == QD_DEPTH_BODY)
-        return 1;
+        return true;
 
     //
     // FOOTER
     //
     if (0 == qd_check_field_LH(content, QD_DEPTH_ALL,
-                               FOOTER_LONG, FOOTER_SHORT, TAGS_MAP, 
&content->section_footer, 0))
-        return 0;
+                               FOOTER_LONG, FOOTER_SHORT, TAGS_MAP, 
&content->section_footer, 0)) {
 
-    return 1;
+       qd_error(QD_ERROR_MESSAGE, "Invalid footer");
+       return false;
+    }
+
+    return true;
 }
 
 

Copied: qpid/dispatch/trunk/src/static_assert.h (from r1600796, 
qpid/dispatch/trunk/include/qpid/dispatch/error.h)
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/static_assert.h?p2=qpid/dispatch/trunk/src/static_assert.h&p1=qpid/dispatch/trunk/include/qpid/dispatch/error.h&r1=1600796&r2=1600797&rev=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/include/qpid/dispatch/error.h (original)
+++ qpid/dispatch/trunk/src/static_assert.h Fri Jun  6 00:31:21 2014
@@ -1,5 +1,6 @@
-#ifndef __dispatch_error_h__
-#define __dispatch_error_h__ 1
+#ifndef STATIC_ASSERT_H
+#define STATIC_ASSERT_H
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -8,9 +9,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *   http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,11 +20,20 @@
  * under the License.
  */
 
-typedef enum {
-    QD_ERROR_NONE = 0,
-    QD_ERROR_NOT_FOUND,
-    QD_ERROR_ALREADY_EXISTS,
-    QD_ERROR_ALLOC
-} qd_error_t;
+/** @file
+   STATIC_ASSERT allows you to do compile time assertions at file scope
+   or in a funciton.
+ */
+
+#ifdef __GNUC__
+#define STATIC_ASSERT_HELPER(expr, msg) \
+    (!!sizeof(struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; 
}))
+#define STATIC_ASSERT(expr, msg) \
+    extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
+#else
+    #define STATIC_ASSERT(expr, msg)   \
+    extern char STATIC_ASSERTION__##msg[1]; \
+    extern char STATIC_ASSERTION__##msg[(expr)?1:2]
+#endif /* #ifdef __GNUC__ */
 
-#endif
+#endif // STATIC_ASSERT_H



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to