mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
261 lines
7.3 KiB
C++
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;
|
|
}
|