| /* 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 "Charmonizer/Core/Util.h" |
| #include "Charmonizer/Core/ConfWriter.h" |
| #include "Charmonizer/Core/ConfWriterC.h" |
| #include "Charmonizer/Core/OperatingSystem.h" |
| #include "Charmonizer/Core/Compiler.h" |
| #include <ctype.h> |
| #include <errno.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| typedef enum chaz_ConfElemType { |
| CHAZ_CONFELEM_DEF, |
| CHAZ_CONFELEM_GLOBAL_DEF, |
| CHAZ_CONFELEM_TYPEDEF, |
| CHAZ_CONFELEM_GLOBAL_TYPEDEF, |
| CHAZ_CONFELEM_SYS_INCLUDE, |
| CHAZ_CONFELEM_LOCAL_INCLUDE |
| } chaz_ConfElemType; |
| |
| typedef struct chaz_ConfElem { |
| char *str1; |
| char *str2; |
| chaz_ConfElemType type; |
| } chaz_ConfElem; |
| |
| /* Static vars. */ |
| static struct { |
| FILE *fh; |
| char *MODULE_NAME; |
| chaz_ConfElem *defs; |
| size_t def_cap; |
| size_t def_count; |
| } chaz_ConfWriterC = { NULL, NULL, NULL, 0, 0 }; |
| static chaz_ConfWriter CWC_conf_writer; |
| |
| /* Open the charmony.h file handle. Print supplied text to it, if non-null. |
| * Print an explanatory comment and open the include guard. |
| */ |
| static void |
| chaz_ConfWriterC_open_charmony_h(const char *charmony_start); |
| |
| /* Push a new elem onto the def list. */ |
| static void |
| chaz_ConfWriterC_push_def_list_item(const char *str1, const char *str2, |
| chaz_ConfElemType type); |
| |
| /* Free the def list. */ |
| static void |
| chaz_ConfWriterC_clear_def_list(void); |
| |
| static void |
| chaz_ConfWriterC_clean_up(void); |
| static void |
| chaz_ConfWriterC_vappend_conf(const char *fmt, va_list args); |
| static void |
| chaz_ConfWriterC_add_def(const char *sym, const char *value); |
| static void |
| chaz_ConfWriterC_add_global_def(const char *sym, const char *value); |
| static void |
| chaz_ConfWriterC_add_typedef(const char *type, const char *alias); |
| static void |
| chaz_ConfWriterC_add_global_typedef(const char *type, const char *alias); |
| static void |
| chaz_ConfWriterC_add_sys_include(const char *header); |
| static void |
| chaz_ConfWriterC_add_local_include(const char *header); |
| static void |
| chaz_ConfWriterC_start_module(const char *module_name); |
| static void |
| chaz_ConfWriterC_end_module(void); |
| |
| void |
| chaz_ConfWriterC_enable(void) { |
| CWC_conf_writer.clean_up = chaz_ConfWriterC_clean_up; |
| CWC_conf_writer.vappend_conf = chaz_ConfWriterC_vappend_conf; |
| CWC_conf_writer.add_def = chaz_ConfWriterC_add_def; |
| CWC_conf_writer.add_global_def = chaz_ConfWriterC_add_global_def; |
| CWC_conf_writer.add_typedef = chaz_ConfWriterC_add_typedef; |
| CWC_conf_writer.add_global_typedef = chaz_ConfWriterC_add_global_typedef; |
| CWC_conf_writer.add_sys_include = chaz_ConfWriterC_add_sys_include; |
| CWC_conf_writer.add_local_include = chaz_ConfWriterC_add_local_include; |
| CWC_conf_writer.start_module = chaz_ConfWriterC_start_module; |
| CWC_conf_writer.end_module = chaz_ConfWriterC_end_module; |
| chaz_ConfWriterC_open_charmony_h(NULL); |
| chaz_ConfWriter_add_writer(&CWC_conf_writer); |
| return; |
| } |
| |
| static void |
| chaz_ConfWriterC_open_charmony_h(const char *charmony_start) { |
| /* Open the filehandle. */ |
| chaz_ConfWriterC.fh = fopen("charmony.h", "w+"); |
| if (chaz_ConfWriterC.fh == NULL) { |
| chaz_Util_die("Can't open 'charmony.h': %s", strerror(errno)); |
| } |
| |
| /* Print supplied text (if any) along with warning, open include guard. */ |
| if (charmony_start != NULL) { |
| fwrite(charmony_start, sizeof(char), strlen(charmony_start), |
| chaz_ConfWriterC.fh); |
| } |
| fprintf(chaz_ConfWriterC.fh, |
| "/* Header file auto-generated by Charmonizer. \n" |
| " * DO NOT EDIT THIS FILE!!\n" |
| " */\n\n" |
| "#ifndef H_CHARMONY\n" |
| "#define H_CHARMONY 1\n\n" |
| ); |
| } |
| |
| static void |
| chaz_ConfWriterC_clean_up(void) { |
| /* Write the last bit of charmony.h and close. */ |
| fprintf(chaz_ConfWriterC.fh, "#endif /* H_CHARMONY */\n\n"); |
| if (fclose(chaz_ConfWriterC.fh)) { |
| chaz_Util_die("Couldn't close 'charmony.h': %s", strerror(errno)); |
| } |
| } |
| |
| static void |
| chaz_ConfWriterC_vappend_conf(const char *fmt, va_list args) { |
| vfprintf(chaz_ConfWriterC.fh, fmt, args); |
| } |
| |
| static int |
| chaz_ConfWriterC_sym_is_uppercase(const char *sym) { |
| return isupper((unsigned char)sym[0]); |
| } |
| |
| static char* |
| chaz_ConfWriterC_uppercase_string(const char *src) { |
| char *retval = chaz_Util_strdup(src); |
| size_t i; |
| for (i = 0; retval[i]; ++i) { |
| retval[i] = toupper((unsigned char)retval[i]); |
| } |
| return retval; |
| } |
| |
| static void |
| chaz_ConfWriterC_add_def(const char *sym, const char *value) { |
| chaz_ConfWriterC_push_def_list_item(sym, value, CHAZ_CONFELEM_DEF); |
| } |
| |
| static void |
| chaz_ConfWriterC_append_def_to_conf(const char *sym, const char *value) { |
| if (value) { |
| if (chaz_ConfWriterC_sym_is_uppercase(sym)) { |
| fprintf(chaz_ConfWriterC.fh, "#define CHY_%s %s\n", sym, value); |
| } |
| else { |
| fprintf(chaz_ConfWriterC.fh, "#define chy_%s %s\n", sym, value); |
| } |
| } |
| else { |
| if (chaz_ConfWriterC_sym_is_uppercase(sym)) { |
| fprintf(chaz_ConfWriterC.fh, "#define CHY_%s\n", sym); |
| } |
| else { |
| fprintf(chaz_ConfWriterC.fh, "#define chy_%s\n", sym); |
| } |
| } |
| } |
| |
| static void |
| chaz_ConfWriterC_add_global_def(const char *sym, const char *value) { |
| chaz_ConfWriterC_push_def_list_item(sym, value, CHAZ_CONFELEM_GLOBAL_DEF); |
| } |
| |
| static void |
| chaz_ConfWriterC_append_global_def_to_conf(const char *sym, |
| const char *value) { |
| char *name_end = strchr(sym, '('); |
| if (name_end == NULL) { |
| if (strcmp(sym, value) == 0) { return; } |
| fprintf(chaz_ConfWriterC.fh, "#ifndef %s\n", sym); |
| } |
| else { |
| size_t name_len = (size_t)(name_end - sym); |
| char *name = chaz_Util_strdup(sym); |
| name[name_len] = '\0'; |
| fprintf(chaz_ConfWriterC.fh, "#ifndef %s\n", name); |
| free(name); |
| } |
| if (value) { |
| fprintf(chaz_ConfWriterC.fh, " #define %s %s\n", sym, value); |
| } |
| else { |
| fprintf(chaz_ConfWriterC.fh, " #define %s\n", sym); |
| } |
| fprintf(chaz_ConfWriterC.fh, "#endif\n"); |
| } |
| |
| static void |
| chaz_ConfWriterC_add_typedef(const char *type, const char *alias) { |
| chaz_ConfWriterC_push_def_list_item(alias, type, CHAZ_CONFELEM_TYPEDEF); |
| } |
| |
| static void |
| chaz_ConfWriterC_append_typedef_to_conf(const char *type, const char *alias) { |
| if (chaz_ConfWriterC_sym_is_uppercase(alias)) { |
| fprintf(chaz_ConfWriterC.fh, "typedef %s CHY_%s;\n", type, alias); |
| } |
| else { |
| fprintf(chaz_ConfWriterC.fh, "typedef %s chy_%s;\n", type, alias); |
| } |
| } |
| |
| static void |
| chaz_ConfWriterC_add_global_typedef(const char *type, const char *alias) { |
| chaz_ConfWriterC_push_def_list_item(alias, type, |
| CHAZ_CONFELEM_GLOBAL_TYPEDEF); |
| } |
| |
| static void |
| chaz_ConfWriterC_append_global_typedef_to_conf(const char *type, |
| const char *alias) { |
| if (strcmp(type, alias) == 0) { return; } |
| fprintf(chaz_ConfWriterC.fh, "typedef %s %s;\n", type, alias); |
| } |
| |
| static void |
| chaz_ConfWriterC_add_sys_include(const char *header) { |
| chaz_ConfWriterC_push_def_list_item(header, NULL, |
| CHAZ_CONFELEM_SYS_INCLUDE); |
| } |
| |
| static void |
| chaz_ConfWriterC_append_sys_include_to_conf(const char *header) { |
| fprintf(chaz_ConfWriterC.fh, "#include <%s>\n", header); |
| } |
| |
| static void |
| chaz_ConfWriterC_add_local_include(const char *header) { |
| chaz_ConfWriterC_push_def_list_item(header, NULL, |
| CHAZ_CONFELEM_LOCAL_INCLUDE); |
| } |
| |
| static void |
| chaz_ConfWriterC_append_local_include_to_conf(const char *header) { |
| fprintf(chaz_ConfWriterC.fh, "#include \"%s\"\n", header); |
| } |
| |
| static void |
| chaz_ConfWriterC_start_module(const char *module_name) { |
| fprintf(chaz_ConfWriterC.fh, "\n/* %s */\n", module_name); |
| chaz_ConfWriterC.MODULE_NAME |
| = chaz_ConfWriterC_uppercase_string(module_name); |
| } |
| |
| static void |
| chaz_ConfWriterC_end_module(void) { |
| size_t num_globals = 0; |
| size_t i; |
| chaz_ConfElem *defs = chaz_ConfWriterC.defs; |
| for (i = 0; i < chaz_ConfWriterC.def_count; i++) { |
| switch (defs[i].type) { |
| case CHAZ_CONFELEM_GLOBAL_DEF: |
| ++num_globals; |
| /* fall through */ |
| case CHAZ_CONFELEM_DEF: |
| chaz_ConfWriterC_append_def_to_conf(defs[i].str1, |
| defs[i].str2); |
| break; |
| case CHAZ_CONFELEM_GLOBAL_TYPEDEF: { |
| char *sym = chaz_ConfWriterC_uppercase_string(defs[i].str1); |
| chaz_ConfWriterC_append_def_to_conf(sym, defs[i].str2); |
| free(sym); |
| ++num_globals; |
| } |
| /* fall through */ |
| case CHAZ_CONFELEM_TYPEDEF: |
| chaz_ConfWriterC_append_typedef_to_conf(defs[i].str2, |
| defs[i].str1); |
| break; |
| case CHAZ_CONFELEM_SYS_INCLUDE: |
| ++num_globals; |
| break; |
| case CHAZ_CONFELEM_LOCAL_INCLUDE: |
| chaz_ConfWriterC_append_local_include_to_conf(defs[i].str1); |
| break; |
| default: |
| chaz_Util_die("Internal error: bad element type %d", |
| (int)defs[i].type); |
| } |
| } |
| |
| /* Write out short names. */ |
| if (chaz_ConfWriterC.def_count > 0) { |
| fprintf(chaz_ConfWriterC.fh, |
| "\n#if defined(CHY_USE_SHORT_NAMES) " |
| "|| defined(CHAZ_USE_SHORT_NAMES)\n" |
| ); |
| for (i = 0; i < chaz_ConfWriterC.def_count; i++) { |
| switch (defs[i].type) { |
| case CHAZ_CONFELEM_DEF: |
| case CHAZ_CONFELEM_TYPEDEF: |
| { |
| const char *sym = defs[i].str1; |
| const char *value = defs[i].str2; |
| if (!value || strcmp(sym, value) != 0) { |
| const char *prefix |
| = chaz_ConfWriterC_sym_is_uppercase(sym) |
| ? "CHY_" : "chy_"; |
| fprintf(chaz_ConfWriterC.fh, " #define %s %s%s\n", |
| sym, prefix, sym); |
| } |
| } |
| break; |
| case CHAZ_CONFELEM_GLOBAL_DEF: |
| case CHAZ_CONFELEM_GLOBAL_TYPEDEF: |
| case CHAZ_CONFELEM_SYS_INCLUDE: |
| case CHAZ_CONFELEM_LOCAL_INCLUDE: |
| /* no-op */ |
| break; |
| default: |
| chaz_Util_die("Internal error: bad element type %d", |
| (int)defs[i].type); |
| } |
| } |
| |
| fprintf(chaz_ConfWriterC.fh, "#endif /* USE_SHORT_NAMES */\n"); |
| } |
| |
| /* Write out global definitions and system includes. */ |
| if (num_globals) { |
| fprintf(chaz_ConfWriterC.fh, "\n#ifdef CHY_EMPLOY_%s\n\n", |
| chaz_ConfWriterC.MODULE_NAME); |
| for (i = 0; i < chaz_ConfWriterC.def_count; i++) { |
| switch (defs[i].type) { |
| case CHAZ_CONFELEM_GLOBAL_DEF: |
| chaz_ConfWriterC_append_global_def_to_conf(defs[i].str1, |
| defs[i].str2); |
| break; |
| case CHAZ_CONFELEM_GLOBAL_TYPEDEF: |
| chaz_ConfWriterC_append_global_typedef_to_conf( |
| defs[i].str2, defs[i].str1); |
| break; |
| case CHAZ_CONFELEM_SYS_INCLUDE: |
| chaz_ConfWriterC_append_sys_include_to_conf(defs[i].str1); |
| break; |
| case CHAZ_CONFELEM_DEF: |
| case CHAZ_CONFELEM_TYPEDEF: |
| case CHAZ_CONFELEM_LOCAL_INCLUDE: |
| /* no-op */ |
| break; |
| default: |
| chaz_Util_die("Internal error: bad element type %d", |
| (int)defs[i].type); |
| } |
| } |
| fprintf(chaz_ConfWriterC.fh, "\n#endif /* EMPLOY_%s */\n", |
| chaz_ConfWriterC.MODULE_NAME); |
| } |
| |
| fprintf(chaz_ConfWriterC.fh, "\n"); |
| |
| free(chaz_ConfWriterC.MODULE_NAME); |
| chaz_ConfWriterC_clear_def_list(); |
| } |
| |
| static void |
| chaz_ConfWriterC_push_def_list_item(const char *str1, const char *str2, |
| chaz_ConfElemType type) { |
| if (chaz_ConfWriterC.def_count >= chaz_ConfWriterC.def_cap) { |
| size_t amount; |
| chaz_ConfWriterC.def_cap += 10; |
| amount = chaz_ConfWriterC.def_cap * sizeof(chaz_ConfElem); |
| chaz_ConfWriterC.defs |
| = (chaz_ConfElem*)realloc(chaz_ConfWriterC.defs, amount); |
| } |
| chaz_ConfWriterC.defs[chaz_ConfWriterC.def_count].str1 |
| = str1 ? chaz_Util_strdup(str1) : NULL; |
| chaz_ConfWriterC.defs[chaz_ConfWriterC.def_count].str2 |
| = str2 ? chaz_Util_strdup(str2) : NULL; |
| chaz_ConfWriterC.defs[chaz_ConfWriterC.def_count].type = type; |
| chaz_ConfWriterC.def_count++; |
| } |
| |
| static void |
| chaz_ConfWriterC_clear_def_list(void) { |
| size_t i; |
| for (i = 0; i < chaz_ConfWriterC.def_count; i++) { |
| free(chaz_ConfWriterC.defs[i].str1); |
| free(chaz_ConfWriterC.defs[i].str2); |
| } |
| free(chaz_ConfWriterC.defs); |
| chaz_ConfWriterC.defs = NULL; |
| chaz_ConfWriterC.def_cap = 0; |
| chaz_ConfWriterC.def_count = 0; |
| } |
| |