blob: 86890c7c6550ce46b69cd42b4b1c34e413ee557a [file] [log] [blame]
/* 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;
}