#include <locale.h>
#include <stdarg.h>
+#include <stdio.h>
#include <config.h>
#include <system.h>
#include "aop-header.h"
#include "aop-type.h"
+
+/* The default license text for InterAspect-generated headers. This
+ license text _does not_ apply to this file, of course! */
+static const char *default_license =
+ "/* Though this file was auto-generated by InterAspect, it _is not_\n"
+ " bound by InterAspect's license (and copyright does not belong to\n"
+ " the InterAspect team). If this file was provided to you by\n"
+ " somebody else, contact that person to find out its licensing terms.\n"
+ " If you generated this file, you can replace this text with your own\n"
+ " licensing terms by specifying them to aop_write_c_header(). */\n";
+
+/* The default preamble for InterAspect-generated headers. */
+static const char *default_preamble =
+ "/* This header file was auto-generated by an InterAspect-based\n"
+ " plug-in. Do not change this file: modifications will be lost and\n"
+ " may result in errors when InterAspect attempts to parse this file\n"
+ " in the future. */\n";
+
+/* Some typedefs that InterAspect-generated headers use for
+ parameters. */
+static const char *header_typedefs =
+ "typedef int ALL_SIGNED_T;\n"
+ "typedef unsigned int ALL_UNSIGNED_T;\n"
+ "typedef double ALL_FP_T;\n"
+ "typedef void *ALL_POINTER_T;\n";
+
/* An aop_prototype struct represents the prototype of an advice
function, including its name, return type and parameters. */
struct aop_prototype {
memcpy (prototype->param_types, param_types, param_types_size);
}
+/* Returns true if symbol is a valid C preprocessor symbol. */
+static bool
+is_valid_c_symbol (const char *symbol)
+{
+ /* No, the empty string is not a valid symbol. */
+ if (*symbol == '\0')
+ return false;
+
+ /* C symbols may contain numerals, but they may not begin with
+ one. */
+ if (*symbol >= '0' && *symbol <= '9')
+ return false;
+
+ for (; *symbol != '\0'; symbol++)
+ {
+ if (*symbol >= '0' && *symbol <= '9')
+ continue;
+ else if (*symbol >= 'a' && *symbol <= 'z')
+ continue;
+ else if (*symbol >= 'A' && *symbol <= 'Z')
+ continue;
+ else if (*symbol == '_')
+ continue;
+ else
+ return false; /* Invalid character. */
+ }
+
+ return true; /* No invalid characters. */
+}
+
+/* Quick-and-dirty printf variant that will check errors for us. */
+#define CHECK_PRINTF(format, ...) \
+ do { \
+ size = fprintf (header, format, __VA_ARGS__); \
+ if (size < 0) \
+ return 0; \
+ } while (0)
+
+/* Write a single aop_prototype to a header. This is used as a
+ callback for htab_traverse. Returns 0 to stop the table traversal
+ in the event of an error. */
+static int
+write_prototype (void **table_entry, void *info)
+{
+ int i;
+ int size;
+ struct aop_prototype *prototype = *table_entry;
+ FILE *header = info;
+ char c_type[256];
+
+ /* Note that an error will set the stream's error, so we don't need
+ to return anything. */
+ CHECK_PRINTF ("void %s(", prototype->name);
+
+ /* Print each of the types. */
+ for (i = 0; i < prototype->num_params; i++)
+ {
+ const char *separator;
+ const struct aop_type *param_type = prototype->param_types[i];
+ size = format_c_type (param_type, sizeof (c_type), c_type);
+
+ /* There's not much we can do to fix this! */
+ if (size >= sizeof (c_type))
+ sprintf (c_type, "#OVERLONG_TYPE_NAME#");
+
+ /* Use a comma separator if there are more parameters to
+ list. */
+ if (i < prototype->num_params - 1)
+ separator = ", ";
+ else
+ separator = "";
+
+ CHECK_PRINTF ("%s%s", c_type, separator);
+ }
+
+ CHECK_PRINTF ("%s", ");\n");
+
+ return 1; /* Continue the traversal. */
+}
+
+#undef CHECK_PRINTF
+
+/* Write the actual header contents to an already opened file.
+ Returns 0 on success or a UNIX error on failure. */
+static int
+write_header_contents (FILE *header, const char *guard, const char *license,
+ const char *preamble)
+{
+ int size;
+
+ /* Print the guard. */
+ if (guard != NULL)
+ {
+ size = fprintf (header, "#ifndef %s\n#define %s\n\n", guard, guard);
+ if (size < 0)
+ return errno;
+ }
+
+ /* Print the license and preamble text and header typedefs. */
+ if (license == NULL)
+ license = default_license;
+ if (preamble == NULL)
+ preamble = default_preamble;
+
+ size = fprintf (header, "%s\n%s\n%s\n", license, preamble, header_typedefs);
+ if (size < 0)
+ return errno;
+
+ /* Print each of the function prototypes by traversing the hash
+ table. */
+ htab_traverse (prototype_table, write_prototype, header);
+ if (ferror (header))
+ return errno;
+
+ /* Close the guard. */
+ if (guard != NULL)
+ {
+ size = fprintf (header, "\n#endif\n");
+ if (size < 0)
+ return errno;
+ }
+
+ return 0; /* Success. */
+}
+
+/**
+ * Add prototypes for every advice function added with
+ * aop_insert_advice(). If the specified header file already exists,
+ * aop_write_c_header() reads it and adds only prototypes that do not
+ * already appear in the file. InterAspect uses advisory file locks
+ * to control access to a header file, so it is ok for parallel
+ * compiles to write to the same header (so long as your system
+ * supports advisory locks).
+ *
+ * Note that generated header files <i>are not</i> bound to
+ * InterAspect's license. If you choose to distribute an
+ * InterAspect-generated header, you may use any terms you wish.
+ *
+ * \param filename The name of the header file to generate. The file
+ * will be created if it does not exist. May not be NULL.
+ * \param guard A valid C preprocessor symbol to use for the header
+ * file's ifdef guard. If this is NULL, the header file will not have
+ * an ifdef guard. Guard symbols are typically of the form
+ * _FILENAME_H_.
+ * \param license Your choice of license text, if you wish to
+ * distribute the generated header under a license. Your text should
+ * be in the form of a C comment. If this is NULL, the header will
+ * begin with the default license text, which indicates that the file
+ * is <i>not bound</i> by the terms of any license. Pass the empty
+ * string if you do not wish to include any license text.
+ * \param preamble Any other preamble text you wish to begin the
+ * header with. This text should be valid C/C++ comments or code. If
+ * this is NULL, the header preamble will be a general comment about
+ * InterAspect-generated headers.
+ * \return On success, the return value is 0. On failure, the return
+ * value is one of the UNIX error codes from errno.h.
+ * - EINVAL: The specified filename is NULL, or the specified guard is
+ * not a valid C preprocessor symbol.
+ * - Any of the possible errno results from the open(2) function.
+ * - Any of the possible errno results from the write(2) function.
+ * - Any of the possilbe errno results from the fcntl(2) function.
+ * - Any of the possilbe errno results from the fprintf(3) function.
+ * Failure will also set errno to the returned error value, so you can
+ * use the perror(3) function to print a user-readable error message.
+ */
+int
+aop_write_c_header (const char *filename, const char *guard,
+ const char *license, const char *preamble)
+{
+ int result = 0;
+ FILE *header;
+
+ if (filename == NULL)
+ return EINVAL;
+
+ if (guard != NULL && !is_valid_c_symbol (guard))
+ return EINVAL;
+
+ header = fopen (filename, "w+");
+ if (header == NULL)
+ return errno;
+
+ result = write_header_contents (header, guard, license, preamble);
+
+ /* TODO: Flush */
+
+ if (fclose (header) != 0)
+ {
+ /* A bad file descriptor means an error in InterAspect. */
+ aop_assert (errno != EBADF);
+
+ /* Anything else is a regular I/O error. */
+ result = errno;
+ }
+
+ return result;
+}
+
void
init_prototype_table()
{