zeek/tools/binpac/src/pac_main.cc

261 lines
7.3 KiB
C++

#include <ctype.h>
#include <unistd.h>
#include "pac_common.h"
#include "pac_decl.h"
#include "pac_exception.h"
#include "pac_exttype.h"
#include "pac_id.h"
#include "pac_output.h"
#include "pac_parse.h"
#include "pac_type.h"
#include "pac_utils.h"
extern int yydebug;
extern int yyparse();
extern void switch_to_file(FILE* fp_input);
string input_filename;
bool FLAGS_pac_debug = false;
bool FLAGS_quiet = false;
string FLAGS_output_directory;
vector<string> FLAGS_include_directories;
Output* header_output = nullptr;
Output* source_output = nullptr;
void add_to_include_directories(string dirs) {
unsigned int dir_begin = 0, dir_end;
while ( dir_begin < dirs.length() ) {
for ( dir_end = dir_begin; dir_end < dirs.length(); ++dir_end )
if ( dirs[dir_end] == ':' )
break;
string dir = dirs.substr(dir_begin, dir_end - dir_begin);
// Add a trailing '/' if necessary
if ( dir.length() > 0 && *(dir.end() - 1) != '/' )
dir += '/';
FLAGS_include_directories.push_back(std::move(dir));
dir_begin = dir_end + 1;
}
}
void pac_init() {
init_builtin_identifiers();
Type::init();
}
void insert_comments(Output* out, const char* source_filename) {
out->println("// This file is automatically generated from %s.\n", source_filename);
}
void insert_basictype_defs(Output* out) {
out->println("#ifndef pac_type_defs");
out->println("#define pac_type_defs");
out->println("");
out->println("typedef char int8;");
out->println("typedef short int16;");
out->println("typedef long int32;");
out->println("typedef long long int64;");
out->println("typedef unsigned char uint8;");
out->println("typedef unsigned short uint16;");
out->println("typedef unsigned long uint32;");
out->println("typedef unsigned long long uint64;");
out->println("");
out->println("#endif /* pac_type_defs */");
out->println("");
}
void insert_byteorder_macros(Output* out) {
out->println("#define FixByteOrder16(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap16(x))");
out->println("#define FixByteOrder32(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap32(x))");
out->println("#define FixByteOrder64(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap64(x))");
out->println("");
}
const char* to_id(const char* s) {
static char t[1024];
int i;
for ( i = 0; s[i] && i < (int)sizeof(t) - 1; ++i )
t[i] = isalnum(s[i]) ? s[i] : '_';
if ( isdigit(t[0]) )
t[0] = '_';
t[i] = '\0';
return t;
}
int compile(const char* filename) {
FILE* fp_input = fopen(filename, "r");
if ( ! fp_input ) {
string tmp = strfmt("Error in opening %s", filename);
perror(tmp.c_str());
return -1;
}
input_filename = filename;
string basename;
if ( ! FLAGS_output_directory.empty() ) {
// Strip leading directories of filename
const char* last_slash = strrchr(filename, '/');
if ( last_slash )
basename = last_slash + 1;
else
basename = filename;
basename = FLAGS_output_directory + "/" + basename;
}
else
basename = filename;
// If the file name ends with ".pac"
if ( basename.length() > 4 && basename.substr(basename.length() - 4) == ".pac" ) {
basename = basename.substr(0, basename.length() - 4);
}
basename += "_pac";
DEBUG_MSG("Output file: %s.{h,cc}\n", basename.c_str());
int ret = 0;
try {
switch_to_file(fp_input);
if ( yyparse() )
return 1;
Output out_h(strfmt("%s.h", basename.c_str()));
Output out_cc(strfmt("%s.cc", basename.c_str()));
header_output = &out_h;
source_output = &out_cc;
insert_comments(&out_h, filename);
insert_comments(&out_cc, filename);
const char* filename_id = to_id(filename);
out_h.println("#ifndef %s_h", filename_id);
out_h.println("#define %s_h", filename_id);
out_h.println("");
out_h.println("#include <vector>");
out_h.println("");
out_h.println("#include \"binpac.h\"");
out_h.println("");
out_cc.println("");
out_cc.println("#ifdef __clang__");
out_cc.println("#pragma clang diagnostic ignored \"-Wparentheses-equality\"");
out_cc.println("#endif");
out_cc.println("");
out_cc.println("#include \"%s.h\"\n", basename.c_str());
Decl::ProcessDecls(&out_h, &out_cc);
out_h.println("#endif /* %s_h */", filename_id);
} catch ( OutputException& e ) {
fprintf(stderr, "Error in compiling %s: %s\n", filename, e.errmsg());
ret = 1;
} catch ( Exception& e ) {
fprintf(stderr, "%s\n", e.msg());
exit(1);
}
header_output = nullptr;
source_output = nullptr;
input_filename = "";
fclose(fp_input);
return ret;
}
void usage() {
#ifdef BINPAC_VERSION
fprintf(stderr, "binpac version %s\n", BINPAC_VERSION);
#endif
fprintf(stderr, "usage: binpac [options] <pac files>\n");
fprintf(stderr, " <pac files> | pac-language input files\n");
fprintf(stderr, " -d <dir> | use given directory for compiler output\n");
fprintf(stderr, " -D | enable debugging output\n");
fprintf(stderr, " -q | stay quiet\n");
fprintf(stderr, " -h | show command line help\n");
fprintf(stderr, " -I <dir> | include <dir> in input file search path\n");
exit(1);
}
// GCC uses __SANITIZE_ADDRESS__, Clang uses __has_feature
#if defined(__SANITIZE_ADDRESS__)
#define USING_ASAN
#endif
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define USING_ASAN
#endif
#endif
// FreeBSD doesn't support LeakSanitizer
#if defined(USING_ASAN) && ! defined(__FreeBSD__)
#include <sanitizer/lsan_interface.h>
#define BINPAC_LSAN_DISABLE() __lsan_disable()
#else
#define BINPAC_LSAN_DISABLE()
#endif
int main(int argc, char* argv[]) {
// We generally do not care at all if binpac is leaking and other
// projects that use it, like Zeek, only have their build tripped up
// by the default behavior of LSAN to treat leaks as errors.
BINPAC_LSAN_DISABLE();
#ifdef HAVE_MALLOC_OPTIONS
extern char* malloc_options;
#endif
int o;
while ( (o = getopt(argc, argv, "DqI:d:h")) != -1 ) {
switch ( o ) {
case 'D': yydebug = 1; FLAGS_pac_debug = true;
#ifdef HAVE_MALLOC_OPTIONS
malloc_options = "A";
#endif
break;
case 'q': FLAGS_quiet = true; break;
case 'I':
// Add to FLAGS_include_directories
add_to_include_directories(optarg);
break;
case 'd': FLAGS_output_directory = optarg; break;
case 'h': usage(); break;
}
}
// Strip the trailing '/'s
while ( ! FLAGS_output_directory.empty() && *(FLAGS_output_directory.end() - 1) == '/' ) {
FLAGS_output_directory.erase(FLAGS_output_directory.end() - 1);
}
// Add the current directory to FLAGS_include_directories
add_to_include_directories(".");
pac_init();
argc -= optind;
argv += optind;
if ( argc == 0 )
compile("-");
int ret = 0;
for ( int i = 0; i < argc; ++i )
if ( compile(argv[i]) )
ret = 1;
return ret;
}