return (a == b);
}
+/* Quick-and-dirty printf variant that will output to a buffer without
+ overrunning it. */
+#define BUF_PRINTF(format, ...) \
+ do { \
+ int bytes; \
+ bytes = snprintf (out, size, format, __VA_ARGS__); \
+ out += bytes; \
+ total_bytes += bytes; \
+ size -= bytes; \
+ } while (0)
+
/* C names for special aop_type objects. */
static const char *all_signed_name = "ALL_SIGNED_T";
static const char *all_unsigned_name = "ALL_UNSIGNED_T";
static const char *all_fp_name = "ALL_FP_T";
static const char *all_pointer_name = "ALL_POINTER_T";
+static const char *signed_char_name = "signed char";
+static const char *unsigned_char_name = "unsigned char";
/* Format an aop_type as a C/C++ typename. The result is stored in
the output buffer (n is the size of the buffer). Returns the
int
format_c_type (const struct aop_type *type, int n, char *output)
{
- int size;
+ /* Initialize these for the sake of BUF_PRINTF. */
+ int total_bytes = 0;
+ int size = n;
+ char *out = output;
- if (type->kind == ATK_ALL_POINTER)
- {
- size = snprintf (output, n, "%s", all_pointer_name);
- }
- else if (is_all_integer_type (type))
+ switch (type->kind)
{
- if (type->kind == ATK_SIGNED_INT)
- size = snprintf (output, n, "%s", all_signed_name);
- else if (type->kind == ATK_UNSIGNED_INT)
- size = snprintf (output, n, "%s", all_unsigned_name);
+ case ATK_SIGNED_INT:
+ case ATK_UNSIGNED_INT:
+ if (type->size == 0)
+ {
+ BUF_PRINTF ("%s", (type->kind == ATK_SIGNED_INT) ? all_signed_name
+ : all_unsigned_name);
+ }
+ else if (type->size == 1)
+ {
+ /* We special case one byte integers because it looks really
+ awkward to see (int8_t *) when you wanted a (char *).
+
+ It's ok to do this because the standard guarantees that
+ char == 1 byte. */
+ BUF_PRINTF ("%s", (type->kind == ATK_SIGNED_INT) ? signed_char_name
+ : unsigned_char_name);
+ }
else
- aop_assert (0); /* Should never happen. */
- }
- else if (is_all_fp_type (type))
- {
- size = snprintf (output, n, "%s", all_fp_name);
+ {
+ aop_assert (type->size == 2 || type->size == 4 || type->size == 8
+ || type->size == 16);
+
+ BUF_PRINTF ("%s%d_t", (type->kind == ATK_SIGNED_INT) ? "int" : "uint",
+ 8 * type->size);
+ }
+ break;
+ case ATK_FP:
+ switch (type->size)
+ {
+ case 4:
+ BUF_PRINTF ("%s", "float");
+ break;
+ case 8:
+ BUF_PRINTF ("%s", "double");
+ break;
+ case 16:
+ BUF_PRINTF ("%s", "long double");
+ break;
+ case 0:
+ BUF_PRINTF ("%s", all_fp_name);
+ break;
+ default:
+ /* Invalid size for floating point type. */
+ aop_assert (0);
+ }
+ break;
+ case ATK_ALL_POINTER:
+ BUF_PRINTF ("%s", all_pointer_name);
+ break;
+ case ATK_STRUCT:
+ BUF_PRINTF ("struct %s", type->tag);
+ break;
+ case ATK_UNION:
+ BUF_PRINTF ("union %s", type->tag);
+ break;
+ case ATK_ENUM:
+ BUF_PRINTF ("enum %s", type->tag);
+ break;
+ default:
+ /* Unknown type kind. */
+ aop_assert (0);
}
- else
+
+ if (type->pointer_levels > 0)
{
- aop_assert (0); /* Not yet supported. */
+ int i;
+
+ /* What can I say? It's the C convention. */
+ BUF_PRINTF("%s", " ");
+
+ for (i = 0; i < type->pointer_levels; i++)
+ BUF_PRINTF("%s", "*");
}
/* Before returning, make absolutely sure that the result is
NULL-terminated. Note that snprintf will not terminate a string
that it has to truncate because of too small buffer. */
- if (size < n)
- output[size] = '\0';
+ if (total_bytes < n)
+ output[total_bytes] = '\0';
else
output[n - 1] = '\0';
- return size;
+ return total_bytes;
}