From: Justin Seyster Date: Thu, 15 Jul 2010 23:22:37 +0000 (-0400) Subject: Added initial support for writing out a header file. X-Git-Tag: release-v1.0~48^2~16 X-Git-Url: https://git.fsl.cs.stonybrook.edu/?a=commitdiff_plain;h=b1459823881318c752b87f90c285e013d19415d2;p=interaspect.git Added initial support for writing out a header file. --- diff --git a/src/aop-header.c b/src/aop-header.c index 9ca2c61..f98e374 100644 --- a/src/aop-header.c +++ b/src/aop-header.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -39,6 +40,32 @@ #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 { @@ -201,6 +228,204 @@ insert_prototype (bool has_return_value, const char *name, int num_params, 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 are not 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 not bound 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() { diff --git a/src/aop-type.c b/src/aop-type.c index 52eb022..605bf78 100644 --- a/src/aop-type.c +++ b/src/aop-type.c @@ -117,3 +117,55 @@ are_types_equal (const struct aop_type *a, const struct aop_type *b) { return (a == b); } + +/* 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"; + +/* 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 + number characters written (but without regard to truncation because + of a too small output buffer, as with snprintf()). */ +int +format_c_type (const struct aop_type *type, int n, char *output) +{ + int size; + + if (type->kind == ATK_ALL_POINTER) + { + size = snprintf (output, n, "%s", all_pointer_name); + goto terminate; + } + else if (type->pointer_levels == 0) + { + switch (type->kind) + { + case ATK_ALL_SIGNED: + size = snprintf (output, n, "%s", all_signed_name); + goto terminate; + case ATK_ALL_UNSIGNED: + size = snprintf (output, n, "%s", all_unsigned_name); + goto terminate; + case ATK_ALL_FP: + size = snprintf (output, n, "%s", all_fp_name); + goto terminate; + default: + break; + } + } + + aop_assert (0); + + terminate: + /* 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'; + else + output[n - 1] = '\0'; + + return size; +} diff --git a/src/aop-type.h b/src/aop-type.h index aa8d379..4eff58c 100644 --- a/src/aop-type.h +++ b/src/aop-type.h @@ -38,4 +38,6 @@ struct aop_type { bool does_type_match (tree gcc_type, const struct aop_type *aop_type); bool are_types_equal (const struct aop_type *a, const struct aop_type *b); +int format_c_type (const struct aop_type *type, int n, char *output); + #endif diff --git a/src/aop.h b/src/aop.h index b74f080..d2d40ba 100644 --- a/src/aop.h +++ b/src/aop.h @@ -263,4 +263,7 @@ extern struct aop_dynval *aop_capture_lhs_addr (struct aop_joinpoint *jp); extern const char *aop_capture_lhs_name (struct aop_joinpoint *jp); extern struct aop_dynval *aop_capture_assigned_value (struct aop_joinpoint *jp); +extern int aop_write_c_header (const char *filename, const char *guard, + const char *license, const char *preamble); + #endif