00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "write_build_config.h"
00016
00017 #include <basis/function.h>
00018 #include <basis/portable.h>
00019 #include <basis/set.cpp>
00020 #include <basis/version_record.h>
00021 #include <data_struct/string_table.h>
00022 #include <opsystem/byte_filer.h>
00023 #include <loggers/console_logger.h>
00024 #include <data_struct/static_memory_gremlin.h>
00025 #include <opsystem/version_ini.h>
00026 #include <textual/tokenizer.h>
00027
00028 #include <stdio.h>
00029
00030 const int MAX_LINE_SIZE = 2048;
00032
00033 const int MAX_HEADER_FILE = 128 * KILOBYTE;
00035
00036 const char *DEFINITIONS_STATEMENT = "DEFINITIONS";
00038
00039 const char *EXPORT_STATEMENT = "export ";
00041
00042
00043 const char *IFEQ_STATEMENT = "ifeq";
00044 const char *IFNEQ_STATEMENT = "ifneq";
00045 const char *ENDIF_STATEMENT = "endif";
00046
00047 #undef LOG
00048 #define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger(), to_print)
00049
00050 write_build_config::write_build_config()
00051 : application_shell(static_class_name()),
00052 _end_matter(new istring),
00053 _ver(new version),
00054 _nesting(0)
00055 {}
00056
00057 write_build_config::~write_build_config()
00058 {
00059 WHACK(_end_matter);
00060 WHACK(_ver);
00061 }
00062
00063 const string_set &write_build_config::exclusions()
00064 {
00065 static string_set _hidden;
00066 static bool _initted = false;
00067 if (!_initted) {
00068 _hidden += "DEBUG";
00069 _hidden += "OPTIMIZE";
00070 _hidden += "STRICT_WARNINGS";
00071 _hidden += "NO_SETUP";
00072 }
00073 return _hidden;
00074 }
00075
00076
00077 #define ADD_COMMENT_RETURN(sym, val) { \
00078 *_end_matter += istring(" ") + sym + " = " + val + "\n"; \
00079 return common::OKAY; \
00080 }
00081
00082 outcome write_build_config::output_macro(const istring &symbol,
00083 const istring &value, istring &accumulator)
00084 {
00085
00086 if (exclusions().member(symbol))
00087 ADD_COMMENT_RETURN(symbol, value);
00088
00089 if (symbol.contains("\"") || value.contains("\""))
00090 ADD_COMMENT_RETURN(symbol, value);
00091 accumulator += " #ifndef ";
00092 accumulator += symbol;
00093 accumulator += "\n";
00094 accumulator += " #define ";
00095 accumulator += symbol;
00096 accumulator += " \"";
00097 accumulator += value;
00098 accumulator += "\"\n";
00099 accumulator += " #endif\n";
00100 return common::OKAY;
00101 }
00102
00103 bool write_build_config::process_version_parts(const istring &symbol,
00104 const istring &value)
00105 {
00106 if (symbol == "major")
00107 { _ver->set_component(version::MAJOR, value); return true; }
00108 if (symbol == "minor")
00109 { _ver->set_component(version::MINOR, value); return true; }
00110 if (symbol == "revision")
00111 { _ver->set_component(version::REVISION, value); return true; }
00112 if (symbol == "build")
00113 { _ver->set_component(version::BUILD, value); return true; }
00114 return false;
00115 }
00116
00117 bool write_build_config::check_nesting(const istring &to_check)
00118 {
00119 if (to_check.compare(IFEQ_STATEMENT, 0, 0, int(strlen(IFEQ_STATEMENT)))
00120 || to_check.compare(IFNEQ_STATEMENT, 0, 0,
00121 int(strlen(IFNEQ_STATEMENT)))) {
00122 _nesting++;
00123 return true;
00124 }
00125 if (to_check.compare(ENDIF_STATEMENT, 0, 0, int(strlen(ENDIF_STATEMENT)))) {
00126 _nesting--;
00127 return true;
00128 }
00129 return false;
00130 }
00131
00132 outcome write_build_config::output_decorated_macro(const istring &symbol_in,
00133 const istring &value, istring &cfg_accumulator, istring &ver_accumulator)
00134 {
00135
00136 if (check_nesting(symbol_in))
00137 ADD_COMMENT_RETURN(symbol_in, value);
00138
00139 if (exclusions().member(symbol_in))
00140 ADD_COMMENT_RETURN(symbol_in, value);
00141 if (symbol_in.contains("\"") || value.contains("\""))
00142 ADD_COMMENT_RETURN(symbol_in, value);
00143 if (symbol_in[0] == '[')
00144 ADD_COMMENT_RETURN(symbol_in, value);
00145 if (_nesting)
00146 ADD_COMMENT_RETURN(symbol_in, value);
00147
00148 istring *the_accumulator = &cfg_accumulator;
00149 if (process_version_parts(symbol_in, value)) {
00150 the_accumulator = &ver_accumulator;
00151 }
00152
00153 istring symbol = istring("__build_") + symbol_in;
00154 return output_macro(symbol, value, *the_accumulator);
00155 }
00156
00157 outcome write_build_config::output_definition_macro
00158 (const istring &embedded_value, istring &accumulator)
00159 {
00160 FUNCDEF("output_definition_macro");
00161
00162 tokenizer t;
00163 t.parse(embedded_value);
00164 if (!t.symbols())
00165 ADD_COMMENT_RETURN("bad definition", embedded_value);
00166 if (exclusions().member(t.table().name(0)))
00167 ADD_COMMENT_RETURN(t.table().name(0), t.table()[0]);
00168 if (_nesting)
00169 ADD_COMMENT_RETURN(t.table().name(0), t.table()[0]);
00170 return output_macro(t.table().name(0), t.table()[0], accumulator);
00171 }
00172
00173 bool write_build_config::write_output_file(const istring &filename,
00174 const istring &new_contents)
00175 {
00176 FUNCDEF("write_output_file");
00177
00178 bool write_header = true;
00179 byte_filer check_header(filename, "rb");
00180 if (check_header.good()) {
00181 byte_array file_contents;
00182 int read = check_header.read(file_contents, MAX_HEADER_FILE);
00183 if (read < 1) LOG("why is existing header contentless?");
00184 if (read > 0) {
00185 istring found(istring::UNTERMINATED, (char *)file_contents.observe(),
00186 read);
00187
00188
00189 if (found == new_contents) {
00190 write_header = false;
00191 }
00192 }
00193 }
00194
00195
00196
00197 if (write_header) {
00198
00199 byte_filer build_header(filename, "wb");
00200 if (!build_header.good())
00201 non_continuable_error(static_class_name(), func, istring("failed to create "
00202 "build header file in ") + build_header.filename());
00203 build_header.write(new_contents);
00204 LOG(istring(static_class_name()) + ": wrote config to "
00205 + build_header.filename());
00206 } else {
00207
00208
00209
00210 }
00211 return true;
00212 }
00213
00214 int write_build_config::execute()
00215 {
00216 FUNCDEF("execute");
00217 SET_DEFAULT_CONSOLE_LOGGER;
00218
00219
00220 istring repodir = portable::env_string("REPOSITORY_DIR");
00221
00222
00223 #ifdef __WIN32__
00224 if (!repodir) repodir = "l:";
00225 #else // unix and other locations.
00226 if (!repodir)
00227 repodir = portable::env_string("HOME") + "/hoople";
00228 #endif
00229
00230 istring fname = repodir + "/build.ini";
00231
00232
00233
00234
00235 istring cfg_header_filename = repodir + "/source/lib_src/library/"
00236 "__build_configuration.h";
00237 istring ver_header_filename = repodir + "/source/lib_src/library/"
00238 "__build_version.h";
00239
00240
00241 byte_filer ini(fname, "r");
00242 if (!ini.good())
00243 non_continuable_error(static_class_name(), func, istring("failed to open "
00244 "build.ini file for reading at ") + ini.filename());
00245
00246
00247 istring cfg_accumulator;
00248 istring ver_accumulator;
00249
00250
00251
00252 cfg_accumulator += "\
00253 #ifndef BUILD_SYSTEM_CONFIGURATION\n\
00254 #define BUILD_SYSTEM_CONFIGURATION\n\n\
00255 // This file provides all of the code flags which were used when this\n\
00256 // build was generated. Some of the items in build.ini have been stripped\n\
00257 // out because they are not used.\n\n";
00258 ver_accumulator += "\
00259 #ifndef BUILD_VERSION_CONFIGURATION\n\
00260 #define BUILD_VERSION_CONFIGURATION\n\n\
00261 // This file provides the version macros for this particular build.\n\n";
00262
00263
00264 istring symbol, value;
00265 istring buffer;
00266 while (!ini.eof()) {
00267 int chars = ini.getline(buffer, MAX_LINE_SIZE);
00268 if (!chars) continue;
00269
00270 tokenizer t;
00271 t.parse(buffer);
00272 if (!t.symbols()) continue;
00273
00274
00275 symbol = t.table().name(0);
00276 value = t.table()[0];
00277 symbol.strip_spaces(istring::FROM_BOTH_SIDES);
00278
00279
00280 while ( (symbol[symbol.end()] == '+') || (symbol[symbol.end()] == ':') ) {
00281 symbol.zap(symbol.end(), symbol.end());
00282 symbol.strip_spaces(istring::FROM_END);
00283 }
00284
00285 if (symbol[0] == '#') continue;
00286
00287 if (!symbol) continue;
00288
00289 if (symbol.compare(EXPORT_STATEMENT, 0, 0, int(strlen(EXPORT_STATEMENT)))) {
00290
00291 symbol.zap(0, int(strlen(EXPORT_STATEMENT) - 1));
00292 }
00293
00294
00295 if (symbol.compare(DEFINITIONS_STATEMENT, 0, 0,
00296 int(strlen(DEFINITIONS_STATEMENT)))) {
00297
00298
00299 output_definition_macro(value, cfg_accumulator);
00300 } else {
00301
00302
00303 output_decorated_macro(symbol, value, cfg_accumulator, ver_accumulator);
00304 }
00305 }
00306
00307
00308 ver_accumulator += "\n";
00309 ver_accumulator += " // calculated macros are dropped in here.\n\n";
00310
00311
00312
00313
00314
00315 ver_accumulator += " #define __build_SYSTEM_VERSION \"";
00316 ver_accumulator += _ver->flex_text_form();
00317 ver_accumulator += "\"\n\n";
00318
00319
00320 ver_accumulator += " #define __build_FILE_VERSION_COMMAS ";
00321 ver_accumulator += _ver->flex_text_form(version::COMMAS);
00322 ver_accumulator += "\n";
00323
00324 ver_accumulator += " #define __build_FILE_VERSION \"";
00325 ver_accumulator += _ver->flex_text_form();
00326 ver_accumulator += "\"\n";
00327
00328
00329 _ver->set_component(version::REVISION, "0");
00330 _ver->set_component(version::BUILD, "0");
00331
00332 ver_accumulator += " #define __build_PRODUCT_VERSION_COMMAS ";
00333 ver_accumulator += _ver->flex_text_form(version::COMMAS);
00334 ver_accumulator += "\n";
00335
00336 ver_accumulator += " #define __build_PRODUCT_VERSION \"";
00337 ver_accumulator += _ver->flex_text_form(version::DOTS, version::MINOR);
00338 ver_accumulator += "\"\n";
00339
00340
00341 cfg_accumulator += "\n";
00342 cfg_accumulator += "/*\n";
00343 cfg_accumulator += "These settings were not used:\n";
00344 cfg_accumulator += *_end_matter;
00345 cfg_accumulator += "*/\n";
00346 cfg_accumulator += "\n";
00347 cfg_accumulator += "#endif /* outer guard */\n\n";
00348
00349
00350 ver_accumulator += "\n";
00351 ver_accumulator += "#endif /* outer guard */\n\n";
00352
00353 if (!write_output_file(cfg_header_filename, cfg_accumulator)) {
00354 LOG(istring("failed writing output file ") + cfg_header_filename);
00355 }
00356 if (!write_output_file(ver_header_filename, ver_accumulator)) {
00357 LOG(istring("failed writing output file ") + ver_header_filename);
00358 }
00359
00360 return 0;
00361 }
00362
00363 HOOPLE_MAIN(write_build_config, )
00364
00365 #ifdef __BUILD_STATIC_APPLICATION__
00366
00367 #include <basis/array.cpp>
00368 #include <basis/byte_array.cpp>
00369 #include <basis/callstack_tracker.cpp>
00370 #include <basis/chaos.cpp>
00371 #include <basis/convert_utf.cpp>
00372 #include <basis/definitions.cpp>
00373 #include <basis/earth_time.cpp>
00374 #include <basis/guards.cpp>
00375 #include <basis/istring.cpp>
00376 #include <basis/log_base.cpp>
00377 #include <basis/memory_checker.cpp>
00378 #include <basis/mutex.cpp>
00379 #include <basis/object_base.cpp>
00380 #include <basis/outcome.cpp>
00381 #include <basis/packable.cpp>
00382 #include <basis/portable.cpp>
00383 #include <basis/sequence.cpp>
00384 #include <basis/set.cpp>
00385 #include <basis/utility.cpp>
00386 #include <basis/version_checker.cpp>
00387 #include <basis/version_record.cpp>
00388 #include <data_struct/amorph.cpp>
00389 #include <data_struct/bit_vector.cpp>
00390 #include <data_struct/byte_hasher.cpp>
00391 #include <data_struct/configurator.cpp>
00392 #include <data_struct/hash_table.cpp>
00393 #include <data_struct/pointer_hash.cpp>
00394 #include <data_struct/stack.cpp>
00395 #include <data_struct/static_memory_gremlin.cpp>
00396 #include <data_struct/string_hash.cpp>
00397 #include <data_struct/string_hasher.cpp>
00398 #include <data_struct/string_table.cpp>
00399 #include <data_struct/symbol_table.cpp>
00400 #include <data_struct/table_configurator.cpp>
00401 #include <loggers/console_logger.cpp>
00402 #include <loggers/file_logger.cpp>
00403 #include <loggers/locked_logger.cpp>
00404 #include <loggers/null_logger.cpp>
00405 #include <loggers/program_wide_logger.cpp>
00406 #include <opsystem/application_base.cpp>
00407 #include <opsystem/application_shell.cpp>
00408 #include <opsystem/byte_filer.cpp>
00409 #include <opsystem/command_line.cpp>
00410 #include <opsystem/critical_events.cpp>
00411 #include <opsystem/directory.cpp>
00412 #include <opsystem/filename.cpp>
00413 #include <opsystem/ini_config.cpp>
00414 #include <opsystem/ini_parser.cpp>
00415 #include <opsystem/path_configuration.cpp>
00416 #include <opsystem/rendezvous.cpp>
00417 #include <opsystem/version_ini.cpp>
00418 #include <textual/byte_format.cpp>
00419 #include <textual/parser_bits.cpp>
00420 #include <textual/string_manipulation.cpp>
00421 #include <textual/tokenizer.cpp>
00422 #endif // __BUILD_STATIC_APPLICATION__
00423